docs & ux improvmeents

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-25 20:31:58 +00:00
parent 90e6e96b2b
commit 4bffede052
247 changed files with 6869 additions and 53517 deletions

View File

@@ -1,76 +0,0 @@
# Global UI Components and Providers
## Purpose
Describe global layout, guards, and utility components/providers used throughout the frontend.
## Code Locations (exact paths)
- App composition and routing: `frontend/src/App.tsx`
- Entry/providers: `frontend/src/main.tsx`
- Layout: `frontend/src/layout/AppLayout.tsx`, `frontend/src/layout/AppSidebar.tsx`, `frontend/src/layout/AppHeader.tsx` (and related layout files)
- Guards: `frontend/src/components/auth/ProtectedRoute.tsx`, `frontend/src/components/common/ModuleGuard.tsx`
- Global utilities: `frontend/src/components/common/ScrollToTop.tsx`, `frontend/src/components/common/GlobalErrorDisplay.tsx`, `frontend/src/components/common/LoadingStateMonitor.tsx`, `frontend/src/components/common/ErrorBoundary.tsx`
- Providers: `frontend/src/context/ThemeContext.tsx`, `frontend/src/context/HeaderMetricsContext.tsx`, `frontend/src/components/ui/toast/ToastContainer.tsx`
## High-Level Responsibilities
- Wrap the app with error handling, theming, metrics, toasts, and routing.
- Enforce authentication and module access at the route level.
- Provide global UI behaviors (scroll reset, error banner, loading monitor).
- Supply consistent layout (sidebar/header/content) for protected areas.
## Detailed Behavior
- Providers (`main.tsx`):
- `ErrorBoundary` wraps the entire app.
- `ThemeProvider` supplies theme context.
- `HeaderMetricsProvider` supplies header metrics context.
- `ToastProvider` exposes toast notifications.
- `BrowserRouter` provides routing; renders `<App />`.
- Routing shell (`App.tsx`):
- `GlobalErrorDisplay` renders global errors; `LoadingStateMonitor` tracks loading states.
- `ScrollToTop` resets scroll on route changes.
- Public routes: `/signin`, `/signup`.
- Protected routes: wrapped in `ProtectedRoute``AppLayout`; `ModuleGuard` used per-module.
- Lazy-loaded module pages inside routes; ModuleGuard enforces module access flags.
- Guards:
- `ProtectedRoute`: checks `useAuthStore` for authentication; redirects unauthenticated users to sign-in; logs out on failed refresh in App effect.
- `ModuleGuard`: gates module pages based on module enable settings/permissions.
- Layout:
- `AppLayout` composes sidebar/header/content; `AppSidebar` uses auth store for user/nav; header components provide top-level actions and metrics.
- Utilities:
- `ScrollToTop` listens to route changes and scrolls to top.
- `GlobalErrorDisplay` shows global error banners.
- `LoadingStateMonitor` tracks loading indicators globally.
- `ToastProvider` supplies toast UI primitives for notifications.
## Data Structures / Models Involved (no code)
- Context values from theme, header metrics, toast providers; auth state from `authStore`; module enable settings from `settingsStore`.
## Execution Flow
- App bootstrap wraps providers → routes render → ProtectedRoute checks auth → ModuleGuard checks module access → layout renders with sidebar/header → pages load lazily and fetch data.
## Cross-Module Interactions
- Auth/module settings drive guards; toasts/errors/loading monitors are available to all pages; layout navigation links modules.
## Error Handling
- `ErrorBoundary` catches render errors.
- `GlobalErrorDisplay` surfaces application-level errors.
- `ProtectedRoute` logs out on failed refresh in App effect; unauthorized users are redirected.
## Tenancy Rules
- Enforced via backend auth and module enable settings; guards rely on auth/module settings to gate access.
## Billing Rules
- None in UI components; billing info shown in pages that consume billing store/endpoints.
## Background Tasks / Schedulers
- None; components react to store state and router changes.
## Key Design Considerations
- Provider stack covers theme, metrics, toasts, error boundary, routing.
- Guards ensure unauthorized access is blocked at the route level.
- Global utilities avoid repeated boilerplate for scroll/error/loading behaviors.
## How Developers Should Work With This Module
- Add new protected pages under `ProtectedRoute` and wrap with `ModuleGuard` when module-scoped.
- Use existing toast/error/loading utilities instead of duplicating.
- Keep provider order consistent (ErrorBoundary → Theme/Header/Toast → Router → App).

View File

@@ -1,84 +0,0 @@
# Frontend Architecture
## Purpose
Explain the frontend structure, routing, state management, providers, and module organization in the React/Vite app.
## Code Locations (exact paths)
- Entry: `frontend/src/main.tsx`
- Root app/routing: `frontend/src/App.tsx`
- State (Zustand stores): `frontend/src/store/*` (authStore, siteStore, billingStore, settingsStore, onboardingStore, columnVisibilityStore, pageSizeStore)
- API layer: `frontend/src/api/*` and `frontend/src/services/api.ts`
- Layout and components: `frontend/src/layout/*`, `frontend/src/components/*`
- Pages: `frontend/src/pages/*` (modules and settings)
- Config: `frontend/src/config/*`
- Styles: `frontend/src/index.css`, `frontend/src/styles/igny8-colors.css`
## High-Level Responsibilities
- Provide SPA routing with protected routes and module guards.
- Maintain global state for auth, site context, billing, settings, UI preferences via Zustand.
- Lazy-load module pages to optimize initial load.
- Wrap the app with providers for theming, toasts, header metrics, error boundary, and router.
## Detailed Behavior
- Entry (`main.tsx`):
- Imports global styles and vendor CSS (Swiper, Flatpickr).
- Wraps the app with `ErrorBoundary`, `ThemeProvider`, `HeaderMetricsProvider`, `ToastProvider`, `BrowserRouter`, then renders `<App />` via React 18 `createRoot`.
- Routing (`App.tsx`):
- Uses `BrowserRouter` (in main) with `<Routes>`/`<Route>` inside App.
- Public routes: `/signin`, `/signup`.
- Protected routes wrapped by `ProtectedRoute``AppLayout`; `ModuleGuard` used per-module.
- Default dashboard `/` loads `Dashboard/Home`.
- Planner routes redirect `/planner``/planner/keywords`; writer routes redirect `/writer``/writer/tasks`.
- Extensive lazy-loaded pages for Planner, Writer, Automation, Linker, Optimizer, Thinker (system), Billing, Admin, Settings, Sites, Help, Reference, Components, UI elements, etc.
- `GlobalErrorDisplay` and `LoadingStateMonitor` mounted globally; `ScrollToTop` for navigation changes.
- Auth refresh: on mount, if authenticated with token, calls `refreshUser`; on failure with missing credentials message, ignores; otherwise logs out.
- State (Zustand examples):
- `authStore`: persists user/token/refreshToken; `login`/`register` hit `/api/v1/auth/...`; enforces account and active plan presence; `refreshUser` fetches user from `/api/v1/auth/users/me/`; `refreshToken` hits `/api/v1/auth/refresh/`; logout clears all auth fields.
- `siteStore`: stores current site/sector and list; used for context across modules.
- `billingStore`, `settingsStore`, `onboardingStore`, `columnVisibilityStore`, `pageSizeStore`: manage billing data, settings flags, onboarding steps, table visibility, pagination sizes.
- API layer:
- `services/api.ts` provides `fetchAPI` helper for authenticated calls (uses token from auth store, handles JSON, throws on non-OK).
- `api/*` modules define typed client calls per domain (auth, planner, writer, etc.).
- Layout/components:
- `AppLayout` wraps sidebar/header/content; `ModuleGuard` enforces module access flags; `ProtectedRoute` enforces auth.
- UI utilities: toasts, error boundary, global loading monitor, scroll-to-top, etc.
## Data Structures / Models Involved (no code)
- Frontend state shapes defined in Zustand stores (auth user, site context, billing info, settings).
## Execution Flow
- App bootstrap → providers → App routes → ProtectedRoute checks auth → ModuleGuard checks module access → lazy-loaded pages fetch data via `api/*` using tokens from authStore → state updates via stores.
## Cross-Module Interactions
- Auth store tokens used by fetchAPI for all modules.
- Site store context influences planner/writer/automation calls.
- Billing store interacts with billing endpoints; settings store influences UI/features; onboarding/table stores affect page rendering.
## State Transitions
- Auth: login/register → set user/token; refresh → update tokens/user; logout clears.
- Site context changes update current site/sector for downstream calls.
- Billing/settings/onboarding/table state mutate via respective store actions.
## Error Handling
- `GlobalErrorDisplay` shows errors; `LoadingStateMonitor` tracks loading; `ProtectedRoute` logs out on failed refresh.
- `fetchAPI` throws on non-OK; authStore catches and surfaces messages; ModuleGuard/ProtectedRoute handle unauthorized access.
## Tenancy Rules
- Enforced via tokens and site context; ModuleGuard and ProtectedRoute rely on backend responses (account/plan) and module flags.
## Billing Rules
- Auth store enforces active plan on login; billing store/pages call billing endpoints for balances/transactions/purchases.
## Background Tasks / Schedulers
- None on frontend; relies on backend/Celery for async work; uses Suspense for lazy loading.
## Key Design Considerations
- Lazy-loaded routes minimize initial bundle.
- Zustand persistence keeps auth/session across reloads.
- Providers wrap app for theming, toasts, error boundary to improve UX stability.
## How Developers Should Work With This Module
- Add routes inside `App.tsx` under ProtectedRoute for authenticated pages; use ModuleGuard for module-gated pages.
- Create new stores in `src/store` for shared state; use `fetchAPI` for authenticated requests.
- Keep lazy loading for heavy pages and maintain Suspense fallbacks where needed.

View File

@@ -1,76 +0,0 @@
# Global UI Components and Providers
## Purpose
Describe global layout, guards, and utility components/providers used throughout the frontend.
## Code Locations (exact paths)
- App composition and routing: `frontend/src/App.tsx`
- Entry/providers: `frontend/src/main.tsx`
- Layout: `frontend/src/layout/AppLayout.tsx`, `frontend/src/layout/AppSidebar.tsx`, `frontend/src/layout/AppHeader.tsx` (and related layout files)
- Guards: `frontend/src/components/auth/ProtectedRoute.tsx`, `frontend/src/components/common/ModuleGuard.tsx`
- Global utilities: `frontend/src/components/common/ScrollToTop.tsx`, `frontend/src/components/common/GlobalErrorDisplay.tsx`, `frontend/src/components/common/LoadingStateMonitor.tsx`, `frontend/src/components/common/ErrorBoundary.tsx`
- Providers: `frontend/src/context/ThemeContext.tsx`, `frontend/src/context/HeaderMetricsContext.tsx`, `frontend/src/components/ui/toast/ToastContainer.tsx`
## High-Level Responsibilities
- Wrap the app with error handling, theming, metrics, toasts, and routing.
- Enforce authentication and module access at the route level.
- Provide global UI behaviors (scroll reset, error banner, loading monitor).
- Supply consistent layout (sidebar/header/content) for protected areas.
## Detailed Behavior
- Providers (`main.tsx`):
- `ErrorBoundary` wraps the entire app.
- `ThemeProvider` supplies theme context.
- `HeaderMetricsProvider` supplies header metrics context.
- `ToastProvider` exposes toast notifications.
- `BrowserRouter` provides routing; renders `<App />`.
- Routing shell (`App.tsx`):
- `GlobalErrorDisplay` renders global errors; `LoadingStateMonitor` tracks loading states.
- `ScrollToTop` resets scroll on route changes.
- Public routes: `/signin`, `/signup`.
- Protected routes: wrapped in `ProtectedRoute``AppLayout`; `ModuleGuard` used per-module.
- Lazy-loaded module pages inside routes; ModuleGuard enforces module access flags.
- Guards:
- `ProtectedRoute`: checks `useAuthStore` for authentication; redirects unauthenticated users to sign-in; logs out on failed refresh in App effect.
- `ModuleGuard`: gates module pages based on module enable settings/permissions.
- Layout:
- `AppLayout` composes sidebar/header/content; `AppSidebar` uses auth store for user/nav; header components provide top-level actions and metrics.
- Utilities:
- `ScrollToTop` listens to route changes and scrolls to top.
- `GlobalErrorDisplay` shows global error banners.
- `LoadingStateMonitor` tracks loading indicators globally.
- `ToastProvider` supplies toast UI primitives for notifications.
## Data Structures / Models Involved (no code)
- Context values from theme, header metrics, toast providers; auth state from `authStore`; module enable settings from `settingsStore`.
## Execution Flow
- App bootstrap wraps providers → routes render → ProtectedRoute checks auth → ModuleGuard checks module access → layout renders with sidebar/header → pages load lazily and fetch data.
## Cross-Module Interactions
- Auth/module settings drive guards; toasts/errors/loading monitors are available to all pages; layout navigation links modules.
## Error Handling
- `ErrorBoundary` catches render errors.
- `GlobalErrorDisplay` surfaces application-level errors.
- `ProtectedRoute` logs out on failed refresh in App effect; unauthorized users are redirected.
## Tenancy Rules
- Enforced via backend auth and module enable settings; guards rely on auth/module settings to gate access.
## Billing Rules
- None in UI components; billing info shown in pages that consume billing store/endpoints.
## Background Tasks / Schedulers
- None; components react to store state and router changes.
## Key Design Considerations
- Provider stack covers theme, metrics, toasts, error boundary, routing.
- Guards ensure unauthorized access is blocked at the route level.
- Global utilities avoid repeated boilerplate for scroll/error/loading behaviors.
## How Developers Should Work With This Module
- Add new protected pages under `ProtectedRoute` and wrap with `ModuleGuard` when module-scoped.
- Use existing toast/error/loading utilities instead of duplicating.
- Keep provider order consistent (ErrorBoundary → Theme/Header/Toast → Router → App).

228
docs/30-FRONTEND/PAGES.md Normal file
View File

@@ -0,0 +1,228 @@
# Frontend Pages & Routes
**Last Verified:** December 25, 2025
**Framework:** React 18 + TypeScript + React Router 6
---
## Route Configuration
Routes defined in `/frontend/src/App.tsx` with:
- Auth guards via `PrivateRoute` component
- Public routes for auth pages
- Nested layouts with sidebar
---
## Public Routes (No Auth Required)
| Route | Component | Description |
|-------|-----------|-------------|
| `/login` | `LoginPage` | User login |
| `/register` | `RegisterPage` | New account |
| `/forgot-password` | `ForgotPasswordPage` | Request reset |
| `/reset-password/:token` | `ResetPasswordPage` | Set new password |
| `/verify-email/:token` | `VerifyEmailPage` | Email verification |
---
## Dashboard Routes
| Route | Component | Module | Description |
|-------|-----------|--------|-------------|
| `/` | `Dashboard` | - | Main dashboard |
| `/dashboard` | `Dashboard` | - | Main dashboard (alias) |
---
## Planner Routes
| Route | Component | Module | Description |
|-------|-----------|--------|-------------|
| `/planner` | `PlannerPage` | Planner | Keyword management |
| `/planner/keywords` | `KeywordsPage` | Planner | Keywords list |
| `/planner/clusters` | `ClustersPage` | Planner | Cluster view |
| `/planner/ideas` | `ContentIdeasPage` | Planner | Content ideas |
---
## Writer Routes
| Route | Component | Module | Description |
|-------|-----------|--------|-------------|
| `/writer` | `WriterPage` | Writer | Task management |
| `/writer/tasks` | `TasksPage` | Writer | Task list |
| `/writer/content` | `ContentListPage` | Writer | Content list |
| `/writer/content/:id` | `ContentEditorPage` | Writer | Edit content |
---
## Automation Routes
| Route | Component | Module | Description |
|-------|-----------|--------|-------------|
| `/automation` | `AutomationPage` | Automation | Pipeline view |
| `/automation/config` | `AutomationConfigPage` | Automation | Configuration |
| `/automation/logs` | `AutomationLogsPage` | Automation | Activity logs |
---
## Linker Routes
| Route | Component | Module | Description |
|-------|-----------|--------|-------------|
| `/linker` | `LinkerPage` | Linker | Internal linking (inactive) |
---
## Optimizer Routes
| Route | Component | Module | Description |
|-------|-----------|--------|-------------|
| `/optimizer` | `OptimizerPage` | Optimizer | SEO optimization (inactive) |
---
## Settings Routes
| Route | Component | Description |
|-------|-----------|-------------|
| `/settings` | `SettingsPage` | Settings index |
| `/settings/sites` | `SitesSettingsPage` | Site management |
| `/settings/sites/:id` | `SiteDetailPage` | Site details |
| `/settings/sectors` | `SectorsSettingsPage` | Sector management |
| `/settings/users` | `UsersSettingsPage` | User management |
| `/settings/integrations` | `IntegrationsSettingsPage` | Integration setup |
| `/settings/integrations/:id` | `IntegrationDetailPage` | Integration details |
| `/settings/prompts` | `PromptsSettingsPage` | AI prompts |
| `/settings/modules` | `ModulesSettingsPage` | Module enable/disable |
| `/settings/api-keys` | `APIKeysSettingsPage` | AI API keys |
| `/settings/billing` | `BillingSettingsPage` | Credit/billing |
---
## Profile Routes
| Route | Component | Description |
|-------|-----------|-------------|
| `/profile` | `ProfilePage` | User profile |
| `/profile/account` | `AccountPage` | Account settings |
| `/profile/security` | `SecurityPage` | Password/2FA |
---
## Page Components Location
```
frontend/src/pages/
├── auth/
│ ├── LoginPage.tsx
│ ├── RegisterPage.tsx
│ ├── ForgotPasswordPage.tsx
│ └── ResetPasswordPage.tsx
├── dashboard/
│ └── Dashboard.tsx
├── planner/
│ ├── PlannerPage.tsx
│ ├── KeywordsPage.tsx
│ ├── ClustersPage.tsx
│ └── ContentIdeasPage.tsx
├── writer/
│ ├── WriterPage.tsx
│ ├── TasksPage.tsx
│ ├── ContentListPage.tsx
│ └── ContentEditorPage.tsx
├── automation/
│ ├── AutomationPage.tsx
│ ├── AutomationConfigPage.tsx
│ └── AutomationLogsPage.tsx
├── linker/
│ └── LinkerPage.tsx
├── optimizer/
│ └── OptimizerPage.tsx
├── settings/
│ ├── SettingsPage.tsx
│ ├── SitesSettingsPage.tsx
│ ├── SectorsSettingsPage.tsx
│ ├── UsersSettingsPage.tsx
│ ├── IntegrationsSettingsPage.tsx
│ ├── PromptsSettingsPage.tsx
│ ├── ModulesSettingsPage.tsx
│ ├── APIKeysSettingsPage.tsx
│ └── BillingSettingsPage.tsx
└── profile/
├── ProfilePage.tsx
└── SecurityPage.tsx
```
---
## Route Guards
### PrivateRoute Component
```typescript
// frontend/src/components/auth/PrivateRoute.tsx
- Checks authentication state
- Redirects to /login if not authenticated
- Stores intended destination for post-login redirect
```
### Module-Based Visibility
Sidebar items hidden when module disabled:
- Controlled by `moduleStore.isModuleEnabled()`
- Does NOT block direct URL access (pending implementation)
---
## Navigation Structure
### Main Sidebar (`AppSidebar.tsx`)
```
Dashboard
├── Planner [if enabled]
│ ├── Keywords
│ ├── Clusters
│ └── Ideas
├── Writer [if enabled]
│ ├── Tasks
│ └── Content
├── Automation [if enabled]
├── Linker [if enabled, hidden by default]
├── Optimizer [if enabled, hidden by default]
└── Settings
```
---
## Layout Components
| Component | Location | Purpose |
|-----------|----------|---------|
| `AppLayout` | `/layouts/AppLayout.tsx` | Main app wrapper |
| `AppSidebar` | `/components/sidebar/AppSidebar.tsx` | Navigation sidebar |
| `AppHeader` | `/components/header/AppHeader.tsx` | Top navigation |
| `PageHeader` | `/components/common/PageHeader.tsx` | Page title section |
| `ContentContainer` | `/components/common/ContentContainer.tsx` | Content wrapper |
---
## State Context
All routes have access to:
- `useAuthStore()` - User/account info
- `useSiteStore()` - Current site selection
- `useSectorStore()` - Current sector selection
- `useModuleStore()` - Module enable states
---
## Planned Changes
| Item | Description | Priority |
|------|-------------|----------|
| Route-level guards | Block disabled module routes, not just hide sidebar | High |
| Breadcrumbs | Add breadcrumb navigation | Medium |
| Route analytics | Track page views | Low |

View File

@@ -1,90 +0,0 @@
# State Management
## Purpose
Describe how the frontend manages global state with Zustand stores, including authentication, site context, billing, and settings.
## Code Locations (exact paths)
- Auth store: `frontend/src/store/authStore.ts`
- Site store: `frontend/src/store/siteStore.ts`
- Billing store: `frontend/src/store/billingStore.ts`
- Settings store: `frontend/src/store/settingsStore.ts`
- Other UI/state stores: `frontend/src/store/onboardingStore.ts`, `columnVisibilityStore.ts`, `pageSizeStore.ts`, `settingsStore.ts`, etc.
## High-Level Responsibilities
- Persist authentication state (user, tokens), refresh sessions, and enforce account/plan presence.
- Track the active site (and sector via sector store) across modules, with persistence and change events.
- Fetch and cache billing balances/usage/limits.
- Load and update account/module settings with coalesced fetches and persistence.
## Detailed Behavior
- `authStore`:
- Persists `user`, `token`, `refreshToken`, `isAuthenticated`, `loading`.
- `login(email,password)`: POST `/api/v1/auth/login/`; stores tokens/user; errors mapped to PLAN_REQUIRED/ACCOUNT_REQUIRED/AUTH_FAILED; resets loading on error.
- `register(data)`: POST `/api/v1/auth/register/`; stores tokens/user; resets loading on error.
- `refreshToken()`: POST `/api/v1/auth/refresh/`; updates access token; attempts `refreshUser`; logs out on failure.
- `refreshUser()`: GET `/api/v1/auth/users/me/`; requires account+plan; updates user or logs out on auth failure; clears loading guard.
- `logout()`: clears all auth fields.
- `siteStore`:
- Persists `activeSite`; stores `loading`/`error`.
- `setActiveSite(site)`: sets/persists site, dispatches `siteChanged` event, triggers sector store load for the site.
- `loadActiveSite()`: fetches sites via `fetchSites`; picks prior site if still active, else first active; persists selection.
- `refreshActiveSite()`: refreshes current site from server; reloads if inactive/missing.
- `billingStore`:
- Holds `balance`, `usageSummary`, `usageLimits`, `loading`/`error`, `lastUpdated`.
- `loadBalance()`: calls `getCreditBalance`; keeps prior balance during retry; sets `lastUpdated`.
- `loadUsageSummary(startDate?, endDate?)`: calls `getCreditUsageSummary`; updates summary.
- `loadUsageLimits()`: calls `getCreditUsageLimits`; tolerates 404 by returning null; records errors otherwise.
- `reset()`: clears billing state.
- `settingsStore`:
- Persists `accountSettings`, `moduleSettings`, `moduleEnableSettings`, `loading`/`error`.
- Account settings: load all, load one, create/update with create/update endpoints; handles typed errors (not found vs validation).
- Module settings: load/update per module; stores per-module map.
- Module enable settings: caches for 60s, coalesces concurrent fetches; `isModuleEnabled` helper.
- `reset()` clears settings state.
- Other stores:
- `onboardingStore`, `columnVisibilityStore`, `pageSizeStore` manage UI/onboarding/table preferences (see respective files for exact fields/actions).
## Data Structures / Models Involved (no code)
- Store state interfaces defined in each file (auth user shape, site, billing balance/usage, settings maps).
## Execution Flow
- Components/hooks read/write state via `useXStore` hooks.
- Auth flows call store actions, which perform fetches and update state; ProtectedRoute/ModuleGuard rely on auth and settings/module enable flags.
- Site changes dispatch `siteChanged` for downstream listeners and trigger sector loading.
- Billing/settings loads fetch data on demand and cache/persist where configured.
## Cross-Module Interactions
- Auth tokens consumed by `fetchAPI` for all API calls.
- Active site influences planner/writer/automation calls via query params/context.
- Module enable settings influence `ModuleGuard`.
- Billing data feeds billing pages and credit displays.
## State Transitions
- Auth: unauthenticated → login/register → authenticated; refresh updates tokens/user; logout clears.
- Site: load/refresh/set updates `activeSite` and notifies listeners.
- Billing/settings: load/update actions mutate cached maps and loading/error flags.
## Error Handling
- Auth store resets loading on all error paths; throws descriptive errors.
- Billing store tolerates missing limits (404) and surfaces messages; balance retry preserves prior state.
- Settings store differentiates not-found vs validation errors; stores messages in `error`.
## Tenancy Rules
- Auth store requires account+plan; site store filters on accessible sites; billing/settings calls use authenticated endpoints tied to the users account.
## Billing Rules
- Enforced via backend; billing store reads balances/usage/limits and does not mutate credits.
## Background Tasks / Schedulers
- None; all store actions are user-driven fetches with immediate state updates.
## Key Design Considerations
- Zustand `persist` used for auth/site/settings to survive reloads.
- Guarded loading flags and error handling prevent stuck states.
- Site changes broadcast events for dependent components/stores.
## How Developers Should Work With This Module
- Use existing store actions for auth/site/billing/settings instead of duplicating fetch logic.
- When adding new shared state, create a dedicated store in `src/store` and persist only needed slices.
- Keep error/reset semantics consistent (always clear loading on failure).

375
docs/30-FRONTEND/STORES.md Normal file
View File

@@ -0,0 +1,375 @@
# Zustand State Management
**Last Verified:** December 25, 2025
**Framework:** Zustand 4 with persist middleware
---
## Store Architecture
All stores in `/frontend/src/store/` use Zustand with TypeScript.
**Key Patterns:**
- `persist` middleware for localStorage persistence
- Async actions for API calls
- Selectors for derived state
---
## Auth Store (`authStore.ts`)
**Purpose:** User authentication and session management
```typescript
interface AuthState {
user: User | null;
account: Account | null;
isAuthenticated: boolean;
accessToken: string | null;
refreshToken: string | null;
isLoading: boolean;
error: string | null;
}
interface AuthActions {
login(email: string, password: string): Promise<void>;
logout(): void;
register(data: RegisterData): Promise<void>;
refreshAccessToken(): Promise<void>;
fetchUser(): Promise<void>;
updateUser(data: UserUpdate): Promise<void>;
}
```
**Persistence:** `accessToken`, `refreshToken` in localStorage
**Usage:**
```typescript
const { user, login, logout, isAuthenticated } = useAuthStore();
```
---
## Site Store (`siteStore.ts`)
**Purpose:** Site selection and management
```typescript
interface SiteState {
sites: Site[];
currentSite: Site | null;
isLoading: boolean;
error: string | null;
}
interface SiteActions {
fetchSites(): Promise<void>;
createSite(data: SiteCreate): Promise<Site>;
updateSite(id: string, data: SiteUpdate): Promise<Site>;
deleteSite(id: string): Promise<void>;
setCurrentSite(site: Site): void;
}
```
**Persistence:** `currentSite.id` in localStorage
**Auto-selection:** If no site selected and sites exist, auto-selects first site
---
## Sector Store (`sectorStore.ts`)
**Purpose:** Sector selection and management within sites
```typescript
interface SectorState {
sectors: Sector[];
currentSector: Sector | null;
isLoading: boolean;
error: string | null;
}
interface SectorActions {
fetchSectors(siteId: string): Promise<void>;
createSector(data: SectorCreate): Promise<Sector>;
updateSector(id: string, data: SectorUpdate): Promise<Sector>;
deleteSector(id: string): Promise<void>;
setCurrentSector(sector: Sector): void;
}
```
**Persistence:** `currentSector.id` in localStorage
**Dependency:** Reloads when `currentSite` changes
---
## Module Store (`moduleStore.ts`)
**Purpose:** Track which modules are enabled/disabled
```typescript
interface ModuleState {
modules: ModuleSettings;
isLoading: boolean;
error: string | null;
}
interface ModuleSettings {
planner_enabled: boolean;
writer_enabled: boolean;
linker_enabled: boolean;
optimizer_enabled: boolean;
automation_enabled: boolean;
integration_enabled: boolean;
publisher_enabled: boolean;
}
interface ModuleActions {
fetchModules(): Promise<void>;
updateModules(settings: Partial<ModuleSettings>): Promise<void>;
isModuleEnabled(module: ModuleName): boolean;
}
```
**Usage:**
```typescript
const { isModuleEnabled } = useModuleStore();
if (isModuleEnabled('planner')) { /* show planner */ }
```
**Currently used for:** Sidebar visibility only
---
## Billing Store (`billingStore.ts`)
**Purpose:** Credit balance and usage tracking
```typescript
interface BillingState {
balance: CreditBalance | null;
usage: CreditUsage[];
limits: PlanLimits | null;
isLoading: boolean;
error: string | null;
}
interface CreditBalance {
ideaCredits: number;
contentCredits: number;
imageCredits: number;
optimizationCredits: number;
}
interface BillingActions {
fetchBalance(): Promise<void>;
fetchUsage(period?: string): Promise<void>;
fetchLimits(): Promise<void>;
}
```
**Refresh triggers:**
- After content generation
- After image generation
- After optimization (when implemented)
---
## Planner Store (`plannerStore.ts`)
**Purpose:** Keywords, clusters, and content ideas state
```typescript
interface PlannerState {
keywords: Keyword[];
clusters: Cluster[];
ideas: ContentIdea[];
selectedKeywords: string[];
filters: KeywordFilters;
isLoading: boolean;
error: string | null;
}
interface PlannerActions {
fetchKeywords(siteId: string, sectorId?: string): Promise<void>;
createKeyword(data: KeywordCreate): Promise<Keyword>;
bulkDeleteKeywords(ids: string[]): Promise<void>;
autoCluster(keywordIds: string[]): Promise<void>;
generateIdeas(clusterId: string): Promise<void>;
setFilters(filters: Partial<KeywordFilters>): void;
selectKeywords(ids: string[]): void;
}
```
---
## Writer Store (`writerStore.ts`)
**Purpose:** Tasks and content management
```typescript
interface WriterState {
tasks: Task[];
content: Content[];
currentContent: Content | null;
filters: TaskFilters;
isLoading: boolean;
isGenerating: boolean;
error: string | null;
}
interface WriterActions {
fetchTasks(siteId: string, sectorId?: string): Promise<void>;
createTask(data: TaskCreate): Promise<Task>;
generateContent(taskId: string): Promise<Content>;
fetchContent(contentId: string): Promise<Content>;
updateContent(id: string, data: ContentUpdate): Promise<Content>;
generateImages(contentId: string): Promise<void>;
publishToWordPress(contentId: string): Promise<void>;
}
```
**Generation state:** `isGenerating` tracks active AI operations
---
## Automation Store (`automationStore.ts`)
**Purpose:** Automation pipeline state and control
```typescript
interface AutomationState {
config: AutomationConfig | null;
currentRun: AutomationRun | null;
pipeline: PipelineOverview | null;
history: AutomationRun[];
logs: AutomationLog[];
isLoading: boolean;
error: string | null;
}
interface AutomationActions {
fetchConfig(siteId: string): Promise<void>;
updateConfig(data: ConfigUpdate): Promise<void>;
startRun(siteId: string): Promise<void>;
pauseRun(runId: string): Promise<void>;
resumeRun(runId: string): Promise<void>;
cancelRun(runId: string): Promise<void>;
fetchPipeline(siteId: string): Promise<void>;
fetchLogs(runId: string): Promise<void>;
}
```
**Polling:** Active runs trigger status polling every 5 seconds
---
## Integration Store (`integrationStore.ts`)
**Purpose:** WordPress integration management
```typescript
interface IntegrationState {
integrations: SiteIntegration[];
currentIntegration: SiteIntegration | null;
syncStatus: SyncStatus | null;
isLoading: boolean;
isSyncing: boolean;
error: string | null;
}
interface IntegrationActions {
fetchIntegrations(siteId: string): Promise<void>;
createIntegration(data: IntegrationCreate): Promise<SiteIntegration>;
testConnection(id: string): Promise<TestResult>;
triggerSync(id: string): Promise<void>;
fetchSyncStatus(id: string): Promise<SyncStatus>;
}
```
---
## UI Store (`uiStore.ts`)
**Purpose:** UI state (sidebar, modals, notifications)
```typescript
interface UIState {
sidebarOpen: boolean;
sidebarCollapsed: boolean;
theme: 'light' | 'dark' | 'system';
notifications: Notification[];
}
interface UIActions {
toggleSidebar(): void;
collapseSidebar(): void;
setTheme(theme: Theme): void;
addNotification(notification: Notification): void;
removeNotification(id: string): void;
}
```
**Persistence:** `theme`, `sidebarCollapsed` in localStorage
---
## Store Dependencies
```
authStore
└── siteStore (loads after auth)
└── sectorStore (loads when site changes)
├── plannerStore (scoped to site/sector)
├── writerStore (scoped to site/sector)
├── automationStore (scoped to site)
└── integrationStore (scoped to site)
moduleStore (global, loads once per account)
billingStore (global, loads once per account)
uiStore (local only, no API)
```
---
## Store Files Location
```
frontend/src/store/
├── authStore.ts
├── siteStore.ts
├── sectorStore.ts
├── moduleStore.ts
├── billingStore.ts
├── plannerStore.ts
├── writerStore.ts
├── automationStore.ts
├── integrationStore.ts
├── uiStore.ts
└── index.ts (re-exports)
```
---
## Best Practices
1. **Always scope to site/sector** when fetching module data
2. **Check module enabled** before showing features
3. **Handle loading states** in UI components
4. **Clear store on logout** to prevent data leaks
5. **Use selectors** for derived/filtered data
---
## Planned Changes
| Item | Description | Priority |
|------|-------------|----------|
| Add `linkerStore` | State for internal linking results | Medium |
| Add `optimizerStore` | State for optimization results | Medium |
| Better error typing | Typed error codes per store | Low |
| DevTools integration | Zustand devtools middleware | Low |

View File

@@ -1,149 +0,0 @@
# Automation Frontend Module
**Location:** `frontend/src/pages/automation/`
**Purpose:** UI components and pages for automation module
## Source Files
# Automation Page (AI Automation Pipeline Dashboard)
## Purpose
Provide a site-scoped dashboard to configure, run, pause, resume, and monitor the 7-stage automation pipeline. Surfaces pipeline overview, current run status, metrics, history, configuration modal, and credit sufficiency checks.
## Code Locations (exact paths)
- Primary page: `frontend/src/pages/Automation/AutomationPage.tsx`
- Service: `frontend/src/services/automationService` (config, current run, estimate, pipeline overview, runNow, pause, resume, publishWithoutReview)
- Metrics sources: `frontend/src/services/api` (`fetchKeywords`, `fetchClusters`, `fetchContentIdeas`, `fetchTasks`, `fetchContent`, `fetchContentImages`)
- UI components: `frontend/src/components/Automation/{ActivityLog,ConfigModal,RunHistory,CurrentProcessingCard}`, `frontend/src/components/dashboard/EnhancedMetricCard`, `frontend/src/components/common/ComponentCard`, `frontend/src/components/common/PageMeta`, `frontend/src/components/common/DebugSiteSelector`
## High-Level Responsibilities
- Load automation config, current run, credit estimate, and pipeline overview for the active site.
- Poll current run and pipeline status while running/paused; refresh metrics regularly during runs.
- Provide controls: Run Now, Pause, Resume, Save Config, Publish Without Review.
- Show per-stage cards, current processing card, run history, and activity log.
## Detailed Behavior
- Site binding: requires `useSiteStore.activeSite`; without it, page shows a “select a site” message.
- Initial load (`loadData`): parallel calls to `getConfig`, `getCurrentRun`, `estimate`, `getPipelineOverview` plus low-level metrics (keywords/clusters/ideas/tasks/content/images counts) per site_id.
- Polling: 5s interval; if run status is `running`/`paused`, refresh run, pipeline, and metrics; otherwise refresh pipeline only.
- Metrics: counts for keywords (total/new/mapped), clusters (total/new/mapped), ideas (total/new/queued/completed), tasks (total), content (total/draft/review/published), images (total/pending).
- Stage cards: derived from `STAGE_CONFIG` array representing 7 pipeline stages including manual review gate.
- Actions:
- Run Now: checks credit sufficiency from `estimate`; blocks if insufficient.
- Pause/Resume: call automationService with site + run_id, then refresh run/pipeline/metrics.
- Save Config: persists partial config, updates local state, reloads pipeline/metrics/run.
- Publish Without Review: calls `publishWithoutReview` with confirmation prompt, then reloads.
- UI states: `loading` spinner until initial fetch; `showProcessingCard` toggled on when a run exists.
## Data Structures / Models Involved (no code)
- `AutomationConfig`: site-level automation settings (intervals, gates, etc.).
- `AutomationRun`: run_id, status (`running`, `paused`, etc.), stage info.
- `PipelineStage`: stage list with status/progress.
- Metrics DTOs from planner/writer/image endpoints (`count` fields only).
## Execution Flow
- `useEffect` with site dependency → `loadData`.
- Interval polling while active runs → `loadCurrentRun`, `loadPipelineOverview`, `loadMetrics`.
- User actions dispatch to automationService; toasts for success/error; follow-up refreshes.
## Cross-Module Interactions
- Pulls planner/writer/image counts to present authoritative pipeline context.
- Uses `useSiteStore` for tenant/site scoping; credit checks rely on billing estimate API.
## State Transitions
- `currentRun.status` drives polling and control availability.
- `showProcessingCard` turns on when a run exists.
- `estimate.sufficient` gates Run Now action.
## Error Handling
- Toast-based error reporting; fetch failures log to console but keep page usable.
- Metrics fetch wrapped in try/catch; failure degrades to missing metrics without blocking the rest.
## Tenancy Rules
- All automation service calls require `activeSite.id`; backend enforces account/site scoping. No client override for other tenants.
## Billing Rules (if applicable)
- Run Now is blocked when `estimate.sufficient` is false; shows required vs current credits.
## Background Tasks / Schedulers (if applicable)
- Client-side polling (5s) during active runs; no background scheduling beyond that.
## Key Design Considerations
- Polling keeps UI aligned with long-running Celery pipeline states.
- Credit gate prevents user-initiated runs that would immediately fail server-side.
- Metrics are read-only mirrors of backend aggregates to align UI with planner/writer state.
## How Developers Should Work With This Module
- When adding new stages, extend `STAGE_CONFIG` and ensure backend pipeline overview includes them.
- Keep polling interval modest; if adding heavier metrics, consider staggering fetches to avoid rate limits.
- Wire new config fields through `AutomationConfig` type, `ConfigModal`, and `updateConfig` payload.
# Automation Components
## Purpose
Describe the reusable UI components that compose the automation dashboard: stage cards, current processing card, run history, activity log, and configuration modal. These components visualize pipeline state, history, and settings sourced from automation services.
## Code Locations (exact paths)
- Stage cards & layout: `frontend/src/pages/Automation/AutomationPage.tsx` (renders stage cards from `STAGE_CONFIG`)
- Current run card: `frontend/src/components/Automation/CurrentProcessingCard.tsx`
- Activity log: `frontend/src/components/Automation/ActivityLog.tsx`
- Run history: `frontend/src/components/Automation/RunHistory.tsx`
- Config modal: `frontend/src/components/Automation/ConfigModal.tsx`
- Shared UI: `frontend/src/components/common/{ComponentCard,PageMeta,DebugSiteSelector}`, `frontend/src/components/dashboard/EnhancedMetricCard`
## High-Level Responsibilities
- Stage cards: show each of the 7 pipeline stages with icon/color/status derived from pipeline overview.
- CurrentProcessingCard: surface active run details, stage name, status, percent, timestamps, and controls (Pause/Resume).
- ActivityLog: list recent automation events (from run log feed).
- RunHistory: show prior runs with status and timestamps.
- ConfigModal: edit and persist automation configuration per site.
## Detailed Behavior
- Stage Cards:
- Built from `STAGE_CONFIG` array (keywords→clusters, clusters→ideas, ideas→tasks, tasks→content, content→image prompts, image prompts→images, manual review).
- Status/progress comes from `pipelineOverview.stages` provided by `automationService.getPipelineOverview`.
- CurrentProcessingCard:
- Receives `currentRun` and shows status; displays pause/resume buttons wired to page handlers that call `automationService.pause/resume`.
- Hidden when no current run; toggled by `showProcessingCard`.
- RunHistory:
- Takes run list (from `automationService.getCurrentRun` payload history) and renders chronological entries.
- ActivityLog:
- Displays textual log entries for the active run; consumes run log data supplied by the page.
- ConfigModal:
- Opens from page button; on save calls `automationService.updateConfig(activeSite.id, newConfig)`; merges into local config and refreshes pipeline/metrics.
## Data Structures / Models Involved (no code)
- `AutomationRun` (id, status, stage, progress, started_at/ended_at).
- `PipelineStage` array with stage identifiers, names, progress.
- `AutomationConfig` fields shown in modal (intervals/gates/etc., defined server-side).
## Execution Flow
- Page loads run + pipeline → passes data into stage cards, processing card, history, activity log.
- User opens ConfigModal → submit triggers updateConfig → page reloads pipeline/metrics/run to reflect new settings.
- Pause/Resume buttons on CurrentProcessingCard call page handlers, which in turn call automationService.
## Cross-Module Interactions
- Components depend on site context from `useSiteStore` and data from automationService; no direct planner/writer calls (metrics happen in page).
## State Transitions
- Components are pure renderers; state (visibility, selected config) managed by `AutomationPage`.
## Error Handling
- Errors in save/pause/resume are surfaced by the page via toasts; components render based on provided props.
## Tenancy Rules
- All data passed in is already scoped to `activeSite`; components do not alter scoping.
## Billing Rules (if applicable)
- None inside components; Run Now credit gating handled at page level.
## Background Tasks / Schedulers (if applicable)
- None; updates driven by page polling interval.
## Key Design Considerations
- Separation of concerns: components stay presentational; network calls remain in page.
- Stage cards use color/icon metadata for fast visual scanning of pipeline status.
## How Developers Should Work With This Module
- Add new stages by extending `STAGE_CONFIG` and ensuring pipeline overview includes the new stage id/status.
- Extend ConfigModal fields in sync with backend `AutomationConfig`; persist via automationService.
- Keep CurrentProcessingCard controls minimal; any new action should call automationService and refresh run/pipeline afterward.

View File

@@ -1,183 +0,0 @@
# Writer Frontend Module
**Location:** `frontend/src/pages/writer/`
**Purpose:** UI components and pages for writer module
## Source Files
# Writer Main Page (Queue/Drafts/Images Navigation)
## Purpose
Serve as the entry surface for writer workflows, routing users to task queue, drafts, images, review, and published content views. It relies on shared table templates and writer navigation tabs defined in the content/tasks/images pages.
## Code Locations (exact paths)
- Key pages under Writer:
- Tasks (queue): `frontend/src/pages/Writer/Tasks.tsx`
- Content drafts/list: `frontend/src/pages/Writer/Content.tsx`
- Images: `frontend/src/pages/Writer/Images.tsx`
- Content view: `frontend/src/pages/Writer/ContentView.tsx`
- Navigation tabs defined inside Tasks/Content/Images pages (`writerTabs`).
## High-Level Responsibilities
- Present writer-specific navigation and headers.
- Delegate to module pages that implement task creation, AI generation, content listing, and image management.
## Detailed Behavior
- Writer pages use shared navigation tabs (`writerTabs`: Queue, Drafts, Images, Review, Published) rendered via `ModuleNavigationTabs`.
- Each page sets a header (`PageHeader`) with badge icon and binds to the tab component for consistent navigation.
- State (filters, pagination, selections) is managed within each page; there is no global writer-state container beyond shared stores (`useSectorStore`, `usePageSizeStore`).
## Data Structures / Models Involved (no code)
- Task, Content, ContentImage DTOs from `frontend/src/services/api` (writer endpoints).
## Execution Flow
- User enters writer area via route (e.g., `/writer/tasks` or `/writer/content`).
- Navigation tabs switch routes; each route mounts its page and fetches data (tasks/content/images).
## Cross-Module Interactions
- Sector/site scoping via `useSectorStore` and backend query params in API calls.
- Optimization and image generation actions route into optimizer or image generation APIs.
## State Transitions
- Per-page loading/filters; navigation changes unmount current page and mount target page.
## Error Handling
- Each page uses toasts for API errors; no shared error surface beyond per-page banners.
## Tenancy Rules
- Backend filters by account/site/sector; pages pass sector context via filters or rely on server defaults.
## Billing Rules (if applicable)
- None on navigation; individual actions (AI generation) consume credits on backend.
## Background Tasks / Schedulers (if applicable)
- None at the navigation level.
## Key Design Considerations
- Tabs keep writer UX consistent; each page owns its data loading to avoid cross-coupling.
## How Developers Should Work With This Module
- When adding a new writer view (e.g., “Outlines”), add a tab entry and a route in `App.tsx`, and implement the page with the same header/tab pattern.
# Image Editor Page (Images List & Generation)
## Purpose
Manage generated images linked to writer content: list images grouped by content, filter/search, trigger generation, update statuses, and download/view images. Uses table template patterns similar to content/tasks.
## Code Locations (exact paths)
- Page: `frontend/src/pages/Writer/Images.tsx`
- API: `frontend/src/services/api` (`fetchContentImages`, `fetchImageGenerationSettings`, `generateImages`, `bulkUpdateImagesStatus`, `deleteContent`, `bulkDeleteContent`)
- Config: `frontend/src/config/pages/images.config` (columns/filters)
- UI components: `frontend/src/components/common/ImageQueueModal`, `frontend/src/components/common/SingleRecordStatusUpdateModal`, `frontend/src/components/common/PageHeader`, `frontend/src/components/navigation/ModuleNavigationTabs`, `frontend/src/components/ui/modal`
- Hooks: `frontend/src/hooks/useResourceDebug` (AI logs toggle), `frontend/src/hooks/useProgressModal` (via modal usage pattern)
## High-Level Responsibilities
- Fetch and render content-image groups with client-side filtering/search/sorting/pagination.
- Trigger image generation for selected content with queue modal and provider/model selection.
- Update image status in bulk and delete images/content.
- Provide AI function log visibility when resource debug is enabled.
## Detailed Behavior
- Data load: `loadImages` calls `fetchContentImages({})`, applies client-side search (`content_title`) and status filter (`overall_status`), sorts (default `content_title`), paginates client-side (page size 10), and adds `id` field mirroring `content_id` for selection.
- Filters: search text; status dropdown; sort controls; pagination tracked in local state.
- Actions:
- Generate images: opens `ImageQueueModal`, builds queue items, calls `generateImages` with provider/model; tracks taskId/model/provider state; shows AI logs when resource debug enabled.
- Bulk status update: `bulkUpdateImagesStatus` on selected ids.
- Delete (single/bulk): uses `deleteContent`/`bulkDeleteContent`.
- Download/view: handled by row actions in config (template-driven).
- Navigation: writer tabs rendered via `ModuleNavigationTabs` (Queue/Drafts/Images/Review/Published).
- Resource debug: AI logs captured only when `useResourceDebug` returns true; `addAiLog` appends logs for visibility.
- Loading UX: `loading` + `showContent` gating; debounced search resets page as needed.
## Data Structures / Models Involved (no code)
- `ContentImagesGroup`: content_id, content_title, overall_status, images[].
- `ContentImage`: individual image entries with URL/status/prompt (from API).
- Generation settings: provider/model options from `fetchImageGenerationSettings`.
## Execution Flow
- `useEffect``loadImages`.
- Filters/sort/page changes → recompute client-side subsets.
- Generate action → open modal → call `generateImages` → optionally log steps → reload images.
- Status update/delete actions → call API → reload.
## Cross-Module Interactions
- Tied to writer content records; delete actions use writer content endpoints.
- AI generation leverages shared API endpoints that consume credits server-side.
## State Transitions
- `loading`/`showContent` manage render timing; modal open states for queue/status/image viewer.
- `aiLogs` maintained only when debug is enabled.
## Error Handling
- Toast errors for load/generate/update/delete; generation errors also recorded in AI logs when enabled.
- Debounced search handles errors gracefully by keeping prior data until reload.
## Tenancy Rules
- Backend enforces account/site/sector; client passes no explicit tenant fields beyond any default filters in API layer.
## Billing Rules (if applicable)
- Image generation consumes credits on backend; page performs no credit gating.
## Background Tasks / Schedulers (if applicable)
- None; generation is user-triggered, and polling is not used here.
## Key Design Considerations
- Client-side pagination used because API returns grouped images; keeps UI responsive without extra endpoints.
- Resource debug toggle avoids unnecessary log storage unless explicitly enabled.
## How Developers Should Work With This Module
- If server adds server-side pagination/filtering, remove client-side slicing and pass filters to API.
- Extend row actions by updating `images.config` with handlers wired to new behaviors.
- Keep generation flow in sync with backend provider/model options; surface credit estimates if backend exposes them.
# Content Editor Page
## Purpose
Display a single content record with full details for review/read-only inspection. Acts as the per-record viewer for content generated or managed by the Writer module.
## Code Locations (exact paths)
- Page: `frontend/src/pages/Writer/ContentView.tsx`
- Template: `frontend/src/templates/ContentViewTemplate` (renders the actual layout/content fields)
- API: `frontend/src/services/api` (`fetchContentById`)
## High-Level Responsibilities
- Fetch a specific content item by id from route param and render it via `ContentViewTemplate`.
- Validate id parameter, handle not-found/error states, and provide back navigation to content list.
## Detailed Behavior
- Route: `/writer/content/:id`.
- On mount: validates `id` is numeric; on invalid, shows toast and redirects to `/writer/content`.
- Fetches content via `fetchContentById(contentId)`; sets `content` state and clears `loading`.
- Errors: shows toast (`Failed to load content`) and leaves `content` null.
- Back action: `onBack` navigates to `/writer/content`.
- Page metadata: sets document title/description via `PageMeta`.
## Data Structures / Models Involved (no code)
- Content DTO from writer API (includes title, body/html, status, external_url, etc.; structure defined server-side).
## Execution Flow
- `useEffect` → validate id → fetch content → update state → render template.
- Template receives `{ content, loading, onBack }`.
## Cross-Module Interactions
- Navigation back to writer drafts list; no direct cross-module calls.
## State Transitions
- `loading` toggles during fetch; `content` set on success; invalid id triggers navigation away.
## Error Handling
- Toast errors for missing/invalid id or fetch failure; console logs errors.
## Tenancy Rules
- Backend enforces account/site/sector scoping; client only supplies id from route.
## Billing Rules (if applicable)
- None within this view; generation/updates handled elsewhere.
## Background Tasks / Schedulers (if applicable)
- None.
## Key Design Considerations
- Strict id validation avoids bad requests.
- Keeps view read-only; editing handled elsewhere (not in this component).
## How Developers Should Work With This Module
- If adding inline editing, extend `ContentViewTemplate` and add PATCH/PUT calls; keep id validation and error handling intact.