DESIGN SYSTEM
VietGara — Multi-Tenant SaaS Platform for Auto Garage Management & Maintenance
Version 1.0 — July 12, 2026 · Cloud: Google Cloud Platform (GCP) · Backend: Go
Superseded. Version 2 (
../v2/03_Design_System.md) replaces this document; it is kept for history, and where the two differ, v2 is the decision.
1. Introduction & Principles
The Design System is the single source of truth for every visual decision (color, typography, spacing) and UI component in VietGara. Every screen in 02_UI_Design_Spec.md must use components from this system — no ad-hoc variants may be created for individual screens.
Organized following the Atomic Design model: Design Token (color, typography, spacing) → Atom (Button, Input, Icon) → Molecule (Form Field with label+input+error, Card) → Organism (Data Table, Kanban Board) → Template (standard screen layout).
1.1. Figma Structure
The Design System is built in a dedicated Figma file (“VietGara Design System”), published as a Team Library so every product file (Owner Web, Admin Web, Owner App, Admin App, Customer App, Technician App) pulls components in as linked instances — when the Design System is updated, every consumer is notified and can sync.
2. Design Tokens
2.1. Color Palette
| Group | Token | Suggested Hex | Used For |
|---|---|---|---|
| Primary | primary/600 | #2E74B5 | Primary action buttons, links, active state |
| Primary | primary/900 | #1F3864 | Emphasized headings, dark sidebar background |
| Neutral | neutral/50 → neutral/900 | Gray scale #F9FAFB → #111827 | Background, borders, secondary text |
| Semantic | success/600 | #2E7D32 | Completed/success states |
| Semantic | warning/600 | #B26A00 | Low-stock alerts, expiring soon |
| Semantic | error/600 | #C00000 | Errors, destructive actions (delete, cancel) |
| Semantic | info/600 | #0B6BCB | Neutral informational messages |
Every text/background color pair used in a component must achieve a minimum contrast ratio of 4.5:1 (checked using the Figma “Contrast” plugin or equivalent before adding it to the library).
2.2. Typography
| Token | Font size / line-height | Weight | Used For |
|---|---|---|---|
| display/lg | 32px / 40px | Bold | Large page titles (Dashboard) |
| heading/md | 24px / 32px | Semibold | Section headings |
| heading/sm | 18px / 26px | Semibold | Card titles, table column headers |
| body/md | 16px / 24px | Regular | Main content, form labels |
| body/sm | 14px / 20px | Regular | Captions, secondary descriptions |
| caption | 12px / 16px | Medium | Badges, timestamps, helper text |
Recommended fonts: Inter or Be Vietnam Pro — both provide full Vietnamese diacritic support, are available on Google Fonts, and are lightweight to embed in Flutter/React.
2.3. Spacing & Grid
- A 4px-base spacing scale: 4, 8, 12, 16, 24, 32, 48, 64 — no arbitrary values outside this scale.
- Border radius: sm=4px (input, small badge), md=8px (card, button), lg=16px (modal, bottom sheet).
- Elevation/shadow: 3 levels — level-1 (card on background), level-2 (dropdown/tooltip), level-3 (modal/dialog).
3. Component Library
3.1. Button
Purpose: Triggers primary/secondary actions on every screen.
Variants: primary, secondary, tertiary (text-only), destructive
States: default, hover, pressed, disabled, loading (spinner replaces the label)
Accessibility note: Minimum tap target of 44x44pt on mobile; the disabled state must still retain enough contrast to be readable, not rely solely on opacity
3.2. Form Field (Input, Select, Date Picker)
Purpose: Controlled data entry: always has a label, may have helper text/error text.
Variants: text, number (with currency formatting), phone, select/dropdown, date picker, textarea
States: default, focus, filled, error, disabled
Accessibility note: The label is programmatically associated with the input via for/htmlFor (Web) or semantics (Flutter) — never rely on placeholder text alone as the label
3.3. Data Table
Purpose: Displays sortable/filterable/paginated lists (customers, inventory, receivables).
Variants: compact (Dashboard), full (main listing pages)
States: default, loading (skeleton rows), empty, row-selected, row-warning (e.g. low stock)
Accessibility note: Column headers support keyboard navigation when sorting on Owner Web
3.4. Badge / Status Tag
Purpose: Represents quote, repair order, receivable, or inventory status with a short colored label.
Variants: neutral, info, success, warning, error
States: default (no interactive state)
Accessibility note: Never use color as the sole indicator — always pair with text or an icon (for color-blind users)
3.5. Kanban Card & Kanban Column
Purpose: Displays repair orders as a drag-and-drop board by status (Owner Web).
Variants: default, overdue (warning border)
States: default, dragging, drop-target-highlight
Accessibility note: Supports status changes via a context menu (drag-and-drop not mandatory) to ensure keyboard-only operability
3.6. Modal / Dialog
Purpose: Confirms important or irreversible actions.
Variants: confirmation (2 buttons), form-modal (contains a short form)
States: default, loading (while submitting)
Accessibility note: Traps focus inside the modal, closable via the Esc key on Owner Web
3.7. Toast / Inline Notification
Purpose: Brief feedback after an action (saved successfully, network error).
Variants: success, error, info
States: appears/auto-dismisses after a few seconds (except error — requires manual dismissal)
Accessibility note: Never use a toast as the sole place to convey important information — actions requiring confirmation must still go through a Modal
3.8. Offline Banner (Technician App only)
Purpose: Communicates network status and the number of changes pending sync, without blocking interaction.
Variants: offline, syncing, synced
States: Automatically switches based on the device’s actual network connectivity
Accessibility note: Never rely on color alone to distinguish states — pair with a distinct icon for each
3.9. Bottom Navigation (Customer App & Technician App)
Purpose: Primary navigation between sections in the mobile apps.
Variants: Customer App: Home, My Vehicles, Notifications, Account. Technician App: Today, All Orders, Account
States: default, active-tab
Accessibility note: Icons paired with text labels — never icon-only for primary navigation
4. Icon System
- A single consistent icon set: Lucide Icons (open source, has a Figma plugin, easy to sync into React/Flutter).
- Standard sizes: 16px (icons within text/badges), 20px (icons within inputs/buttons), 24px (navigation icons).
- Never mix multiple icon sets within the same product, to avoid inconsistent stroke style.
5. Design System Versioning
- Versioned using semantic versioning (MAJOR.MINOR.PATCH): MAJOR for foundational token changes (primary colors, fonts), MINOR for adding a new component, PATCH for minor fixes (spacing, naming).
- Every Team Library publish includes a short changelog in the Figma version description, so product files know what to update when the “Library update available” notification appears.
- Proposals to change or add a new component must be approved by the Design System owner before publishing, to prevent style fragmentation over time.
6. Multi-Garage Theming
Garages can customize the logo shown on Owner Web and printed documents (quotes, invoices) — see FR-DOC-03. The system’s color palette/typography CANNOT be customized per garage in Phase 1–3, to preserve experience consistency and reduce design/testing complexity. Full theming (white-label) could be considered as a premium paid feature in a later stage, outside the scope of the current 4 phases.
7. Dark Mode
Not implemented in the current Phase 1–4 (out of scope per the Vision & Scope). However, it is recommended to name Design Tokens by purpose (e.g. “surface/primary” instead of “white”) from the start, so that adding Dark Mode later only requires defining an additional set of token values, not redesigning each component.
8. Design QA Checklist Before Handoff
- Every screen has all 4 standard states: default, loading, empty, error (see 02_UI_Design_Spec.md, Section 2.2).
- No “detached” components (disconnected from the Team Library) remain in the UI Screens file.
- Text/background contrast reaches at least 4.5:1 for all primary text.
- Minimum mobile tap target of 44x44pt for every interactive element.
- Full Dev Mode annotations for spacing/color/typography are in place before attaching a ticket link for developers.