Workspace UX Design Decisions
Canonical reference for recurring UI/UX pattern decisions. Every feature must follow these conventions to maintain consistency. Deviations require explicit justification in the feature's screen spec.
Guiding Principles
Two meta-principles govern every UX decision in the Workspace:
1. Five-Minutes-to-Value
The goal is to get the user to their "Aha!" moment with the absolute least amount of friction and cognitive load. Every page load, click, or moment of confusion eats into that budget. Every interaction pattern must be evaluated through this lens: does this help the user see value faster, or does it add a detour?
2. Convention over Configuration
Rely on established industry standards (conventions) so the user doesn't have to learn a new UI or waste time customizing their workspace (configuration). Leverage existing mental models from tools operators already use. Avoid "View Toggles" — picking the strongest default and owning it is always better than letting the user configure their way out of confusion.
Pattern 1: List Views
Decision: DataTable (Quasar QTable)
For any screen with 10+ records (vehicles, crew, tours, bookings), use the Quasar QTable component with sortable columns, filtering, and inline actions.
- Card grids are acceptable only for highly visual, low-volume content (e.g., a dashboard widget showing 3 active trips).
- Long-term, we may migrate to AG Grid for advanced use cases (dispatch, pricing matrices). QTable is the V1 standard.
- All tables must support: column sorting, search/filter, status chip rendering, and row-level action menus.
Pattern 2: Detail Views
Decision: Context-dependent, tiered approach
The layout choice depends on the entity's complexity and the user's task:
| Entity Complexity | Layout | Example |
|---|---|---|
| Lightweight / quick glance | Slide-over Drawer | View a crew member's basic info, quick-edit a vehicle status |
| Medium / focused editing | Popup / Modal overlay | Vehicle detail with inspections sub-table, crew detail with qualifications |
| Heavy / multi-tab entity | Full dedicated page | Operator settings, tour template editor (Phase 2+) |
Rationale:
- Slide-Over Drawers keep the user anchored to the list. They allow peeking at details and making quick edits without rebuilding the mental map of where they are.
- Split-List-Detail is the fastest pattern when the core value is triage (processing 50 items quickly). Reserve for the Omnichannel Inbox (Phase 7) where the convention matches Gmail/Zendesk.
- Full Pages introduce friction (navigating away, clicking "Back"). Use them only when the content genuinely requires the full viewport.
For Fleet & Staff V1, the primary detail view pattern is Popup/Modal.
Pattern 3: Create Flows
Decision: Tiered by action complexity
| Action Size | Pattern | Example |
|---|---|---|
| Micro-action (1–2 fields) | Modal | Change vehicle status, approve a leave request |
| Standard action (3–8 fields) | Drawer | Add a new vehicle, register a crew member |
| Macro-action (multi-step, multi-section) | Dedicated page | Tour template builder (Phase 2), Magic Upload wizard (Phase 3) |
The Drawer is the default for most CRUD create flows. It keeps the user looking at the list where the new record will appear after saving.
Pattern 4: Form Validation
Decision: Schema-driven validation
Use a schema-driven approach (e.g., VeeValidate + Valibot) rather than manual v-model + hand-rolled checks. This provides:
- Type-safe validation rules derived from the DB schema.
- Reusable field-level validators across all CRUD forms.
- Consistent error message formatting.
Pattern 5: Empty States
Decision: Actionable onboarding prompts (never just an illustration)
Every empty state must include four elements:
- Visual — A lightweight illustration or polished icon that communicates "you are in the right place." Don't let it dominate the screen.
- Headline — Action-oriented, not passive system-speak.
- ❌ "No vehicles."
- ✅ "Add your first vehicle" or "Let's build your fleet."
- Subtext — A value pitch reminding the user why this action matters.
- Example: "Add a vehicle to start tracking maintenance schedules, logging mileage, and reducing downtime."
- Primary CTA — A prominent button (e.g., "+ Add Vehicle") that triggers the create Drawer. The user never leaves the page.
Bonus — Sample Data: Consider offering a secondary action: "Load sample data." This lets users see what the app looks like when fully populated without committing real data. Include a dismissible banner to "Clear sample data" when they are ready.
Pattern 6: Deletion & Confirmation
Decision: Soft-delete with undo toasts
- Soft-delete is the standard. Vehicles transition to
DECOMMISSIONED, crew members toINACTIVE. Records are never hard-deleted from the UI. - Skip the "Are you sure?" modal for standard deletions. Instead, immediately apply the status change and show an undo toast (see Pattern 7).
- Use a confirmation modal only for catastrophic actions (e.g., deleting an entire tenant/operator account).
Pattern 7: Feedback & Notifications
Decision: Toasts for success, inline messages for errors
Success (Create, Update, Delete) → Toasts
- Non-blocking. Auto-dismisses after 3–5 seconds.
- The user clicks "Save" in the Drawer → Drawer closes → list updates → toast slides in: "Vehicle added."
- For deletions: toast includes an [Undo] action link.
- Position: bottom-right or top-right (pick one, stay consistent).
Errors & Validation → Inline Messages
- When validation fails, the Drawer/Modal does not close.
- Field-level errors appear directly below the offending input (e.g., "License plate must be unique" in red).
- Form-level errors appear as a banner at the top of the form.
Never use both simultaneously
- Don't show an inline success message and fire a toast — that's redundant.
- Don't show a red error toast and red inline text — that's overwhelming.
- Keep it binary: toasts for global success, inline for local errors.
Pattern 8: Data Architecture Convention
Decision: Quasar as the layout/component shell, Tailwind for custom styling
- Quasar components (QTable, QDrawer, QDialog, QBtn, etc.) serve as the primary UI toolkit for complex interactive elements.
@busflow/ui-coreprovides branded primitives (Button, ThemeToggle) and design tokens.- Tailwind CSS handles custom layout, spacing, and utility styling within feature pages.
- This hybrid approach avoids reinventing complex components while maintaining full styling control.
Pattern 9: Workspace Navigation Architecture
Decision: Deferred — two candidate options under evaluation.
The workspace serves two distinct workflow phases that map directly to the domain schema boundaries:
- Planning & Product — tour design, costing, pricing, bookings (Backoffice + Commerce schemas).
- Dispatch & Operations — vehicle/crew assignment, live execution, incident management (Operations schema).
The sidebar must make this distinction visible to users while keeping cross-context navigation frictionless. Two options are under evaluation; the final choice depends on nav item count after feature planning.
Domain-to-Context Mapping
| Context | V0.1 Features | V0.2+ Features |
|---|---|---|
| Planning & Product | Tours & Departures, Magic Upload, Costing/Pricing, Bookings | Yield Management, Promo Manager, B2B Quotes, Financial Reconciliation |
| Dispatch & Operations | Dispatch Board, Fleet Management, Staff/Crew | Live Map, Incident Management, Compliance Dashboard, Expense Review |
| Shared | Home/Dashboard, Settings | — |
| Future standalone contexts | — | Commerce Manager, Communications Inbox, Analytics |
Role-Based Visibility
| Role | Visible Contexts |
|---|---|
| Manager | Planning + Dispatch (full) |
| Dispatcher | Planning (read-heavy) + Dispatch (full) |
| Sales-only user | Planning only |
Both options enforce the same visibility rules — only the rendering mechanism differs.
Option 1: Sidebar Section Groups
A single sidebar groups nav items under labeled, collapsible section headers.
Wireframe:
── PLANNING & PRODUCT ────────
🏠 Home
📤 Magic Upload
🚌 Tours & Departures
🎟️ Bookings
── DISPATCH & OPERATIONS ─────
📋 Dispatch Board
🚐 Fleet
👷 Staff
── SYSTEM ────────────────────
⚙️ SettingsStrengths:
- Zero switching cost — every destination is always one click away.
- Teaches the domain model through section labels without forcing users into separate modes.
- Familiar B2B SaaS pattern (Notion, Linear, HubSpot). Intuitive for the DACH SMB target audience.
- Trivial implementation — add a
groupproperty toNavLink, render section headers. - Role-gating hides entire sections or individual items based on capabilities.
Weaknesses:
- Does not scale past ~15 nav items. Collapsible sections mitigate but do not fully solve sidebar overflow.
- No visual "context switch" — the user does not feel the workflow phase transition. This can be a feature (low friction) or a bug (no guardrails).
Best for: ≤15 total nav items. The right choice if V0.2 stays lean.
Option 2: Hybrid Contextual Tab Bar
A persistent top bar with tab-style pills (Planning | Dispatch) that swap the sidebar contents per context.
Wireframe:
┌──────────────────────────────────────────────┐
│ 🚌 busflow [Planning ▾] [Dispatch ▾] 👤 │ ← tab pills in header
├────────┬─────────────────────────────────────┤
│ Tours │ (page content) │ ← sidebar adapts to
│ Costs │ │ the active tab
│ Price │ │
│ Book │ │
│ ────── │ │
│ ⚙ Set │ │
└────────┴─────────────────────────────────────┘Strengths:
- One-click context switching — tabs are always visible in the header, never hidden behind a menu.
- Contextual sidebar prevents overload — each context shows only its 4–6 items. Clean and focused.
- Scales horizontally — adding Commerce or Communications later means adding a third tab pill. Stays clean up to ~5 contexts.
- URL-driven state (
/planning/tours/123vs./dispatch/board) — bookmarkable, shareable, debuggable. - Code architecture aligns perfectly — each tab maps to a top-level route group, giving natural lazy-loading and FSD feature-slice boundaries.
- When a user has access to only one context, the tab bar hides entirely, removing visual noise.
Weaknesses:
- Higher implementation cost — requires a context-aware sidebar, route restructuring, and a tab-bar component.
- Shared entities (vehicles, crew) need a canonical home with cross-links to avoid "mode confusion."
- Tab bar consumes header vertical space; on narrow screens or the dispatch Gantt, every pixel counts.
Best for: 2–5 workflow contexts with 8+ nav items per context. The right choice if V0.2+ grows the feature set significantly.
Switching Frequency (User Journey Analysis)
Cross-context switching is infrequent and deliberate — typically once per tour lifecycle, not dozens of times per day:
| Journey | Cross-Context Switches |
|---|---|
| AI-Assisted End-to-End (J1) | Planning → Dispatch — 1 switch per tour lifecycle |
| B2B Fleet Re-routing (J4) | Commerce → Dispatch — reactive, infrequent |
| AI Optimization (J5) | Planning only — 0 switches |
| Financial Reconciliation (J6) | Planning only — 0 switches |
| Customer Support (J7) | Planning only — 0 switches |
This means the separation matters more for mental model clarity than for rapid task switching. Both options handle this well.
Decision Criteria
Choose Option 1 if the total nav item count after feature planning stays below ~12–15. Choose Option 2 if planning reveals 3+ distinct contexts or 15+ total nav items.
Open Questions
- Bookings: Lives under Planning for V0.1 (dispatcher manages bookings). May deserve its own context tab if a dedicated Commerce Manager role emerges in V0.2+.
- Fleet & Staff: Master data (Backoffice schema) but primarily consumed by Dispatch. Canonical placement depends on the dominant user flow — currently leans Dispatch.
- Dashboard: A single global dashboard risks becoming a kitchen sink. Per-context dashboards (Planning pipeline vs. Dispatch day-view) are more focused but double the work.