Vendor panel overview
Nội dung này hiện chưa có sẵn bằng ngôn ngữ của bạn.
Executive summary
Section titled “Executive summary”The vendor web app covers store operations: POS, orders, catalog, inventory, finance, marketing, and staff. This page summarizes owner vs employee access, how DashboardOutlet uses ROUTE_RULES (vendor-module-access.ts), how ProtectedRoute matches app-router.tsx, and how the sidebar / command palette mirrors vendorNavConfig (vendor-dashboard-nav.ts).
UI and screen flow
Section titled “UI and screen flow”Public auth and landing
Section titled “Public auth and landing”| Route | Purpose |
|---|---|
/ | Marketing landing (same public landing settings contract as admin-web). |
/login | Vendor sign-in (staff vs owner). |
/forgot-password, /reset-password, /verify-otp | Password / OTP recovery flow. |
There is no public vendor self-registration route in the app; account provisioning is out of band. Details and automated login tests: Vendor account & sign-in.
Two kinds of surfaces
Section titled “Two kinds of surfaces”| Surface | Routes | Chrome |
|---|---|---|
| Dashboard app | Most URLs under /dashboard/* | Sidebar + TopBar + DashboardOutlet → Outlet (apps/vendor-web/src/app/dashboard/layout.tsx) |
| Fullscreen checkout / POS workspace | /pos, /point-of-sale/*, /dashboard/orders/create | No classic dashboard sidebar: /pos and /dashboard/orders/create are standalone; /point-of-sale/* uses PointOfSaleAppShell (own side nav + top bar). All remain behind ProtectedRoute / order module rules where applicable. User guide: Cashier help center. |
Store context (dashboard)
Section titled “Store context (dashboard)”Inside the dashboard shell, StoreSelector (toolbar) drives selectedStoreId (Zustand + APIs) so lists and home metrics are store-scoped. Owners pick a store; employees may be pinned to one store (Employees and stores).
Dashboard home (/dashboard)
Section titled “Dashboard home (/dashboard)”The index route renders DashboardHomePage, which mounts VendorDashboardHome (apps/vendor-web/src/components/dashboard/home/VendorDashboardHome.tsx):
- Period filters: Today, This week, This month, and custom Range (store timezone via
dashboard_prefs.timezone). - Hero KPIs: Net sales, paid orders, average order size — compared to the prior period of equal length.
- Summary cards: Open orders (successful sales — paid and on account), discounts, refunds.
- Panels: Top items (analytics) and amount collected by tender (Card / Cash / Other), with links to catalog and Sales overview.
Data sources: GET /vendor/finance/sales-report (current + previous period) and GET /vendor/dashboard/analytics (top products, with timezone). Helpers live in dashboard-period-filter.util.ts and vendor-dashboard-home-display.ts.
Navigation (sidebar + command palette)
Section titled “Navigation (sidebar + command palette)”- Structure:
vendorNavConfiginvendor-dashboard-nav.ts. The sale rail is Clover-style always-open sections (parent is a label, children stay visible): Home, Sales activity, Reports, Finances, Items, Inventory, Customers, Employees. organization lists Stores and Support; personal is employee self-service. The command palette flattens visible children (plus account/settings extras). - Active state: selected child uses a gray row fill and a 3px left bar (emerald, matching the Clover reference screenshots).
- Visibility:
navItemVisible—ownerOnly, singlemodule, ormodulesAny(e.g. marketing banners: store or product read). - Visibility:
navItemVisible—ownerOnly, singlemodule, ormodulesAny(e.g. marketing banners: store or product read). - Command palette adds Account: Profile (
/dashboard/profile), Settings (/dashboard/settings) when the user is owner or has settings read; Terminals (/dashboard/terminals,/dashboard/terminals/:deviceId) when settings access applies and the device list is non-empty.
Route guard inside the layout
Section titled “Route guard inside the layout”DashboardOutlet calls canAccessVendorPath(profile, pathname). If access fails, the app Navigates to defaultLandingPath(profile) (tries a small ordered list of paths, then /dashboard/help — see vendor-module-access.ts). Bookmarked URLs are enforced here even when a nav item was visible.
Important: ROUTE_RULES uses first match. Any /dashboard/... path that does not match a rule is treated as owner-only (canAccessVendorPath returns true only for owners). That includes prefixes such as /dashboard/marketing/... and /dashboard/terminals/... until/unless rules are added for them. ProtectedRoute on those routes may still allow employees (e.g. banners: requiredModulesAny; terminals: settings); layout and nav visibility can therefore disagree — prefer aligning new routes with ROUTE_RULES. The Support screen (/dashboard/support) is documented in Tickets (vendor ↔ admin).
Screen-flow diagram
Section titled “Screen-flow diagram”flowchart TB
subgraph pub["Public"]
L["/ — landing"]
LI["/login · recovery routes"]
end
subgraph dash["Dashboard · /dashboard/*"]
SB[Sidebar / search]
TB[TopBar]
ST[StoreSelector]
OUT["Outlet: home, orders, catalog…"]
end
subgraph standalone["Fullscreen POS / orders"]
POS["/pos"]
POS2["/point-of-sale/…"]
OC["/dashboard/orders/create"]
end
LI -->|session| dash
L -->|optional sign-in| LI
LI -->|session + order write| POS
LI -->|session + order| POS2
LI -->|session + order write| OC
SB --> OUT
Typical clicks
Section titled “Typical clicks”- Home —
/dashboard→ operational KPIs for the selected store. - Orders —
/dashboard/orders→ list; row →/dashboard/orders/:id. - Deliveries —
/dashboard/orders/deliveries(+ detail:id). - Work shifts —
/dashboard/orders/shifts(+/templates,/lanes,/:shiftId). Templates and checkout lanes require settings module on those nested routes. See Work shifts (Vendor) for the full open / operate / close lifecycle, RBAC matrix, and POS attribution rules. - New order —
/dashboard/orders/create(standalone). - POS —
/posor/point-of-sale/sale(orderwith write); see POS. HTTP checkout uses/vendor/point-of-sale/*(mandatorystore_id). - Products —
/dashboard/productsand sub-routes (categories, units, attributes, tags, suppliers, gallery). - Marketing —
/dashboard/marketing/banners(ProtectedRoute: store or product). - Inventory — warehouses, stocks, lots, adjustments (+ detail / create where routed).
- Finance — transactions, expenses, refunds, receivables, report (
/dashboard/finance/...); legacy/dashboard/financesstill mapped to finance inROUTE_RULES. - Customers, discounts, stores, employees, roles — parallel routes; roles nav is owner-only; employees use
employeemodule. - Managers —
/dashboard/managers(owner-only inROUTE_RULES). - Settings —
/dashboard/settings/*(general, notifications, team, devices, shift-templates, checkout-lanes, POS bridge / lab pages under settings where wrapped). - Profile —
/dashboard/profile(allowAll in layout rules). - Terminals —
/dashboard/terminals,/dashboard/terminals/:deviceId(settings onProtectedRoute). - Notifications —
/dashboard/notifications(allowAll for authenticated vendor in layout rules).
Goals and non-goals
Section titled “Goals and non-goals”| Goals | Non-goals |
|---|---|
| Map main screens to routes and modules | Duplicate every edge case of ProtectedRoute wrappers |
| Explain owner-only vs module-gated areas | Replace backend permission checks |
Current platform behavior
Section titled “Current platform behavior”After sign-in, most features live under /dashboard. Checkout is reachable at /pos (classic), /point-of-sale/sale (POS workspace), and /dashboard/orders/create (manual). Owners bypass module membership checks; employees need slugs in profile.modules plus read/write via module_permissions. /pos, /point-of-sale/sale, and /dashboard/orders/create require order with write. vendorCanManageWorkShifts (shift management helpers) treats owner or order write as able to manage store-wide shift operations where the UI uses it.
Sequence: happy path
Section titled “Sequence: happy path”- Vendor user signs in →
/dashboardor first path indefaultLandingPaththat passescanAccessVendorPath. - StoreSelector persists
selectedStoreIdfor scoped APIs. - User opens POS, orders, catalog, etc. per assigned modules and layout rules.
Security and operations
Section titled “Security and operations”- Never share owner credentials; role changes flow through Roles (Vendor).
- Employees with forced
store_idcannot switch stores in the selector (Employees and stores). - Tokens and refresh behavior: Authentication.
Automated checks (vendor web)
Section titled “Automated checks (vendor web)”The vendor documentation baseline is now:
- Every user-facing screen must ship with both:
- Unit tests (component/hook/schema logic in
apps/vendor-web/src/**) - E2E tests (browser flow in
apps/vendor-web/e2e/**)
- Unit tests (component/hook/schema logic in
- Each documented screen should also have at least one docs screenshot under
apps/docs/public/screenshots/vendor/captured by Playwright docs screenshot specs.
Current implementation status (what already exists vs backlog) is tracked in Vendor testing and screenshots index. Treat that page as the source of truth before releasing screen changes.
Audience
Section titled “Audience”- Owners (
vendor_type === "owner") pass module checks for every slug and ownerOnly rules. - Employees get
profile.modulesand optionalmodule_permissions. The UI usesvendorHasModuleRead/vendorHasModuleWriteinvendor-module-access.ts.
Module and route matrix (layout: ROUTE_RULES)
Section titled “Module and route matrix (layout: ROUTE_RULES)”Rules are evaluated in array order in vendor-module-access.ts. For a match, dashboardPathRequiresModuleWrite upgrades the check to write on create/edit/detail patterns (see source for regex details).
| Path prefix (first match) | Module / flag | Notes |
|---|---|---|
/dashboard/roles | role + ownerOnly | |
/dashboard/employees | employee | |
/dashboard/managers | ownerOnly | No module slug |
/pos | order | Also ProtectedRoute write |
/point-of-sale | order | Workspace shell; sale path requires write |
/dashboard/inventory | inventory | |
/dashboard/finance | finance | |
/dashboard/products | product | |
/dashboard/orders | order | Includes deliveries, shifts, … |
/dashboard/customers | customer | |
/dashboard/discounts | coupon | |
/dashboard/stores | store | |
/dashboard/notifications | allowAll | Authenticated vendor |
/dashboard/messages | notification | Rule exists; no messages route in app-router.tsx at time of writing |
/dashboard/finances | finance | |
/dashboard/settings | settings | |
/dashboard/help | allowAll | Rule exists for defaultLandingPath fallback; no help child route in app-router.tsx at time of writing |
/dashboard/profile | allowAll | |
/dashboard/system | ownerOnly | e.g. /dashboard/system/translations, … |
/dashboard/analytics | dashboard | Rule present; no analytics segment in app-router.tsx at time of writing |
/dashboard (exact) | dashboard | Home |
Unlisted /dashboard/... paths (e.g. /dashboard/marketing/..., /dashboard/terminals/...): canAccessVendorPath → owners only until a ROUTE_RULES entry exists.
Write vs read: Owners always pass. Employees need write on mutating URL patterns for the mapped module.
Source of truth for declared routes: apps/vendor-web/src/routes/app-router.tsx.
Main areas (route map)
Section titled “Main areas (route map)”| Area | Typical routes |
|---|---|
| POS | /pos, /point-of-sale/sale, … (order write on sale) |
| Create order | /dashboard/orders/create |
| Home | /dashboard |
| Orders | /dashboard/orders, /dashboard/orders/:id |
| Deliveries | /dashboard/orders/deliveries, .../deliveries/:id |
| Work shifts | /dashboard/orders/shifts, .../shifts/templates, .../shifts/lanes, .../shifts/:shiftId |
| Products | /dashboard/products, create/edit/detail, categories, units, attributes, tags, suppliers, gallery |
| Marketing | /dashboard/marketing/banners |
| Inventory | warehouses, stocks, lots, adjustments (+ detail / forms) |
| Finance | transactions, expenses, refunds, receivables, report; /dashboard/finances |
| Customers | /dashboard/customers, :id |
| Discounts | /dashboard/discounts, :id |
| Stores | /dashboard/stores, create, detail, edit |
| Employees | /dashboard/employees, create, detail, edit |
| Roles | /dashboard/roles, create, :id, :id/edit (owner-only nav) |
| Managers | /dashboard/managers, create, :id/edit (owner-only layout rule) |
| Notifications | /dashboard/notifications |
| Settings | /dashboard/settings/* (nested tabs + device / POS bridge labs) |
| Profile | /dashboard/profile |
| Terminals | /dashboard/terminals, /dashboard/terminals/:deviceId |
| System (placeholders) | /dashboard/system/translations, business-settings, currencies, withdrawals, delivery-men |
Related
Section titled “Related”- Vendor account & sign-in — login, recovery, automated tests.
- Cashier help center — step-by-step POS workspace guide for lane staff.
- Vendor testing and screenshots index — required test matrix (unit + e2e + docs screenshots).
- Admin panel overview — head office.
- POS — checkout flow.
- Work shifts (Vendor) — open / close cashier sessions, lane uniqueness, slip suggestions.
- Roles (Vendor) — assigning module slugs to employees.