ARC // OS — Architecture Documentation
Last Updated: 2026-01-18
Overview
ARC // OS is a full-stack TypeScript application built with a service-oriented architecture. The system follows strict design principles to ensure maintainability, testability, and scalability.
System Architecture
High-Level Architecture
┌─────────────────┐
│ React Frontend │ (Vite + TypeScript)
│ (Port 3000) │
└────────┬────────┘
│ HTTP/REST
│
┌────────▼────────┐
│ Fastify API │ (TypeScript)
│ (Port 3001) │
└────────┬────────┘
│
┌────────▼────────┐
│ PostgreSQL │ (Database)
│ (Port 5432) │
└─────────────────┘
Technology Stack
Backend:
- Fastify 4.x - High-performance HTTP server
- TypeScript - Strict mode, no
anytypes - Prisma ORM - Type-safe database access
- PostgreSQL - Relational database
- Zod - Runtime validation
- JWT - Authentication (httpOnly cookies)
- Pino - Structured logging
Frontend:
- React 18 - UI framework
- TypeScript - Strict mode
- Vite - Build tool
- React Router - Navigation
- CSS Modules - Scoped styling
- Lucide React - Icon library
Testing:
- Vitest - Unit, integration, component tests
- Playwright - E2E tests
- Test Database - Separate from development
Backend Architecture
Service Layer Pattern
The backend follows a service-oriented architecture where:
- Routes are thin - Routes handle HTTP concerns only (request/response, validation, authentication)
- Services contain business logic - All business rules, data manipulation, and domain logic live in services
- Services are pure and testable - Services are classes with methods that can be tested in isolation
Example Structure
/routes
└── task.routes.ts # HTTP handlers (thin)
/services
└── task.service.ts # Business logic (thick)
/utils
└── auth.ts # Utilities
Route Handler Pattern
// Route: Thin HTTP handler
fastify.post('/api/tasks', async (request, reply) => {
const user = await authenticateRequest(request);
if (!user) {
sendError(reply, 'UNAUTHORIZED', 'Not authenticated', 401);
return;
}
try {
const body = createTaskSchema.parse(request.body);
const service = new TaskService();
const task = await service.create(user.id, body);
sendSuccess(reply, task, 201);
} catch (error) {
// Error handling
}
});
Service Pattern
// Service: Business logic
export class TaskService {
async create(userId: string, input: CreateTaskInput): Promise<unknown> {
// Validation
if (!input.title) {
throw new Error('Title is required');
}
// Business rules
if (input.timebox && input.timebox > 480) {
throw new Error('Timebox cannot exceed 8 hours');
}
// Data access
return prisma.task.create({
data: {
userId,
title: input.title,
timebox: input.timebox,
// ...
},
});
}
}
Database Architecture
Prisma ORM
- Schema-first - Database schema defined in
schema.prisma - Migrations - Version-controlled database changes
- Type-safe - Generated TypeScript types from schema
- Relations - Heavily relational design (no arrays/JSON columns)
Relational Design Principle
⚠️ CRITICAL RULE: Never use arrays or JSON columns. Use linked tables instead.
Bad:
model Task {
tags String[] // ❌ NO ARRAYS
metadata Json // ❌ NO JSON
}
Good:
model Task {
tags TaskTag[]
}
model TaskTag {
taskId String
tagId String
task Task @relation(...)
tag Tag @relation(...)
}
Key Models
- User - Core user entity
- Week - Monday-Sunday container
- Day - 24-hour period (atomic unit)
- Task - Work items with timeboxes
- TrainingSession - Gym workouts
- Exercise - Reusable exercise definitions
- PerimeterTask - Reusable daily focus tasks
- ChecklistItem - Daily habits
- Project - Work/study projects
- ProjectTask - Kanban board tasks
- Person - Social contacts
- SocialHappening - Social events
- Transaction - Financial transactions
- Item - Personal items database
- Outfit - Outfit definitions
- File - File uploads with variants
Authentication & Authorization
JWT Authentication
- Token Storage - httpOnly cookies (secure, not accessible via JavaScript)
- Token Generation - JWT signed with
JWT_SECRET - Token Validation - Middleware validates token on protected routes
- Session Tracking - Sessions logged for security auditing
User Ownership
All services verify user ownership before operations:
const task = await prisma.task.findFirst({
where: {
id: taskId,
userId, // Always verify ownership
},
});
if (!task) {
throw new Error('Task not found');
}
File Storage Architecture
Adapter Pattern
File storage uses the adapter pattern for flexibility:
IFileStorageAdapter (interface)
├── DiskStorageAdapter (development/local)
└── S3StorageAdapter (production - future)
Benefits:
- Easy to swap storage backends
- Consistent interface
- Testable with mocks
Image Processing
- Multiple Variants - Automatic resizing (thumbnail, small, medium, large, original)
- Eager/Lazy Processing - Configurable generation mode
- Sharp Library - High-performance image processing
Error Handling
Consistent Error Format
{
ok: false,
error: {
code: "ERROR_CODE",
message: "Human-readable message",
details: { ... }
}
}
Error Codes
UNAUTHORIZED- Authentication requiredNOT_FOUND- Resource not foundVALIDATION_ERROR- Invalid inputINTERNAL_ERROR- Server error
Error Handling Pattern
try {
// Business logic
} catch (error) {
if (error instanceof z.ZodError) {
sendError(reply, 'VALIDATION_ERROR', 'Invalid input', 400, { errors: error.errors });
return;
}
if (error instanceof Error && error.message.includes('not found')) {
sendError(reply, 'NOT_FOUND', error.message, 404);
return;
}
sendError(reply, 'INTERNAL_ERROR', 'Operation failed', 500);
}
Validation
Zod Schemas
All API inputs validated with Zod:
const createTaskSchema = z.object({
title: z.string().min(1).max(500),
timebox: z.number().int().positive().max(480),
categoryId: z.string().uuid().optional(),
});
Benefits:
- Runtime validation
- Type inference
- Detailed error messages
- Prevents invalid data
Frontend Architecture
Component Structure
/src
/components # Reusable UI components
/pages # Page components
/styles # CSS modules and design tokens
/utils # Utilities (API client, auth)
/types # TypeScript types
Design System
CSS Modules
All styles use CSS Modules for scoped styling:
import styles from './Button.module.css';
<button className={styles.button}>Click</button>
Design Tokens
Centralized design tokens in variables.css:
:root {
--bg: #ffffff;
--fg: #000000;
--muted: #666666;
--border: #e0e0e0;
--space-1: 0.25rem;
--space-2: 0.5rem;
/* ... */
}
Monochrome Design
- Black, white, grayscale only - No colors, no gradients
- Technical aesthetic - Clean, minimal, functional
- Icon-first - Lucide React icons for UI elements
State Management
React Hooks
- Local State -
useStatefor component state - Context -
useAuth()for authentication - No Global State Library - Keep state local or in context
API Client Pattern
All API calls go through centralized api utility:
import { api } from '@/utils/api';
const response = await api.post<Task>('/api/tasks', {
title: 'Task title',
timebox: 60,
});
if (response.ok) {
// Handle success
} else {
// Handle error
}
Benefits:
- Consistent error handling
- Automatic cookie inclusion
- Type-safe responses
- Centralized configuration
Routing
React Router
- Protected Routes - Authentication required
- Nested Routes - Organized by feature
- Deep Linking - Direct navigation to specific pages
Code Splitting
- Lazy Loading - Pages loaded on demand
- React.lazy() - Dynamic imports
- Suspense - Loading fallbacks
Data Flow
Request Flow
1. User Action (Frontend)
↓
2. API Call (api utility)
↓
3. HTTP Request (Fastify)
↓
4. Authentication (auth middleware)
↓
5. Route Handler (validation)
↓
6. Service Layer (business logic)
↓
7. Database (Prisma)
↓
8. Response (JSON)
↓
9. Frontend Update (React state)
Data Relationships
Heavily Relational Design:
- User → Week → Day → ChecklistItem, Task, TrainingSession, etc.
- Task → TaskCategory (many-to-many)
- TrainingSession → Exercise → TrainingEntry
- SocialHappening → Person (many-to-many via guests)
- Transaction → Account, SocialHappening (optional)
- Item → Outfit → OutfitWear → Day
Benefits:
- Cross-domain analytics
- Pattern detection
- Predictive power
- Holistic management
Testing Architecture
Test Structure
/server/src
/routes/__tests__ # Integration tests (API endpoints)
/services/__tests__ # Unit tests (business logic)
/utils/__tests__ # Unit tests (utilities)
/web/src
/components/__tests__ # Component tests
/pages/__tests__ # Page tests
/utils/__tests__ # Utility tests
/e2e # E2E tests (Playwright)
Test Categories
- Unit Tests - Services, utilities, business logic
- Integration Tests - API endpoints with real database
- Component Tests - React components
- Page Tests - Full page components
- E2E Tests - Critical user journeys
Test Database
- Separate Database - Isolated from development
- Automatic Cleanup - Reset between tests
- Migrations Applied - Schema synced before tests
Security Architecture
Authentication
- JWT Tokens - Signed with secret
- httpOnly Cookies - Not accessible via JavaScript
- Secure in Production - HTTPS only
- Session Tracking - Logged for auditing
Authorization
- User Ownership - All operations verify ownership
- No Cross-User Access - Users can only access their own data
- Service Layer Enforcement - Authorization in services, not routes
Data Validation
- Zod Schemas - All inputs validated
- Type Safety - TypeScript strict mode
- SQL Injection Prevention - Prisma parameterized queries
- XSS Prevention - React automatic escaping
File Upload Security
- File Type Validation - Only allowed MIME types
- Size Limits - Configurable max file sizes
- Path Sanitization - Prevent directory traversal
- User Isolation - Users can only access their own files
Deployment Architecture
Development
Local Development:
- Frontend: Vite dev server (port 3000)
- Backend: Fastify dev server (port 3001)
- Database: Local PostgreSQL (port 5432)
Production (Docker)
Docker Compose:
- Frontend: Nginx (serves static files)
- Backend: Node.js (Fastify)
- Database: PostgreSQL
Environment Variables
Backend:
DATABASE_URL- PostgreSQL connectionJWT_SECRET- Token signing secretPORT- Server portNODE_ENV- Environment (development/production)CORS_ORIGIN- Frontend originFILE_STORAGE_ADAPTER- Storage adapter (disk/s3)
Frontend:
VITE_API_URL- Backend API URL
Design Principles
1. Strong Typing
- TypeScript strict mode - No
any, explicit types everywhere - Zod validation - Runtime type checking
- Prisma types - Database types generated
2. Business Logic Outside Frameworks
- Services contain logic - Not in routes or Prisma
- Pure functions - Testable, predictable
- No framework coupling - Logic can be reused
3. Mandatory Testing
- 90% minimum coverage - Enforced
- 100% for critical paths - Auth, validation, business rules
- Tests with code - Not after
4. Heavily Relational
- Link everything - Maximum relational power
- No arrays/JSON - Use linked tables
- Cross-domain analytics - Enabled by relationships
5. Monochrome UI
- Black/white/grayscale - Technical aesthetic
- Icon-first - Lucide React icons
- Consistent spacing - Design tokens
6. Local-First (Future)
- Works offline - Sync when online
- Data integrity - Local-first ensures consistency
Key Design Patterns
1. Service Layer Pattern
Business logic in services, routes are thin wrappers.
2. Adapter Pattern
File storage, email service use adapters for flexibility.
3. Factory Pattern
Service factories for dependency injection (e.g., getFileStorageAdapter()).
4. Repository Pattern (via Prisma)
Prisma provides repository-like interface for data access.
5. Dependency Injection
Services instantiated in route handlers, not globally.
Performance Considerations
Backend
- Fastify - High-performance HTTP server
- Connection Pooling - Prisma connection pool
- Parallel Queries -
Promise.all()for independent queries - Indexes - Database indexes on foreign keys and search fields
Frontend
- Code Splitting - Lazy-loaded pages
- CSS Modules - Scoped styles (no global conflicts)
- React.memo - Component memoization where needed
- Virtual Scrolling - For long lists (future)
Database
- Indexes - On foreign keys, search fields, date ranges
- Cascade Deletes - Efficient cleanup
- Query Optimization - Prisma query optimization
Future Enhancements
Scalability
- Caching - Redis for frequently accessed data
- Rate Limiting - API rate limiting
- CDN - For static assets and images
- Database Replication - Read replicas
Features
- Real-time Updates - WebSocket support
- Offline Support - Service workers, local storage
- Mobile Apps - React Native
- API Versioning - Versioned endpoints
For implementation details of specific features, see docs/features/.