- Migrate LiveView, GearView, PurchasesView, SocialView, AnalyticsView into features - Create features: admin, developer, seller; add QueuePage, WishlistPage - Migrate pages/marketplace to features/marketplace - Remove components/views/ and pages/ legacy directories - Update lazyExports, docs (ARCHITECTURE) - Mark audit 2.1, 2.6 as done Refs: AUDIT_TECHNIQUE_INTEGRAL_2026_02_15.md items 2.1, 2.6
4.5 KiB
Veza Frontend Architecture Guide
Status: Living Document
Version: 2.0 (Post-Audit 2026)
This document outlines the architectural principles, patterns, and rules that govern the Veza frontend. It supersedes previous ad-hoc audit reports.
1. Core Philosophy: "Visual First"
"If it can't be rendered in Storybook, it is architecturally broken."
We follow a Storybook-Driven Development (SDD) approach.
- Isolation: Every component must be renderable in isolation. Dependencies (Providers, Router, Store) must be explicit.
- Verification: Storybook is our primary verification tool for UI logic and layout.
2. State Management Strategy
We distinguish three types of state. Mixing them is strictly forbidden.
2.1. Server State (Data) -> React Query
Data that belongs to the backend (Users, Tracks, Playlists).
- Tool:
@tanstack/react-query - Rule: Never copy server data into a global store (Zustand) unless strictly necessary for client-side manipulation (e.g., a complex audio editor buffer).
- Caching: Managed automatically by query keys.
2.2. Client Global State (App) -> Zustand
Data that is truly global to the client session (Auth Token, Shopping Cart, Audio Player Status).
- Tool:
zustand - Rule: Use atomic selectors to prevent render-thrashing.
- Structure:
authStore: User session.cartStore: E-commerce state (Items, Total).playerStore: Audio playback state.
Legacy Note: React Context is BANNED for high-frequency state updates. It is reserved for dependency injection (Theme, i18n).
2.3. UI Local State -> useState / useReducer
Ephemeral state specific to a component (Modal Open/Close, Form Inputs).
- Rule: If it doesn't need to persist when navigating away, it stays local.
3. Component Engineering
We adhere to the Smart vs Dumb (Container vs Presentational) separation to ensure testability.
3.1. Dumb Components (UI)
- Role: Render props into HTML. Emit events via callbacks.
- Dependencies: ZERO. No explicit side-effects, no API calls, no Context consumers (except Theme).
- Testing: Storybook.
// ✅ Correct Dumb Component
export const ProductCard = ({ title, price, onAddToCart }: Props) => (
<div onClick={onAddToCart}>{title} - {price}</div>
);
3.2. Smart Components (Containers)
- Role: Wire data to UI.
- Dependencies: Allowed (
useQuery,useCartStore,useParams). - Testing: Integration Tests (MSW + Storybook play functions).
// ✅ Correct Smart Component
export const ProductCardContainer = ({ id }) => {
const { data } = useProduct(id);
const addToCart = useCartStore(s => s.addItem);
return <ProductCard title={data.title} onAddToCart={() => addToCart(data)} />;
};
4. Design System & Styling
We use Tailwind CSS with a rigorous Design System (Kodo).
- Tokens Only: Do not use arbitrary values (e.g.,
w-[350px]). Use design tokens (w-sidebar). - Dark Mode: All UI/Layout components must implement
dark:variants. - Icons:
lucide-react. Icons must inherit color viacurrentColor.
5. Storybook Usage
Storybook is not optional. It is the definition of "Done".
5.1. Decorators
Use granular decorators from src/stories/decorators.tsx instead of global wrapping in preview.tsx.
withToast: Injects ToastProvider.withRouter: Injects MemoryRouter.withStoreState: Mocks Zustand state.
5.2. Interaction Testing
Critical user flows (e.g., Add to Cart) must have a .play function in their story to verify interaction without manual testing.
6. Testing Pyramid
- Unit (Vitest): Utilities, Store Reducers, Hooks.
- Integration (Storybook + Vitest): Component wiring, Props interface.
- E2E (Playwright): Critical Paths (Login, Checkout, Signup).
7. Feature Structure (Audit 2.1)
Pattern unique : features/*/pages/
- Toutes les pages principales vivent dans
src/features/<domain>/pages/. - Chaque feature peut avoir :
pages/,components/,hooks/,services/,types/. - Les routes chargent via
lazyExports.ts:import('@/features/<domain>/pages/<Page>'). - Référence : FULL_LAYOUT_PAGE.md.
8. Anti-Patterns (Dos & Don'ts)
| ❌ Don't | ✅ Do |
|---|---|
useContext(CartContext) |
useCartStore(selector) |
w-[17px] |
w-4 or w-5 (stick to grid) |
| Props Drilling (> 3 levels) | Composition (Slots) or Context (if static) |
API calls in useEffect |
useQuery |
any type |
Generated types from OpenAPI |