f22e0d45e1
Build & Deploy / Build & Push Docker Image (push) Successful in 7m57s
Test / Type Check (all packages) (push) Successful in 4m27s
Build & Deploy / Deploy to VPS (push) Successful in 7s
Test / API Unit Tests (push) Failing after 3m2s
Test / Homepage Unit Tests (push) Successful in 4m3s
Test / Storefront Unit Tests (push) Successful in 3m32s
Test / Admin Unit Tests (push) Successful in 3m27s
Test / Dashboard Unit Tests (push) Successful in 3m3s
Test / API Integration Tests (push) Failing after 3m53s
539 lines
14 KiB
Markdown
539 lines
14 KiB
Markdown
# Subscription Page Redirect Fix Plan
|
|
|
|
## 1. Objective
|
|
|
|
Restore reliable access to:
|
|
|
|
```text
|
|
http://localhost:3000/dashboard/subscription
|
|
```
|
|
|
|
The subscription page must remain accessible to authorized account owners, including owners whose subscription is expired, unpaid, past due, canceled, or suspended.
|
|
|
|
The fix must not weaken backend authorization or allow non-owner employees to manage billing.
|
|
|
|
---
|
|
|
|
## 2. Current Problem
|
|
|
|
The subscription page exists, but authorized users are redirected to:
|
|
|
|
```text
|
|
http://localhost:3000/dashboard
|
|
```
|
|
|
|
The likely causes are:
|
|
|
|
1. The dashboard route guard treats the generated sidebar menu as a route-authorization list.
|
|
2. `/subscription` may not be returned by `GET /auth/employee/menu`.
|
|
3. The subscription page trusts the cached `employee_profile` value in `localStorage`.
|
|
4. Subscription enforcement may return `402 Payment Required` before the owner can reach the billing recovery page.
|
|
5. Redirect targets use ambiguous paths such as `/`, which resolve to `/dashboard` because of the configured Next.js base path.
|
|
|
|
---
|
|
|
|
## 3. Required Access Policy
|
|
|
|
The subscription page must be classified as an owner-only system route.
|
|
|
|
| User state | Expected access |
|
|
|---|---|
|
|
| Authenticated owner with active subscription | Allowed |
|
|
| Authenticated owner in trial | Allowed |
|
|
| Authenticated owner with expired subscription | Allowed |
|
|
| Authenticated owner with past-due subscription | Allowed |
|
|
| Authenticated owner with unpaid subscription | Allowed |
|
|
| Authenticated owner with canceled subscription | Allowed |
|
|
| Authenticated owner with suspended account | Allowed for billing recovery |
|
|
| Manager | Denied |
|
|
| Agent or regular employee | Denied |
|
|
| Unauthenticated user | Redirect to sign-in |
|
|
|
|
The route must not depend on whether it appears in the configurable dashboard menu.
|
|
|
|
---
|
|
|
|
## 4. Separate Navigation From Authorization
|
|
|
|
### Problem
|
|
|
|
The dashboard menu currently appears to serve two different purposes:
|
|
|
|
- Controlling which sidebar links are displayed
|
|
- Controlling which routes a user may access
|
|
|
|
These responsibilities must be separated.
|
|
|
|
### Required change
|
|
|
|
Use the menu response only for navigation visibility.
|
|
|
|
Use a dedicated access policy for route authorization.
|
|
|
|
The following route categories should be defined:
|
|
|
|
- Public authentication routes
|
|
- Core authenticated dashboard routes
|
|
- Owner-only system routes
|
|
- Subscription-dependent feature routes
|
|
- Admin-configurable feature routes
|
|
- Billing recovery routes
|
|
|
|
Register `/subscription` as:
|
|
|
|
```ts
|
|
{
|
|
authenticationRequired: true,
|
|
allowedRoles: ["OWNER"],
|
|
subscriptionRequired: false,
|
|
menuRegistrationRequired: false
|
|
}
|
|
```
|
|
|
|
The exact implementation may differ, but there must be one authoritative route policy.
|
|
|
|
---
|
|
|
|
## 5. Create a Central Route Access Policy
|
|
|
|
Add a shared route-policy configuration.
|
|
|
|
Example:
|
|
|
|
```ts
|
|
export const dashboardRoutePolicies = {
|
|
"/subscription": {
|
|
authenticationRequired: true,
|
|
allowedRoles: ["OWNER"],
|
|
subscriptionRequired: false,
|
|
menuRegistrationRequired: false,
|
|
},
|
|
};
|
|
```
|
|
|
|
The policy should be used by:
|
|
|
|
- `DashboardAccessGuard`
|
|
- Dashboard layout
|
|
- Subscription page
|
|
- Sidebar rendering
|
|
- Subscription-status middleware
|
|
- Automated tests
|
|
|
|
Do not duplicate owner checks and subscription checks across unrelated components.
|
|
|
|
---
|
|
|
|
## 6. Update `DashboardAccessGuard`
|
|
|
|
### Current behavior to remove
|
|
|
|
The guard must not redirect a user merely because the current route is absent from `/auth/employee/menu`.
|
|
|
|
### Required behavior
|
|
|
|
The guard should:
|
|
|
|
1. Resolve the current route policy.
|
|
2. Confirm authentication.
|
|
3. Confirm the authenticated role.
|
|
4. Apply subscription restrictions only when the route requires an active subscription.
|
|
5. Allow billing recovery routes regardless of subscription state.
|
|
6. Redirect only after all required state has finished loading.
|
|
7. Avoid redirecting to the current route.
|
|
8. Use a stable role-based fallback route.
|
|
|
|
### Expected error handling
|
|
|
|
| Response | Required behavior |
|
|
|---|---|
|
|
| `401 Unauthorized` | Redirect to sign-in |
|
|
| `403 Forbidden` | Show access denied or redirect to an allowed dashboard route |
|
|
| `402 Payment Required` | Redirect owner to `/subscription`, unless already there |
|
|
| Network failure | Show retryable error |
|
|
| Server failure | Show error state without pretending it is an authorization failure |
|
|
|
|
---
|
|
|
|
## 7. Fix Owner Verification on the Subscription Page
|
|
|
|
### Current risk
|
|
|
|
The page uses `employee_profile` from `localStorage` as an authorization source.
|
|
|
|
Browser storage can be:
|
|
|
|
- Missing
|
|
- Stale
|
|
- Malformed
|
|
- Left from another session
|
|
- Temporarily unavailable
|
|
|
|
### Required behavior
|
|
|
|
1. Treat local storage only as optional display cache.
|
|
2. Fetch the authenticated profile from:
|
|
|
|
```text
|
|
GET /auth/employee/me
|
|
```
|
|
|
|
3. Wait for the request to resolve before redirecting.
|
|
4. Allow access only when the API confirms the user is an owner.
|
|
5. Redirect confirmed non-owners to an allowed dashboard route.
|
|
6. Redirect unauthenticated users to sign-in.
|
|
7. Show a loading state during verification.
|
|
8. Show a retryable error for temporary API failures.
|
|
|
|
The page must not redirect while authentication or role state is unresolved.
|
|
|
|
---
|
|
|
|
## 8. Add Billing Recovery Route Exceptions
|
|
|
|
Subscription enforcement must never block the routes needed to repair a subscription.
|
|
|
|
Minimum allowlist:
|
|
|
|
```text
|
|
/dashboard/subscription
|
|
/dashboard/subscription/success
|
|
/dashboard/subscription/cancel
|
|
```
|
|
|
|
Depending on the product flow, also consider:
|
|
|
|
```text
|
|
/dashboard/profile
|
|
/dashboard/support
|
|
/dashboard/logout
|
|
```
|
|
|
|
These exceptions must be implemented wherever subscription enforcement occurs:
|
|
|
|
- Frontend route guards
|
|
- API middleware
|
|
- API interceptors
|
|
- Account suspension guards
|
|
- Subscription-status hooks
|
|
|
|
---
|
|
|
|
## 9. Review Backend Authorization
|
|
|
|
Inspect these API areas:
|
|
|
|
- `GET /auth/employee/menu`
|
|
- `GET /auth/employee/me`
|
|
- Authentication middleware
|
|
- Subscription-status middleware
|
|
- Account suspension middleware
|
|
- Subscription controllers
|
|
- Subscription services
|
|
- Billing portal endpoint
|
|
- Checkout endpoint
|
|
- Subscription update endpoint
|
|
- Menu configuration schema
|
|
- Menu seed data
|
|
|
|
### Backend requirements
|
|
|
|
- `/auth/employee/me` must remain available to authenticated owners during billing failure.
|
|
- Subscription read and recovery endpoints must remain available during `PAST_DUE`, `UNPAID`, `EXPIRED`, `CANCELED`, or `SUSPENDED` states.
|
|
- Owner authorization must be enforced server-side.
|
|
- Managers and employees must remain unable to manage subscriptions.
|
|
- Menu entries must not be treated as route permissions unless the API explicitly defines them as permissions.
|
|
- `402` responses must include enough structured information for the frontend to route owners to billing recovery.
|
|
|
|
---
|
|
|
|
## 10. Correct Redirect Targets
|
|
|
|
Audit redirects in:
|
|
|
|
- `DashboardAccessGuard.tsx`
|
|
- `subscription/page.tsx`
|
|
- Dashboard layout
|
|
- Authentication hooks
|
|
- API client interceptors
|
|
- Subscription hooks
|
|
- Suspended-account handling
|
|
|
|
Avoid ambiguous redirects such as:
|
|
|
|
```ts
|
|
router.replace("/");
|
|
```
|
|
|
|
Use explicit destinations based on the router and base-path convention.
|
|
|
|
Examples:
|
|
|
|
```ts
|
|
router.replace("/dashboard");
|
|
router.replace("/login");
|
|
router.replace("/dashboard/subscription");
|
|
```
|
|
|
|
Confirm whether the project router expects paths with or without the configured `/dashboard` base path, then use one convention consistently.
|
|
|
|
---
|
|
|
|
## 11. Prevent Redirect Loops
|
|
|
|
Protect against:
|
|
|
|
```text
|
|
/subscription -> /dashboard -> /subscription
|
|
/login -> /dashboard -> /login
|
|
/subscription -> / -> /dashboard
|
|
```
|
|
|
|
The route guard must:
|
|
|
|
- Compare the current path with the redirect destination.
|
|
- Never redirect to the current path.
|
|
- Avoid redirecting while authentication is loading.
|
|
- Avoid redirecting while role verification is loading.
|
|
- Avoid redirecting while route policy is loading.
|
|
- Preserve intended destinations after login where appropriate.
|
|
- Use a deterministic fallback route for each role.
|
|
|
|
---
|
|
|
|
## 12. Fix Sidebar Behavior
|
|
|
|
The sidebar must remain a navigation tool, not an authorization engine.
|
|
|
|
Required behavior:
|
|
|
|
- Show `Subscription` only to owners.
|
|
- Hide it from managers and regular employees.
|
|
- Keep it outside admin-configurable feature menu items.
|
|
- Do not allow subscription-plan configuration to disable it.
|
|
- Do not require it to be returned by `/auth/employee/menu`.
|
|
- Validate direct URL access through the central route policy.
|
|
|
|
The administrator may configure optional feature menus, but must not be able to remove the account owner's billing recovery route.
|
|
|
|
---
|
|
|
|
## 13. Add Loading and Error States
|
|
|
|
The subscription page should support these explicit states:
|
|
|
|
1. Verifying authentication
|
|
2. Verifying owner role
|
|
3. Loading subscription data
|
|
4. Subscription loaded
|
|
5. No subscription found
|
|
6. Payment required
|
|
7. Subscription expired
|
|
8. Subscription past due
|
|
9. Subscription canceled
|
|
10. Account suspended
|
|
11. Access denied
|
|
12. API unavailable
|
|
|
|
Do not briefly render protected content before redirecting.
|
|
|
|
Do not convert every API failure into a redirect.
|
|
|
|
---
|
|
|
|
## 14. Add Development Logging
|
|
|
|
During implementation, log structured route decisions:
|
|
|
|
```ts
|
|
{
|
|
pathname,
|
|
authenticated,
|
|
role,
|
|
subscriptionStatus,
|
|
menuContainsRoute,
|
|
routePolicy,
|
|
accessDecision,
|
|
redirectTarget
|
|
}
|
|
```
|
|
|
|
Do not log:
|
|
|
|
- Authentication tokens
|
|
- Payment details
|
|
- Full customer records
|
|
- Personal information
|
|
- Complete API response bodies
|
|
|
|
Remove or disable verbose logs before production release.
|
|
|
|
---
|
|
|
|
## 15. Automated Test Plan
|
|
|
|
### 15.1 Route guard tests
|
|
|
|
Test that:
|
|
|
|
- An owner can access `/subscription` when it is absent from the menu response.
|
|
- An owner with an active subscription can access the page.
|
|
- An owner in trial can access the page.
|
|
- An owner with an expired subscription can access the page.
|
|
- An owner with a past-due subscription can access the page.
|
|
- An owner with an unpaid subscription can access the page.
|
|
- An owner with a canceled subscription can access the page.
|
|
- An owner can access the page when another request returns `402`.
|
|
- Stale local storage does not override the authenticated API profile.
|
|
- A manager cannot access the page.
|
|
- An agent cannot access the page.
|
|
- An unauthenticated user is redirected to sign-in.
|
|
- A temporary API failure shows an error instead of redirecting.
|
|
- A redirect is not issued when the destination equals the current path.
|
|
|
|
### 15.2 Subscription page tests
|
|
|
|
Test that:
|
|
|
|
- No redirect occurs before `/auth/employee/me` resolves.
|
|
- A confirmed owner sees subscription information.
|
|
- A confirmed non-owner is denied.
|
|
- `401` redirects to sign-in.
|
|
- `403` shows access denied or redirects safely.
|
|
- `402` displays billing recovery.
|
|
- Network errors provide retry behavior.
|
|
- Loading state prevents protected-content flicker.
|
|
|
|
### 15.3 Integration tests
|
|
|
|
Test the complete flow:
|
|
|
|
```text
|
|
Owner login
|
|
-> open /dashboard/subscription directly
|
|
-> load current subscription
|
|
-> open checkout or billing portal
|
|
-> return through success or cancel URL
|
|
-> subscription page loads correctly
|
|
```
|
|
|
|
Test all supported statuses:
|
|
|
|
```text
|
|
ACTIVE
|
|
TRIALING
|
|
PAST_DUE
|
|
UNPAID
|
|
EXPIRED
|
|
CANCELED
|
|
SUSPENDED
|
|
```
|
|
|
|
---
|
|
|
|
## 16. Localization Validation
|
|
|
|
Validate the complete flow in:
|
|
|
|
- English
|
|
- French
|
|
- Arabic
|
|
|
|
Required checks:
|
|
|
|
- All labels are translated.
|
|
- Error messages are translated.
|
|
- Loading states are translated.
|
|
- Billing recovery messages are translated.
|
|
- Access-denied messages are translated.
|
|
- Arabic renders in true RTL.
|
|
- Buttons and status badges remain correctly aligned in RTL.
|
|
- No hard-coded English strings remain in the subscription flow.
|
|
|
|
---
|
|
|
|
## 17. Implementation Order
|
|
|
|
Execute the work in this order:
|
|
|
|
1. Define the route access policy.
|
|
2. Classify `/subscription` as an owner-only recovery route.
|
|
3. Update `DashboardAccessGuard`.
|
|
4. Remove menu-based authorization for system routes.
|
|
5. Replace local-storage-only role verification.
|
|
6. Verify the user through `/auth/employee/me`.
|
|
7. Add subscription recovery exceptions.
|
|
8. Review backend subscription enforcement.
|
|
9. Correct redirect targets and base-path handling.
|
|
10. Add redirect-loop protection.
|
|
11. Update sidebar visibility rules.
|
|
12. Add loading and error states.
|
|
13. Add unit tests.
|
|
14. Add integration tests.
|
|
15. Validate every subscription state.
|
|
16. Validate English, French, and Arabic.
|
|
17. Run type-check, lint, tests, and production build.
|
|
18. Remove development-only logging.
|
|
|
|
---
|
|
|
|
## 18. Required Code for Complete Implementation
|
|
|
|
The dashboard package is sufficient for a temporary frontend patch.
|
|
|
|
A complete fix requires these API parts:
|
|
|
|
- `/auth/employee/menu` route, controller, and service
|
|
- `/auth/employee/me` route, controller, and service
|
|
- Authentication middleware
|
|
- Role authorization middleware
|
|
- Subscription enforcement middleware
|
|
- Account suspension middleware
|
|
- Subscription routes
|
|
- Subscription controller
|
|
- Subscription service
|
|
- Billing portal integration
|
|
- Checkout integration
|
|
- API error interceptor or response-normalization logic
|
|
- Menu configuration schema
|
|
- Menu seed files
|
|
|
|
---
|
|
|
|
## 19. Acceptance Criteria
|
|
|
|
The fix is complete only when:
|
|
|
|
- `/dashboard/subscription` no longer redirects an authorized owner to `/dashboard`.
|
|
- The route works when it is absent from the generated menu.
|
|
- Owners with billing problems can access billing recovery.
|
|
- Non-owners remain blocked.
|
|
- Backend authorization remains enforced.
|
|
- Authorization does not rely on local storage.
|
|
- No redirect loop occurs.
|
|
- Direct URL access and sidebar navigation behave consistently.
|
|
- Base-path routing works correctly.
|
|
- `401`, `402`, `403`, network errors, and server errors are handled distinctly.
|
|
- English, French, and Arabic render correctly.
|
|
- Type-check passes.
|
|
- Lint passes.
|
|
- Unit tests pass.
|
|
- Integration tests pass.
|
|
- Production build succeeds.
|
|
|
|
---
|
|
|
|
## 20. Out of Scope
|
|
|
|
Do not include unrelated work in this repair:
|
|
|
|
- Subscription pricing redesign
|
|
- Billing provider migration
|
|
- Dashboard visual redesign
|
|
- New subscription tiers
|
|
- General sidebar restructuring
|
|
- Domain or publishing settings
|
|
- Unrelated permission-system changes
|
|
|
|
Any broader authorization redesign should be handled as a separate phase after the subscription route is stable.
|