make the booking in many steps
Build & Deploy / Build & Push Docker Image (push) Successful in 8m27s
Test / Type Check (all packages) (push) Successful in 3m34s
Build & Deploy / Deploy to VPS (push) Successful in 2s
Test / API Unit Tests (push) Failing after 3m16s
Test / Homepage Unit Tests (push) Failing after 2m40s
Test / Storefront Unit Tests (push) Failing after 24s
Test / Admin Unit Tests (push) Failing after 22s
Test / Dashboard Unit Tests (push) Failing after 24s
Test / API Integration Tests (push) Failing after 33s

This commit is contained in:
root
2026-06-29 08:54:41 -04:00
parent ae10f5272f
commit 3d6607e6c8
20 changed files with 3894 additions and 836 deletions
+634
View File
@@ -0,0 +1,634 @@
# Progressive Reservation Creation: Action Plan
## 1. Objective
Replace the single long reservation form at:
`/dashboard/reservations/new`
with a progressive wizard that:
* Shows one focused section at a time.
* Validates only the current section before continuing.
* Preserves entered information when moving backward or forward.
* Provides a final review before creating the reservation.
* Works correctly in English, French, and Arabic.
* Supports desktop, mobile, light mode, dark mode, LTR, and RTL.
* Prevents duplicate submissions and handles partial API failures safely.
The reservation should not be created until the user confirms the final review step.
---
## 2. Problems in the Current Implementation
The existing page combines all responsibilities inside one component:
* Customer search and selection.
* New customer creation.
* Customer identity information.
* Driver license information.
* License image upload.
* Vehicle selection.
* Rental dates and locations.
* Deposit and payment method.
* Additional driver information.
* Notes.
* Validation.
* Customer creation and updates.
* Reservation submission.
* Translated copy.
This creates several practical problems:
1. The user sees too much information at once.
2. Validation returns one generic error instead of identifying the exact field.
3. Adding a customer is confusing because required identity and license fields appear outside the customer creation panel.
4. Navigation away from the page loses the entire form.
5. Customer updates, license uploads, and reservation creation can partially succeed.
6. The component will become increasingly difficult to maintain.
7. Vehicle availability is currently based only on `status === 'AVAILABLE'`, not the selected rental dates. That does not reliably prevent conflicting reservations.
---
## 3. Proposed Wizard Structure
Use six fixed steps. Six is the upper reasonable limit here. More steps would create needless clicking; fewer would leave several sections overloaded.
### Step 1: Customer
Purpose: Identify who is making the reservation.
Fields and actions:
* Choose `Existing customer` or `New customer`.
* Search existing customers.
* Select an existing customer.
* For a new customer:
* First name.
* Arabic first name.
* Last name.
* Arabic last name.
* Email.
* Phone.
Completion requirements:
* Existing customer mode: a customer must be selected.
* New customer mode: first name, last name, email, and phone must be valid.
Important behavior:
* Selecting an existing customer preloads known identity and license data.
* Creating a new customer should not call the API at this step.
* Switching between existing and new customer modes must not silently mix the two records.
* Changing the selected customer after editing loaded data should display a confirmation before replacing those edits.
### Step 2: Identity
Purpose: Verify the renters personal information.
Fields:
* Date of birth.
* Nationality.
* CIN or passport number.
* Full address.
* International permit number, optional.
Completion requirements:
* Date of birth is present and in the past.
* Nationality is present.
* Identity document number is present.
* Full address is present.
The section should display whether values were loaded from an existing customer and allow the user to correct them.
### Step 3: Driver License
Purpose: Verify that the primary renter is legally eligible to drive.
Fields:
* Driver license number.
* License country.
* License issue date.
* License expiry date.
* License category.
* License image, optional unless business rules later require it.
Completion requirements:
* Required license fields are complete.
* Issue date is not in the future.
* Expiry date is after the issue date.
* Expiry date has not already passed.
* Uploaded file is a supported image type and within the configured size limit.
The current image and newly selected preview should be clearly distinguished.
### Step 4: Rental Details
Purpose: Define what is being rented and when.
Recommended field order:
1. Start date and time.
2. End date and time.
3. Vehicle.
4. Pickup location.
5. Return location.
Completion requirements:
* Start date is valid.
* End date is later than the start date.
* A vehicle is selected.
* The vehicle remains available for the chosen period.
Important correction:
The current implementation lists vehicles using only their general `AVAILABLE` status. The final implementation should request or revalidate date-based availability. A vehicle can be marked available now while already reserved for the requested dates.
If the API does not currently support date-based availability, this must be recorded as a backend dependency rather than pretending the status filter is sufficient.
### Step 5: Payment and Extras
Purpose: Collect optional and commercial details.
Main fields:
* Deposit amount.
* Payment method.
* Notes.
Optional additional driver:
* Display a compact `Add another driver` control.
* Opening it reveals an additional-driver panel or nested form.
* Allow removal before submission.
* Structure the state as an array even if the current interface initially supports only one driver.
Additional-driver fields:
* First and last name.
* Arabic first and last name.
* Email, optional.
* Phone, optional.
* Date of birth, optional.
* Nationality, optional.
* License number.
* License issue date, optional.
* License expiry date, optional.
Completion requirements:
* Deposit cannot be negative.
* A payment method must be selected.
* If an additional driver is enabled, name and license number are required.
* Any entered additional-driver dates must be logically valid.
### Step 6: Review and Confirm
Purpose: Prevent avoidable mistakes before committing data.
Display concise summaries for:
* Customer.
* Identity.
* Primary driver license.
* Vehicle.
* Rental period.
* Pickup and return locations.
* Payment.
* Additional drivers.
* Notes.
Each summary section should include an `Edit` action that returns directly to the relevant step.
Final actions:
* Back.
* Cancel.
* Create reservation.
The final button must display a loading state and remain disabled after the first click until the request succeeds or fails.
---
## 4. Navigation and Progress Behavior
### Desktop
Use a horizontal stepper containing:
* Step number.
* Short step label.
* Completed state.
* Current state.
* Future state.
### Mobile
Use a compact header:
`Step 3 of 6 · Driver license`
Include a progress bar rather than compressing all six labels into unusable decorative confetti.
### Navigation rules
* `Continue` validates the current step.
* `Back` never discards information.
* Completed steps may be revisited.
* Future incomplete steps cannot be opened directly.
* The final review step is available only after all previous steps are valid.
* Pressing Enter must not accidentally submit the final reservation from an earlier step.
* The footer containing Back and Continue should remain visible on long steps where practical.
---
## 5. Validation Strategy
Replace the current generic `Please fill all required fields` behavior with step-specific validation.
Use Zod, which is already installed, to create separate schemas:
* `customerStepSchema`
* `identityStepSchema`
* `licenseStepSchema`
* `rentalStepSchema`
* `paymentExtrasStepSchema`
* `completeReservationSchema`
Validation behavior:
* Validate on Continue.
* Show the message beside the invalid field.
* Focus the first invalid field.
* Clear an error once the value becomes valid.
* Run complete validation again before final submission.
* Translate validation messages into English, French, and Arabic.
Do not depend on disabled buttons alone. A disabled button gives the user no useful explanation and is a remarkably efficient way to make software feel broken.
---
## 6. State Management Refactor
Replace the large collection of independent `useState` calls with one structured draft state managed by `useReducer`.
Suggested shape:
```ts
type ReservationDraft = {
customer: {
mode: 'existing' | 'new'
selectedCustomerId: string | null
firstName: BilingualField
lastName: BilingualField
email: string
phone: string
}
identity: {
dateOfBirth: string
nationality: string
fullAddress: string
identityDocumentNumber: string
internationalLicenseNumber: string
}
license: {
number: string
country: string
issuedAt: string
expiry: string
category: string
existingImageUrl: string | null
newImageFile: File | null
}
rental: {
vehicleId: string
startDate: string
endDate: string
pickupLocation: string
returnLocation: string
}
payment: {
depositAmount: string
paymentMode: string
notes: string
}
additionalDrivers: AdditionalDriverDraft[]
}
```
The reducer should support explicit actions such as:
* Select existing customer.
* Start new customer.
* Update step field.
* Add additional driver.
* Remove additional driver.
* Hydrate customer information.
* Clear customer information.
* Store a newly created customer ID after partial submission.
* Reset the entire draft.
This makes state transitions testable and prevents unrelated fields from being scattered throughout the page.
---
## 7. Component Structure
Reduce `page.tsx` to a data-loading and route-level shell.
Suggested structure:
```text
src/components/reservations/new/
├── ReservationWizard.tsx
├── ReservationStepper.tsx
├── ReservationWizardActions.tsx
├── ReservationReview.tsx
├── reservationWizard.types.ts
├── reservationWizard.reducer.ts
├── reservationWizard.schemas.ts
├── reservationWizard.copy.ts
├── reservationWizard.submit.ts
├── steps/
│ ├── CustomerStep.tsx
│ ├── IdentityStep.tsx
│ ├── LicenseStep.tsx
│ ├── RentalDetailsStep.tsx
│ ├── PaymentExtrasStep.tsx
│ └── ReviewStep.tsx
└── __tests__/
```
Responsibilities:
* `page.tsx`: load customers and vehicles, render the wizard.
* `ReservationWizard`: control current step and draft state.
* Step components: render fields only.
* Schemas: validation only.
* Reducer: state transitions only.
* Submission module: API orchestration only.
* Copy file: typed English, French, and Arabic labels.
* Review component: display formatted summaries only.
---
## 8. API Submission Strategy
No customer or reservation records should be created merely because the user moved to another step.
On final confirmation:
1. Validate the complete draft.
2. Revalidate vehicle availability.
3. For a new customer:
* Create the customer using the accumulated customer, identity, and license fields.
4. For an existing customer:
* Patch only changed customer fields.
5. Upload the license image when a new image was selected.
6. Create the reservation.
7. Redirect to the new reservation details page.
### Partial-failure handling
The current operations are not atomic. For example, customer creation may succeed while reservation creation fails.
The wizard must therefore:
* Remember the newly created customer ID in memory.
* Retry using that customer instead of creating another duplicate.
* Show which operation failed.
* Keep all form data available for correction or retry.
* Never redirect until reservation creation succeeds.
### Recommended backend improvement
The strongest solution is a dedicated backend operation that creates or updates the customer, uploads document metadata, validates vehicle availability, and creates the reservation as one controlled workflow.
Without such an endpoint, the frontend can handle retries carefully, but it cannot provide a true database transaction across the current independent requests.
---
## 9. Data Loading and Customer Hydration
Current customer and vehicle loading should be extracted from the form component.
Required behavior:
* Show a proper loading state for the wizard shell.
* Show separate customer-load and vehicle-load errors where possible.
* Do not overwrite user-edited customer data when background data refreshes.
* Hydrate fields only when the selected customer actually changes.
* Cancel or ignore stale requests when the component unmounts.
* Avoid loading arbitrary large lists indefinitely as the database grows.
Future improvement:
Replace `pageSize=100` customer loading with server-side customer search. Loading the first 100 customers and searching them in the browser will eventually fail as a business grows, which is traditionally when software chooses to reveal its assumptions.
---
## 10. Draft-Loss Protection
For the first implementation:
* Keep all information when navigating between wizard steps.
* Warn before leaving the page when unsaved changes exist.
* Do not persist license images in browser storage.
* Clear the draft after successful creation.
* Clear object URLs used for image previews.
Do not automatically store sensitive customer identity and license information in long-lived local storage.
A server-side draft feature can be designed separately if staff need to resume reservations across devices or sessions.
---
## 11. Accessibility and Localization
The wizard must preserve the applications existing multilingual requirements.
Requirements:
* English and French use LTR.
* Arabic uses true RTL.
* Step order and navigation layout adapt correctly in RTL.
* Every field has an associated label.
* Required fields are announced to assistive technology.
* Errors use `aria-describedby`.
* The active step uses `aria-current="step"`.
* Focus moves to the step heading after navigation.
* Keyboard users can operate all controls.
* Color is not the only indicator of progress or error.
* Buttons and inputs remain usable in dark mode.
* Dates and amounts are presented using the active locale on the review screen.
The current hardcoded English license-image alt text must also be localized.
---
## 12. Testing Plan
### Unit tests
Test:
* Reducer actions.
* Step validation schemas.
* Date relationships.
* Deposit normalization.
* Existing customer hydration.
* Switching customer modes.
* Additional-driver add and remove behavior.
* Final payload construction.
### Component tests
Test:
* Only the active step is displayed.
* Continue blocks invalid data.
* Back preserves data.
* Completed steps can be revisited.
* Existing customer details are prefilled.
* New customer information remains in draft state.
* Additional-driver fields appear conditionally.
* Edit actions on the review page open the correct step.
* Arabic step layout uses RTL correctly.
### Submission tests
Test:
* Existing customer reservation.
* New customer reservation.
* License image upload.
* Customer update failure.
* Image upload failure.
* Reservation creation failure after customer creation.
* Retry without duplicate customer creation.
* Double-click prevention.
* Vehicle availability conflict.
### Required verification
Run:
```bash
npm run type-check
npm run test
npm run build
```
for the dashboard workspace after implementation.
---
## 13. Implementation Sequence
### Phase 1: Extract and stabilize
* Create typed draft models.
* Extract copy, validation, and payload-building logic.
* Add tests around current behavior.
* Do not change the visible interface yet.
### Phase 2: Build the wizard shell
* Add stepper.
* Add reducer.
* Add navigation.
* Add shared action footer.
* Render one step at a time.
### Phase 3: Move form sections
* Move customer fields.
* Move identity fields.
* Move license fields.
* Move rental fields.
* Move payment and optional driver fields.
* Build the review screen.
### Phase 4: Correct submission behavior
* Delay new-customer creation until final confirmation.
* Add partial-failure recovery.
* Prevent duplicate requests.
* Revalidate vehicle availability.
* Preserve the draft after recoverable errors.
### Phase 5: Accessibility and responsive refinement
* Add keyboard and screen-reader behavior.
* Verify mobile presentation.
* Verify dark mode.
* Verify Arabic RTL.
* Verify translated error messages.
### Phase 6: Testing and regression review
* Complete unit and component tests.
* Run type-check, tests, and production build.
* Verify both existing-customer and new-customer flows manually.
* Confirm redirect to the created reservation.
---
## 14. Acceptance Criteria
The work is complete only when:
* Exactly one focused step is displayed at a time.
* The user can see their current position and progress.
* Invalid current-step fields prevent progression and explain why.
* Going backward does not lose information.
* New customers are not created before final confirmation.
* Existing-customer data is loaded without repeatedly overwriting edits.
* Additional drivers remain optional.
* The final review contains all reservation information.
* Every review section can be edited.
* Duplicate reservations cannot be created by repeated clicks.
* Partial API failures do not force the user to restart.
* Vehicle availability is revalidated for the selected dates.
* English, French, and Arabic are complete.
* Arabic layout is true RTL.
* Mobile, desktop, light mode, and dark mode work.
* Type-check, tests, and production build pass.
---
## 15. Scope Boundaries
Included:
* Progressive reservation wizard.
* Refactoring of the current new-reservation page.
* Step validation.
* Review screen.
* Existing and new customer flows.
* License image handling.
* Additional-driver handling.
* API failure recovery.
* Responsive, multilingual, and accessible behavior.
* Relevant tests.
Not included unless separately approved:
* Redesigning the reservation details page.
* Server-side saved drafts.
* OCR extraction from driver licenses.
* Multiple primary renters.
* Payment processing.
* Contract generation.
* Changing unrelated dashboard pages.
* Broad customer-management redesign.
@@ -0,0 +1,775 @@
# RentalDriveGo Dashboard Menu and Subscription Entitlements Plan
## Document status
- **Purpose:** Implementation plan only
- **Source code changes:** None
- **Target applications:** Dashboard, Admin, API, Database, Shared i18n package
- **Primary objective:** Make the initial dashboard sidebar match the approved seven-item menu while allowing platform administrators to control advanced modules by subscription plan.
- **Localization objective:** Provide one consistent terminology system for English (`en`), French (`fr`), and Arabic (`ar`), including true RTL behavior for Arabic.
---
## 1. Approved baseline sidebar
The default owner sidebar must contain exactly these items, in this order:
| Order | Menu item | System key | Route |
|---:|---|---|---|
| 10 | Dashboard | `dashboard` | `/` |
| 20 | Reservations | `reservations` | `/reservations` |
| 30 | Fleet | `fleet` | `/fleet` |
| 40 | Customers | `customers` | `/customers` |
| 50 | Reports | `reports` | `/reports` |
| 60 | Billing | `billing` | `/billing` |
| 70 | Settings | `settings` | `/settings` |
The existing sidebar styling, layout, branding, theme controls, language controls, responsive behavior, and RTL behavior must remain unchanged.
---
## 2. Advanced subscription modules
The following existing modules will remain available as configurable advanced features:
- Online Reservations
- Offers
- Team
- Contracts
- Notifications
- Reviews
- Complaints
Initial entitlement proposal:
| Module | STARTER | GROWTH | PRO |
|---|:---:|:---:|:---:|
| Dashboard | Yes | Yes | Yes |
| Reservations | Yes | Yes | Yes |
| Fleet | Yes | Yes | Yes |
| Customers | Yes | Yes | Yes |
| Reports | Yes | Yes | Yes |
| Billing | Yes | Yes | Yes |
| Settings | Yes | Yes | Yes |
| Online Reservations | No | Yes | Yes |
| Offers | No | Yes | Yes |
| Team | No | Yes | Yes |
| Contracts | No | Yes | Yes |
| Notifications | No | Yes | Yes |
| Reviews | No | No | Yes |
| Complaints | No | No | Yes |
The platform administrator may later change the advanced-module assignments. Core baseline modules remain protected.
---
## 3. Multilingual terminology and translation contract
All menu items must use immutable system keys and shared translation keys. Application logic must never depend on translated labels.
### 3.1 Approved menu terminology
| System key | Translation key | English (`en`) | French (`fr`) | Arabic (`ar`) |
|---|---|---|---|---|
| `dashboard` | `navigation.dashboard` | Dashboard | Tableau de bord | لوحة التحكم |
| `reservations` | `navigation.reservations` | Reservations | Réservations | الحجوزات |
| `fleet` | `navigation.fleet` | Fleet | Flotte | الأسطول |
| `customers` | `navigation.customers` | Customers | Clients | العملاء |
| `reports` | `navigation.reports` | Reports | Rapports | التقارير |
| `billing` | `navigation.billing` | Billing | Facturation | الفوترة |
| `settings` | `navigation.settings` | Settings | Paramètres | الإعدادات |
| `online-reservations` | `navigation.onlineReservations` | Online Reservations | Réservations en ligne | الحجوزات عبر الإنترنت |
| `offers` | `navigation.offers` | Offers | Offres | العروض |
| `team` | `navigation.team` | Team | Équipe | الفريق |
| `contracts` | `navigation.contracts` | Contracts | Contrats | العقود |
| `notifications` | `navigation.notifications` | Notifications | Notifications | الإشعارات |
| `reviews` | `navigation.reviews` | Reviews | Avis | التقييمات |
| `complaints` | `navigation.complaints` | Complaints | Réclamations | الشكاوى |
These translations are the approved product glossary. Core labels are protected and must not be edited casually from the Admin application.
### 3.2 Shared localization architecture
Recommended structure:
```text
packages/i18n/
├── locales/
│ ├── en.json
│ ├── fr.json
│ └── ar.json
├── glossary.ts
├── validation.ts
└── index.ts
```
Dashboard, Admin, and any future storefront or mobile application must consume the same translation package. Independent translation copies are prohibited because they create terminology drift.
Example menu definition:
```ts
{
systemKey: "reservations",
labelKey: "navigation.reservations",
route: "/reservations"
}
```
The database and API may store `systemKey` and `labelKey`. They must not use translated text as an identifier.
### 3.3 Translation publishing rules
- Core menu translations are locked.
- Custom modules require English, French, and Arabic labels before publishing.
- A label override must provide all three languages.
- Empty translations are rejected.
- Unknown or obsolete translation keys are rejected.
- Translation variables must match across all languages.
- Administrators may configure plan access, roles, order, status, and icons without modifying protected terminology.
- Only `SUPER_ADMIN` may approve changes to the shared product glossary.
### 3.4 Fallback behavior
The application fallback order is:
```text
Requested locale
→ English fallback in local development only
→ Validation or build failure before production deployment
```
Production must not silently display English labels inside French or Arabic interfaces.
### 3.5 Arabic RTL requirements
When Arabic is selected:
```html
<html lang="ar" dir="rtl">
```
When English or French is selected:
```html
<html lang="en" dir="ltr">
<html lang="fr" dir="ltr">
```
Arabic verification must include:
- Sidebar alignment
- Menu indentation
- Chevron direction
- Breadcrumb order
- Form and modal layout
- Text alignment
- Number formatting
- Date formatting
- Currency formatting
- Mobile navigation behavior
Only directional icons should be mirrored. Neutral icons such as Settings, Billing, Fleet, and Reports must keep their original orientation.
### 3.6 Locale-aware formatting
Dates, numbers, percentages, and currencies must use locale-aware formatting rather than translated strings.
```ts
new Intl.DateTimeFormat(locale).format(date);
new Intl.NumberFormat(locale, {
style: "currency",
currency: "MAD",
}).format(amount);
```
Stored values remain locale-independent.
---
## 4. Authorization rule
A module is available only when all required conditions are true:
```text
Module is globally enabled
AND module is included in the company's subscription plan
AND the company has not disabled the module
AND the employee role is allowed to use the module
AND the subscription status permits access
```
Company-level settings may disable or reorder entitled modules. They must not unlock a module outside the active subscription plan.
Sidebar visibility alone is not authorization. The API and direct routes must enforce the same entitlement rules.
---
## 5. Role behavior
Subscription access and employee-role access remain separate.
Recommended baseline policy:
| Module | OWNER | MANAGER | AGENT |
|---|:---:|:---:|:---:|
| Dashboard | Yes | Yes | Yes |
| Reservations | Yes | Yes | Yes |
| Fleet | Yes | Yes | Yes |
| Customers | Yes | Yes | Yes |
| Reports | Yes | Yes | Optional |
| Billing | Yes | Optional | No |
| Settings | Yes | Optional | No |
The final role matrix must be approved before implementation. The screenshot represents the owner-level default menu, not automatic access for every employee.
---
## 6. Subscription-status behavior
| Subscription status | Menu behavior |
|---|---|
| `ACTIVE` | Full entitled menu |
| `TRIALING` | Full entitled menu |
| `PAST_DUE` | Configurable restricted or read-only behavior |
| `SUSPENDED` | Recovery menu only |
| `EXPIRED` | Recovery menu only |
| `CANCELLED` | Recovery menu only |
| Missing subscription | Onboarding or recovery menu only |
Recommended recovery menu:
- Dashboard
- Billing
- Settings
This keeps account recovery possible without exposing paid operational modules.
---
## 7. Data model
### 7.1 Menu module catalog
Each module should define:
```text
id
systemKey
defaultLabel
localizedLabels
routeOrUrl
icon
defaultOrder
parentId
minimumRole or allowedRoles
isRequired
isGloballyEnabled
createdAt
updatedAt
```
### 7.2 Subscription-plan entitlement
```text
plan
menuItemId
enabled
displayOrder
```
### 7.3 Company override
```text
companyId
menuItemId
enabled
displayOrder
optionalLabelOverride
optionalIconOverride
```
### 7.4 Audit record
```text
actorId
action
targetType
targetId
before
after
reason
createdAt
```
---
## 8. Implementation phases
## Phase 1: Confirm the menu contract
### Work
- Approve the seven baseline items.
- Approve the initial advanced-module plan matrix.
- Approve the employee-role matrix.
- Define protected system fields.
- Define subscription-status behavior.
- Confirm whether companies may customize labels and icons.
- Approve the English, French, and Arabic terminology glossary.
- Confirm which translation fields are protected.
### Deliverable
A frozen entitlement matrix and protected-module contract.
### Exit criteria
- No unresolved module ownership questions.
- No unresolved role-access questions.
- No unresolved downgrade behavior.
- No unresolved translation or RTL terminology decisions.
---
## Phase 2: Database migration and seed
### Work
- Create or update the menu catalog.
- Seed the seven baseline modules.
- Assign the baseline modules explicitly to `STARTER`, `GROWTH`, and `PRO`.
- Seed the advanced-module plan assignments.
- Normalize menu order.
- Create company-override records only where required.
- Add unique constraints for `systemKey`.
- Add audit support if missing.
- Detect and report existing assignments that exceed subscription access.
- Make the migration idempotent.
### Deliverable
Database migration, seed, and rollback procedure.
### Exit criteria
- Re-running the migration causes no duplicates.
- No navigable module relies on implicit plan access.
- Existing companies receive deterministic menus.
---
## Phase 3: Central entitlement resolver in the API
### Work
Create one canonical entitlement service used by both menu generation and API authorization.
Suggested responsibility:
```ts
resolveModuleAccess({
companyId,
employeeId,
systemKey,
})
```
The resolver must evaluate:
- Global module state
- Active subscription plan
- Subscription status
- Explicit plan entitlement
- Company override
- Employee role
- Required recovery access
### Deliverable
A reusable entitlement service with unit tests.
### Exit criteria
- Menu generation and API guards use the same decision logic.
- Company overrides cannot grant higher-plan access.
- Missing plan assignments mean unavailable.
---
## Phase 4: Harden menu-management API
### Work
- Protect required modules.
- Prevent ordinary administrators from changing:
- `systemKey`
- Core routes
- Required status
- Core plan assignments
- Core role assignments
- Parent relationships
- Validate unique system keys.
- Prevent circular parent relationships.
- Require explicit plan selection for new navigable modules.
- Record all changes in the audit log.
- Require a reason and expiration for exceptional plan overrides.
- Add clear validation errors.
### Deliverable
Secure admin menu endpoints and boundary tests.
### Exit criteria
- Required modules cannot be weakened through general update endpoints.
- Invalid menu trees are rejected.
- All entitlement-changing actions are auditable.
---
## Phase 5: Enforce advanced-module API access
### Work
Apply reusable entitlement middleware to advanced modules:
```ts
requireModuleEntitlement("online-reservations")
requireModuleEntitlement("offers")
requireModuleEntitlement("team")
requireModuleEntitlement("contracts")
requireModuleEntitlement("notifications")
requireModuleEntitlement("reviews")
requireModuleEntitlement("complaints")
```
Also enforce baseline role restrictions where applicable.
### Deliverable
Server-side module protection across all relevant routes.
### Exit criteria
- Entering a hidden route manually does not bypass access.
- Calling an advanced API directly does not bypass the subscription.
- Unauthorized responses are consistent and testable.
---
## Phase 6: Refine the Admin menu-management interface
### Work
Create a clear plan matrix as the primary management view:
```text
Module | STARTER | GROWTH | PRO | Roles | Enabled | Order
```
Add:
- Plan tabs or columns
- Required-item locks
- Role controls
- Ordering controls
- Company and role preview
- Subscription-status preview
- Audit history
- Warning before removing a module used by active companies
- Supported icon selector instead of unrestricted icon text
- Advanced configuration restricted to `SUPER_ADMIN`
### Deliverable
A safer, plan-oriented administration interface.
### Exit criteria
- An administrator can configure advanced subscriptions without editing routes or system keys.
- The preview matches the actual dashboard menu.
- Protected items are visibly locked.
---
## Phase 7: Update the Dashboard sidebar
### Work
- Replace the large hardcoded fallback with the seven approved baseline items.
- Preserve the exact approved order.
- Keep the API-generated menu as the source of truth.
- Distinguish:
- Loading state
- API failure
- Successful empty response
- Successful populated response
- Treat a successful empty response as intentional.
- Never restore advanced modules after an empty response.
- Use a role-aware safe fallback only when the API genuinely fails.
- Remove the separate Subscription item from the initial menu.
- Keep subscription access available through Billing or Settings.
- Preserve visual design and unrelated behavior.
### Deliverable
A deterministic sidebar matching the approved design.
### Exit criteria
- A `STARTER` owner sees exactly seven items.
- No menu flicker exposes restricted modules.
- RTL, mobile, theme, and localization behavior remain intact.
---
## Phase 8: Route guards in Dashboard and Admin
### Work
- Align frontend route guards with API entitlements.
- Show a clear access-denied or upgrade-required screen.
- Do not silently redirect users to unrelated pages.
- Prevent stale cached menus after plan or role changes.
- Invalidate menu data after admin updates.
### Deliverable
Consistent frontend route protection.
### Exit criteria
- Hidden modules cannot be opened by entering their URL.
- Downgrades remove route access without requiring a new login.
- Upgrade messaging is explicit and accurate.
---
## Phase 9: Implement shared localization validation
### Work
- Create or update the shared `packages/i18n` package.
- Add the approved `en`, `fr`, and `ar` navigation keys.
- Replace hardcoded menu labels in Dashboard and Admin with translation keys.
- Validate that all locale files contain the same required keys.
- Validate that interpolation variables match across languages.
- Reject empty, unknown, and obsolete keys.
- Add CI checks for translation completeness.
- Add development logging for missing keys.
- Ensure Arabic applies `lang="ar"` and `dir="rtl"` at the document root.
- Verify locale-aware dates, numbers, and MAD currency formatting.
- Prevent translated labels from being used in permissions, routes, plan assignments, or database lookups.
### Deliverable
Shared translation package, approved glossary, validation script, and CI enforcement.
### Exit criteria
- Every required English key exists in French and Arabic.
- No navigation label is hardcoded in Dashboard or Admin.
- Core glossary terms are protected.
- Arabic uses true RTL layout.
- Missing translations fail CI before deployment.
---
## Phase 10: Testing
### API tests
- Explicit plan assignment is required.
- Company override cannot upgrade a plan.
- Required items cannot be disabled by ordinary admins.
- Suspended subscriptions receive only recovery access.
- Role restrictions remain active.
- Advanced APIs reject unauthorized requests.
- Audit entries are created.
### Localization tests
- Every navigation key exists in English, French, and Arabic.
- Core terminology matches the approved glossary exactly.
- Missing or empty translations fail CI.
- Interpolation variables match across locales.
- Switching language does not change routes, permissions, subscription access, or system keys.
- French labels do not overflow.
- Arabic labels do not truncate.
- Arabic sets `lang="ar"` and `dir="rtl"`.
- Directional icons mirror correctly and neutral icons do not.
- Dates, numbers, and MAD currency values format correctly by locale.
### Dashboard tests
- `STARTER` owner sees exactly seven items.
- Approved order is preserved.
- Empty successful response remains empty.
- API failure uses only the safe fallback.
- Advanced modules appear only when entitled.
- Direct routes are blocked.
- Mobile and desktop menus behave consistently.
- EN, FR, and AR labels render correctly.
- Arabic remains true RTL.
### Admin tests
- Plan toggles save correctly.
- Locked modules cannot be modified.
- Preview matches the generated employee menu.
- Invalid parent relationships are rejected.
- Removing a widely used entitlement produces a warning.
- Audit history displays the change.
### Deliverable
Unit, integration, boundary, and end-to-end test coverage.
---
## Phase 11: Deployment and rollback
### Deployment order
1. Database migration and seed
2. API entitlement resolver
3. API route enforcement
4. Admin management interface
5. Dashboard sidebar and route guards
6. End-to-end verification
### Rollback requirements
- Database rollback or compensating migration
- Feature flag for new entitlement enforcement
- Ability to restore previous menu assignments
- Audit record of rollback actions
- No destructive deletion of historical menu configuration
### Exit criteria
- Production smoke tests pass.
- Existing companies retain expected access.
- No restricted module is exposed.
- Recovery access remains available.
---
## 9. File-level work areas
Expected targets, subject to repository verification:
### Dashboard
```text
src/components/layout/Sidebar.tsx
src/components/layout/DashboardAccessGuard.tsx
src/components/layout/Sidebar.boundary.test.ts
src/components/layout/DashboardAccessGuard.boundary.test.ts
```
### Admin
```text
src/app/dashboard/menu-management/page.tsx
related menu-management components
related API client modules
related tests
```
### API
```text
src/modules/menu/menu.service.ts
src/modules/menu/menu.entitlement.ts
src/middleware/requireModuleEntitlement.ts
menu administration routes
advanced-module routes
related unit, boundary, and E2E tests
```
### Database
```text
Prisma schema
menu seed
subscription entitlement seed
migration
rollback or repair script
```
### Shared i18n package
```text
packages/i18n/locales/en.json
packages/i18n/locales/fr.json
packages/i18n/locales/ar.json
packages/i18n/glossary.ts
packages/i18n/validation.ts
packages/i18n/index.ts
related localization tests
```
No file should be changed until the repository structure is verified against these expected paths.
---
## 10. Non-goals
This milestone will not:
- Redesign the sidebar visually.
- Change dashboard branding.
- Change the theme system.
- Change localization architecture.
- Replace existing pages.
- Introduce machine translation at runtime.
- Allow translated labels to control routes, permissions, or entitlements.
- Add unrelated subscription billing features.
- Grant tenant administrators permission to alter platform routes.
- Treat hidden navigation as sufficient security.
---
## 11. Definition of done
The implementation is complete only when:
- The initial owner sidebar contains exactly the seven approved items.
- The order matches the approved design.
- Advanced items are explicitly assigned by subscription plan.
- Company overrides cannot bypass subscription entitlements.
- Employee roles remain enforced.
- Subscription status affects access.
- Direct frontend routes are protected.
- Direct API calls are protected.
- Required system items cannot be weakened by ordinary administrators.
- Admin previews match actual dashboard results.
- All changes are audited.
- Existing visual behavior remains unchanged.
- English, French, and Arabic use the approved shared terminology.
- Arabic uses true RTL behavior.
- Missing or inconsistent translations fail CI.
- Routes, permissions, subscriptions, and API logic use immutable system keys rather than translated labels.
- Tests pass across Dashboard, Admin, API, and Database.
- Deployment and rollback procedures are documented.
---
## 12. Execution gate
Implementation must not begin until these items are approved:
1. Baseline seven-item menu
2. Advanced-module plan matrix
3. Employee-role matrix
4. Subscription-status policy
5. Company customization limits
6. Required-item protection rules
7. Database migration strategy
8. Approved EN/FR/AR glossary
9. Translation fallback and CI policy
10. Arabic RTL acceptance criteria
This prevents the usual ritual of coding first and discovering the business rules afterward.