Screens reference

Every page in the live app (https://idp.ethanseow.com), grouped by nav area: what each page is, what it shows, what you can do, and the API behind it. For task walkthroughs see Users; for the full endpoint list see Functions.

A captioned screenshot set exists for the user-facing pages (kept out of git to avoid committing live client/member data); ask for an illustrated internal version.

The nav: Quotes · Builder · SOWs · Procurement▾ · P&L · Forecast · Carpentry▾ · Team · Admin, with a 🌙/☀️ theme toggle and a workspace switcher (when you belong to more than one). Sign in lands you on a launcher grouping every destination.


Sales

Quotes — /ui/quote_send_accept

Send & accept quotes, and import a BOQ into a structured quote. - You see: every quote for the workspace (number · project · client · status pill · total), newest first. - You can: open a quote (→ line items, totals, timeline, Send to client / Mark accepted); or Import a BOQ → grouped quotedrop a BOQ PDF (Gemini transcribes it) or paste CSV rows; lines are auto-classified onto the trade taxonomy and rolled into Section → Group → Line. - Behind it: GET /quotes, GET /quotes/{id}, POST /quotes/{id}/send|accept, POST /quotes/extract-boq-pdf · extract-boq · import-boq.

Quote builder — /ui/quote_builder?quote_id=…

Build/edit a quote line by line. - You see: the editable line grid (description · trade · qty · unit · unit-cost · markup · line price), running subtotal/total. - You can: add lines from the catalog (bilingual 中⇄EN search, e.g. hinge finds 铰链), apply a cost suggestion from price history, recommend lines from a materials list (paste → auto-match SKUs → review → add), and save/apply templates. Lines are editable while the quote is draft. - Behind it: GET/POST/PATCH/DELETE /quotes/{id}/lines, /quotes/{id}/lines/reorder|{line}/choose, /catalog/skus/search, /quotes/{id}/recommend-lines, /quote-templates.

BOQ view — /ui/boq?quote_id=…

The grouped Bill of Quantities for a quote, with sub-totals + PDF. - You see: a summary table (section totals → grand total, always reconciling), then every section with group sub-totals and line items; Included = bundled, TBC = provisional (excluded from total). - You can: Download PDF (server-rendered, branded) or Print; and verify flagged lines — a "verify trade" dropdown lets a human confirm the trade. Confirmations are learned per workspace, so the same line auto-classifies (unflagged) on future imports. - Behind it: GET /quotes/{id}/boq, GET /quotes/{id}/boq.pdf, PATCH /quotes/{id}/lines/{line}/classify.

Quotation (printable) — /ui/quote?quote_id=…

A clean, standalone rendering of one quotation, grouped for printing/sharing. - You see: the quote rendered server-side, grouped by kind, formatted for a tidy print/PDF or a quick read — distinct from the editable Builder and the BOQ breakdown. - You can: print, or use it as the human-readable face of a quote.

SOWs & milestones — /ui/sow_milestones

Statements of Work (created when a quote is accepted) and their billing. - You see: every SOW (number · project · client · status · milestone count · contract value); open one for milestones (name · % · amount), scheduled client invoices, variations. - You can: Schedule invoices (draft invoices from the milestone schedule), Generate POs (draft purchase orders grouped by vendor). - Behind it: GET /sows, GET /sows/{id}, POST /sows/{id}/invoices/schedule · /generate-pos, POST /billing/schedule-milestones.

Forecast — /ui/forecast

The weighted sales pipeline. - You see: pipeline value weighted by win-probability, with expected margin. - Behind it: GET /forecast/pipeline.

Project P&L — /ui/project_pnl

Per-project revenue vs cost. - You see: projects with contract value; open one for revenue (contract) vs cost (committed POs / actual bills), gross margin, and cost variance. - Behind it: GET /projects, GET /projects/{id}, GET /pricing/projects/{id}/actuals.

Margin tracker — /ui/margin_tracker

Where margin is set and watched across quotes/projects. - You see: margin per quote/project against the workspace's margin rules. - You can (admin): set margin rules and per-SKU cost overrides that feed the sell-side maths. - Behind it: GET /admin/margin-tracker, POST /admin/margin-rules, POST /admin/sku-overrides.


Carpentry & warehouse

Warehouse — /ui/warehouse

Stock levels derived from an append-only ledger. - You see: stat cards (SKUs/items · on-hand · reserved), a Record event form, and a low-stock table (item · available · reorder point). - You can: record stock events (receive / consume / adjust…) and Draft reorder POs for everything under its reorder point. - Behind it: GET /warehouse/{levels,low-stock,locations}, POST /warehouse/events, POST /approvals/reorder.

Inventory dashboard — /ui/inventory_dashboard

The visual at-a-glance view of stock. - You see: total inventory value, distinct SKUs, units on hand, low-stock & negative-stock counts; value by material type (hardware · tools · lighting · boards · adhesives · fixings · finishing · measuring · electrical), value by location, and the most-urgent low-stock items. - You can: spot where value sits and what's running low at a glance. Material type is inferred from each SKU's name; correct a mislabel by setting Material type on the SKU (Catalog). When SKUs span currencies, value is shown for the dominant currency with a "mixed currencies" note. - Behind it: GET /warehouse/dashboard.

Job board — /ui/job_board

Fabrication work-orders by status. - You see: work-orders grouped by stage (cutting → assembly → finishing → done). - You can: open a work-order; create new ones; seed a cutting list from a quote. - Behind it: GET /work-orders, POST /work-orders, POST /work-orders/{id}/seed-from-quote.

Work order — /ui/work_order?wo=…

One fabrication job in detail. - You see: the work-order Status, its Cutting list (BOM), and a Draw stock panel. - You can: move the job through stages, add BOM lines, and reserve/consume materials against the warehouse ledger (drawing stock from a chosen location). - Behind it: GET /work-orders/{id}, POST /work-orders/{id}/status · /bom · /reserve · /consume, GET /warehouse/locations.

Approvals — /ui/approvals

The draft-and-approve gate (human-in-the-loop). - You see: pending drafts for outward/irreversible actions (reorder PO, customer reply). - You can: approve (executes) or reject. Internal stock effects auto-apply; only external actions queue here. - Behind it: GET /approvals, POST /approvals/{id}/approve|reject.

Catalog & locations — /ui/catalog

SKUs, vendors, categories, and stock locations. - You see: stock locations, vendors, categories, and the full SKU table (code · description · vendor · cost · reorder point/qty) — bilingual SKU names supported. - You can: add/edit SKUs (with aliases), locations, set reorder thresholds, and set a material type override for the inventory dashboard. - Behind it: GET /catalog/{skus,vendors,categories}, POST /catalog/skus, PATCH /catalog/skus/{id}, GET /warehouse/locations.


Procurement & pricing (Procurement▾ menu)

Purchase orders & bills — /ui/po_bill

POs with goods receipts and vendor bills. - You see: every PO (vendor · project · status · GRN/bill counts · total); open one for line items, goods receipts, vendor bills. - You can: Send to vendor (issue a draft PO), record a goods receipt, capture a bill, run the 3-way match, record a vendor payment. - Behind it: GET /pos, GET /pos/{id}, POST /pos/{id}/send · /grn · /bills, POST /bills/{id}/match · /payments.

RFQ — /ui/rfq_compose

Request quotes from suppliers via magic links. - You see: every RFQ (title · project · status · quote count). - You can: create an RFQ, invite a vendor by email (issues a magic link — no account needed), Send, view received supplier quotes, Compare →. - Behind it: GET /rfqs, GET /rfq/{id}, POST /rfq · /rfq/{id}/invite|send, GET /rfq/{id}/compare.

Supplier comparison — /ui/supplier_comparison?rfq_id=…

Side-by-side supplier quotes for an RFQ. - You see: a line-by-line matrix across suppliers, cheapest cell marked ✓, totals + lead times. - You can: Accept a supplier quote → drafts a PO automatically. - Behind it: GET /rfq/{id}/compare, POST /supplier-quotes/{id}/accept.

Historical import — /ui/historical_import

Seed pricing intelligence from past quotes/bills. - You see: recent imports (file · kind · status · rows/matched/pending). - You can: upload a CSV/Excel/PDF; per-import, review fuzzy SKU matches (Link / New SKU). Each line lands as a price observation → smarter cost suggestions. - Behind it: GET /imports, GET /imports/{id} · /candidates, POST /imports, POST /imports/candidates/{id}/resolve.


Design intake (sketch / scan → plan)

Sketch → priced quote — /sketch

Legacy VLM demo: a plan photo/sketch → walls, surfaces, fixtures → a priced quote. - You see: project + dimensions inputs, a photo/scan dropzone, and steps to Decompose, Detect interior walls (VLM), doors, fixtures, and finishes. - You can: run the extraction pipeline that absorbs the sketch2plan prototype (chain-solver, room detection) and turns a drawing into priced lines. - Behind it: POST /projects/{id}/ingest/{photo,pdf,dxf,disto}, POST /plans/{id}/{solve,detect-walls,confirm-walls,detect-doors,detect-fixtures,extract-specs,apply-specs,…}, GET /plans/{id}.

Floorplanner — /ui/floorplanner?plan_id=…

The embedded 3D canvas (Floorplanner SDK), with the scene saved on the plan. - You see: the Floorplanner iframe for a plan. - You can: design in the canvas; the scene JSON is persisted on the plan and read back for downstream BOM work. - Behind it: GET/POST /plans/{plan_id}/scene.


External pages (no login — magic-link)

Client portal — /ui/client_portal (client opens /portal/{token})

The client-facing quote approval page. - The client sees: What you're approving (the quote summary) and an Approve this quote action — reached through a single-use magic link you issue from the project. - You can (staff): issue the portal link for a project. - Behind it: POST /projects/{id}/client-portal/issue, GET /portal/{token}, POST /portal/{token}/accept-quote.

Respond to RFQ (supplier) — /ui/supplier_response (supplier opens /supplier/respond/{token})

The supplier-facing quote submission page. - The supplier sees: the RFQ lines and a Your quote form — no account required (magic link). They may optionally create a persistent supplier login. - Behind it: GET /supplier/respond/{token}, POST /supplier/respond/{token}, POST /supplier/{signup,login,account/history}.


Admin

Team & roles — /ui/members

Workspace members, roles, and invitations. - You see: members with role (owner / admin / manager / member / staff / viewer) and status; pending invitations. - You can: change a member's role, invite by email, revoke invites. Roles map to granular permissions (who can write quotes, act on approvals, manage warehouse…). - Behind it: GET /members, GET /members/invites, POST/PATCH/DELETE members & invites.

Security (2FA) — /ui/mfa_setup

Enrol an authenticator app (TOTP); scan the QR, confirm a code, save recovery codes. (Optional.) - Behind it: POST /auth/mfa/enroll · /confirm · /disable.

Catalog admin — /admin

Bulk SKU management, designer assignment, and per-user notification channels. - Behind it: POST /admin/sku-overrides · /margin-rules · /projects/{id}/designer · /users/{id}/channels.

Webhook outbox — /ui/admin_outbox

Inspector for outbound integration deliveries. - You see: the IntegrationOutbox rows, filterable by provider + status — what we've sent (or failed to send) to Attio / PandaDoc / ERP / etc. - You can: retry a failed/stuck row (resets it to pending for the next drain), or replay a webhook event. - Behind it: GET /admin/outbox, POST /admin/outbox/{id}/retry, POST /admin/webhooks/{event_id}/replay.


Auth & utility pages

These are reached as part of a flow rather than from the nav:

Page Route Purpose
Home launcher / Post-sign-in tile launcher grouping every destination.
Quick start / Help centre /ui/help In-app version of this wiki (generated from users + this page).
Invite accept /ui/invite_accept?token=… A teammate accepts a workspace invitation.
Verify email /ui/verify_email?token=… Confirm an email address.
Forgot password /ui/forgot_password Request a reset link.
Reset password /ui/reset_password?token=… Set a new password from the emailed link.

See Functions for the complete endpoint reference, or the live interactive API at /docs.