docs: add frontend routing design
This commit is contained in:
80
docs/superpowers/specs/2026-06-16-frontend-routing-design.md
Normal file
80
docs/superpowers/specs/2026-06-16-frontend-routing-design.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Frontend Routing Design
|
||||
|
||||
## Goal
|
||||
|
||||
Add URL-backed frontend routing so users can refresh or directly open the main app views without losing their place.
|
||||
|
||||
## Scope
|
||||
|
||||
In scope:
|
||||
|
||||
- Add routes for login, book list, book workspace, and admin user management.
|
||||
- Keep the existing component structure: `LoginPage`, `BookListPage`, `WorkspaceView`, and `AdminPage`.
|
||||
- Preserve the existing auth behavior and API calls.
|
||||
- Preserve the existing backend API routes and static SPA fallback.
|
||||
- Add focused tests for routing behavior.
|
||||
|
||||
Out of scope:
|
||||
|
||||
- Adding nested lesson-level URLs.
|
||||
- Adding a new navigation layout.
|
||||
- Replacing the current auth model.
|
||||
- Adding a third-party router package unless the existing code makes a local router impractical.
|
||||
|
||||
## Approaches Considered
|
||||
|
||||
The recommended approach is a small local router built around `window.history` and `popstate`. The project does not currently use `vue-router`, and the app only needs four top-level route states. A local router keeps the change small and avoids a new dependency.
|
||||
|
||||
A second option is adding `vue-router`. It would be more conventional for a growing Vue app, but it adds dependency and setup overhead for a narrow routing surface.
|
||||
|
||||
A third option is hash routing, such as `/#/books/b1`. It avoids server fallback concerns, but the server already serves `dist/index.html` for unknown paths, so clean history URLs are a better fit.
|
||||
|
||||
## Routes
|
||||
|
||||
The frontend will support these clean URLs:
|
||||
|
||||
- `/login` shows `LoginPage`.
|
||||
- `/books` shows `BookListPage`.
|
||||
- `/books/:bookId` shows `WorkspaceView` for the selected book.
|
||||
- `/admin` shows `AdminPage`.
|
||||
|
||||
Unknown paths redirect to the best available default: `/books` when logged in and `/login` when logged out.
|
||||
|
||||
## Auth Behavior
|
||||
|
||||
`App.vue` still calls `fetchMe()` on mount. While logged out, any route except `/login` resolves to the login page and updates the URL to `/login`.
|
||||
|
||||
After login succeeds, the app routes to `/books`. Logout continues to clear tokens through `useAuth`; when the app observes the logged-out state, it routes to `/login`.
|
||||
|
||||
The admin page remains visible only through the existing admin entry point in `BookListPage`. If a non-admin user reaches `/admin` directly, the backend admin API will still return authorization errors. The frontend may render the page shell, but protected data will not load.
|
||||
|
||||
## Component Behavior
|
||||
|
||||
`BookListPage` keeps emitting `open` and `admin`. `App.vue` will translate those events into route changes:
|
||||
|
||||
- `open(id)` navigates to `/books/{id}`.
|
||||
- `admin` navigates to `/admin`.
|
||||
|
||||
`WorkspaceView` keeps emitting `back`; `App.vue` maps it to `/books`.
|
||||
|
||||
`AdminPage` keeps emitting `back`; `App.vue` maps it to `/books`.
|
||||
|
||||
This preserves component contracts and confines route ownership to the app shell.
|
||||
|
||||
## Error Handling
|
||||
|
||||
Book load errors remain handled by `WorkspaceView`. Its existing "返回列表" action navigates back to `/books`.
|
||||
|
||||
Route parsing should be strict enough to avoid invalid view state. Empty or malformed book IDs fall back to `/books`.
|
||||
|
||||
## Testing
|
||||
|
||||
Add or update `App.test.ts` coverage for:
|
||||
|
||||
- Starting at `/books` renders the book list.
|
||||
- Opening a book updates the URL to `/books/:bookId` and renders the workspace.
|
||||
- Pressing workspace back updates the URL to `/books`.
|
||||
- Opening admin updates the URL to `/admin`.
|
||||
- Logged-out users are routed to `/login`.
|
||||
|
||||
Run the focused app tests and the project build after implementation.
|
||||
Reference in New Issue
Block a user