-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
Browser Client (Next.js 16 + React 19.3)
|
+-- Vercel Edge Network
| +-- App Router + SSR
| +-- GraphQL API (Apollo Server 5.4)
| +-- Neon PostgreSQL (Prisma 7)
| +-- Upstash Redis (cache + PubSub)
|
+-- Cloudflare Workers
+-- CAS Service (symbolic math)
+-- Export Service (LaTeX to PDF/PNG/SVG) --> R2 Bucket
+-- Rate Limiter --> KV Store
@nextcalc/web
+-- @nextcalc/math-engine
+-- @nextcalc/plot-engine
| +-- @nextcalc/math-engine
+-- @nextcalc/database
+-- @nextcalc/api
| +-- @nextcalc/database
+-- @nextcalc/types
@nextcalc/cas-service (standalone, uses mathjs)
@nextcalc/export-service (standalone, uses mathjax)
@nextcalc/rate-limiter (standalone, uses Cloudflare KV)
Build order (enforced by Turborepo):
-
@nextcalc/types(no deps) -
@nextcalc/math-engine(depends on mathjs) -
@nextcalc/database(depends on Prisma + Neon adapter) -
@nextcalc/plot-engine(depends on math-engine, Three.js, D3) -
@nextcalc/api(depends on database) -
@nextcalc/web(depends on all above)
User Input --> Calculator Component --> Math Engine (client-side)
--> Display Result --> Save to History (Zustand)
--> (if authenticated) GraphQL Mutation --> Prisma --> Neon PostgreSQL
Apollo Client --> /api/graphql route --> Apollo Server
--> Auth Check (NextAuth session)
--> DataLoaders (batch + cache)
--> Prisma Client --> Neon PostgreSQL
Client --> Cloudflare Worker --> Rate Limit Check (KV)
--> Process Request (CAS / Export)
--> (if export) Store to R2 --> Return URL
| Decision | Rationale |
|---|---|
| Monorepo (pnpm + Turborepo) | Shared types, coordinated builds |
| Next.js App Router | Server Components, streaming, nested layouts |
| OKLCH colors | Perceptually uniform, P3 gamut |
| Prisma in shared package | Single schema, reusable across web and API |
| Apollo over tRPC | Schema-first, subscriptions, DataLoader integration |
| Edge Workers for CAS | Sub-50ms global latency |
| WebGL/WebGPU rendering | GPU acceleration for real-time visualization |
| Zustand over Redux | Simpler API, TypeScript-first |
| Biome over ESLint+Prettier | Faster, single tool |
All GraphQL resolvers use DataLoader to prevent N+1 query problems. DataLoader instances are created per-request in the Apollo Server context and batch database calls within a single event loop tick.
Location: apps/api/src/lib/dataloaders.ts
| DataLoader | Batches | Used by |
|---|---|---|
userById |
User lookups by ID |
Worksheet, ForumPost, Comment resolvers |
folderById |
Folder lookups by ID |
Worksheet resolver |
worksheetSharesByWorksheetId |
Share records per worksheet | Worksheet resolver |
childFoldersByParentId |
Child folders per parent | Folder resolver |
upvoteCountByTargetId |
Upvote counts per target | ForumPost, Comment resolvers |
commentCountByPostId |
Comment counts for post listings | ForumPost resolver |
forumPostById |
Forum post lookups by ID | Forum resolvers |
commentById |
Comment lookups by ID | Comment resolvers |
repliesByParentCommentId |
Nested comment replies | Comment resolver |
worksheetsByFolderId |
Worksheets per folder | Folder resolver |
hasUpvoted |
Current user's upvote status (composite key) | ForumPost, Comment resolvers |
How it works: When resolving a list of forum posts, instead of issuing one SELECT * FROM users WHERE id = ? per post, DataLoader collects all user IDs and issues a single SELECT * FROM users WHERE id IN (?, ?, ...) query.
All mutations that modify user-owned resources validate ownership before proceeding. For example, updateWorksheet and deleteWorksheet verify that the authenticated user's userId matches the worksheet's userId. Admin users can bypass this check for moderation.
Affected resolvers: worksheet, folder, forum post, comment, profile.
WebSocket subscriptions authenticate via JWT tokens passed in the connection connectionParams. The token is verified using jose.jwtVerify() with the NEXTAUTH_SECRET key, ensuring subscriptions cannot be opened without a valid session.
The Cloudflare rate-limiter Worker uses timing-safe comparison (crypto.subtle.timingSafeEqual) for API key validation, preventing timing-based side-channel attacks on the shared secret.
The database package uses Prisma 7.5.0-dev.33's Neon serverless adapter. The adapter constructor takes a config object, not a Pool instance:
// Correct
const adapter = new PrismaNeon({ connectionString: process.env.DATABASE_URL });
// Wrong -- causes "No database host or connection string" errors
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const adapter = new PrismaNeon(pool);Prisma 7 creates its own connection pool internally via the adapter's connect() method.
| Feature | Since | Description |
|---|---|---|
compilerBuild = "fast" |
7.3 | Speed-optimized query compiler (larger footprint, ideal for Node.js) |
partialIndexes preview |
7.4 | Filtered indexes with WHERE conditions for smaller, faster lookups |
| Query plan caching | 7.4 | LRU cache for compiled query plans (~100% hit rate for repeated shapes) |
| BigInt precision in JSON | 7.3 | BigInt values cast to text inside JSON aggregation with relationJoins
|
-
OKLCH color tokens in
apps/web/app/globals.css -
Tailwind 4 CSS-first config via
@themedirective -
Semantic tokens:
bg-background,text-foreground,border-border -
Glass morphism:
oklch()+backdrop-filter+ SVG noise texture -
Modern CSS: nesting,
@property,color-mix(),@starting-style
Custom geometric crystal favicon using the OKLCH glass-morphism design language. Faceted hexagonal gem with blue/purple/teal gradient glass panels on a dark navy background.
| File | Size | Purpose |
|---|---|---|
icon.svg |
512x512 | Primary SVG favicon (all modern browsers) |
favicon.ico |
16x16 + 32x32 | Legacy ICO for older browsers |
apple-touch-icon.png |
180x180 | Apple devices home screen |
icon-192.png |
192x192 | PWA standard icon |
icon-512.png |
512x512 | PWA splash screen |
icon-192-maskable.png |
192x192 | Android adaptive icon (maskable) |
icon-512-maskable.png |
512x512 | Android adaptive icon (maskable) |
Theme colors: #3B47FF (primary blue), #0F1629 (dark background) — derived from oklch(0.55 0.27 264).
-
XP Formula: RS3-style
sum(floor(i + 300 * 2^(i/7)) / 4)— exponential curve, 100 levels - 10 Tiers: Novice (1-10), Apprentice (11-20), Journeyman (21-30), Adept (31-40), Expert (41-50), Master (51-60), Grandmaster (61-70), Legend (71-80), Mythic (81-90), Transcendent (91-100)
- Admin Tier: Architect (L101) — admin-only, 3 special icon variants
-
Level Icons: Programmatic crystal SVGs (
LevelIconcomponent) + 103 pre-generated SVG files - OKLCH Colors: Per-level hue progression through full spectrum, per-tier CSS classes
-
Files:
apps/web/components/profile/level-utils.ts,level-icon.tsx,level-icon-static.tsx
-
Library:
next-intlwith App Router - Locales: en, ru, es, uk, de, fr, ja, zh (8 languages)
-
Translation files:
apps/web/messages/{locale}.json(1200+ keys per locale) -
Routing:
[locale]dynamic segment (e.g.,/en/plot,/ru/matrix)
NextCalc Pro v1.2.1 | Home | Getting Started | Architecture | API Reference | Deployment | GitHub | Release Notes | Live Demo
v1.2.1
🏠 NextCalc Pro
📦 Packages
🔧 Backend
🚀 Operations