Finishes functional design for unit 0 (back-end changes before front-end work)
This commit is contained in:
+60
@@ -0,0 +1,60 @@
|
||||
# Unit of Work Dependencies — CMS Frontend
|
||||
|
||||
## Dependency Matrix
|
||||
|
||||
| Unit | Depends On | Blocks |
|
||||
|------|-----------|--------|
|
||||
| **Unit 0** — Backend Prerequisites | (none — standalone .NET change) | Unit 1 (CORS must work before frontend can call API) |
|
||||
| **Unit 1** — Project Scaffold | Unit 0 | Units 2, 3, 4, 5, 6 |
|
||||
| **Unit 2** — Auth Pages | Unit 1 (ApiClient, AuthContext) | Units 3, 4, 5, 6 (auth layer required) |
|
||||
| **Unit 3** — Layout & Navigation | Unit 2 (ProtectedRoute, RoleGuard) | Units 4, 5, 6 (authenticated shell) |
|
||||
| **Unit 4** — Dashboard | Unit 3 (AppLayout) | Unit 5, 6 (patterns established) |
|
||||
| **Unit 5** — User Management | Unit 3 (RoleGuard), Unit 4 (patterns) | Unit 6 |
|
||||
| **Unit 6** — Remaining Pages & Docs | Unit 3 (AppLayout, RoleGuard) | (none — final unit) |
|
||||
|
||||
## Dependency Diagram
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
U0["Unit 0\nBackend Prerequisites"]
|
||||
U1["Unit 1\nProject Scaffold"]
|
||||
U2["Unit 2\nAuth Pages"]
|
||||
U3["Unit 3\nLayout & Navigation"]
|
||||
U4["Unit 4\nDashboard"]
|
||||
U5["Unit 5\nUser Management"]
|
||||
U6["Unit 6\nRemaining Pages"]
|
||||
|
||||
U0 -->|"CORS + cookie\nenabled"| U1
|
||||
U1 -->|"ApiClient\nAuthContext"| U2
|
||||
U2 -->|"ProtectedRoute\nRoleGuard\nInitGuard"| U3
|
||||
U3 -->|"AppLayout\nSidebar"| U4
|
||||
U3 -->|"AppLayout\nRoleGuard"| U5
|
||||
U3 -->|"AppLayout\nRoleGuard"| U6
|
||||
U4 -->|"patterns\nestablished"| U5
|
||||
|
||||
style U0 fill:#4CAF50,stroke:#2E7D32,color:#fff
|
||||
style U1 fill:#FFC107,stroke:#F57F17,color:#000
|
||||
style U2 fill:#FF5722,stroke:#BF360C,color:#fff
|
||||
style U3 fill:#9C27B0,stroke:#4A148C,color:#fff
|
||||
style U4 fill:#2196F3,stroke:#0D47A1,color:#fff
|
||||
style U5 fill:#009688,stroke:#004D40,color:#fff
|
||||
style U6 fill:#607D8B,stroke:#263238,color:#fff
|
||||
```
|
||||
|
||||
## Shared Components Across Units
|
||||
|
||||
| Component | Created In | Used By |
|
||||
|-----------|-----------|---------|
|
||||
| `ApiClient` | Unit 1 | Units 2, 4, 5, 6 |
|
||||
| `AuthContext` / `useAuth` | Unit 1 | Units 2, 3, 4, 5, 6 |
|
||||
| `types.ts` (TS interfaces) | Unit 1 | All units |
|
||||
| `ProtectedRoute` | Unit 2 | Units 3, 4, 5, 6 (via layout route) |
|
||||
| `RoleGuard` | Unit 2 | Units 3, 5, 6 |
|
||||
| `InitGuard` | Unit 2 | All authenticated routes (via `__root.tsx`) |
|
||||
| `AppLayout` | Unit 3 | Units 4, 5, 6 |
|
||||
| `Sidebar` | Unit 3 | Units 4, 5, 6 |
|
||||
| `useAvailabilityStatus` | Unit 4 | Unit 6 (`SettingsPage`) |
|
||||
| `AvailabilityStatusBadge` | Unit 4 | Unit 6 (`SettingsPage`) |
|
||||
| `useValidateInvitation` | Unit 5 | Unit 2 (`InviteCompletePage`) — note: hook defined in Unit 5, used in Unit 2 route |
|
||||
|
||||
> **Note on cross-unit hook usage**: `useValidateInvitation` and `useCompleteSetup` are logically invitation hooks (Unit 5) but are used in `InviteCompletePage` (Unit 2). In practice, these hooks can be created in Unit 2 and moved/refactored in Unit 5, or created directly in Unit 5 and `InviteCompletePage` completed then. Implementation order to follow: create stubs in Unit 2, full implementation in Unit 5.
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
# Unit of Work Story Map — CMS Frontend
|
||||
|
||||
## Story-to-Unit Mapping
|
||||
|
||||
All 20 user stories from `stories.md` are assigned to units. Every story is covered.
|
||||
|
||||
| Story | Title | Unit | Rationale |
|
||||
|-------|-------|------|-----------|
|
||||
| US-06 | Initialize system as first Owner | Unit 0 + Unit 2 | Backend endpoint already exists; frontend SetupPage in Unit 2 |
|
||||
| US-07 | Redirect to setup when not initialized | Unit 0 + Unit 2 | Backend returns `initialized: false`; InitGuard in Unit 2 |
|
||||
| US-01 | Login with email and password | Unit 2 | LoginPage + AuthContext.login() |
|
||||
| US-02 | Session persistence via refresh token | Unit 2 | AuthContext restore-on-mount + httpOnly cookie (Unit 0 backend) |
|
||||
| US-03 | Logout | Unit 2 | AuthContext.logout() + AuthController.Revoke() |
|
||||
| US-04 | Redirect to login when not authenticated | Unit 2 | ProtectedRoute |
|
||||
| US-05 | Auto token refresh on expiry | Unit 2 | ApiClient 401 interceptor → AuthContext.refresh() |
|
||||
| US-13 | Complete account setup via invitation link | Unit 2 | InviteCompletePage (stubs for invitation hooks; full hooks in Unit 5) |
|
||||
| US-14 | Handle expired/invalid invitation token | Unit 2 | InviteCompletePage error states |
|
||||
| US-18 | Role-appropriate sidebar navigation | Unit 3 | Sidebar with role-filtered nav items |
|
||||
| US-19 | Toggle dark/light theme | Unit 3 | ThemeProvider + theme toggle in Sidebar |
|
||||
| US-08 | View dashboard after login | Unit 4 | DashboardPage |
|
||||
| US-09 | View availability status on dashboard | Unit 4 | AvailabilityStatusBadge + useAvailabilityStatus |
|
||||
| US-10 | View list of users | Unit 5 | UsersPage + useUsers |
|
||||
| US-11 | Invite a new user | Unit 5 | InviteUserDialog + useInviteUser |
|
||||
| US-12 | Share invite link | Unit 5 | InviteUserDialog (step 2 — share link) |
|
||||
| US-15 | View own profile | Unit 6 | ProfilePage |
|
||||
| US-16 | View availability status in settings | Unit 6 | SettingsPage + useAvailabilityStatus (reused from Unit 4) |
|
||||
| US-17 | Access denied to System Settings for non-Owners | Unit 6 | RoleGuard on `/settings` |
|
||||
| US-20 | View CMS management placeholder | Unit 6 | CmsPage (Owner only) |
|
||||
|
||||
---
|
||||
|
||||
## Coverage Verification
|
||||
|
||||
| Unit | Stories | Count |
|
||||
|------|---------|-------|
|
||||
| Unit 0 (Backend) | US-02 (partial), US-06 (partial), US-07 (partial) | 3 |
|
||||
| Unit 2 (Auth Pages) | US-01, US-02, US-03, US-04, US-05, US-06, US-07, US-13, US-14 | 9 |
|
||||
| Unit 3 (Layout) | US-18, US-19 | 2 |
|
||||
| Unit 4 (Dashboard) | US-08, US-09 | 2 |
|
||||
| Unit 5 (User Management) | US-10, US-11, US-12 | 3 |
|
||||
| Unit 6 (Remaining Pages) | US-15, US-16, US-17, US-20 | 4 |
|
||||
|
||||
**Total: 20/20 stories assigned** ✅
|
||||
|
||||
---
|
||||
|
||||
## Story Map Visualization
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph U0["Unit 0 — Backend"]
|
||||
s06b["US-06 partial\nsetup endpoint"]
|
||||
s07b["US-07 partial\nstatus endpoint"]
|
||||
s02b["US-02 partial\ncookie support"]
|
||||
end
|
||||
|
||||
subgraph U2["Unit 2 — Auth Pages"]
|
||||
s01["US-01 Login"]
|
||||
s02["US-02 Session restore"]
|
||||
s03["US-03 Logout"]
|
||||
s04["US-04 Auth redirect"]
|
||||
s05["US-05 Token refresh"]
|
||||
s06["US-06 Setup page"]
|
||||
s07["US-07 Init redirect"]
|
||||
s13["US-13 Invite complete"]
|
||||
s14["US-14 Invalid token"]
|
||||
end
|
||||
|
||||
subgraph U3["Unit 3 — Layout"]
|
||||
s18["US-18 Sidebar nav"]
|
||||
s19["US-19 Theme toggle"]
|
||||
end
|
||||
|
||||
subgraph U4["Unit 4 — Dashboard"]
|
||||
s08["US-08 Dashboard"]
|
||||
s09["US-09 Availability"]
|
||||
end
|
||||
|
||||
subgraph U5["Unit 5 — User Mgmt"]
|
||||
s10["US-10 User list"]
|
||||
s11["US-11 Invite user"]
|
||||
s12["US-12 Share link"]
|
||||
end
|
||||
|
||||
subgraph U6["Unit 6 — Remaining"]
|
||||
s15["US-15 Profile"]
|
||||
s16["US-16 Settings"]
|
||||
s17["US-17 Access denied"]
|
||||
s20["US-20 CMS placeholder"]
|
||||
end
|
||||
|
||||
U0 --> U2 --> U3 --> U4 --> U5 --> U6
|
||||
|
||||
style U0 fill:#4CAF50,stroke:#2E7D32,color:#fff
|
||||
style U2 fill:#FF5722,stroke:#BF360C,color:#fff
|
||||
style U3 fill:#9C27B0,stroke:#4A148C,color:#fff
|
||||
style U4 fill:#2196F3,stroke:#0D47A1,color:#fff
|
||||
style U5 fill:#009688,stroke:#004D40,color:#fff
|
||||
style U6 fill:#607D8B,stroke:#263238,color:#fff
|
||||
```
|
||||
@@ -0,0 +1,198 @@
|
||||
# Units of Work — CMS Frontend
|
||||
|
||||
## Overview
|
||||
|
||||
The CMS frontend is decomposed into **7 sequential units** (Unit 0–6). Each unit builds on the previous; dependencies flow strictly forward. All units together produce a single deployable SPA + updated backend API.
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
U0["Unit 0\nBackend Prerequisites"]
|
||||
U1["Unit 1\nProject Scaffold"]
|
||||
U2["Unit 2\nAuth Pages"]
|
||||
U3["Unit 3\nLayout & Nav"]
|
||||
U4["Unit 4\nDashboard"]
|
||||
U5["Unit 5\nUser Management"]
|
||||
U6["Unit 6\nRemaining Pages"]
|
||||
|
||||
U0 --> U1 --> U2 --> U3 --> U4 --> U5 --> U6
|
||||
|
||||
style U0 fill:#4CAF50,stroke:#2E7D32,color:#fff
|
||||
style U1 fill:#FFC107,stroke:#F57F17,color:#000
|
||||
style U2 fill:#FF5722,stroke:#BF360C,color:#fff
|
||||
style U3 fill:#9C27B0,stroke:#4A148C,color:#fff
|
||||
style U4 fill:#2196F3,stroke:#0D47A1,color:#fff
|
||||
style U5 fill:#009688,stroke:#004D40,color:#fff
|
||||
style U6 fill:#607D8B,stroke:#263238,color:#fff
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Unit 0 — Backend Prerequisites
|
||||
|
||||
**Type**: Backend (.NET) — blocking prerequisite for all frontend units
|
||||
**Priority**: Must complete before Unit 1
|
||||
|
||||
### Deliverables
|
||||
- `ServiceCollectionExtensions.cs` — add `AddCorsFrontendPolicy()` reading `Cors:AllowedOrigins[]` from config
|
||||
- `Program.cs` — add `app.UseCors("FrontendPolicy")` before `UseAuthentication`
|
||||
- `AuthController.cs` — update `Login`, `Refresh`, `Revoke` to use httpOnly cookie
|
||||
- `RefreshTokenRequest.cs` — **remove** (no backward compatibility needed; refresh now uses httpOnly cookie)
|
||||
- `TokenResponse.cs` — add `Name` property (display name from `UserName` or `Email`)
|
||||
- `appsettings.json` — add `Cors` section (production placeholder)
|
||||
- `appsettings.Development.json` — add `Cors:AllowedOrigins: ["http://localhost:5173"]`
|
||||
- Tests — update `AuthController` tests for cookie-based flow
|
||||
|
||||
### Key Decisions
|
||||
- Cookie name: `refreshToken`, Path: `/api/v1/auth`, HttpOnly, Secure, SameSite=Strict
|
||||
- CORS: `AllowCredentials()` required for cookie flow
|
||||
- `name` field in `TokenResponse` maps from `user.UserName ?? user.Email`
|
||||
|
||||
---
|
||||
|
||||
## Unit 1 — Project Scaffold & Infrastructure
|
||||
|
||||
**Type**: Frontend — foundation for all subsequent units
|
||||
**Depends on**: Unit 0 (API must be reachable with CORS)
|
||||
|
||||
### Deliverables
|
||||
```
|
||||
frontend/
|
||||
├── src/
|
||||
│ ├── api/
|
||||
│ │ ├── client.ts # ApiClient: fetch + auth header + 401 interceptor
|
||||
│ │ └── types.ts # Shared TS interfaces (User, AuthResponse, etc.)
|
||||
│ ├── auth/
|
||||
│ │ ├── AuthContext.tsx # AuthProvider: in-memory token + user state
|
||||
│ │ └── useAuth.ts # useAuth hook
|
||||
│ ├── components/
|
||||
│ │ ├── layout/
|
||||
│ │ │ └── ThemeProvider.tsx
|
||||
│ │ └── error/
|
||||
│ │ └── ErrorBoundary.tsx
|
||||
│ ├── main.tsx # Entry: QueryClientProvider + AuthProvider + RouterProvider
|
||||
│ └── app.tsx # App root
|
||||
├── .env.example # VITE_API_BASE_URL=http://localhost:5000
|
||||
├── .env # gitignored
|
||||
├── vite.config.ts
|
||||
├── tailwind.config.ts # Primary color #ac0000
|
||||
├── tsconfig.json
|
||||
└── package.json # pnpm workspace
|
||||
```
|
||||
|
||||
### Key Decisions
|
||||
- TanStack Router file-based routing initialized (empty route tree)
|
||||
- shadcn/ui configured with `#ac0000` primary
|
||||
- `ApiClient` created; `AuthContext` wired up; `QueryClient` configured
|
||||
|
||||
---
|
||||
|
||||
## Unit 2 — Authentication Pages
|
||||
|
||||
**Type**: Frontend — public + session management
|
||||
**Depends on**: Unit 1 (ApiClient, AuthContext)
|
||||
|
||||
### Deliverables
|
||||
```
|
||||
frontend/src/
|
||||
├── auth/
|
||||
│ ├── ProtectedRoute.tsx # Redirects unauthenticated → /login
|
||||
│ ├── RoleGuard.tsx # Redirects wrong role → /403
|
||||
│ └── InitGuard.tsx # Redirects uninitialized → /setup
|
||||
├── api/
|
||||
│ └── useSetup.ts # useSetupStatus, useCreateOwner
|
||||
└── routes/
|
||||
├── __root.tsx # Root route: InitGuard + global ErrorBoundary
|
||||
├── login.tsx # LoginPage
|
||||
├── setup.tsx # SetupPage
|
||||
└── invite.complete.tsx # InviteCompletePage
|
||||
```
|
||||
|
||||
### Key Decisions
|
||||
- `react-hook-form` + `zod` for all forms; password schema enforces exact backend rules
|
||||
- `InitGuard` in `__root.tsx` blocks all routes until setup status confirmed
|
||||
- `ProtectedRoute` uses `beforeLoad` in TanStack Router
|
||||
|
||||
---
|
||||
|
||||
## Unit 3 — Layout & Navigation
|
||||
|
||||
**Type**: Frontend — authenticated shell
|
||||
**Depends on**: Unit 2 (ProtectedRoute, RoleGuard, AuthContext)
|
||||
|
||||
### Deliverables
|
||||
```
|
||||
frontend/src/
|
||||
├── components/layout/
|
||||
│ ├── AppLayout.tsx # Shell: Sidebar + <Outlet />
|
||||
│ └── Sidebar.tsx # Role-filtered nav, logout, theme toggle
|
||||
└── routes/
|
||||
└── _authenticated.tsx # Authenticated layout route wrapping all protected pages
|
||||
```
|
||||
|
||||
### Key Decisions
|
||||
- `_authenticated.tsx` is a TanStack Router layout route — all child routes inherit `ProtectedRoute`
|
||||
- Sidebar filters nav items by `user.role` from `AuthContext`
|
||||
- Responsive: hamburger menu on mobile
|
||||
|
||||
---
|
||||
|
||||
## Unit 4 — Dashboard
|
||||
|
||||
**Type**: Frontend — first authenticated page
|
||||
**Depends on**: Unit 3 (AppLayout, AuthContext)
|
||||
|
||||
### Deliverables
|
||||
```
|
||||
frontend/src/
|
||||
├── api/
|
||||
│ └── useAvailability.ts # useAvailabilityStatus (staleTime: 30s)
|
||||
├── components/shared/
|
||||
│ └── AvailabilityStatusBadge.tsx
|
||||
└── routes/
|
||||
└── index.tsx # DashboardPage: welcome + availability widget
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Unit 5 — User Management
|
||||
|
||||
**Type**: Frontend — Owner/Admin feature
|
||||
**Depends on**: Unit 3 (AppLayout, RoleGuard), Unit 4 (patterns established)
|
||||
|
||||
### Deliverables
|
||||
```
|
||||
frontend/src/
|
||||
├── api/
|
||||
│ ├── useUsers.ts # useUsers, useInviteUser
|
||||
│ └── useInvitation.ts # useValidateInvitation, useCompleteSetup
|
||||
├── components/users/
|
||||
│ └── InviteUserDialog.tsx # Two-step: invite form → share link
|
||||
└── routes/
|
||||
└── users.tsx # UsersPage: user table + invite dialog
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Unit 6 — Remaining Pages & Documentation
|
||||
|
||||
**Type**: Frontend + Documentation
|
||||
**Depends on**: Unit 3 (AppLayout, RoleGuard)
|
||||
|
||||
### Deliverables
|
||||
```
|
||||
frontend/src/routes/
|
||||
├── profile.tsx # ProfilePage: read-only user info
|
||||
├── settings.tsx # SettingsPage: Owner-only, availability + placeholders
|
||||
├── cms.tsx # CmsPage: Owner-only placeholder
|
||||
├── 403.tsx # AccessDeniedPage
|
||||
└── $404.tsx # NotFoundPage
|
||||
```
|
||||
|
||||
**Documentation**:
|
||||
- `README.md` — add **Frontend Development** section:
|
||||
- Prerequisites (Node.js, pnpm)
|
||||
- `pnpm install` in `frontend/`
|
||||
- `.env` setup (copy `.env.example`)
|
||||
- `pnpm dev` to start dev server
|
||||
- `pnpm build` for production build
|
||||
- Security headers note for production deployment
|
||||
@@ -0,0 +1,27 @@
|
||||
# Unit of Work Plan — CMS Frontend
|
||||
|
||||
## Context
|
||||
Unit decomposition is derived directly from the Workflow Planning and Application Design stages. No additional questions are needed — all decomposition decisions were already made:
|
||||
- **Decomposition approach**: Sequential units ordered by dependency (infrastructure → auth → layout → features)
|
||||
- **Team alignment**: Single developer — no cross-team boundaries needed
|
||||
- **Technical considerations**: All units deploy as one SPA + one backend API
|
||||
- **Code organization**: Monorepo-style, `frontend/` at solution root
|
||||
|
||||
## Planning Checklist
|
||||
- [x] Context analyzed (execution-plan.md + application-design.md)
|
||||
- [x] Unit boundaries confirmed by user (via Workflow Planning approval)
|
||||
- [x] Story-to-unit mapping defined
|
||||
- [x] unit-of-work.md generated
|
||||
- [x] unit-of-work-dependency.md generated
|
||||
- [x] unit-of-work-story-map.md generated
|
||||
|
||||
## Unit Definitions
|
||||
| Unit | Name | Scope |
|
||||
|------|------|-------|
|
||||
| 0 | Backend Prerequisites | .NET backend changes: CORS, httpOnly cookie, TokenResponse DTO with `name` |
|
||||
| 1 | Project Scaffold & Infrastructure | Vite init, TanStack Router, shadcn/ui, Tailwind v4, ApiClient, AuthContext, ThemeProvider, ErrorBoundary, .env |
|
||||
| 2 | Authentication Pages | LoginPage, SetupPage, InviteCompletePage, ProtectedRoute, RoleGuard, InitGuard |
|
||||
| 3 | Layout & Navigation | AppLayout, Sidebar (role-filtered), responsive layout |
|
||||
| 4 | Dashboard | DashboardPage, AvailabilityStatusBadge, useAvailabilityStatus |
|
||||
| 5 | User Management | UsersPage, InviteUserDialog, useUsers, useInviteUser, useValidateInvitation, useCompleteSetup |
|
||||
| 6 | Remaining Pages & Docs | ProfilePage, SettingsPage, CmsPage, NotFoundPage, AccessDeniedPage, README.md frontend section |
|
||||
Reference in New Issue
Block a user