|
2 | 2 |
|
3 | 3 | ## High-Level Architecture |
4 | 4 |
|
5 | | -``` |
6 | | - +-----------------------+ |
7 | | - | Browser Client | |
8 | | - | (Next.js 16 + React) | |
9 | | - +----------+------------+ |
10 | | - | |
11 | | - +--------------+--------------+ |
12 | | - | | | |
13 | | - +----v----+ +-----v-----+ +-----v-----+ |
14 | | - | Vercel | | Cloudflare | | Cloudflare | |
15 | | - | Next.js | | Workers | | Workers | |
16 | | - | App | | (CAS, | | (Rate | |
17 | | - | + API | | Export) | | Limiter) | |
18 | | - +----+-----+ +-----+------+ +-----+------+ |
19 | | - | | | |
20 | | - +----v-----+ +----v----+ +----v----+ |
21 | | - | Neon | | R2 | | KV | |
22 | | - | PostgreSQL| | Bucket | | Store | |
23 | | - +----+------+ +---------+ +---------+ |
24 | | - | |
25 | | - +----v------+ |
26 | | - | Upstash | |
27 | | - | Redis | |
28 | | - +-----------+ |
| 5 | +```mermaid |
| 6 | +graph TB |
| 7 | + subgraph Client["Browser Client"] |
| 8 | + A["Next.js 16 + React 19.3"] |
| 9 | + end |
| 10 | + subgraph Vercel["Vercel Edge Network"] |
| 11 | + B["App Router + SSR"] |
| 12 | + C["GraphQL API (Apollo 5.4)"] |
| 13 | + end |
| 14 | + subgraph CF["Cloudflare Workers"] |
| 15 | + D["CAS Service"] |
| 16 | + E["Export Service"] |
| 17 | + F["Rate Limiter"] |
| 18 | + end |
| 19 | + subgraph Storage |
| 20 | + G[("Neon PostgreSQL")] |
| 21 | + H[("Upstash Redis")] |
| 22 | + I[("R2 Bucket")] |
| 23 | + J[("KV Store")] |
| 24 | + end |
| 25 | + A --> B |
| 26 | + A --> D |
| 27 | + A --> E |
| 28 | + B --> C |
| 29 | + C --> G |
| 30 | + C --> H |
| 31 | + D --> F |
| 32 | + E --> I |
| 33 | + F --> J |
29 | 34 | ``` |
30 | 35 |
|
31 | 36 | ## Package Dependency Graph |
@@ -149,50 +154,40 @@ Three edge microservices deployed to Cloudflare's global network: |
149 | 154 |
|
150 | 155 | ### Client-Side Calculation |
151 | 156 |
|
152 | | -``` |
153 | | -User Input -> Calculator Component -> Math Engine (client-side) |
154 | | - | |
155 | | - v |
156 | | - Display Result |
157 | | - | |
158 | | - v |
159 | | - Save to History (Zustand store) |
160 | | - | |
161 | | - v (if authenticated) |
162 | | - GraphQL Mutation -> Prisma -> Neon PostgreSQL |
| 157 | +```mermaid |
| 158 | +flowchart LR |
| 159 | + A[User Input] --> B[Calculator Component] |
| 160 | + B --> C[Math Engine] |
| 161 | + C --> D[Display Result] |
| 162 | + D --> E[Zustand History] |
| 163 | + E -->|if authenticated| F[GraphQL Mutation] |
| 164 | + F --> G[Prisma] |
| 165 | + G --> H[(Neon PostgreSQL)] |
163 | 166 | ``` |
164 | 167 |
|
165 | 168 | ### Server-Side (GraphQL) |
166 | 169 |
|
167 | | -``` |
168 | | -Apollo Client -> Next.js API Route (/api/graphql) |
169 | | - | |
170 | | - v |
171 | | - Apollo Server |
172 | | - | |
173 | | - v |
174 | | - Auth Check (NextAuth session) |
175 | | - | |
176 | | - v |
177 | | - DataLoaders (batch + cache) |
178 | | - | |
179 | | - v |
180 | | - Prisma Client -> Neon PostgreSQL |
| 170 | +```mermaid |
| 171 | +flowchart TD |
| 172 | + A[Apollo Client] --> B["API Route (/api/graphql)"] |
| 173 | + B --> C[Apollo Server] |
| 174 | + C --> D[Auth Check] |
| 175 | + D --> E[DataLoaders] |
| 176 | + E --> F[Prisma Client] |
| 177 | + F --> G[(Neon PostgreSQL)] |
181 | 178 | ``` |
182 | 179 |
|
183 | 180 | ### Edge Worker Flow |
184 | 181 |
|
185 | | -``` |
186 | | -Client -> Cloudflare Worker (global edge) |
187 | | - | |
188 | | - v |
189 | | - Rate Limit Check (KV) |
190 | | - | |
191 | | - v |
192 | | - Process Request (CAS / Export) |
193 | | - | |
194 | | - v (if export) |
195 | | - Store to R2 -> Return URL |
| 182 | +```mermaid |
| 183 | +flowchart TD |
| 184 | + A[Client] --> B[Cloudflare Worker] |
| 185 | + B --> C{Rate Limit Check} |
| 186 | + C -->|Allowed| D[Process Request] |
| 187 | + D -->|CAS| E[Return Result] |
| 188 | + D -->|Export| F[Store to R2] |
| 189 | + F --> G[Return URL] |
| 190 | + C -->|Denied| H[429 Too Many Requests] |
196 | 191 | ``` |
197 | 192 |
|
198 | 193 | ## Authentication Flow |
@@ -275,18 +270,32 @@ export const useStore = create<State>()( |
275 | 270 |
|
276 | 271 | | Pattern | Purpose | |
277 | 272 | |---------|---------| |
278 | | -| `app/**/page.tsx` | Route pages | |
279 | | -| `app/**/layout.tsx` | Layouts | |
280 | | -| `app/**/loading.tsx` | Loading UI (Suspense) | |
281 | | -| `app/**/error.tsx` | Error boundary | |
282 | | -| `app/**/not-found.tsx` | 404 page | |
| 273 | +| `app/[locale]/**/page.tsx` | Route pages (i18n) | |
| 274 | +| `app/[locale]/**/layout.tsx` | Layouts | |
| 275 | +| `app/[locale]/**/loading.tsx` | Loading UI (Suspense) | |
| 276 | +| `app/[locale]/**/error.tsx` | Error boundary | |
| 277 | +| `app/[locale]/**/not-found.tsx` | 404 page | |
283 | 278 | | `components/ui/*.tsx` | shadcn/ui components | |
284 | 279 | | `components/calculator/*.tsx` | Calculator feature components | |
285 | 280 | | `components/plots/*.tsx` | Plot visualization components | |
286 | 281 | | `lib/stores/*.ts` | Zustand stores | |
287 | 282 | | `lib/hooks/*.ts` | Custom React hooks | |
288 | 283 | | `lib/workers/*.ts` | Web Worker scripts | |
289 | 284 |
|
| 285 | +## Internationalization (i18n) |
| 286 | + |
| 287 | +- **Library:** `next-intl` with App Router integration |
| 288 | +- **Locales:** en, ru, es, uk, de, fr, ja, zh (8 languages) |
| 289 | +- **Translation files:** `apps/web/messages/{locale}.json` (1200+ keys per locale) |
| 290 | +- **Routing:** `[locale]` dynamic segment (e.g., `/en/plot`, `/ru/matrix`) |
| 291 | +- **Middleware:** Locale detection + redirect in `apps/web/middleware.ts` |
| 292 | + |
| 293 | +### Adding a Language |
| 294 | + |
| 295 | +1. Create `apps/web/messages/{code}.json` (copy from `en.json`) |
| 296 | +2. Add locale to `apps/web/i18n/config.ts` |
| 297 | +3. Translate all keys |
| 298 | + |
290 | 299 | ## Performance Targets |
291 | 300 |
|
292 | 301 | | Metric | Target | |
|
0 commit comments