==================================================================== MULTI-OUTLET & OWNER COMBINED DASHBOARD — WORK PLAN Written: 2026-08-24 ==================================================================== CONTEXT ------- PetZY already has a full multi-tenant data model (Company -> Outlet -> Users -> POS/Orders/Payments, every business record carries company_id and outlet_id, spec section 9/67) and every POS/KOT/inventory/hotel screen is already outlet-scoped with a working outlet switcher in the Topbar. What's genuinely missing — confirmed by reading the actual code, not assumed — is the ability to *operate* more than one outlet day-to-day, and for an owner to see the business as a whole instead of one outlet at a time: 1. No frontend page to create/edit an Outlet at all (API already exists: full CRUD at /api/outlets via crudRouter). You can seed a second outlet in SQL but not add one from the app. 2. No frontend page to edit the Company profile (API already exists: GET/PUT /api/companies/:id). 3. Settings > Team only lists users read-only — no way to create a login user, assign a role, or assign them to specific outlets (API already exists: full CRUD at /api/users incl. outlet_ids[]). 4. Dashboard.jsx and Reports.jsx are hard-scoped to exactly one outlet_id (from OutletContext) with no "all outlets" option — an owner with 3 outlets can only ever see one at a time, never a combined total or a side-by-side comparison. dashboardController.js falls back to req.user.outletIds[0] (first assigned outlet) when no outlet_id is given, not a real company-wide aggregate. 5. Stock Transfers (outlet <-> outlet) already works correctly — no change needed there. Menu items already support outlet_id = NULL (shared across every outlet) or a specific outlet — no change needed there either. This plan closes gaps 1-4 only. It does not re-touch anything already built and working (POS, KOT, hotel, inventory, reports' existing single-outlet filtering, etc.). -------------------------------------------------------------------- 1. OUTLETS ADMIN PAGE [BE done][FE] -------------------------------------------------------------------- - New: frontend/src/pages/settings/Outlets.jsx (CrudPage, same pattern as Taxes.jsx) — name, code, type (restaurant/hotel/resort/cafe/qsr/ other), address, phone, email, gstin, invoice_prefix, kot_prefix, opening_time, closing_time, status. - Reachable from Settings (new "Outlets" section/tab), gated on can('settings.edit'). - service: settingsService.listOutlets (exists) + add createOutlet/updateOutlet. - This is the actual "add a second/third outlet" control an owner needs — without it "multiple outlets" only exists in the seed data. -------------------------------------------------------------------- 2. COMPANY PROFILE SETTINGS [BE done][FE] -------------------------------------------------------------------- - Settings.jsx gets a "Business Profile" card above/alongside General: name, legal_name, gstin, pan, address/city/state/pincode, currency, timezone, invoice_footer, terms. Uses existing GET/PUT /api/companies/:id (companyService — new small service file). - Gated on can('settings.edit'); read-only display otherwise. -------------------------------------------------------------------- 3. TEAM / USER MANAGEMENT [BE done][FE] -------------------------------------------------------------------- - Settings.jsx "Team" card becomes create/edit-capable instead of a read-only list: - "Add User" -> modal: name, email, phone, password, role (Select, from settingsService.listRoles), outlet_ids (multi-checkbox from settingsService.listOutlets) — THIS is the actual "staff outlet A with cashiers, outlet B with different cashiers, and a manager who can see both" control. - Row actions: edit (same modal, no password field, add "Reset Password" separately), deactivate. - Gated on can('users.manage') (already used to show/hide the card). -------------------------------------------------------------------- 4. COMBINED ("ALL OUTLETS") OWNER DASHBOARD — the explicit ask [BE][FE] -------------------------------------------------------------------- Backend — backend/src/controllers/dashboardController.js: - getSummary gains a real "all my outlets" mode: when outlet_id is omitted/'all' AND the user has more than one assigned outlet (or is Super Admin), compute company-wide totals (today's sales, orders, avg ticket, restaurant revenue, pending payments, low stock, active customers, occupancy) across every outlet_id the user can see — not just outletIds[0] — PLUS a byOutlet[] breakdown array (outlet name, today's sales, orders, occupancy%) for a comparison table. Single-outlet users keep getting exactly what they get today (outletIds has only one entry either way, so this is additive). Frontend: - OutletContext: expose an "All Outlets" pseudo-selection (id: 'all') offered only when outlets.length > 1 — added to the Topbar select and persisted the same way as a real outlet id. - Dashboard.jsx: when outletId === 'all', render the existing stat cards against the company-wide totals, plus a new "Outlet Performance" table (one row per outlet: sales today, orders today, occupancy%) instead of the single-outlet Hotel Room Status card. Single-outlet view is visually unchanged. -------------------------------------------------------------------- 5. REPORTS: ALL-OUTLETS BREAKDOWN [BE][FE] -------------------------------------------------------------------- - reportController.salesReport (and payments/items where it makes sense) adds an outlet_name column to each row when outlet_id is omitted, so an owner comparing outlets sees the split, not just a blended company-wide number. - Reports.jsx: outlet selector gains "All Outlets"; when selected, requests omit outlet_id (already company-scoped server-side) and the Sales tab shows the outlet column. - GST filing report already treats outlet_id as optional — verified, no change needed. -------------------------------------------------------------------- 6. VERIFICATION -------------------------------------------------------------------- - Live smoke test against the seeded DB: add a second outlet, assign one cashier to outlet 1 only, one to outlet 2 only, confirm each only sees their own outlet in POS/orders, then confirm the owner account's "All Outlets" dashboard/report totals equal the sum of the two outlets' individual numbers. - Update README.md section 11 to remove the closed gaps ("Company/Outlet edit forms") and add anything genuinely still open. -------------------------------------------------------------------- BUILD ORDER -------------------------------------------------------------------- 1. Outlets admin page (unblocks everything else — need 2 outlets to test any of the rest) 2. Company profile settings 3. Team/user management 4. Combined dashboard (the explicit ask) 5. Reports outlet breakdown 6. Verification + README update