UI DESIGN SPECIFICATION
VietGara — Multi-Tenant SaaS Platform for Auto Garage Management & Maintenance
Version 2.0 (approved and implemented) — October 7, 2026 · Cloud: Google Cloud Platform (GCP) · Backend: Go
v2 replaces v1 (
../v1/02_UI_Design_Spec.md) for all work (approved by the product owner on October 7, 2026; implemented in the web apps and the Flutter core package); the redesign is described in04_UI_Audit_and_Redesign_Proposal.md.
1. Introduction
This document specifies the content, layout, and behavior of the main screens in VietGara in detail. It does not repeat visual values: exact colors, type, spacing, radius and component states are defined once, in 03_Design_System.md and in the code that implements it (vietgara-web-ui, vietgara_core). This document describes the content and behavior requirements for each screen.
The layout diagrams below use block notation (text-based wireframes, which Mermaid cannot express) purely to illustrate structure and do not reflect the final visual design; flows are drawn in Mermaid.
2. General Conventions
2.1. Grid & Breakpoints
| Platform | Breakpoint | Grid Columns | Notes |
|---|---|---|---|
| Owner Web | ≥1280px (desktop) | 12 columns, 24px gutter | Primary layout, optimized for office screens |
| Owner Web | 768–1279px (tablet) | 8 columns, 16px gutter | Sidebar collapses to an icon rail with tooltips |
| Owner Web | <768px (phone) | 4 columns, 16px gutter | Usable, not optimized (the Flutter Owner App is the phone product): the sidebar is replaced by a menu button opening a navigation sheet (garage switcher at its top); tables become card lists; dialogs become bottom sheets; the primary action is full width; text inputs are 16px; touch targets are at least 44px |
| Customer App / Technician App | Native 8pt grid (iOS/Android) | 4 columns (mobile) | No desktop layout needed |
2.2. Standardized States (applied to every screen with dynamic data)
| State | Display Requirement |
|---|---|
| Loading | A skeleton screen matching the upcoming content layout — never a full-screen spinner or a bare “Loading…” line; the region is aria-busy; no layout shift when data arrives |
| Empty (no data yet) | A spot illustration + a short explanation + a CTA for the next action (e.g. “No quotes yet — Create your first quote”); a zero-result search is a separate state that offers “Clear filters” |
| Error (failed to load data) | An error message stating the cause (if known) + a “Retry” button, shown in place of the content that failed; action errors appear as a toast (or beside the control that caused them), not as stacked banners at the top of the page |
| Success (after an action) | A short toast (“Quote saved”), with Undo where the action is reversible |
| Offline (Technician App only) | A persistent banner at the top of the screen, not blocking interaction, stating the number of actions pending sync |
2.3. Web Shell and Page Template
- Shell: a light sidebar grouped as Operations (Dashboard, Quotes, Repair Orders, Inventory), Customers (Customers, Vehicles, Suppliers), Finance (Billing & Receivables, Reports), Garage (Staff, Roles, Garage settings) and Account (Subscription, Invitations, Account); items follow the member’s permissions as in UX Guideline 4.1. A 56px top bar holds the garage switcher, global search / command palette (
Ctrl/⌘ K), language, invitations bell and the user menu (sign out). The sidebar can be collapsed to an icon rail with a toggle at its foot (remembered per browser, default expanded); a collapsed sidebar opens over the page, without shifting content, when the mouse rests on it for 150 ms or keyboard focus enters it (Design System 4.22). Below 1024px it is the icon rail, below 768px a navigation sheet. The Admin Web uses the same shell with Plans, Subscriptions and Account and no garage switcher. - Page template: title (24px), optional one-line description (first-use empty states only), primary action on the right, tabs under the title when a page has several views; a breadcrumb trail only on detail and edit pages (it replaces the garage name currently shown above list pages); content in panels on the page background; a sticky action bar for long forms. Every page sets its document title (“Quotes · Garage A · VietGara”) and moves focus to its heading on route change.
- Lists: search and filters sit above the table in one toolbar with active-filter chips; the table follows the Data Table component (Design System 4.15).
3. Screen Specifications — Owner Web
3.1. Dashboard
Purpose: Gives the garage owner an overview immediately upon login: revenue, repair orders in progress, low-stock alerts, overdue receivables.
+--------------------------------------------------------------+| [Logo] [Select garage: Garage A v] [Notifications] [Avatar] |+---------+------------------------------------------------------+| Sidebar | KPI Cards: Monthly revenue | Orders in progress | AR || - Dashb.|------------------------------------------------------|| - Quotes | Revenue chart, last 30 days || - Orders |------------------------------------------------------|| - Stock | Alerts: [Low stock: 3 items] [Overdue receivables] || - Cust. |------------------------------------------------------|| - Reports| List of repair orders in progress (5 most recent) |+---------+------------------------------------------------------+UI components used (from the Design System):
- Sidebar Navigation
- KPI Card
- Chart (line/bar)
- Alert Banner
- Data Table (condensed) | State | Display Requirement | | --- | --- | | Empty (new garage) | KPIs show 0, chart replaced with guidance: “Create your first quote to get started” | | Loading | Skeleton for each KPI Card and the chart |
Release 1.5: “Monthly revenue” and the revenue chart are the one figure this screen needed that nothing already served — both come from the new Reporting revenue-by-period endpoint (API Specification 13.1). “Orders in progress”, “AR” (outstanding receivables) and the low-stock alert, and the in-progress orders list, are each composed from the module that already owns that data (Repair Order, Billing & Settlement’s outstandingOnly filter, Inventory) — the screen itself does the composing, not a new backend aggregate call.
3.2. Quote List & Creation
Purpose: Lets the service advisor create a quote quickly while the customer waits, selecting an existing vehicle/customer or creating a new one inline.
+--------------------------------------------------------------+| Quotes > New [Save][Send] |+--------------------------------------------------------------+| Customer: [Search/Select...] [+ New] || Vehicle: [Search by plate...] [+ Add new vehicle] || Approval: (o) Send a link ( ) Record manually |+--------------------------------------------------------------+| Labor / Parts line items || [+ Add line item] || ---------------------------------------------------------------|| | Description | Qty | Unit price | Line total | [x] || | Oil change... | 1 | 250,000 | 250,000 | |+--------------------------------------------------------------+| Total: 730,000 VND |+--------------------------------------------------------------+UI components used (from the Design System):
- Autocomplete Search (customer/vehicle)
- Dynamic Table (add/remove rows)
- Currency-formatted Number Input
- Segmented Control (approval mode: Send a link / Record manually)
- Sticky Footer (total + action buttons) | State | Display Requirement | | --- | --- | | Draft saving | Show a small indicator “Saved at HH:mm” next to the Save button | | Missing required field | Disable the “Send” button, highlight the missing field with a red border + a specific message |
Approval mode (FR-QUO-02): pre-selected from the garage’s default (Garage Settings), changeable per quote. Pressing Send:
- Send a link — generates the public approval link; a confirmation shows it with a “Copy link” button and states whether it was also e-mailed (“E-mailed to {customer}” or “No e-mail on file — share the link yourself”). The quote’s status badge becomes “Sent”.
- Record manually — no link or e-mail; the quote’s status becomes “Sent” and the screen opens the Record decision panel directly: the same line list with an Approve/Reject toggle per line and a “Save decision” button, for the advisor to enter what the customer said face to face.
Once decided (either path), the quote becomes read-only with an “Approved”/“Rejected” badge and, when approved, a Convert to repair order button.
3.3. Repair Orders — Kanban Board
Purpose: Shows service advisors/garage owners every repair order in progress by status, with the status derived from line progress (the board itself is read-only; Q7).
+--------------------------------------------------------------+| Repair Orders [Filter: Technician v] |+------------+------------+------------+---------------------+| To Do | In Progress| Waiting on | Completed || (3) | (5) | Parts (1) | (2 today) ||------------|------------|------------|---------------------|| [Card A] | [Card C] | [Card E] | [Card F] || [Card B] | [Card D] | | [Card G] |+------------+------------+------------+---------------------+The board is read-only (Q7 decided in the UI audit, 04_UI_Audit_and_Redesign_Proposal.md): the card’s column is derived from line progress (next paragraph), so cards are never dragged between columns, and each card has a keyboard-accessible status menu. A card at risk of delay shows the warning border plus a clock icon (never color alone), and each column header shows its count.
Opening a card shows its detail panel: the order’s lines, each with an item-type badge (Labor/Part), a per-line status control (Not Started/In Progress/Completed) and a technician multi-select (FR-REP-02) — one or more technicians per line, not per order. The card’s column is derived automatically from line progress, not moved by a free drag between arbitrary columns: editing a line’s status is what actually advances the card. A Close button, enabled once every line reads Completed, performs the explicit close action (FR-REP-06) and removes the card from the board.
UI components used (from the Design System):
- Kanban Column
- Kanban Card (plate, technician name, time, priority badge)
- Card Detail Panel: per-line status control, technician multi-select, Close button
- Filter Dropdown | State | Display Requirement | | --- | --- | | Card at risk of delay | Card border switches to a warning color (amber/red) + a clock icon | | Waiting on Parts | Defined status, but Release 1.3 has no automatic trigger for it — no inventory-stock link to Repair Order yet |
3.4. Inventory — Stock on Hand
Purpose: Lets inventory staff quickly check current stock levels and spot parts running low.
+--------------------------------------------------------------+| Inventory > Stock on Hand [Search...] [+ New goods receipt] |+--------------------------------------------------------------+| SKU | Part Name | On Hand | Reorder Threshold | ... || P-001 | Engine oil 4L | 12 | 5 | || P-002 | Engine air filter| 2 (!!) | 5 | |+--------------------------------------------------------------+The + New goods receipt button opens the goods receipt editor (FR-INV-06): a header with the receipt date, the delivery note number, notes and an optional default supplier, and lines of part (searched by SKU/name), quantity, unit cost (optional) and supplier. Save draft changes no stock; Complete receipt records the stock-in movements and refreshes the On Hand and average cost of each part. The Goods receipts tab lists the receipts (FR-INV-06), Stock Movements lists every transaction (FR-INV-05) newest first — direction (In/Out), quantity, reference (goods receipt or stock issue), date — filterable by part and direction, matching the Data Table conventions of Quote List (3.2).
UI components used (from the Design System):
- Data Table with sort/filter
- Low-stock warning Badge (red/amber)
- Search Input
- Goods receipt editor (full page): header fields, line table with part search, quantity, unit cost and supplier per line, running total
- Goods receipts tab and Stock Movements tab: Data Tables with status, supplier and direction/part filters
- Purchases and Stock valuation tabs: Data Tables with Excel export (visible only with the cost permission) | State | Display Requirement | | --- | --- | | Low stock | Red badge + a subtly highlighted row background, not relying on text color alone (accessibility) |
3.5. Sign-in, Sign-up, E-mail Verification and Password Reset
Purpose: let an owner start in minutes and recover access without support (FR-IAM-01/02/04).
+---------------------------+----------------------------------+| Brand panel | [Language: VI v] || tagline, 3 feature bullets| Sign in || | [ G Continue with Google ] || | ---------- or ---------- || | Email [ ] || | Password [ ] (eye) || | Forgot password? || | [ Sign in ] || | No user yet? Create one |+---------------------------+----------------------------------+stateDiagram-v2 [*] --> SignUp SignUp --> VerifyEmail: user created, code e-mailed SignIn --> VerifyEmail: e-mail not verified (a new code is sent) SignIn --> Garages: verified VerifyEmail --> Garages: correct code VerifyEmail --> VerifyEmail: resend (after 30 s) SignIn --> ForgotEmail: Forgot password? ForgotEmail --> ForgotCode: code e-mailed ForgotCode --> NewPassword: correct code NewPassword --> SignIn: password changed
| Element | Behavior |
|---|---|
| Sign-up form | Full name, e-mail, optional phone, password (≥ 8, hint shown); the current interface language becomes the user language |
| OTP field | 6 digits, numeric keyboard, one-time-code autofill; countdown “Code expires in 1:52”; submit disabled once expired; “Resend code” disabled with a 30 s countdown |
| Unverified user | Every page except Account redirects to verification; the page explains that garages, staff and data are available after verification |
| Password reset | Three steps on one page (e-mail → code → new password + confirmation); the e-mail step never reveals whether the user exists |
| Errors | Translated from the API error code (e.g. OTP_EXPIRED → “The code has expired. Request a new one.”) |
3.6. Garages and Garage Settings
- Garages: one row per garage with logo, name, address, “Owner”/“Staff” tag, Active/Inactive status, “Open” (switch the active garage) and a settings button when the user may edit it. Empty state: “No garage yet — create your first garage”. Creating a garage beyond the plan shows the
PLAN_LIMIT_REACHEDmessage with a link to Subscription. - Garage settings (
/garages/:id/settings), cards saved independently: Profile (name, address, phone, e-mail, tax ID); Configuration (time zone, currency, quote and repair-order numbering templates with the placeholder hint, and a default quote approval mode — Send a link / Record manually, FR-QUO-02 — new quotes start with, still changeable per quote); Operating hours (7 rows: open checkbox, opens, closes); Logo (preview, upload PNG/JPEG/WebP ≤ 1 MB, remove); Status (owner only: deactivate with a confirmation that explains staff lose access, or reactivate). Users withoutgarage.writesee the page read-only.
3.7. Staff, Invitations, Roles and Groups
+--------------------------------------------------------------+| Staff [+ Invite staff] || Members || (AV) An Vo [email protected] · 0901.. Service Advisor ● Active ⋯ || (BN) Binh [email protected] Technician ○ Inactive ⋯ || Invitations || Chi [email protected] Technician Pending Expires 03/10 [Revoke]|+--------------------------------------------------------------+- Invite: a dialog with one field “E-mail or phone” and “Find”; the found user is shown with its name and contact; if it is already a member or invited, a notice replaces the form; otherwise the owner ticks staff groups and presses “Send invitation”.
- Member actions (with
staff.write): change groups, deactivate/reactivate, remove (confirmation states that access is lost immediately). The owner row has no actions. - Roles & groups (owners,
/roles): roles list (name, Default tag, permission count, “used by N groups”) with Add and Edit opening the role editor; below, the active garage’s groups (name, role, member count) with create/edit/delete. - Role editor (owners,
/roles/new,/roles/:id/edit), a full page rather than a dialog so it stays readable on mobile:- Header: breadcrumb back to Roles & groups, and a role selector (edit mode) that switches to another role’s editor.
- Name and description fields; an impact line: “Applies at once to all your garages, for the members of N groups using this role” (or “No staff group uses this role yet”).
- Permission grid: one row per catalogue module, in catalogue order, and two columns: View (
<module>.read) and Add & edit (<module>.write). Each cell is a checkbox labelled with the permission’s description (e.g. “View customers and vehicles”). A cell whose action the module does not offer shows ”—” (screen readers: “Not available”). Modules of later releases (quotes, repair orders, inventory, billing, reports) are muted with a “Coming soon” tag but stay editable, so owners can prepare roles in advance. - Write includes read: ticking Add & edit also ticks View; unticking View also unticks Add & edit.
- Reset to default (default roles only, next to the impact line): replaces the grid with the permissions the platform created the role with (
defaultPermissions). The name and description are kept. The result is an unsaved change like any other, reviewed in the grid and applied with Save. The button is disabled when the grid already matches the defaults. - Save bar (sticky at the bottom): “N unsaved changes” / “No unsaved changes”, Undo changes and Save. Save is enabled only with changes and a name, and sends the role’s whole permission set in one request. It then shows “Changes saved.” (or “Role created.” after a create, which moves to the new role’s editor).
- Unsaved changes: leaving the page or picking another role in the selector opens “Discard unsaved changes?” (Cancel / Discard); closing or reloading the tab triggers the browser’s own warning.
- My invitations (
/invitations, linked from the e-mail as/invitations/:id): “{inviter} invites you to join {garage}” with Accept / Decline; a badge on the navigation item and a dot on the bell show pending invitations.
3.8. Subscription (Owner Web) and Platform Administration (Admin Web)
- Subscription (all verified users): current plan and status, period/trial end, grace end when read-only; usage meters for garages, staff and today’s transactions against the plan limits; plan cards (price per month/year, limits line “2 garages · 20 staff · 100 transactions/day”, features) with “Choose this plan” or “Renew”, the credit balance, and the open payment request with its status. Choosing a plan opens the payment request sheet (FR-LIC-07): the plan limits check (an invalid plan names the exceeded limits and cannot continue), the amount due with the credit for the unused days, the platform’s bank details with the QR code and the transfer reference with a copy button, then the form with the payer, bank, account, amount, bank transaction reference, date and an evidence screenshot; a submitted request shows “Waiting for review”, its cancel action, or the rejection reason with a way to submit again.
- License banner (all Owner Web pages): trial countdown (info), read-only (warning), suspended (error); owners get a “Choose a plan” button, staff are told to contact the owner.
- Admin Web — Plans (
/plans,vietgara-admin-web): table (code, name, price, limits, active/hidden) and a two-column plan form (code fixed after creation, price, currency, cycle, the three limits, features, public, active, sort order). - Admin Web — Subscriptions (
/subscriptions): search by owner e-mail or name, status filter, paginated table (owner, plan, status, period end, usage) with “Extend” (number of days), the credit balance and an open-request badge. - Admin Web — Payment requests (
/payment-requests): the review queue of submitted requests (owner, plan, quoted and declared amounts with a mismatch warning, submitted time, waiting days); a detail with the evidence image, the owner’s plan and usage, Approve (a note is required when the amounts differ) and Reject (reason required). - Admin Web — Payment details (
/payment-settings): bank, account number, holder, branch, transfer instructions and the QR code upload with a preview; a change shows who and when it was last edited.
3.9. Header and Language
The header of the Owner Web holds the active-garage selector (a popover listing the member’s garages with search, switching in place — not a link to the Garages page), a language switcher (Tiếng Việt / English, Vietnamese by default; the choice is saved on the user), the invitations bell and sign-out. The sidebar shows only the modules the member’s permissions allow; modules of later releases appear disabled with a “Soon” tag. The Admin Web has no garage selector: its sidebar lists Plans, Subscriptions and Account, and the header holds the language switcher and sign-out. Non-admin users see an “Access denied” page.
3.10. Vehicle Detail — Repair History
Purpose: Lets a service advisor or owner see everything that has been quoted or done on a specific vehicle before creating a new quote (FR-CUS-03).
+--------------------------------------------------------------+| < 51F-123.45 - Toyota Vios [+ New quote] |+--------------------------------------------------------------+| Owner: Nguyen Van A · 0901234567 |+--------------------------------------------------------------+| History || LSC-202609-0003 Repair Ord. In Progress 730,000 VND 30/09/26 || BG-202609-0007 Quote Approved 730,000 VND 30/09/26 || BG-202608-0012 Quote Converted 1,250,000 VND 12/08/26 |+--------------------------------------------------------------+UI components used (from the Design System): Data Table (condensed), Status Badge (per entry type/status), Empty state.
| State | Display Requirement |
|---|---|
| Empty (no history yet) | “Quotes, repair orders and settlements for this vehicle appear here — create the first quote to get started.” |
| Loading | Skeleton rows matching the table layout |
Release 1.2 lists quotes; Release 1.3 adds repair orders to the same list (its own type badge and status text), newest first regardless of type; settlements join in Release 1.4.
3.11. Billing & Receivables (Release 1.4)
Purpose: Lets the Garage Accountant turn a closed repair order into a settlement, record what the customer actually paid, and track what is still outstanding — one list, not two screens (UX Guideline 5.4).
+--------------------------------------------------------------+| Billing & Receivables [ ] Outstanding only [Status: v] |+--------------------------------------------------------------+| Number | Customer | Vehicle | Total | Status || QT-202610-0001 | Nguyen V.A | 51F-123.45 | 1,000,000| Pending|| QT-202609-0042 | Tran T.B | 29A-456.78 | 730,000| Partial|+--------------------------------------------------------------+The Outstanding only toggle is FR-REC-01’s receivables view — a client-side label over the same list with outstandingOnly=true, not a different page. A closed repair order with no settlement yet shows a Create settlement action on its own detail screen (Section 3.3); creating one here is a single confirmation, nothing to fill in (FR-BIL-01). Opening a settlement row shows its detail panel:
+--------------------------------------------------------------+| QT-202610-0001 [Export receipt PDF] |+--------------------------------------------------------------+| Customer: Nguyen Van A Vehicle: 51F-123.45 || Total: 1,000,000 VND Status: Partially paid |+--------------------------------------------------------------+| Payments [ + Record payment ] || 30/09/26 Cash 300,000 Voucher 0001 |+--------------------------------------------------------------+The customer is the only payer (Release 5.0; the insurer split returns in Phase 17), so there is no allocation form. Record payment opens a short form (amount, method, payer, reason, collector, note); the amount field is capped to what is still due, and the status badge updates immediately (Pending → Partially paid → Paid) once saved. Export receipt PDF (FR-DOC-01) downloads the document directly, no preview step, the same pattern as the Quote and Repair Order PDF buttons below.
UI components used (from the Design System):
- Data Table with status filter and a toggle filter (Outstanding only)
- Status Badge (Pending/Partially paid/Paid)
- Record Payment form (Modal): amount (capped), method select, payer name and address (default: the customer), reason, collector, note
- Export button (PDF download, no preview)
| State | Display Requirement |
|---|---|
| No settlement yet on a closed order | “Create settlement” button on the repair order’s own detail screen, not here |
| Payment amount exceeds what is due | Inline validation before submit, not a server round-trip |
| Empty (no settlements yet) | “Settlements appear here once a repair order is closed and settled.” |
PDF/Excel export buttons also appear on the screens that already existed: the Quote List & Creation detail view (3.2) and the Repair Order Kanban card panel (3.3) each get an Export PDF button (FR-DOC-01); the Inventory Stock Movements tab (3.4) gets an Export Excel button (FR-DOC-02) next to its existing filters. All three share the same no-preview, direct-download pattern as the settlement receipt above.
4. Screen Specifications — Customer App
4.1. Quote Detail & Approval
Purpose: Lets the customer clearly see each line item and the total, and decide to approve/reject — this is the single most trust-critical screen for the customer. Reached only when the advisor chose the Send a link approval mode (FR-QUO-02); a Record manually quote never shows this screen to the customer at all — the advisor enters the decision directly in Owner Web instead (Section 3.2). Delivered in Release 1.2 as a public, no-login web page at the link’s URL; it moves into the native Customer App shown below once that app ships (Phase 2), same content and rule.
+----------------------------+| < Quote #Q-1024 |+----------------------------+| Vehicle: 51A-123.45 - Toyota Vios|| Line items: || - Engine oil change 250,000|| - Air filter (x4) 480,000|+----------------------------+| Total: 730,000 VND|+----------------------------+| [ Reject ] [ Approve Quote ]|+----------------------------+UI components used (from the Design System):
- Line Item List
- Sticky Bottom CTA (2 buttons, Approve emphasized)
- Price Formatting | State | Display Requirement | | --- | --- | | Approved | Hide the 2 action buttons, show a badge “Approved at HH:mm” + a “View repair order” button |
4.2. Real-Time Repair Progress Tracking
Purpose: Lets the customer know exactly what stage their vehicle is at without calling the garage.
+----------------------------+| Repair progress: 51A-123.45 |+----------------------------+| [x] Received || [x] In repair || [ ] Quality check || [ ] Ready for pickup |+----------------------------+| Latest photo update: [img] |+----------------------------+UI components used (from the Design System):
- Stepper/Progress Timeline
- Image Gallery (photos uploaded by the technician) | State | Display Requirement | | --- | --- | | Real-time update | The timeline auto-updates without requiring a refresh (via push/socket), with a subtle animation when a new status arrives |
5. Screen Specifications — Technician App
5.1. Today’s Repair Order List
Purpose: Lets the technician see what needs to be done as soon as they open the app, without needing to search.
+----------------------------+| Today - Jul 12 [Sync: OK]|+----------------------------+| [Card] 51A-123.45 || Oil change + air filter || Status: In progress |+----------------------------+| [Card] 29B-678.90 || Brake inspection || Status: Not started |+----------------------------+UI components used (from the Design System):
- Sync indicator (top corner)
- Large Task Card, easy to tap with a thumb
- Status Badge | State | Display Requirement | | --- | --- | | Offline | Persistent amber banner: “Offline — 2 changes pending sync” |
5.2. Update Line Item + Take Photos
Purpose: The technician’s core action of the day — needs to minimize the number of taps.
+----------------------------+| Engine oil change |+----------------------------+| [ Not started ] || [ In progress ] (selected) || [ Completed ] |+----------------------------+| Before/after photos: [+][+][+]|+----------------------------+| [ Save Update ] |+----------------------------+UI components used (from the Design System):
- Segmented Control (status selection, not a dropdown)
- Photo Capture Button (opens camera directly)
- Large Primary Button | State | Display Requirement | | --- | --- | | Saving while offline | Button changes to “Saved locally” with an hourglass icon, no error shown |
6. Developer Handoff
- Every screen in this document is built from the kit (web) or the core widgets (mobile) and shows every state: default, loading, empty, error (and success feedback).
- Components used in a specification are the ones in 03_Design_System.md — never hand-build basic controls (input, button, table) inside a page.
- Before handoff, run the design QA checklist in 03_Design_System.md, Section 10.