Architecture Instructions – React SPA (Feature-Based, Query/Mutation-Centric, Notification Errors)
Architecture Instructions – React SPA (Feature-Based, Query/Mutation-Centric, Fully Observable)
1. Architectural Style
- Feature-based architecture with hard boundaries.
-
Explicit separation of:
- Queries → read-only server state
- Mutations → state-changing operations
- Hooks manage server state and orchestration.
- Components are presentation-only.
- React Query → server state (single source of truth).
- Zustand → UI / session / ephemeral cross-feature state only.
- Wouter → routing.
- Mantine → UI, theming, notifications.
- Centralized fetch client for all HTTP communication.
- Backend errors returned as ProblemDetails are normalized and surfaced via notifications according to strict rules.
- All feature calls, queries, mutations, workflows, and user-visible errors MUST be traced to Azure Application Insights.
2. Project Structure
src/
├── api/
│ ├── client.ts # fetch wrapper, error normalization, tracing
│ └── telemetry.ts # Application Insights abstraction (only SDK usage)
│
├── assets/ # images, icons, fonts
│
├── components/ # reusable UI components
│
├── features/ # feature modules
│ ├── <feature>/
│ │ ├── service.ts # semantic API (business intent)
│ │ ├── hooks/
│ │ │ ├── useQueries.ts
│ │ │ └── useMutations.ts
│ │ ├── store.ts # feature-scoped Zustand (UI only)
│ │ ├── components/ # feature UI
│ │ └── types.ts
│
├── workflows/ # cross-feature orchestration
│ ├── <workflow>/
│ │ ├── use<Workflow>.ts
│ │ ├── state.ts # optional local workflow state
│ │ └── types.ts
│
├── hooks/
│ ├── useApiError.ts # notification + telemetry-driven error handling
│ └── useTrace.ts # standardized tracing helper
│
├── layouts/ # MainLayout, AuthLayout
│
├── routes/ # Wouter routes, PrivateRoute
│
├── store/ # global Zustand (if needed)
│
├── styles/ # Mantine theme overrides
│
├── utils/ # helpers
│
├── App.tsx
├── main.tsx
└── index.css
3. API Client (api/client.ts)
Responsibilities (Non-Negotiable)
- Base URL and headers
- Auth token injection
- Correlation ID propagation
- Request execution
- Normalize all failures into a single error model
- Automatic dependency telemetry
- Never leak raw
fetcherrors upstream
Unified Error Model
All failures are converted into:
ApiError {
type: 'network' | 'auth' | 'validation' | 'server'
status?: number
title: string
detail?: string
errors?: Record<string, string[]>
}
ProblemDetails, network failures, CORS issues, and proxy errors must all map here and be logged to Application Insights.
4. Telemetry & Tracing (Mandatory)
Tooling
- Azure Application Insights
- Direct SDK usage is allowed only in
api/telemetry.ts
What Must Be Traced
| Event | Required Metadata |
|---|---|
| Query start / failure | feature, queryKey |
| Mutation start / success / failure | feature, operationName |
| Workflow start / success / failure | workflowName |
| Workflow step failure | workflowName, step |
| HTTP dependency | method, url, status |
| User-visible notification | severity, source |
| Auth / network fatal errors | always |
No silent paths.
Telemetry Ownership
-
api/client.ts- HTTP dependencies
- Correlation IDs
-
Feature hooks
- Semantic intent (
loadProfile,updatePassword)
- Semantic intent (
-
Workflows
- Business processes
-
useApiError- User-visible failures only
5. Feature Service Layer (features/<feature>/service.ts)
Purpose
Semantic boundary, not a transport wrapper.
Rules
- Express business intent, not URLs.
- Normalize backend responses into frontend invariants.
- Hide backend naming, structure, and quirks.
- No React Query usage.
- No side effects.
- Every exported function defines a stable operation name for tracing.
Ownership
- One feature owns its services.
- Other features may consume, never redefine.
6. Queries & Mutations (React Query)
Queries
- Read-only server state.
- Cached globally.
- Namespaced query keys:
['<feature>', '<resource>', ...]
- Feature that defines the query owns invalidation.
- Query lifecycle events are traced.
Mutations
- State-changing only.
- Always user-initiated.
-
Must:
- Emit telemetry (
start,success,failure) - Trigger invalidation
- Trigger notifications via
useApiError
- Emit telemetry (
Mutation hooks own side effects and observability.
7. Error Notification Policy (Critical)
Not all errors are equal.
Notification Rules
| Context | Notification |
|---|---|
| Mutation error | Always |
| Query – initial blocking load | Yes |
| Query – background refetch | No |
| Query – polling | No |
| Network / auth fatal errors | Yes |
useApiError Responsibilities
- Decide if error is visible
- Decide severity (
info | warning | error) - Format ProblemDetails and validation errors
- Deduplicate notifications
- Emit telemetry for all user-visible errors
Hooks must pass explicit context:
{ silent, isBackground, severity, source }
Components never handle errors.
8. Zustand State Rules (Strict)
Zustand may contain only:
- UI state (dialogs, steps, filters)
- Ephemeral cross-feature state
Zustand must never contain:
- Server entities
- Lists
- Cached data
- Error state
- Retry counters
- Telemetry state
React Query is the only source of server state.
9. Components
- Presentation-only.
- Receive data via hooks or props.
- No API calls.
- No mutations directly.
- No orchestration.
- No error handling.
- No telemetry.
- Display loading / empty / success states only.
10. Routing (Wouter)
- One route → one page component.
-
Route components:
- Extract route params
- Pass params to page-level hooks
- Routing layer contains zero business logic.
- Authentication enforced via
PrivateRoute.
11. Workflows
Definition
Workflows are explicit cross-feature orchestration units representing business processes.
Characteristics
- Orchestrate multiple features.
- Span multiple mutations and queries.
-
Own:
- Ordering
- Retry logic
- Compensation / rollback
- Cross-feature error semantics
- User-visible notifications
- Business-level telemetry
- Expose one semantic operation.
- No UI.
- No direct API access.
- Located at top level:
src/workflows/<workflow>/
Rules (Hard)
- Workflows may call feature hooks only
- Workflows must not call feature services directly
- Features must never depend on workflows
- Components may call workflows
- No orchestration in components
- No orchestration in feature services
- No React Query usage inside workflows
- Workflows emit start / success / failure telemetry
- Workflows are isolated and testable
12. Layouts
- Apply Mantine providers.
- Configure theme and notifications.
- Contain no feature logic.
13. SSR / Preloading Position
- SPA-first architecture.
- SSR not assumed.
- Query keys are deterministic.
- Side effects isolated in mutations.
- SSR or preloading can be added later without structural rewrite.
14. Mental Model
Component (UI)
├─> Feature Hook (Query / Mutation)
│ ├─> service.ts (semantic intent)
│ ├─> React Query (server state)
│ ├─> telemetry (feature-level)
│ └─> api/client
│ ├─> HTTP
│ ├─> dependency telemetry
│ └─> ApiError
│
└─> Workflow Hook (optional)
├─> Feature Hook A
├─> Feature Hook B
├─> telemetry (workflow-level)
└─> useApiError → Notification
15. Hard Rules (Enforced)
- Feature services express business intent, not transport
- Hooks are the only layer allowed to call services
- React Query owns all server state
- Zustand never mirrors server data
- Query keys are feature-namespaced
- Only owning feature invalidates its queries
- Mutations always notify; queries notify selectively
- Components never handle errors or orchestration
- Workflows are explicit and isolated
- No feature call without telemetry
- No user-visible error without an Application Insights trace
- No direct Application Insights SDK usage outside telemetry layer
- Workflows are the unit of business observability
- If it cannot be traced, it must not exist
- No exceptions