fix production issues
Build & Push / Pipeline Tests (push) Failing after 59s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Failing after 51s
Test / API Unit Tests (push) Has been skipped
Test / Homepage Unit Tests (push) Has been skipped
Test / Carplace Unit Tests (push) Has been skipped
Test / Admin Unit Tests (push) Has been skipped
Test / Dashboard Unit Tests (push) Has been skipped
Test / API Integration Tests (push) Has been skipped

This commit is contained in:
root
2026-08-12 16:48:41 -04:00
parent 53de25120a
commit 8fc88ffc14
117 changed files with 4717 additions and 1443 deletions
@@ -0,0 +1,501 @@
# RentalDriveGo Manual UI Test Plan
**Version:** v1.0
**Scope:** Phase 16 unified UI across homepage, Carplace/storefront, renter area, operator dashboard, platform admin, authentication pages, localization, theming, responsiveness, accessibility, and cross-app navigation.
**Repository baseline:** `RentalDriveGo_Phase16_Dashboard_Admin_Unified_v1.0.zip`
**Test type:** Manual functional UI, visual consistency, accessibility spot checks, responsive behavior, localization, and regression testing.
---
## 1. Objective
Verify that all public and authenticated RentalDriveGo applications use the Phase 16 homepage design system consistently and remain usable across English, French, Arabic RTL, light mode, dark mode, desktop, tablet, and mobile.
The testing must prove three things:
1. The new design is applied consistently across all major pages.
2. Existing user flows still work after the visual refactor.
3. Shared navbar, footer, dashboard shell, admin shell, forms, tables, cards, and page headings behave correctly across contexts.
---
## 2. Applications in scope
| Area | Application | Manual coverage required |
|---|---|---|
| Marketing website | `homepage` | Public homepage, navigation, language switcher, theme switcher, CTAs, demo flow, responsive layout, localized routes |
| Marketplace / Carplace | `storefront` | Public marketplace, explore/search, company pages, vehicle detail, booking form, footer pages, renter auth and renter account pages |
| Operator dashboard | `dashboard` | Public auth pages, dashboard shell, all operational routes, forms, tables, detail pages, modals, billing, settings, print surfaces |
| Platform admin | `admin` | Admin auth, admin shell, all admin management routes, company management, pricing, billing, containers, menu/config pages |
| API-connected behavior | `api` through UI | Confirm UI states for loading, success, validation errors, authorization errors, and network failures where available |
---
## 3. Test environments
Run manual UI testing in at least these environments:
| Environment | Required? | Notes |
|---|---:|---|
| Local development | Yes | Primary smoke and visual review environment |
| Staging / preview deployment | Yes | Required before production release |
| Production-like deployment | Recommended | Use production build settings, HTTPS, real domains, and realistic API URLs |
Do not approve release from local testing only. That would be optimism wearing a fake mustache.
---
## 4. Browser and device matrix
### Desktop browsers
| Browser | OS | Priority |
|---|---|---:|
| Chrome latest | Windows | P0 |
| Edge latest | Windows | P0 |
| Safari latest | macOS | P1 |
| Firefox latest | Windows or macOS | P1 |
### Mobile and tablet
| Device class | Width target | Priority |
|---|---:|---:|
| Small mobile | 360 x 800 | P0 |
| Large mobile | 390 x 844 | P0 |
| Tablet | 768 x 1024 | P1 |
| Small laptop | 1280 x 800 | P0 |
| Desktop | 1440 x 900 | P0 |
| Wide desktop | 1920 x 1080 | P1 |
Use real devices where possible for mobile navigation, keyboard behavior, touch target size, and scroll locking. Browser dev tools are useful, but they are not a phone, no matter how hard the viewport dropdown tries.
---
## 5. Test users and roles
Prepare these accounts before testing:
| Role | Needed for |
|---|---|
| Public visitor | Homepage, marketplace, footer pages, sign-in/create-account flows |
| Renter | Carplace renter dashboard, profile, saved companies, notifications |
| Operator / agency admin | Main dashboard, reservations, contracts, fleet, customers, team, billing, settings |
| Operator team member with limited permissions | Permission visibility and blocked routes |
| Platform super admin | Admin dashboard and platform management pages |
| Invalid/expired user | Auth error states, reset password, invite, verification edge cases |
---
## 6. Required test data
Create or seed the following before full UI testing:
| Data | Minimum requirement |
|---|---|
| Companies/agencies | At least 3 active companies with different logos, statuses, locales, and subscription states |
| Vehicles | At least 10 vehicles across available, reserved, maintenance, inactive, and incomplete states |
| Reservations | Draft, confirmed, active, overdue, cancelled, completed, online-requested |
| Contracts | At least one printable contract with customer, vehicle, dates, photos, and charges |
| Customers/renters | Customers with complete, partial, and missing information |
| Team members | Admin, manager, agent, inactive user, invited user |
| Reviews/complaints | Open, resolved, escalated, empty-state capable |
| Billing/subscription | Active plan, trial, past due, cancelled or expired state where possible |
| Notifications | Read, unread, action-required, empty state |
| Admin data | Companies, renters, platform admins, pricing plans, containers, audit logs, menu entries, site config |
| Localization content | English, French, Arabic strings for public and authenticated areas |
---
## 7. Global design acceptance criteria
Every page must satisfy these checks:
- Uses Phase 16 blue/orange token system.
- Blue is used for primary operational actions.
- Orange is reserved for conversion, emphasis, selected states, focus, or warnings.
- Page background, panels, cards, forms, tables, badges, and shadows match the homepage visual language.
- No old `FleetOS` branding appears anywhere.
- No mixed brand names such as `RentalCarDrive`, `RentalDrive`, or legacy storefront naming appear in visible UI unless intentionally part of old data.
- Light and dark mode both remain readable.
- Arabic uses true RTL layout, not just Arabic text shoved into left-to-right furniture.
- Public navbar and footer appear on standalone public/auth pages where expected.
- Embedded auth pages using `embedded=1` do not show duplicated navbar/footer.
- Mobile layouts avoid horizontal scrolling.
- Buttons, links, inputs, selects, and controls have visible hover, active, disabled, loading, and focus-visible states.
- Interactive controls are approximately 44 px minimum height where practical.
- Tables, modals, drawers, menus, and dropdowns remain usable on mobile.
- Loading, empty, success, validation-error, permission-error, and server-error states are visually consistent.
---
## 8. Global navigation and layout tests
| ID | Area | Steps | Expected result | Priority |
|---|---|---|---|---:|
| NAV-001 | Public navbar | Open homepage desktop. Inspect logo, nav links, language switcher, theme switcher, CTAs. | Navbar matches Phase 16 design, no clipping, active/hover states visible. | P0 |
| NAV-002 | Public mobile navbar | Open homepage at 360 px. Open and close mobile menu. | Menu opens cleanly, traps visual focus appropriately, scroll does not break, links are usable. | P0 |
| NAV-003 | Public footer | Open homepage, marketplace home, sign-in, create account. | Shared footer appears consistently on standalone public pages. | P0 |
| NAV-004 | Auth public layout | Open dashboard sign-in, sign-up, forgot password, reset password, verify email, onboarding. | Shared navbar/footer are visible unless `embedded=1` is present. | P0 |
| NAV-005 | Embedded auth layout | Add `?embedded=1` to auth URLs. | Navbar/footer are hidden and page does not show nested chrome. | P0 |
| NAV-006 | Dashboard shell | Log in as operator. Move through all dashboard routes. | Sidebar, topbar, active states, page width, and spacing remain consistent. | P0 |
| NAV-007 | Admin shell | Log in as platform admin. Move through all admin routes. | Admin sidebar/topbar match dashboard design system, with admin-specific nav. | P0 |
| NAV-008 | Mobile operational shell | Open dashboard/admin at mobile width. Open sidebar/menu. | Drawer works, content is not hidden behind topbar, no horizontal scrolling. | P0 |
| NAV-009 | Logout/account controls | Use user/account menu in dashboard/admin. | Menu opens, closes, keyboard works, logout/account actions are visible. | P1 |
| NAV-010 | Active route state | Visit every sidebar route. | Correct nav item uses active state and accessible current-page indication. | P1 |
---
## 9. Homepage manual tests
Test locales: `/en`, `/fr`, `/ar`.
| ID | Page/feature | Steps | Expected result | Priority |
|---|---|---|---|---:|
| HOME-001 | Homepage load | Open each locale homepage. | Hero, proof section, comparison, workflow, feature sections, pricing/CTA areas load without broken layout. | P0 |
| HOME-002 | Hero CTAs | Click primary demo CTA and secondary tour/explore CTA if present. | Correct dialog, route, or section opens. No dead links. | P0 |
| HOME-003 | Demo dialog/form | Open demo request flow. Submit empty form, invalid email, then valid data. | Validation messages are clear; valid submission shows success or expected API result. | P0 |
| HOME-004 | Language switcher | Switch EN to FR to AR and back. | User remains on matching route; copy changes; Arabic direction flips to RTL. | P0 |
| HOME-005 | Theme switcher | Switch light, dark, system. Refresh page. | Theme applies consistently and persists if persistence is supported. | P0 |
| HOME-006 | Header scroll behavior | Scroll through page. | Sticky/header behavior is stable and does not obscure content. | P1 |
| HOME-007 | Public content pages | Open localized slug pages available in the site. | Header/footer render; not-found and loading states are localized and styled. | P1 |
| HOME-008 | Component lab | Open component lab if enabled. | Components render without layout breakage and match tokens. | P2 |
| HOME-009 | SEO/basic metadata | Inspect tab title, favicon, social preview if available. | Branding is RentalDriveGo and no old brand appears. | P2 |
| HOME-010 | Public accessibility pass | Keyboard through homepage from top to bottom. | Focus order is logical, focus rings visible, menus/dialogs usable. | P0 |
---
## 10. Carplace / storefront public tests
| ID | Page/feature | Steps | Expected result | Priority |
|---|---|---|---|---:|
| CP-001 | Marketplace home | Open storefront public home. | Uses Phase 16 navbar/footer and visual tokens. | P0 |
| CP-002 | Explore page | Open `/explore`. Search/filter if controls exist. | Filters are usable; results grid/cards align with design; empty state works. | P0 |
| CP-003 | Company workspace page | Open company workspace creation/info page. | Public layout, CTA hierarchy, and form controls are consistent. | P0 |
| CP-004 | Company profile | Open `/explore/[slug]` for at least 3 companies. | Branding, vehicles, contact/booking areas load correctly. | P0 |
| CP-005 | Vehicle detail | Open `/explore/[slug]/vehicles/[id]`. | Vehicle photos/details/pricing/availability render without overflow. | P0 |
| CP-006 | Booking form | Submit booking with empty, invalid, and valid fields. | Validation, date handling, price display, and success/error states are clear. | P0 |
| CP-007 | Public sign-in | Open storefront sign-in. | Styling matches public auth design and routes correctly. | P0 |
| CP-008 | Policy pages | Open EN/FR/AR privacy and terms pages. | Footer/header are consistent; copy direction is correct; long content is readable. | P1 |
| CP-009 | Footer content pages | Open footer dynamic pages. | Content loads; no broken layout or missing footer. | P1 |
| CP-010 | Marketplace mobile | Test home, explore, company, vehicle detail at 360 px. | Cards stack properly, no horizontal scroll, booking CTA remains usable. | P0 |
---
## 11. Renter account tests
| ID | Page/feature | Steps | Expected result | Priority |
|---|---|---|---|---:|
| RENT-001 | Renter sign-in | Open renter sign-in and test invalid credentials. | Validation/error state is styled and readable. | P0 |
| RENT-002 | Renter sign-up | Create account with missing, invalid, and valid data. | Form states and success path are clear. | P0 |
| RENT-003 | Renter dashboard | Log in as renter and open dashboard. | Shell is consistent with marketplace/renter context; key data appears. | P0 |
| RENT-004 | Saved companies | Save and remove company where supported. | State updates visually and persists after refresh if expected. | P1 |
| RENT-005 | Renter profile | Update profile fields. | Field styling, validation, save state, and success message are consistent. | P0 |
| RENT-006 | Renter notifications | Open notifications with read/unread data. | Notification cards/states are readable in light/dark. | P1 |
| RENT-007 | Permission boundary | Try accessing renter pages while logged out. | Redirect or guard behavior is correct. | P0 |
---
## 12. Dashboard public authentication tests
| ID | Page/feature | Steps | Expected result | Priority |
|---|---|---|---|---:|
| AUTH-001 | Sign in | Open dashboard sign-in. Test empty, invalid, and valid credentials. | Public navbar/footer show; errors are clear; success redirects to dashboard. | P0 |
| AUTH-002 | Create account | Open sign-up/create account. Test required fields and valid registration. | Form matches design; validation and success path are clear. | P0 |
| AUTH-003 | Forgot password | Request reset with empty, invalid, unknown, and valid email. | Safe, clear messaging; no layout break. | P0 |
| AUTH-004 | Reset password | Open reset page with missing, invalid, expired, and valid token. | Correct error/success states and password field behavior. | P0 |
| AUTH-005 | Verify email | Open valid, invalid, and expired verification states. | Styled message and next action are clear. | P1 |
| AUTH-006 | Onboarding | Open onboarding flow as invited/new user. | Layout, steps, forms, and final redirect work. | P0 |
| AUTH-007 | Accept invite | Open invitation acceptance with valid/expired invite. | Correct messaging and route behavior. | P0 |
| AUTH-008 | Embedded auth | Open each auth URL with `?embedded=1`. | No duplicated navbar/footer; form remains centered and usable. | P0 |
---
## 13. Operator dashboard tests
### Dashboard overview
| ID | Page/feature | Steps | Expected result | Priority |
|---|---|---|---|---:|
| DASH-001 | Overview | Open dashboard home. | Hero/heading, metrics, quick actions, and recent activity match Phase 16 style. | P0 |
| DASH-002 | Empty state | Use company/account with minimal data. | Empty panels are intentional, helpful, and styled. | P1 |
| DASH-003 | Loading state | Throttle network and reload. | Skeleton/loading states do not cause layout jumps or unreadable text. | P1 |
### Reservations
| ID | Page/feature | Steps | Expected result | Priority |
|---|---|---|---|---:|
| RES-001 | Reservation list | Open reservations page. Search/filter/sort if available. | Table/cards are readable and responsive; statuses are clear. | P0 |
| RES-002 | New reservation | Create reservation with missing, invalid, and valid data. | Form fields, validation, customer/vehicle/date selection, and save states work. | P0 |
| RES-003 | Reservation detail | Open confirmed, active, cancelled, completed reservation. | Detail layout, actions, status badges, panels, and timeline are consistent. | P0 |
| RES-004 | Reservation photos | Upload/view/remove photos if supported. | Upload UI, previews, errors, and mobile behavior work. | P1 |
| RES-005 | Vehicle condition | Complete damage/condition inspection if supported. | Cards, controls, required fields, and summary are usable. | P1 |
### Contracts
| ID | Page/feature | Steps | Expected result | Priority |
|---|---|---|---|---:|
| CON-001 | Contract list | Open contracts page and inspect table/actions. | Table style, filters, and empty states match design. | P0 |
| CON-002 | Contract detail | Open contract detail. | Panels, customer/vehicle/rate sections, and actions align with design. | P0 |
| CON-003 | Print contract | Use print preview. | Printable contract remains document-like and does not include broken app chrome. | P0 |
### Fleet
| ID | Page/feature | Steps | Expected result | Priority |
|---|---|---|---|---:|
| FLEET-001 | Fleet list | Open fleet page with many vehicles. | Cards/table/grid are readable; status colors include text/icons. | P0 |
| FLEET-002 | Vehicle detail | Open vehicle detail for available, reserved, maintenance vehicles. | Detail panels, pricing, availability, and actions are consistent. | P0 |
| FLEET-003 | Vehicle calendar | Open calendar view if present. | Calendar cells, selected date, availability, and overflow are usable. | P1 |
| FLEET-004 | Vehicle pricing | Edit pricing rules if supported. | Inputs, tables, add/remove states, and save behavior are clear. | P1 |
### Customers and team
| ID | Page/feature | Steps | Expected result | Priority |
|---|---|---|---|---:|
| CUST-001 | Customers | Open customers page, search, inspect profiles/actions. | Table/cards, empty states, and row actions match design. | P0 |
| TEAM-001 | Team list | Open team page with active/invited/inactive members. | Roles/statuses are clear and not color-only. | P0 |
| TEAM-002 | Invite modal | Open invite member modal and submit invalid/valid data. | Modal, focus, validation, and success/error states work. | P0 |
| TEAM-003 | Edit member modal | Change role/permissions where allowed. | Permission matrix is readable and keyboard usable. | P1 |
| TEAM-004 | Limited permission user | Log in as limited member. | Restricted nav/actions are hidden or disabled consistently. | P0 |
### Online reservations, reviews, complaints, offers
| ID | Page/feature | Steps | Expected result | Priority |
|---|---|---|---|---:|
| OPS-001 | Online reservations | Open page with pending/accepted/rejected requests. | Statuses, action buttons, details, and empty states are consistent. | P0 |
| OPS-002 | Reviews | Open reviews page with data and empty state. | Review cards/table and response controls are readable. | P1 |
| OPS-003 | Complaints | Open complaints page with open/resolved items. | Priority/status treatment is accessible and consistent. | P1 |
| OPS-004 | Offers | Create/edit/disable an offer where supported. | Orange is used only for promotional emphasis; operational saves are blue. | P1 |
### Reports, notifications, billing, subscription, settings
| ID | Page/feature | Steps | Expected result | Priority |
|---|---|---|---|---:|
| MGT-001 | Reports | Open reports page with and without data. | Charts/tables/cards align and stay readable in dark mode. | P1 |
| MGT-002 | Notifications | Open notifications, mark read/unread if supported. | Read/unread states are visible and accessible. | P1 |
| MGT-003 | Billing | Open billing page with active/past-due/trial states. | Plan cards, invoices, payment CTAs, and warnings are clear. | P0 |
| MGT-004 | Subscription | Open subscription page and test plan state display. | Current plan, upgrade/downgrade/cancel paths are visually clear. | P0 |
| MGT-005 | Settings | Open all settings sections. | Sections are organized, forms are consistent, and save states work. | P0 |
| MGT-006 | Dashboard route refresh | Refresh every dashboard page directly. | No route loses layout, auth, locale, or styling after refresh. | P0 |
---
## 14. Platform admin tests
### Admin authentication
| ID | Page/feature | Steps | Expected result | Priority |
|---|---|---|---|---:|
| AD-AUTH-001 | Admin login | Open admin login and test invalid/valid credentials. | Page matches design; errors are readable; success redirects to admin dashboard. | P0 |
| AD-AUTH-002 | Admin forgot/reset password | Test forgot and reset flows. | Validation and success/error states are clear. | P1 |
| AD-AUTH-003 | Auth redirect | Open admin root and auth redirect routes. | Correct redirect behavior for logged-in/logged-out users. | P0 |
### Admin dashboard and management pages
| ID | Page/feature | Steps | Expected result | Priority |
|---|---|---|---|---:|
| AD-001 | Admin overview | Open admin dashboard home. | Hero/metrics/actions match Phase 16 style. | P0 |
| AD-002 | Companies list | Open companies page with many companies. Search/filter/sort where available. | Table/cards, statuses, and actions are consistent. | P0 |
| AD-003 | Company detail | Open company detail for active, trial, suspended/past-due companies. | Panels, admin actions, metadata, and billing/status sections are clear. | P0 |
| AD-004 | Renters | Open renters page. Inspect search/filter/detail actions. | Layout and status treatment are consistent. | P1 |
| AD-005 | Admin users | Open admin users page. Create/edit/disable if supported. | Forms/modals/buttons use shared design and permissions are clear. | P0 |
| AD-006 | Billing | Open admin billing page. | Invoices/subscriptions/payment states are readable and consistent. | P0 |
| AD-007 | Pricing | Open pricing management. Add/edit plans where supported. | Form fields, conversion accents, and save buttons follow token rules. | P0 |
| AD-008 | Containers | Open containers page. | Container status, controls, tables, and warnings are clear. | P1 |
| AD-009 | Audit logs | Open audit logs with dense data. Search/filter if available. | Dense table remains readable, scrollable, and accessible. | P1 |
| AD-010 | Notifications | Open admin notifications page. | Creation/list/status/empty states are consistent. | P1 |
| AD-011 | Menu management | Open menu management page. Edit/reorder/toggle items if supported. | Drag/drop or controls work and are usable on mobile. | P1 |
| AD-012 | Site config | Open site configuration page. Edit fields and save. | Field styling, section hierarchy, validation, and success states work. | P0 |
| AD-013 | Admin mobile | Test all admin pages at 360 px. | Drawer, tables, modals, and forms remain usable without horizontal page scroll. | P0 |
| AD-014 | Admin route refresh | Refresh every admin page directly. | No page loses shell, auth state, or styling. | P0 |
---
## 15. Localization and RTL tests
Run these checks across homepage, Carplace, dashboard auth, dashboard, and admin where language switching is available.
| ID | Scenario | Steps | Expected result | Priority |
|---|---|---|---|---:|
| LOC-001 | English | Use English UI. | Copy fits controls; dates/numbers are readable. | P0 |
| LOC-002 | French | Switch to French. | Longer French labels do not overflow buttons, cards, tables, or nav. | P0 |
| LOC-003 | Arabic RTL | Switch to Arabic. | Layout direction flips; sidebar, nav, icons, paddings, and text alignment are RTL-aware. | P0 |
| LOC-004 | Mixed content | View emails, names, phone numbers, prices, and vehicle names in Arabic UI. | LTR data remains readable inside RTL layout. | P1 |
| LOC-005 | Mobile Arabic | Test public and authenticated mobile pages in Arabic. | Drawers open from the correct side; content does not clip. | P0 |
| LOC-006 | Missing translation | Force/identify missing string where possible. | No raw translation keys leak into UI. | P1 |
---
## 16. Theme tests
| ID | Scenario | Steps | Expected result | Priority |
|---|---|---|---|---:|
| THEME-001 | Light mode | Switch to light mode and inspect all major routes. | Contrast, shadows, borders, and panels match Phase 16. | P0 |
| THEME-002 | Dark mode | Switch to dark mode and inspect all major routes. | Text, inputs, badges, tables, dialogs, and menus remain readable. | P0 |
| THEME-003 | System mode | Set system theme and change OS preference. | App follows system setting if supported. | P1 |
| THEME-004 | Theme persistence | Change theme, refresh, open new tab. | Theme persists consistently where expected. | P1 |
| THEME-005 | Dark mode modals/dropdowns | Open menus, dialogs, date pickers, selects. | Overlays do not appear with mismatched light/dark styling. | P0 |
---
## 17. Responsive testing checklist
For each major route group, test 360 px, 390 px, 768 px, 1280 px, and 1440 px widths.
| ID | Check | Expected result |
|---|---|---|
| RESP-001 | No horizontal page scroll | Content fits viewport except intentional internal table scrolling. |
| RESP-002 | Sidebar/drawer behavior | Desktop sidebar becomes usable mobile drawer. |
| RESP-003 | Topbar behavior | Topbar does not cover content or controls. |
| RESP-004 | Tables | Tables either stack, scroll inside a panel, or remain readable. |
| RESP-005 | Forms | Labels, inputs, helper text, errors, and buttons fit. |
| RESP-006 | Modals | Dialogs fit viewport and scroll internally if needed. |
| RESP-007 | Cards/grids | Cards stack with reasonable spacing. |
| RESP-008 | Footer | Footer columns collapse cleanly. |
| RESP-009 | CTAs | Primary actions remain reachable without awkward scrolling. |
| RESP-010 | Touch targets | Controls are large enough for touch interaction. |
---
## 18. Accessibility spot-check plan
This is not a full WCAG audit, but these checks are mandatory before release.
| ID | Check | Steps | Expected result | Priority |
|---|---|---|---|---:|
| A11Y-001 | Keyboard navigation | Use Tab/Shift+Tab through every major page. | Focus order is logical and visible. | P0 |
| A11Y-002 | Skip/repeated navigation | Test repeated nav areas. | User can reach main content without excessive tabbing where supported. | P1 |
| A11Y-003 | Menus/dialogs | Open and close nav menus, dropdowns, modals. | Focus enters, remains usable, and returns predictably. | P0 |
| A11Y-004 | Forms | Trigger validation errors. | Errors are associated with fields and readable. | P0 |
| A11Y-005 | Color contrast | Inspect text, badges, disabled states, links in light/dark. | Text and states are legible. | P0 |
| A11Y-006 | Color-only status | Inspect statuses. | Status is not communicated by color alone. | P0 |
| A11Y-007 | Zoom | Test browser zoom at 200%. | Content remains usable without major clipping. | P1 |
| A11Y-008 | Reduced motion | Enable reduced motion. | No essential interaction depends on animation. | P1 |
| A11Y-009 | Forced colors | Test high-contrast/forced-colors mode if available. | Focus, text, and controls remain usable. | P1 |
| A11Y-010 | Screen reader smoke | Use VoiceOver/NVDA on key pages. | Headings, buttons, form labels, links, and menus are understandable. | P1 |
---
## 19. Error, empty, loading, and permission states
Verify these states across homepage forms, Carplace booking, dashboard pages, and admin pages.
| ID | State | How to test | Expected result | Priority |
|---|---|---|---|---:|
| STATE-001 | Loading | Throttle network or reload API-heavy pages. | Loading UI uses shared styling and avoids layout collapse. | P0 |
| STATE-002 | Empty data | Use account with no records. | Empty state explains what to do next and uses matching card/panel style. | P0 |
| STATE-003 | Validation error | Submit required forms empty or invalid. | Error messages are clear, close to fields, and accessible. | P0 |
| STATE-004 | Server error | Simulate 500/API failure where possible. | Error message is readable and not a raw stack trace. | P0 |
| STATE-005 | Unauthorized | Access dashboard/admin while logged out. | Redirect or blocked state is correct. | P0 |
| STATE-006 | Forbidden | Access admin-only route with non-admin user. | User sees safe forbidden state or redirect. | P0 |
| STATE-007 | Not found | Open invalid public, dashboard, storefront, and admin URLs. | Styled not-found behavior, no broken shell. | P1 |
| STATE-008 | Offline | Disable network after page load and perform action. | User receives clear failure feedback. | P1 |
---
## 20. Cross-app route and brand consistency tests
| ID | Check | Steps | Expected result | Priority |
|---|---|---|---|---:|
| XAPP-001 | Homepage to dashboard auth | Use homepage CTA that leads to sign-in/create account. | Correct app opens with public navbar/footer and same design language. | P0 |
| XAPP-002 | Homepage to Carplace | Use marketplace/explore links if present. | Carplace opens with shared public design. | P0 |
| XAPP-003 | Dashboard to public site | Use logo/help/home links where present. | Correct destination; no old domain/path if not intended. | P1 |
| XAPP-004 | Admin to company detail | From admin companies, open company detail. | Route works and design remains consistent. | P0 |
| XAPP-005 | Branding | Search visible UI for old names. | Only `RentalDriveGo` and intentional `Carplace` marketplace naming appear. | P0 |
| XAPP-006 | Favicon/logo assets | Inspect browser tab and logos across apps. | Assets are not broken, stretched, or legacy-branded. | P1 |
---
## 21. Manual regression checklist before release
Run this checklist after every UI/design change:
- Homepage loads in EN, FR, AR.
- Public navbar works on desktop and mobile.
- Public footer appears on homepage, Carplace, sign-in, create-account, forgot-password, reset-password, verify-email, onboarding.
- Embedded auth hides navbar/footer with `embedded=1`.
- Dashboard login works.
- Dashboard overview loads.
- Dashboard reservations list, new reservation, and reservation detail load.
- Dashboard contracts list, contract detail, and print preview work.
- Dashboard fleet list and vehicle detail load.
- Dashboard customers, team, billing, subscription, reports, notifications, settings load.
- Admin login works.
- Admin overview, companies, company detail, renters, admin users, billing, pricing, containers, audit logs, notifications, menu management, site config load.
- Carplace home, explore, company page, vehicle page, booking form, renter dashboard load.
- Light/dark mode checked on at least homepage, dashboard overview, admin companies, Carplace explore.
- Arabic RTL checked on at least homepage, dashboard overview, admin companies, Carplace explore.
- Mobile checked on at least homepage, dashboard overview, admin companies, Carplace vehicle detail.
- Keyboard navigation checked on homepage, dashboard sign-in, reservation form, admin companies.
- No visible old branding.
- No horizontal scroll at mobile width.
- No raw errors, stack traces, broken images, or unstyled default controls.
---
## 22. Defect reporting format
Every UI defect should include:
```text
Title:
Environment:
App:
Route:
Role/account:
Browser/device:
Language:
Theme:
Viewport size:
Steps to reproduce:
Expected result:
Actual result:
Severity:
Screenshot/video:
Console errors:
Network/API errors:
Regression? yes/no:
```
Severity definitions:
| Severity | Meaning | Example |
|---|---|---|
| S0 Blocker | User cannot complete a core flow | Cannot sign in, dashboard crashes, booking cannot submit |
| S1 Critical | Major page/flow broken or misleading | Wrong layout on mobile, save action hidden, admin table unusable |
| S2 Major | Important UI defect with workaround | Modal overflow, dark mode unreadable badge, RTL alignment bug |
| S3 Minor | Cosmetic or low-impact issue | Slight spacing mismatch, non-critical hover inconsistency |
| S4 Trivial | Polish only | Tiny copy or icon alignment issue |
---
## 23. Release exit criteria
Manual UI testing may be accepted when:
- All P0 tests pass.
- No S0 or S1 defects remain open.
- S2 defects have approved fixes or explicit release acceptance.
- Homepage, Carplace, dashboard, and admin have been tested in light, dark, and Arabic RTL.
- Mobile smoke tests pass at 360 px width.
- Keyboard navigation smoke tests pass for public auth, dashboard, and admin.
- Public navbar/footer behavior is verified on all standalone public/auth pages.
- Embedded auth behavior is verified with `embedded=1`.
- Visual consistency review confirms Phase 16 design language across public and authenticated pages.
- Stakeholder signs off with screenshots or recordings attached for the main flows.
---
## 24. Suggested execution order
1. Smoke test all apps and authentication first.
2. Test homepage and public navigation/footer.
3. Test Carplace public marketplace and renter flows.
4. Test operator dashboard routes.
5. Test platform admin routes.
6. Run localization and RTL passes.
7. Run dark mode pass.
8. Run mobile pass.
9. Run accessibility spot checks.
10. Re-test fixed defects and complete release checklist.
This order catches structural failures early. Testing every button color before confirming login works.
@@ -0,0 +1,492 @@
# RentalDriveGo — Plan to Reach Production Ready
**Purpose of this document:** This is the **execution plan to take the current codebase to production ready**. It is not a feature roadmap and not an architecture rewrite. Success is measured only by the definition in §1 and the checkpoint in §13.
**Status:** Phases 04 **application code / runbooks complete** (12 Aug 2026). Remaining work is **ops evidence** (CI smoke, restore/alert drills, pen-test, soak) — not missing features. Phase 4 correctly does **not** extract microservices (ADR-003).
**Code root:** `D:\1\management`
**Last re-verified against source:** 12 Aug 2026 (Phases 04 code pass)
**Inputs:** Live repo state + *Technical Architecture & Investor Due Diligence* (v1.0, 9 Aug 2026) + prior hardening reports under `docs/`
**Architecture decision:** Keep the modular monolith. Do not split services until Phase 3 load/ownership evidence justifies it.
### How this plan works
```mermaid
flowchart TD
now[Current_beta_pre_scale] --> sec[Close_security_P0]
sec --> p0[Finish_Phase0_evidence]
p0 --> p1[Phase1_replica_safe]
p1 --> p2[Phase2_operate_recover]
p2 --> p3[Phase3_prove_under_load]
p3 --> prod[Production_ready_gate]
```
| Stage | Outcome |
|-------|---------|
| Security P0 + Phase 0 close | Safe enough to run a controlled environment; envelope proven |
| Phase 1 | Safe to run **two API replicas** + worker |
| Phase 2 | Operable: observe, backup/restore, commercial/privacy baselines |
| Phase 3 + §13 checklist | **Production ready** — claims allowed only after exit evidence |
---
## 1. Definition of “production ready” (the finish line)
The project is **production ready** only when all of the following are true and evidenced:
1. Install, generate, lint, type-check, test, and build from a clean checkout
2. Deploy a known topology (API, frontends, PostgreSQL, Redis, storage, worker)
3. Run **two API replicas** without duplicate bookings, duplicate cron side effects, or missing files
4. Deliver notifications that were written to the outbox (email + realtime) without multi-replica double-send
5. Detect failure, restore data within agreed RPO/RTO, and show no unresolved critical/high dependency vulnerabilities outside a dated exception
6. Ship with Critical/High application-security findings closed (§3)
7. §13 diligence checkpoint items are checked off with retained evidence
Until then, the accurate label remains **capable beta / pre-scale**, not production SaaS.
**Out of scope for this plan:** new marketplace features, KYC/OCR, per-tenant Docker isolation, microservices rewrite, marketing-only work.
### Why this path
> The core product and data architecture exist; the next milestone is to convert that breadth into a reproducible, secure, observable, horizontally safe production system.
---
## 2. Current state (re-verified after project update)
### 2.1 Progress since the original diligence snapshot
| Area | Previous gap | Status now | Evidence |
|------|--------------|------------|----------|
| Turbo pipeline | Missing | **Done** | `turbo.json` (build/dev/lint/type-check/db:*) |
| Shared TS base | Missing | **Done** | `tsconfig.base.json` |
| Scripts / ops helpers | Missing | **Done** | `scripts/` (env, docker-prod-*, admin, `security-static-check.mjs`, backup guides) |
| Compose / Docker | Missing | **Done** | `docker-compose.dev.yml`, `docker-compose.production.yml`, `Dockerfile.dev` / `.production` / `.test`, `production/` mirror |
| `.gitignore` | Missing | **Done** | Root `.gitignore` |
| Static security script | Missing | **Done** | `scripts/security-static-check.mjs` + `npm run security:static` |
| CI | No workflows | **Partial** | `.gitea/workflows/` (`test.yml`, `build-and-deploy.yml`) + `.gitlab-ci.yml`; **no** `.github/workflows` |
| Notification outbox consumer | Missing | **Partial** | `processNotificationOutbox()` in `notificationService.ts`; cron every minute in `apps/api/src/index.ts` — still **inside the API process**; email/IN_APP delivery + DLQ; **no** `redis.publish` for realtime |
| Prior hardening passes | — | **Documented** | `SECURITY_HARDENING_APPLIED_REPORT.md`, leftover report, `docs/SECURITY_HARDENING_*` (June 2026) — API-key hash-only, Socket.IO actor verify, cookie session work, etc. |
### 2.2 What remains strong
| Area | Evidence |
|------|----------|
| Product surfaces | `apps/homepage`, `dashboard`, `admin`, `carplace`, `api` |
| Domain depth | Prisma: fleet, reservations, billing, payments, notifications, collections, admin |
| API shape | Express modular monolith |
| Auth / tenancy | JWT actors, HttpOnly cookies, admin 2FA, company middleware, subscription gates |
| Payments foundation | Stripe / PayPal / AmanPay; webhook signature verify; `WebhookEvent` |
| Upload validation | Magic bytes + MIME + size limits |
| Deploy intent | Compose + Traefik configs, backup/restore scripts present |
### 2.3 What still blocks a production claim
| Priority | Gap | Repo evidence (current) |
|----------|-----|-------------------------|
| **P0** | App security Critical/High still open | Team API spreads `passwordHash` / reset tokens; plaintext invite tokens; open redirect; unrestricted payment return URLs on authenticated checkout; admin presenter scrub incomplete; container Docker-socket design still in tree — see **§3** |
| **P0** | Ghost / dangerous container feature | `containerService.ts` + `apps/admin/.../containers/page.tsx` still present |
| **P0** | Dependency SCA not freshly proven | Diligence (9 Aug): 21 prod vulns; must re-run on CI/clean runner |
| **P0** | Phase 0 exit not fully evidenced | Envelope files exist, but clean-runner green CI + container removal + SCA gate not closed |
| **P1** | Outbox not multi-replica safe | Processor runs via `node-cron` in every API process; no lease/lock; no Redis realtime publish |
| **P1** | Process-local coordination | In-memory `express-rate-limit`; Carplace `idempotencyCache` `Map`; all crons in API `index.ts` |
| **P1** | Local file storage | `FILE_STORAGE_ROOT` disk — no S3/MinIO adapter found |
| **P1** | Ops blind spots | Only `GET /health`; no `/ready`; no `SIGTERM` graceful shutdown |
| **P1** | Catalog drift | Homepage pricing vs shared plan/entitlement constants (unchanged risk) |
```mermaid
flowchart LR
subgraph done [Restored_envelope]
Turbo[turbo_tsconfig]
Compose[compose_Dockerfiles]
Scripts[scripts_security_static]
Gitignore[gitignore]
end
subgraph open [Still_open]
Sec[App_security_Critical_High]
Containers[containerService_UI]
Shared[Redis_rate_limit_idempotency]
Worker[Separate_worker_lease]
Ready[ready_shutdown_object_store]
end
done --> open
```
---
## 3. Security assessment (re-checked 12 Aug 2026 after update)
**Scope:** Static re-verification of findings from the earlier application review against current source.
**Not in this pass:** Live pen-test, production secrets rotation, successful live `npm audit` (registry TLS may still block local runs).
### 3.1 Controls that remain solid
| Control | Evidence |
|---------|----------|
| Tenant scoping on core CRUD | Company routes use session `companyId` |
| JWT from env + HS256 pinned | `security/tokens.ts` |
| Session cookies HttpOnly / Secure / SameSite | `sessionCookies.ts` |
| Hashed company API keys (legacy plaintext removed) | Hardening reports + schema |
| Upload magic-byte validation | `http/upload` |
| Payment webhook signatures | Stripe / PayPal / AmanPay paths |
| Forwarded-header scrubbing by default | `sanitizeForwardedHeaders` unless `TRUSTED_FORWARD_HEADERS=true` |
| Site payment redirect allowlist | `assertAllowedPaymentRedirect` in `site.service.ts` |
### 3.2 Findings status after project update
| Sev | ID | Status | Location | Finding |
|-----|----|--------|----------|---------|
| Critical | S1 | **FIXED (Phase 0)** | `teamService.ts` | Team list/invite use safe presenter; no hash/token leakage |
| Critical | S2 | **FIXED (Phase 0)** | `containerService.ts` + admin containers page + ADR-001 | Feature disabled / fail-closed; UI shows out-of-scope |
| High | S3 | **FIXED (Phase 0)** | `teamService.ts` invite | Invite token stored as SHA-256 hash |
| High | S4 | **FIXED (Phase 0)** | Prisma `Employee` + auth repo | `@@unique([companyId, email])`; login fails closed on ambiguity |
| High | S5 | **FIXED (Phase 0)** | `SignInForm.tsx` | Safe relative-path redirect only |
| High | S6 | **FIXED (Phase 0)** | `paymentRedirects.ts` + payment/subscription services | Authenticated checkout allowlists return URLs |
| High | S7 | **FIXED (Phase 0)** | `admin.schemas` / `admin.repo` | Slug regex + slugify on update |
| High | S8 | **FIXED (Phase 0)** | `admin.presenter.ts` | Strips reset/verification secrets |
| High | S9 | **FIXED (docs + default scrub)** | `forwardedHeaders.ts` + `docs/ops/proxy-trust.md` | Default scrub; TRUSTED_FORWARD_HEADERS documented |
| Medium | S10 | **FIXED (Phase 0)** | employee/admin reset repos | Hash-only reset token lookup |
| Medium | S11 | **FIXED (Phase 3)** | reservation/review presenters | `reviewToken` omitted from API JSON |
| Medium | S12 | **FIXED** | `site.repo` / `site.service` | Public booking token unused-only on payment consume |
| Medium | S13 | **FIXED** | `requireFreshAdmin2FA` | Max-age TTL (`ADMIN_FRESH_2FA_MAX_AGE_MS`, default 30m) |
| Medium | S14 | **FIXED** | `.gitignore` | Present |
| Medium | S15 | **FIXED** | `scripts/security-static-check.mjs` | Present; CI wired; local pass after env scrub |
### 3.3 Dependency / SCA status
| Check | Result |
|-------|--------|
| Diligence SCA (9 Aug 2026) | 21 production findings: 1 critical, 14 high, 5 moderate, 1 low |
| Local re-audit | May fail on TLS to registry — **do not treat as clean** |
| Required | CI/clean-runner `npm audit --omit=dev` (or OSV) with fail-on critical/high |
### 3.4 Security remediations (ordered)
**P0 — before any production traffic**
1. **S1:** Explicit safe select/presenter for team APIs — never return hashes/tokens
2. **S3:** Hash invite tokens at rest; remove raw dual-match after migration (**S10**)
3. **S8:** Expand admin presenter denylist
4. **S2:** Remove/disable `containerService` + admin containers UI from GA
5. **S14/S15:** Already fixed — keep in CI
6. Re-run and clear dependency critical/high
**P1 — before multi-user GA**
7. **S4:** `@@unique([companyId, email])` + fail-closed login
8. **S5:** Allowlist relative same-origin post-login redirects
9. **S6:** Apply payment redirect allowlist to authenticated checkout/subscription
10. **S7:** Slugify/validate admin slug updates
11. **S9:** Document proxy trust; never enable trusted forwards without edge scrubbing
12. **S11S13:** Hide review tokens; single-use public access; align fresh 2FA on money mutations
### 3.5 Security exit criteria
- [ ] No API response includes password hashes, TOTP secrets, or raw reset/invite tokens
- [ ] Invite/reset tokens hashed at rest; legacy raw match removed
- [ ] Container/Docker-socket feature absent from production scope
- [ ] Login redirect and payment return URLs allowlisted on all checkout paths
- [ ] Employee email uniqueness (or fail-closed login) enforced
- [ ] CI runs `security:static` + SCA; no unresolved critical/high outside dated exception
- [ ] Independent pen-test after deploy envelope proven (Phase 3)
---
## 4. Guiding principles
1. **Evidence over claims** — Phase exit criteria must be demonstrable.
2. **Close Critical/High security before scale work** — Envelope restore is largely done; app-sec P0 is now the front of the queue.
3. **Shared state before more replicas** — Redis/DB/object storage before scaling API.
4. **One worker plane** — Notifications and scheduled jobs must not run identically on every API replica.
5. **Disable incomplete privileged features** — Especially Docker-socket container management.
6. **One commercial source of truth** — Marketing, checkout, and enforcement share typed entitlements.
7. **Extract services last** — Only after measurement.
---
## 5. Phase 0 — Evidence recovery
**Goal:** Reproducible build/deploy envelope + security hygiene baseline.
**Update:** Core files are **restored**. Remaining work is **prove + close security/container/SCA**.
### 5.1 Build orchestration — DONE
| Deliverable | Status |
|-------------|--------|
| `turbo.json` | Present |
| `tsconfig.base.json` | Present |
| `scripts/` (env, docker-prod, admin, security-static) | Present |
### 5.2 Runtime topology — DONE (files present)
| Deliverable | Status |
|-------------|--------|
| `docker-compose.dev.yml` / `.production.yml` | Present |
| `Dockerfile.dev` / `.production` / `.test` | Present |
| Env examples | Present (`.env.example`, docker env samples) |
| Backup/restore scripts | Present under `scripts/` |
**Still required as evidence:** recorded smoke that Compose boots API + Postgres + Redis and `/health` succeeds on a clean machine.
### 5.3 Continuous integration — PARTIAL
| Deliverable | Status |
|-------------|--------|
| Gitea workflows | Present (`.gitea/workflows/test.yml`, `build-and-deploy.yml`) |
| GitLab CI | Present (`.gitlab-ci.yml`) |
| GitHub Actions | Not present (optional if Gitea/GitLab is the system of record) |
| Proven green run + SCA fail gate | **Not evidenced in this review** |
### 5.4 Ghost container control plane — NOT DONE
| Action | Status |
|--------|--------|
| Remove admin containers UI | **Still present** |
| Quarantine/delete `containerService.ts` | **Still present** |
| ADR: out of GA | Missing |
### 5.5 Dependency hygiene — NOT EVIDENCED
Must re-run SCA on CI and clear critical/high.
### Phase 0 exit criteria (updated checkboxes)
- [x] `turbo.json` + `tsconfig.base.json` + `scripts/` present in tree
- [x] Compose + Dockerfiles present in tree
- [x] `.gitignore` + `security:static` present
- [x] Team API no longer returns password hashes / reset tokens; invite tokens hashed at rest (**S1/S3**)
- [x] Admin presenter scrubs reset/verification secrets (**S8**)
- [x] Container orchestration disabled + ADR (`docs/ADR-001-disable-per-tenant-containers.md`) (**S2**)
- [x] Login redirect allowlisted; authenticated payment return URLs allowlisted; admin slug validated; employee `(companyId, email)` unique (**S4S7**)
- [x] Env example/dev templates scrubbed of real-looking secrets; `security:static` passes locally
- [x] Gitea CI includes `security:static` + `npm audit --omit=dev --audit-level=high`
- [ ] Fresh clone: `npm ci` → generate → lint → type-check → test → build with no local repair (needs recorded evidence on a clean runner)
- [ ] CI green on default branch with SCA policy (push/run evidence)
- [ ] Compose smoke: API + Postgres + Redis; `/health` ok (recorded)
- [ ] No unresolved critical/high vulns outside dated exceptions (await CI audit result)
---
## 6. Phase 1 — Correctness and shared state
**Goal:** Two API replicas + one dedicated worker are correct under retries and failover.
**Status (12 Aug 2026):** Core code landed. Still needs `npm ci`, migrate, and a two-replica Compose smoke for exit evidence.
### 6.1 Notification outbox — DONE in code
| Piece | Status |
|-------|--------|
| Process isolation | `apps/api/src/workers/index.ts` + Compose `api-worker`; API jobs only if `ENABLE_EMBEDDED_JOBS=true` |
| Leasing | `lockedAt` / `lockedBy` / `attempts` / `availableAt` + claim via `updateMany` |
| Realtime | `redis.publish('notifications:' + userId, …)` on IN_APP delivery |
| Metrics | Phase 2 `/metrics` + outbox counters (scrape/alerts still open) |
### 6.2 Shared rate limiting — DONE in code
Redis store in `redisRateLimitStore.ts` (memory when `NODE_ENV=test` or `RATE_LIMIT_STORE=memory`).
### 6.3 Durable booking idempotency — DONE in code
`idempotencyStore.ts` (Redis; memory in test) used by Carplace `/reservations`.
### 6.4 Externalize scheduled work — DONE in code
Cron moved to `workers/jobs.ts` with Redis leader lock. API no longer starts cron by default.
### 6.5 Object storage — DONE in code (optional)
`FILE_STORAGE_DRIVER=local|s3` + `@aws-sdk/client-s3` + MinIO Compose profile `storage`. Default remains local disk.
### 6.6 Readiness and graceful shutdown — DONE in code
| Item | Status |
|------|--------|
| `GET /health` | Liveness |
| `GET /ready` | DB + Redis + storage probes |
| `SIGTERM` drain | API + worker close HTTP/Socket/Redis/Prisma |
### Phase 1 exit criteria
- [x] Worker entrypoint + outbox lease + Redis publish implemented
- [x] Redis rate limits + durable Carplace idempotency implemented
- [x] Cron externalized with leader lock; `/ready` + graceful shutdown implemented
- [x] S3/MinIO adapter + Compose worker/MinIO services present
- [ ] Two API replicas + one worker: recorded concurrency/retry smoke (needs runner)
- [ ] Outbox no double-send under two API replicas (API without embedded jobs)
- [ ] Files readable across replicas when `FILE_STORAGE_DRIVER=s3` (optional smoke)
---
## 7. Phase 2 — Operational control
**Code baselines landed (2026-08):** metrics/logs endpoint, plan catalog + tests, OpenAPI coverage gate, backup smoke check, privacy + billing/notification source-of-truth docs. Remaining work is **evidence** (drills, owners, alerts).
| Item | Status | Location |
|------|--------|----------|
| Structured JSON access logs + `/metrics` (latency, status, outbox) | **In code** | `apps/api/src/lib/opsMetrics.ts`, `app.ts`, worker |
| Readiness `/ready` | **In code** (Phase 1) | DB / Redis / storage |
| Plan/entitlement catalog + contract tests | **In code** | `packages/types/src/planCatalog.ts`, homepage pricing import |
| OpenAPI completeness gate | **In code** | `npm run openapi:coverage``scripts/check-openapi-coverage.mjs` |
| Backup artifact smoke check + RPO/RTO checklist | **In code / docs** | `scripts/backup-restore-smoke-check.sh`, `scripts/backup-restore-guide.md` |
| Privacy data map | **Doc baseline** | `docs/PRIVACY_DATA_MAP.md` (owners / DSAR still open) |
| Billing & notification SoT | **Doc baseline** | `docs/BILLING_NOTIFICATION_SOURCE_OF_TRUTH.md` |
| Staging alert + restore drill evidence | **Open** | Ops exercise |
| Provider reconciliation sample | **Open** | Finance / eng |
### Phase 2 exit criteria
- [ ] Staging incident detectable and recoverable via runbooks (metrics scraped + alert fired once)
- [ ] Restore exercise meets RPO/RTO (dated drill using backup smoke check)
- [ ] Provider reconciliation sample exists
- [x] Plan catalog single-sourced with tests
- [x] Privacy data map drafted (assign legal/ops owners before GA)
- [x] OpenAPI coverage script in CI
- [x] Billing/notification source-of-truth documented
---
## 8. Phase 3 — Scale and assurance
**Goal:** Prove the system holds under load/failure, tenant isolation, independent security testing, and operable release/secret drills. Keep the modular monolith until measurement says otherwise (ADR-002 defers RLS).
**Code / runbook baselines landed (2026-08):**
| Item | Status | Location |
|------|--------|----------|
| Cross-tenant negative suite | **In code** | `apps/api/src/tests/integration/cross-tenant-isolation.test.ts` |
| S11 reviewToken scrubbed from API payloads | **FIXED** | reservation presenter + review service presenters |
| Soak / load probe (+ optional k6) | **In code** | `scripts/load/soak-probe.mjs`, `booking-smoke.k6.js``npm run test:soak` |
| Failure injection helper | **In code** | `scripts/chaos/failure-injection.sh` |
| Canary / rollback runbook | **Doc** | `docs/ops/canary-rollback.md` |
| Key rotation drill | **Doc** | `docs/ops/key-rotation-drill.md` |
| Pen-test scope pack | **Doc** | `docs/security/pen-test-scope.md` |
| Postgres RLS | **Deferred** | `docs/ADR-002-defer-postgres-rls.md` |
### Phase 3 exit criteria
- [ ] Soak + failure-injection drill completed on staging with dated metrics evidence
- [x] Cross-tenant suite green in CI (`cross-tenant-isolation`) — **code landed**; CI run is evidence
- [ ] Independent pen-test report in `security-reports/`; Critical/High closed or accepted
- [ ] Canary promote **or** rollback drill recorded once
- [ ] Key rotation drill recorded on staging
- [x] App-level isolation suite started; RLS deferred per ADR-002
- [x] S11 review tokens not returned in reservation/review JSON
- [x] S12 single-use public payment token consume
- [x] S13 fresh admin 2FA TTL
### Phase 4 (months 36) — extract only if measured
**Default:** stay on the modular monolith + `api-worker` (ADR-003). Phase 4 is **not** a microservices rewrite.
| Item | Status | Location |
|------|--------|----------|
| Extraction policy ADR | **Accepted** | `docs/ADR-003-defer-service-extraction.md` |
| Gates G1G7 + candidates | **Doc** | `docs/ops/phase4-extraction-gates.md` |
| Measurement template | **Doc** | `docs/ops/phase4-measurement-template.md` |
| Module seam map | **Doc** | `docs/ops/phase4-module-boundaries.md` |
| Actual service split | **Blocked** until a candidate passes G1G7 | — |
#### Phase 4 exit criteria (for *deciding*, not for “having microservices”)
- [x] Extraction gates and candidates documented
- [x] In-monolith-first alternatives listed (scale workers, async media, thin webhooks)
- [ ] At least one soak/profile attribution packaged with the measurement template (needs Phase 3 evidence)
- [ ] Explicit decision recorded per candidate: **do not extract** (default) or approved extract ADR
Candidates if gates ever pass: payments/webhooks, notification worker as independent deployable, media processing.
---
## 9. Risk register → plan mapping
| ID | Risk | Status | Addressed by |
|----|------|--------|--------------|
| R1 | Unreproducible package | **Mostly mitigated** (files restored; prove CI smoke) | Phase 0 evidence |
| R2 | Dependency vulnerabilities | **Open** (CI policy; clear on runner) | Phase 0.5 / CI SCA |
| R3 | Privileged container feature | **Mitigated in code** (ADR-001) | Phase 0.4 + **S2** |
| R4 | Outbox not dispatched | **Mitigated in code** (worker + leases) | Phase 1.1 |
| R5 | Process-local rate limit / idempotency | **Mitigated in code** (Redis stores) | Phase 1.21.3 |
| R6 | Embedded schedules | **Mitigated in code** (worker + lock) | Phase 1.4 |
| R7 | Local file persistence | **Mitigated in code** (S3 driver) | Phase 1.5 |
| R8 | Ops blind spots | **Partial** (metrics/logs in code; alerts/drills open) | Phase 1.6 + Phase 2 |
| R9R14 | Privacy, catalog, OpenAPI, legacy overlap, FE drift, flaky tests | **Partial / later** (catalog, OpenAPI gate, privacy map, SoT docs) | Phase 23 |
| **S1S8** | App security Critical/High | **Fixed in code** (S9 documented) | §3 P0/P1 |
| **S10S15** | Medium app security | **Fixed in code** (S11S13 included) | Hardening + Phase 3 |
| **S16S21** | Medium/Low (undefined IDs) | **Track in pen-test** | Phase 3 evidence |
---
## 10. Suggested ownership and evidence log
| Field | Example |
|-------|---------|
| Phase | 0 / Security P0 |
| Date | YYYY-MM-DD |
| Commit / tag | `prod-ready-phase0` |
| Commands | `npm ci && npm run type-check && npm run security:static && npm audit --omit=dev` |
| Artifacts | CI URL, Compose smoke logs, audit report |
| Exceptions | CVE-xxxx until DATE by OWNER |
| Sign-off | Eng lead |
---
## 11. Explicit non-goals (until gates pass)
- Claiming production ready / HA / horizontally scaled before security P0 + Phase 1 exit evidence
- Shipping per-tenant container orchestration
- Guaranteeing SMS/push without provider paths + worker proof
- Marketing KYC / license authenticity beyond date/expiry validation
- Splitting the monolith for its own sake
---
## 12. Next backlog (when implementation resumes)
**Immediate (security + Phase 0 close)**
1. Fix team API secret leakage (**S1**); hash invite tokens (**S3**); scrub admin presenter (**S8**)
2. Remove/disable `containerService` + admin containers UI (**S2**)
3. Allowlist login redirect (**S5**) and authenticated payment return URLs (**S6**); slugify admin slugs (**S7**); employee email uniqueness (**S4**)
4. Record clean-runner CI green + production SCA clear/critical policy
5. Record Compose smoke evidence
**Then Phase 1**
6. Move outbox + cron to dedicated worker with leases; add Redis publish for realtime
7. Redis rate-limit store; durable Carplace idempotency
8. Object storage (MinIO/S3); `/ready` + graceful shutdown
**Then Phase 23**
9. Observability, restore drill, catalog convergence, privacy map (Phase 2 evidence still open)
10. Soak/failure drills, cross-tenant CI green, pen-test report, canary + key-rotation evidence (Phase 3)
**Then Phase 4 (only if measured)**
11. Fill `docs/ops/phase4-measurement-template.md` from Phase 3 soak data; default decision remains **do not extract** (ADR-003)
---
## 13. Diligence checkpoint (definition of done)
1. Clean checkout builds/tests on documented Node/npm with no local repair
2. Production SCA has no unresolved critical/high outside formal exception
3. Two API replicas pass booking/payment/job/notification/file correctness with shared coordination
4. Authoritative API contract + auth test matrix
5. Restore exercise meets RPO/RTO
6. Logs/metrics/alerts/runbooks demonstrated in a failure exercise
7. Privacy controls cover classification, encryption plan, retention, privileged reads/exports, incident response
8. Plan catalog / checkout / entitlements single-sourced
9. Independent security testing closes critical/high or records explicit acceptance
10. **§3 Critical/High application findings closed**
---
## 14. Thesis and kickoff
**This plan is how RentalDriveGo gets to production ready.** The monorepo envelope is largely restored; the remaining path is: close Critical/High app security → finish Phase 0 evidence → replica-safe Phase 1 → operate/recover Phase 2 → prove Phase 3 → pass §13.
**When implementation starts**, execute §12 in order. Do not skip security P0 for feature work. Do not claim production ready until §1 and §13 are evidenced.
---
*End of production-readiness plan. Code root: `D:\1\management`. Companion diligence: `RentalDriveGo_Technical_Architecture_and_Investor_Due_Diligence.docx`. Re-verified: 12 Aug 2026.*
+7
View File
@@ -0,0 +1,7 @@
{
"message": "request to https://registry.npmjs.org/-/npm/v1/security/advisories/bulk failed, reason: unable to get local issuer certificate",
"error": {
"summary": "",
"detail": ""
}
}
+47
View File
@@ -0,0 +1,47 @@
# Canary deploy & rollback (Phase 3)
**Status:** Ops runbook — evidence required before claiming production ready
**Date:** 2026-08-12
## Goal
Ship a new API image to a small fraction of traffic, watch `/metrics` + `/ready`, and roll back within minutes if error rate or latency regresses.
## Preconditions
- Release image tagged and pulled (`scripts/docker-prod-deploy.sh` path)
- Metrics scraped; alerts for 5xx and readiness exist (Phase 2)
- Previous known-good image tag recorded
## Canary procedure
1. Record baseline: `p95` latency, 5xx rate, `notification_outbox_pending` for 15 minutes.
2. Deploy new tag to **one** API replica (or Traefik weight 10% if configured).
3. Watch 1530 minutes under real or soak traffic (`npm run test:soak`).
4. **Promote** only if error rate and p95 within agreed budget vs baseline.
5. **Rollback** immediately if:
- `/ready` flapping
- 5xx rate > 2× baseline
- Outbox pending unbounded growth
- Payment/webhook failures spike
## Rollback
```bash
# Set IMAGE_TAG to last known-good and redeploy
export IMAGE_TAG=<previous-good>
bash scripts/docker-prod-deploy.sh
```
Verify `/health`, `/ready`, and a booking smoke after rollback.
## Evidence to attach
| Field | Value |
|-------|-------|
| Date | |
| Canary tag | |
| Previous tag | |
| Decision | promote / rollback |
| Metrics summary | |
| Operator | |
+45
View File
@@ -0,0 +1,45 @@
# Key rotation drill (Phase 3)
**Status:** Ops runbook
**Date:** 2026-08-12
## Secrets in scope
| Secret | Used by | Rotation impact |
|--------|---------|-----------------|
| `JWT_SECRET` | API token signing | Invalidates existing employee/admin/renter sessions |
| Company API keys | Partner/Carplace integrations | Per-company reissue via admin/API |
| Payment provider webhooks | Stripe/PayPal/AmanPay | Update dashboard + env together |
| DB / Redis passwords | Compose / managed services | Coordinated restart |
| Object storage keys | S3/MinIO driver | Dual-key period preferred |
## JWT_SECRET drill (staging)
1. Announce maintenance window (sessions will drop).
2. Generate a new high-entropy secret; store in secret manager **before** env change.
3. Update staging `.env` / secret store; rolling-restart API + worker.
4. Confirm:
- Old bearer tokens return 401
- Fresh login issues valid tokens
- `/ready` stays healthy
5. Record time-to-rotate and any customer-facing impact.
## Company API key drill
1. Create a replacement key for a test company.
2. Switch the client to the new key.
3. Revoke/disable the old key.
4. Confirm old key fails; new key succeeds.
## Evidence
| Field | Value |
|-------|-------|
| Date | |
| Environment | staging |
| Secrets rotated | |
| Duration | |
| Issues | |
| Operator | |
Do **not** rotate production secrets without dual-control and a tested rollback path for webhook signing secrets.
+46
View File
@@ -0,0 +1,46 @@
# Phase 4 — Extraction gates & candidates
**Status:** Planning / measurement only (ADR-003)
**Date:** 2026-08-12
**Prerequisite:** Phase 3 exit evidence (soak, pen-test, canary, key rotation) should be underway before any extraction design review.
## Rule
Extract a bounded context into its **own deployable** only if measurement shows the monolith cannot meet SLOs or blast-radius requirements **and** ownership is staffed. Otherwise scale the existing `api` + `api-worker` topology.
## Candidates (from diligence / readiness plan)
| Candidate | Today | Extract when… | Prefer first |
|-----------|--------|---------------|--------------|
| **Notification worker** | Already a separate **process** (`apps/api` worker / Compose `api-worker`) sharing the API package | Worker CPU/memory or release cadence is blocked by API deploys; or need multi-language worker fleet with independent scaling | Scale `api-worker` replicas; keep shared package |
| **Payments / webhooks** | Modules inside API (`payments`, `billing`, `subscriptions`, webhook routes) | Webhook lag or payment CPU dominates API p95; or PCI/provider isolation requires a smaller trust boundary | Dedicated webhook ingress + queue inside monolith; idempotent consumers |
| **Media processing** | Upload + storage drivers in API; local/S3 | Image/PDF processing blocks request threads or storage I/O saturates API | Async job on `api-worker`; object storage (MinIO/S3) already preferred |
## Hard gates (all required per candidate)
Copy to an evidence note before any extract ADR:
| # | Gate | Evidence |
|---|------|----------|
| G1 | Phase 3 soak baseline exists | Dated `test:soak` / k6 + `/metrics` snapshot |
| G2 | Bottleneck attributed | Profile or metrics: p95, queue lag, CPU by route/job — not anecdote |
| G3 | Blast radius / compliance need | Written threat or compliance reason (e.g. webhook storm, media malware scan) |
| G4 | Ownership | Named eng + on-call for the new service |
| G5 | Contract | OpenAPI or event schema + consumer contract tests |
| G6 | Dual-run | Shadow or dual-publish ≥ 1 release cycle with zero silent divergence |
| G7 | Rollback | Documented cutback to monolith path in &lt; 30 minutes |
If any gate fails → **do not extract**; file an in-monolith improvement instead.
## In-monolith improvements (do these before/instead of extract)
1. Keep payment/webhook handlers thin; push side effects through outbox/jobs.
2. Run N `api-worker` replicas with DB leases (already Phase 1).
3. Move heavy media work to worker jobs + S3; never resize on the request path.
4. Publish domain events internally (same DB outbox) so a future service can subscribe without a big-bang rewrite.
## Explicit non-goals for Phase 4
- Rewriting the monorepo into many services
- Separate databases per module “for purity”
- Per-tenant container orchestration (still ADR-001)
+54
View File
@@ -0,0 +1,54 @@
# Phase 4 — Extraction measurement template
Fill one copy per candidate (`notifications` | `payments-webhooks` | `media`). Store dated copies under `docs/ops/evidence/` (create as needed). Do not extract without G1G7.
## Candidate
- Name:
- Date:
- Author:
- Environment measured: staging / production
## G1 — Soak baseline
- Command / duration:
- Error rate / p95:
- Link or paste `/metrics` summary:
## G2 — Bottleneck
- Symptom (SLO miss):
- Attribution (route, job, DB, Redis, storage):
- Supporting graph or log sample:
## G3 — Blast radius / compliance
- Why a separate deployable (not just more workers):
## G4 — Ownership
- Eng owner:
- On-call:
- Budget for dual-run:
## G5 — Contract
- Sync API or async events:
- Contract test location (planned):
## G6 — Dual-run plan
- Shadow period:
- Diff/alert strategy:
## G7 — Rollback
- Cutback steps:
- Drill date (must be practiced once):
## Decision
- [ ] **Do not extract** — pursue in-monolith item: _______________
- [ ] **Extract** — write service ADR and implementation plan (separate change)
Sign-off: _______________ date: _______________
+41
View File
@@ -0,0 +1,41 @@
# Module boundaries for possible Phase 4 extracts
**Purpose:** Document current monolith seams so a future extract does not require archaeology. Not a license to split today (ADR-003).
## Notification / jobs
| Piece | Path |
|-------|------|
| Worker entry | `apps/api/src/workers/index.ts` |
| Job loop | `apps/api/src/workers/jobs.ts` |
| Outbox processing | `apps/api/src/services/notificationService` (and related) |
| Compose | `api-worker` in `docker-compose*.yml` |
**Seam:** DB outbox + Redis pub for IN_APP. Extract later = move worker package + keep outbox schema shared or via events.
## Payments / webhooks
| Piece | Path |
|-------|------|
| Webhook router | `apps/api/src/modules/webhooks/` |
| Payments | `apps/api/src/modules/payments/` |
| Billing | `apps/api/src/modules/billing/` |
| Subscriptions | `apps/api/src/modules/subscriptions/` |
**Seam:** Provider signature verify → idempotent intent/invoice update → outbox side effects. Extract later = webhook ingress service writing to the same billing tables or a command queue.
## Media
| Piece | Path |
|-------|------|
| Storage drivers | `apps/api/src/lib/storage` |
| Upload HTTP | `apps/api/src/http/upload` (and module callers) |
| Compose MinIO | `minio` profile in dev compose |
**Seam:** API accepts upload → stores object key → optional worker job for virus scan / derivatives. Extract later = media service owning bucket + callback to API.
## Shared that must not fork casually
- Prisma schema / migrations (`packages/database`)
- Auth tokens / tenant `companyId` middleware
- Plan catalog (`packages/types` planCatalog)
+22
View File
@@ -0,0 +1,22 @@
# Proxy trust & forwarded headers (S9)
**Default:** `TRUSTED_FORWARD_HEADERS` is unset/false. The API **deletes** client-supplied forwarding headers (`x-forwarded-for`, `x-real-ip`, etc.) so rate limits and logs cannot be spoofed.
## When to set `TRUSTED_FORWARD_HEADERS=true`
Only when:
1. Traefik / nginx / cloud LB is the **only** ingress to the API.
2. That edge **overwrites** (not appends blindly from the client) trusted client IP / proto headers.
3. The API `trust proxy` hop count matches the real proxy chain.
If any of those are false, leave the flag off.
## Operator checklist
- [ ] Edge strips spoofed `X-Forwarded-*` from the public internet
- [ ] Documented hop count for Express `trust proxy`
- [ ] Rate-limit keys still meaningful after deploy
- [ ] Change reviewed in incident/runbook (misconfiguration → IP allowlist / rate-limit bypass)
Related: `apps/api/src/middleware/forwardedHeaders.ts`