ARC // OS
(Adaptive · Regulated · Consistent)
A personal operating system for daily planning, execution, and logging.
⚠️ READ THIS FIRST: Coding Standards
Before writing any code, you MUST read the Coding Standards & Conventions section. These rules are mandatory for all developers and LLMs working on this codebase.
Key Requirements:
- ✅ Strict TypeScript (no
any, explicit types everywhere) - ✅ All components must have tests
- ✅ Use existing design system (CSS Modules, design tokens, monochrome)
- ✅ Small, focused components
- ✅ No dead code, no TODOs in code
If requirements conflict with these standards, stop and ask for clarification.
🎯 Project Goal: A Life Operating System
ARC // OS is not a task manager, calendar, or fitness tracker. It is a complete operating system for human life—a single source of truth that manages, tracks, and regulates every aspect of daily existence.
Critical Principle: ARC // OS is the INPUT method for all systems. You don't log data elsewhere and import it—you input everything directly into ARC. This ensures data integrity, relational power, and a complete picture of your life.
The Philosophy
ARC stands for:
- Adaptive: The system learns and adjusts to your patterns, energy levels, and life circumstances
- Regulated: Built-in rules and constraints prevent overcommitment and ensure sustainable habits
- Consistent: Daily, weekly, and monthly rhythms create predictable structure
Core Design Principle: Everything is Highly Integrated, Relational, and Linked
Every piece of data in ARC // OS is designed to be heavily relational and interconnected. If we can link something, we link it. This enables:
- Cross-domain insights: See how training affects sleep, how sleep affects mood, how mood affects task completion
- Pattern detection: Identify correlations across seemingly unrelated domains
- Predictive power: Use relationships to predict outcomes
- Holistic management: Understand the full picture of your life, not isolated silos
This system is designed to manage you as a human, not just your tasks. It tracks:
- What you plan to do (perimeter scope, tasks, training)
- What you actually do (checklist completion, session logs)
- How you feel (mood, energy, sleep)
- What you consume (nutrition, groceries, supplements, substances)
- How you recover (sleep, mobility, cardio)
- What you learn (reading, journaling, meditation)
- Who you connect with (friends, family, social interactions)
And everything links together to create a complete picture of your life.
Why This Exists
Most productivity tools treat humans like machines—endless task lists, no context, no recovery, no regulation. ARC // OS recognizes that humans are:
- Biological systems that need sleep, nutrition, and recovery
- Emotional beings with variable energy and mood
- Social creatures with relationships and commitments
- Learning organisms that need growth and reflection
This system enforces sustainable patterns through rules, not just suggestions.
🧠 Core Domain Concepts
1. Perimeter Walk (Daily Scope Definition)
Every day starts with selecting your perimeter tasks—reusable tasks that represent what you will focus on today. Tasks are created once and can be selected on any day, then checked off as completed.
Rules: Tasks are created once and reused across days. Select tasks each morning to define your focus. Acts as a guardrail against scope creep.
2. ARC Day (The Fundamental Unit)
An ARC Day is a complete 24-hour period with: Morning checklist, Planning (perimeter scope), Execution (tasks, training, mobility, cardio), Nutrition (cooking, meal planning), Recovery (sleep tracking, mood, energy), Reflection (journaling, reading, meditation).
Days are organized into weeks (Monday-Sunday). The day is the atomic unit—everything else aggregates from days.
3. Minimum Mode (Sustainable Fallback)
Minimum Mode is a toggle that reduces requirements to the absolute essentials when life happens. Not a failure—it's a regulated recovery state.
Normal Mode: Full checklist (10 items), Perimeter scope (3-5 bullets), Training or mobility/cardio, Cooking, Reading, journaling, meditation
Minimum Mode: Core checklist only (make bed, water, perimeter), Simplified perimeter (2-3 bullets), No training/cooking/reading/journaling/meditation requirement
4. Timeboxing (Preventing Overcommitment)
Every task has a timebox—a maximum duration in minutes (hard limit). If a task exceeds its timebox, you must defer it (with required "next step" note), break it into smaller tasks, or accept it won't be completed today.
Purpose: Prevents Parkinson's Law, forces realistic planning, creates urgency and focus.
5. Task Categories (Organization)
Tasks can be organized into categories that users create and manage. Categories help organize tasks by domain (Work, Personal, Home, etc.) with optional colors for visual distinction.
6. Task Deferral (Intentional Postponement)
Tasks can be deferred, but only with a required "next step" note. This prevents indefinite deferral and forces clarity on what needs to happen next.
7. Weekly Split (Training Organization)
The weekly split is a customizable label system for organizing training sessions. Default labels: Push, Pull, Legs, Arms. Each training session is tagged with a split label, enabling progress tracking by muscle group and frequency analysis.
8. Gym & Exercise Module (Comprehensive Training Tracking)
Complete system for tracking resistance training, mobility work, and exercise progress. Provides detailed metrics for every workout and maintains a unified exercise catalog.
Core Features:
- Exercise Catalog: Unified list shared by gym and mobility sessions, category labels, muscle groups, global/user-specific exercises
- Workouts: Create training sessions, select exercises from catalog, multiple exercises per workout, split labels
- Training Metrics: Core (Reps, Sets, Load, RIR/RPE, Rest Time, Tempo/TUT), Additional (ROM, Notes, 1RM, %1RM, Pause Duration), Advanced (e1RM, Velocity, Fatigue Index, Intensity)
- Progress Tracking: Historical data, progress graphs, PR tracking, muscle group frequency, volume analysis, correlation analysis
- Data Input: All exercise data is input IN ARC - no imports from other apps
9. Lunch Slot Rule (Recovery Enforcement)
Rule: You can do either Mobility or Cardio at lunch, but not both. This enforces recovery and prevents overtraining.
10. Cooking System (Nutrition Planning)
Rule: Cook 3 times per week = 6 dinners (leftovers count as second dinner). Each cooking session produces 2 dinners (eat one, save one).
Features: Meal templates, quick apply, cooking frequency tracker, grocery list templates.
11. Bedtime Targets (Sleep Regulation)
Each user has bedtime targets in their week settings: Wake Time, In-Bed Time, Lights-Out Time.
Stress Week Overrides: Mark any week as a "stress week" to use different bedtime targets. System automatically uses stress week targets when isStressWeek is true.
📁 File & Image Upload System (Core Infrastructure)
Status: 🔴 HIGH PRIORITY - Core infrastructure required for multiple features
Overview
ARC // OS requires a comprehensive file and image upload system to support:
- Profile pictures (people, user avatars in social features)
- Progress pictures (training progress, body composition)
- Book covers (reading library)
- Meal photos (cooking/nutrition tracking)
- Recipe images (recipe library)
- Document attachments (PDFs for appointments, notes, etc.)
Architecture Design
The file upload system follows the adapter pattern (similar to the email service) to allow easy switching between storage backends:
IFileStorageAdapter (interface)
├── DiskStorageAdapter (development/local)
└── S3StorageAdapter (production - future)
Key Design Principles:
- Storage Adapter Pattern: Interface-based design allows swapping disk → S3 without code changes
- User Isolation: Users can only access their own files (security enforced at service layer)
- Image Processing: Automatic resizing service creates multiple sizes (original + up to 4 variants)
- File Type Support: Images (JPEG, PNG, WebP) and documents (PDF, etc.)
- Database Tracking: All files tracked in database with metadata (userId, fileType, mimeType, sizes, etc.)
Database Schema
model File {
id String @id @default(uuid())
userId String
fileName String // Original filename
fileType String // 'image', 'document', etc.
mimeType String // 'image/jpeg', 'application/pdf', etc.
size Int // File size in bytes
storageKey String // Storage adapter key (path for disk, S3 key for S3)
storageAdapter String @default('disk') // 'disk' or 's3'
isImage Boolean // True if image (enables resizing)
metadata Json? // Additional metadata (dimensions, etc.)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
imageVariants ImageVariant[] // Resized versions for images
@@index([userId])
@@index([fileType])
@@index([storageAdapter])
@@map("files")
}
model ImageVariant {
id String @id @default(uuid())
fileId String
variant String // 'thumbnail', 'small', 'medium', 'large', 'original'
width Int?
height Int?
size Int // Variant size in bytes
storageKey String // Storage adapter key for this variant
createdAt DateTime @default(now())
file File @relation(fields: [fileId], references: [id], onDelete: Cascade)
@@unique([fileId, variant])
@@index([fileId])
@@map("image_variants")
}
Service Architecture
IFileStorageAdapter Interface:
interface IFileStorageAdapter {
upload(file: Buffer, key: string, metadata: FileMetadata): Promise<string>;
download(key: string): Promise<Buffer>;
delete(key: string): Promise<void>;
getUrl(key: string): Promise<string>; // For serving files
exists(key: string): Promise<boolean>;
}
FileService:
- Handles file uploads, downloads, deletion
- Enforces user ownership (users can only access their own files)
- Manages file metadata in database
- Coordinates with storage adapter
ImageProcessingService:
- Resizes images to multiple variants (thumbnail, small, medium, large, original)
- Can be on-demand or ahead-of-time (configurable)
- Uses sharp library for image processing
- Creates variants: thumbnail (150x150), small (400x400), medium (800x800), large (1200x1200), original
FileUploadService (orchestrator):
- Coordinates FileService + ImageProcessingService
- Handles multipart form uploads
- Validates file types and sizes
- Returns file records with URLs
API Endpoints
POST /api/files/upload - Upload file (multipart/form-data)
GET /api/files/:id - Get file metadata
GET /api/files/:id/download - Download file (with user ownership check)
GET /api/files/:id/url - Get file URL (for images, returns appropriate variant URL)
DELETE /api/files/:id - Delete file (with user ownership check)
GET /api/files - List user's files (with filtering)
Security
- User Isolation: All file operations verify user ownership
- File Type Validation: Only allowed MIME types accepted
- Size Limits: Configurable max file sizes per type
- Path Sanitization: Prevent directory traversal attacks
- Storage Keys: Use UUIDs, not user-provided filenames
Storage Adapters
DiskStorageAdapter (Development/Default):
- Stores files in
server/uploads/{userId}/{fileId}/ - Original files and image variants stored in organized structure
- Serves files via Express static middleware or direct file serving
S3StorageAdapter (Production - Future):
- Stores files in S3 bucket with organized key structure
- Uses signed URLs for secure access
- Supports CDN integration
- Same interface as DiskStorageAdapter (drop-in replacement)
Image Variants
For images, the system automatically creates:
- thumbnail: 150x150 (for lists, avatars)
- small: 400x400 (for cards, previews)
- medium: 800x800 (for detail views)
- large: 1200x1200 (for full-size viewing)
- original: Unmodified original file
Variants are created either:
- On-demand: When first requested (lazy generation)
- Ahead-of-time: Immediately after upload (eager generation)
Integration Points
Files will be linked to:
Person.pictureUrl→ File.id (instead of URL string)Book.coverUrl→ File.idRecipe.imageUrl→ File.idMeal.photoUrl→ File.id (future)TrainingSession.progressPhotoId→ File.id (future)Meeting.attachmentId→ File.id (for PDFs, etc.)
Environment Variables
# File Upload Configuration
FILE_STORAGE_ADAPTER=disk # 'disk' or 's3'
FILE_UPLOAD_DIR=./uploads # For disk adapter
MAX_FILE_SIZE=10485760 # 10MB default
ALLOWED_IMAGE_TYPES=image/jpeg,image/png,image/webp
ALLOWED_DOCUMENT_TYPES=application/pdf
# Image Processing
IMAGE_PROCESSING_MODE=eager # 'eager' or 'lazy'
IMAGE_VARIANTS=thumbnail:150x150,small:400x400,medium:800x800,large:1200x1200
# S3 Configuration (future)
AWS_S3_BUCKET=
AWS_S3_REGION=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
Implementation Notes
- Follow Email Service Pattern: Use interface + factory function pattern (like
getEmailService()) - Service Layer: FileService handles business logic, routes are thin
- User Ownership: Always verify in service layer before file operations
- Type Safety: Strict TypeScript, no
anytypes - Testing: 100% coverage required (critical infrastructure)
- Error Handling: Descriptive errors, proper cleanup on failures
Future Enhancements
- CDN Integration: Serve images via CDN for performance
- Image Optimization: WebP conversion, compression
- Virus Scanning: Scan uploaded files (for documents)
- Backup/Replication: Automatic backup to secondary storage
- Migration Tool: Tool to migrate files from disk → S3
📊 Data Model: Heavily Relational
Critical Design Principle: Every table and data point is heavily relational. If we can link something, we link it.
⚠️ Database Column Design Rule: When creating a database column, if it would contain a list, array, object, or any non-single-value data structure, rethink the architecture to use a linked table instead.
⚠️ CRITICAL: This rule is MANDATORY. No exceptions without explicit approval.
- ❌ NEVER use:
items: String[],tags: String[],settings: Json, etc. - ✅ ALWAYS use: Linked tables with junction tables where needed
- Current violations (to be fixed):
GroceryList.itemsandGroceryList.purchased→ Should beGroceryListItemtableGroceryListTemplate.items→ Should beGroceryListTemplateItemtable
Core Entities
User → The human being being managed
Week → Monday-Sunday container (belongs to User, contains Days, Dinner Plans, Grocery Lists)
Day → 24-hour period (belongs to Week, has Checklist Items, Perimeter Scope, Tasks, Training/Mobility/Cardio Sessions, Dinner Plan, Journal Entries)
Checklist Items → Daily habits (belongs to Day, keys: MAKE_BED, WATER, GYM, MOBILITY, CARDIO, COOK, READING, MEDITATION, JOURNAL, PERIMETER)
Perimeter Tasks → Reusable tasks defined by user, selected on each day
Tasks → Work items with timeboxes (belongs to User, optionally to Day)
Training Session → Gym/workout session (belongs to User, Day, has Exercises via TrainingEntry)
Exercise → Reusable exercise definitions (global or user-specific, used by Training Entries and Mobility Sessions)
Mobility Session → Recovery/mobility work (belongs to User, Day)
Cardio Session → Cardiovascular training (belongs to User, Day)
Dinner Plan → Meal planning (belongs to Day, Week)
Grocery List → Shopping list (belongs to Week, User)
Meal Template → Reusable meal definitions (belongs to User)
Grocery List Template → Reusable grocery lists (belongs to User)
Book → Reading tracking (belongs to User, linked to DayChecklistItem via bookId)
Journal Question → Predefined journal questions (global or user-specific)
Journal Entry → Structured journal responses (belongs to User, Day, JournalQuestion)
Week Settings → User preferences (belongs to User, tracks Weekly Split labels, Bedtime Targets, Stress Week Override Targets)
Relational Power
This heavy relational structure enables future analytics:
- Training frequency by muscle group
- Task completion by category and day of week
- Sleep quality vs. training load
- Mood/energy correlation with checklist completion
- Cooking frequency vs. grocery spending
- Task deferral patterns
- Minimum mode usage patterns
- Journal growth tracking
🚀 How It Manages You as a Human
Daily Flow (All Input Happens in ARC)
-
Morning: Open ARC // OS → See today's day planner
- System auto-creates today if it doesn't exist
- Shows checklist (10 items)
- Select perimeter tasks - choose from your reusable task list each morning
- Shows tasks for today (with timeboxes)
- Shows training/mobility/cardio slots
-
Planning: Select perimeter tasks from your task list IN ARC
- System validates count (must be 3-5)
- Perimeter tasks are reusable - create once, select on any day
-
Execution: Throughout the day IN ARC
- Check off checklist items as you complete them
- Input variable values for checklist items (water amount, book selection, meditation duration, etc.)
- Log training session IN ARC (exercises, sets, reps, weight)
- Log mobility or cardio IN ARC (enforced: one or the other at lunch)
- Update task status (todo → doing → done) IN ARC
- Defer tasks if needed (with required next step) IN ARC
-
Nutrition: IN ARC
- Mark if you cooked (counts for 2 dinners)
- Select dinner from dinner plan
- System tracks: 3 cooks = 6 dinners requirement
-
Recovery: End of day IN ARC
- Log sleep hours (from previous night)
- Rate mood (1-10)
- Rate energy (1-10)
- System correlates with training load, checklist completion, etc.
-
Reflection: IN ARC
- Journal entries - Answer predefined questions (multiple entries per day)
- Growth tracking - View all entries for a specific question over time
- Reading progress - update current page for selected book
- Meditation session - log duration and type
Weekly Flow
-
Week View: See all 7 days at once
- Each day shows: Checklist completion %, Perimeter tasks status, Tasks, Training/Mobility/Cardio
- Identify patterns: "You haven't done legs in 2 weeks"
- See cooking progress: "2/3 cooks this week"
-
Week Settings: Customize your week
- Edit weekly split labels
- Set bedtime targets
- Adjust preferences
-
Grocery Planning:
- System generates grocery list from dinner plans
- Mark items as purchased
- Carry over unpurchased items to next week
Regulation and Enforcement
The system enforces rules, not just tracks data:
- Perimeter tasks: Selected from reusable task list, tracked as checklist
- Lunch slot rule: Can't log both mobility and cardio for same day
- Task deferral: Can't defer without next step
- Timeboxing: Tasks have hard time limits
- Cooking requirement: System tracks 3 cooks = 6 dinners
💻 Coding Standards & Conventions
⚠️ CRITICAL: All developers and LLMs must follow these standards. Read this section before writing any code.
React/TypeScript Frontend Standards
Component Size & Structure
- Keep components small and focused — One primary responsibility per component
- Split large components — If a file grows beyond ~200-300 lines, split it
- Prefer composition — Use composition over large monolithic components
- File organization — Components in
/components, pages in/pages, utilities in/utils, types in/types
Strict Typing (MANDATORY)
- TypeScript strict mode everywhere — No
any, no implicitunknown - Explicit types required — Props, state, hooks, context values, and function returns must all be explicitly typed
- Interface definitions — All component props must use interfaces
- Shared types — Reusable types must live in dedicated
types.tsfiles - API responses — Use generic types for API responses:
ApiResponse<T>
Testing Requirements
- Every component must have tests — Components, hooks, and utilities must be covered
- Test behavior, not implementation — Tests validate what components do, not how they do it
- New functionality = new tests — No new code without corresponding tests
- Tests must pass — All tests must pass before merge
Design Consistency (MANDATORY)
- Use existing design language exclusively — Reuse existing components, spacing, colors, typography
- CSS Modules only — All styles use CSS Modules (
.module.cssfiles) - Design tokens — Use CSS variables from
variables.css:- Colors:
--bg,--fg,--muted,--border,--surface,--focus - Spacing:
--space-1through--space-8 - Typography:
--font-mono,--font-sans
- Colors:
- Monochrome design — Black, white, grayscale only (no colors, no gradients)
- Icons, not emoji, in UI — Use icon components/SVGs for interface affordances
- Icon system — Prefer
lucide-reacticons for all standard UI elements. Game-icons.net icons are only used as fallback for character gamification equipment slots. - No ad-hoc styling — Follow established patterns, use existing components
- Component reuse — Use
Button,Input,Card,SectionHeadercomponents
Code Quality
- Clarity over cleverness — Prefer readable, straightforward code
- Avoid unnecessary abstractions — Keep it simple
- Deterministic logic — Code must be predictable and testable
- No dead code — Remove unused exports, unused imports, commented code
- No TODOs in code — Use docs/project/TODO.md for tracking, not code comments
Feature Requirements (MANDATORY)
Every page/feature must include:
- Navigation items — All pages must be accessible via navigation menu, quick navigation (Ctrl+K/Cmd+K), or logical links from related pages
- Toast notifications — Use
useToast()hook to provide user feedback for:- Successful operations (data saved, items created, etc.)
- Errors (failed API calls, validation errors, etc.)
- Important background events (achievements unlocked, streaks maintained, etc.)
- Info messages (data loaded, status updates, etc.)
- Gamification integration — Where applicable, integrate with gamification system:
- Show XP earned for activities
- Display streaks and achievements
- Award XP and update streaks when actions are completed
- Show gamification stats in relevant contexts
Frontend-Backend Synchronization (MANDATORY)
⚠️ CRITICAL: Frontend and backend must be implemented together.
- No backend-only features — Every backend feature (API endpoint, service, model) must have corresponding frontend UI
- No frontend-only features — Every frontend feature must have backend support
- Visual feedback required — All gamification changes (XP, coins, achievements, battles, etc.) must have visible UI updates
- Implementation order:
- Design the feature (both backend and frontend)
- Implement backend (services, routes, models)
- Immediately implement frontend (pages, components, UI)
- Test both together
- Update documentation
- Exception: Infrastructure-only changes (database migrations, utilities) may not need immediate UI, but should be documented for future UI work
API Client Pattern
- Use
apiutility — All API calls go through/utils/api.ts - Typed responses — Use generic types:
api.get<Type>('/endpoint') - Error handling — Always check
response.okand handleresponse.error - Credentials included — API client automatically includes cookies
- Async/await — Use async/await, not promises with
.then() - Error messages — Display user-friendly error messages from
response.error?.message
State Management
- React hooks — Use
useState,useEffectfor local state - Context for auth — Use
useAuth()hook from/utils/auth.tsx - No global state library — Keep state local or in context (avoid Redux/Zustand unless needed)
File Naming & Organization
- Components: PascalCase (e.g.,
Button.tsx,TodayPage.tsx) - CSS Modules: Match component name (e.g.,
Button.module.css) - Utilities: camelCase (e.g.,
api.ts,auth.tsx) - Tests: Component name +
.test.tsx(e.g.,Button.test.tsx) - Component structure: Each component in its own folder with CSS module
- Exports: Use named exports (
export function Button) not default exports - Barrel exports: Avoid barrel exports (
index.ts), import directly from files
Icon Usage Guidelines
Standard UI Icons (Primary):
- Use
lucide-reactfor all standard UI elements (buttons, navigation, status indicators, cards, etc.) - Import directly:
import { Home, User, Settings } from 'lucide-react'; - Available icons: https://lucide.dev/icons/
Character Gamification Icons (Fallback Only):
- Game-icons.net icons are only used for character equipment slots (helmet, sword, shield, etc.)
- These icons are bundled in
web/src/assets/icons/equipment/and imported viaEquipmentIconcomponent - Do not use game-icons.net icons for standard UI — use lucide-react instead
Backend/TypeScript Standards
Service Layer Pattern
- Services contain business logic — Routes are thin, services do the work
- Pure functions — Services are testable, pure functions where possible
- User ownership verification — Always verify user owns resources before operations
- Error handling — Throw descriptive errors, catch in routes
- Service instantiation — Create service instance in route handler:
const service = new Service() - Return types — Services return
Promise<unknown>orPromise<unknown[]>(type-safe via Prisma)
Type Safety
- TypeScript strict mode — No
any, strict null checks - Zod validation — All API inputs validated with Zod schemas
- Prisma types — Use Prisma-generated types, no manual type definitions for DB models
Database Patterns
- Heavily relational — Link everything that can be linked
- Cascade deletes — Proper cascade relationships for data integrity
- UTC timestamps — All dates in UTC
- UUIDs — All primary keys are UUIDs
API Response Format
- Consistent responses — Use
sendSuccess()andsendError()utilities - Error codes — Standard error codes:
UNAUTHORIZED,NOT_FOUND,VALIDATION_ERROR,INTERNAL_ERROR - Structured errors — Include error details in response
General Conventions
Component Patterns
- Function components only — Use function components, not class components
- Props destructuring — Destructure props in function signature:
function Button({ variant, children, ...props }: ButtonProps) - Spread props — Use
{...props}to pass through HTML attributes - Conditional rendering — Use
{condition && <Component />}or ternary operators - Event handlers — Use
async function handleSubmit()pattern, not arrow functions in JSX
CSS/Styling Patterns
- CSS Modules — All styles use CSS Modules (
.module.cssfiles) - Design tokens — Use CSS variables, never hardcode values
- Class composition — Use template literals:
`${styles.class} ${className || ''}` - No inline styles — Avoid inline styles except for dynamic values (use CSS variables)
- Responsive design — Use CSS media queries, not JavaScript
Error Handling Patterns
- Frontend: Try/catch blocks, check
response.ok, display user-friendly messages - Backend: Try/catch in routes, throw descriptive errors in services, catch and format in routes
- User feedback: Always show error messages to users, never silent failures
When Requirements Conflict
- Stop and ask — If a requirement conflicts with these rules, stop and ask for clarification
- Don't guess — Don't implement conflicting patterns without clarification
- Document exceptions — If an exception is approved, document why in code comments
Code Review Checklist
Before submitting code:
- All types are explicit (no
any, no implicit types) - All components have tests
- Design uses existing components/tokens
- No dead code or unused imports
- Follows file naming conventions
- API calls use
apiutility - Error handling is proper
- User ownership verified (backend)
- Loading and error states handled
- CSS uses design tokens (no hardcoded values)
🏗️ Architecture
Technology Stack
Backend:
- Fastify 4.x (high-performance HTTP server)
- TypeScript (strict mode, no
any) - Prisma ORM (type-safe database access)
- PostgreSQL (relational database)
- Zod (runtime validation)
- JWT (authentication, httpOnly cookies)
- Pino (structured logging)
⚠️ Database Schema Management:
- Always run migrations after schema changes:
npx prisma migrate dev --name <name> - Always generate Prisma Client after schema changes:
npx prisma generate - The database MUST be in sync with the Prisma schema - this is critical
Frontend:
- React 18 (UI framework)
- TypeScript (strict mode)
- Vite (build tool)
- React Router (navigation)
- CSS Modules (scoped styling)
Testing:
- Vitest (unit, integration, component tests)
- Test database (separate from development)
- Coverage enforcement (90% minimum, 100% for critical paths)
Deployment:
- Docker Compose (multi-container setup)
- Nginx (frontend serving)
- PostgreSQL (database)
- Multi-stage builds (optimized images)
Design Principles
- Strong Typing: TypeScript strict mode, no
any, Zod for runtime validation - Input Validation: All API inputs validated with Zod schemas
- Business Logic Outside Frameworks: Services contain logic, routes are thin
- Mandatory Testing: No code without tests, 90%+ coverage required
- Monochrome UI: Black/white/grayscale, technical aesthetic
- Local-First: Works offline, syncs when online (future)
- Docker-Ready:
docker compose up --buildshould work
🚀 Local Development
Prerequisites
- Node.js LTS (v18+)
- PostgreSQL (or use Docker)
- Yarn
Quick Start
See QUICKSTART.md for detailed setup instructions.
⚠️ IMPORTANT: Database Schema Synchronization
After ANY schema changes in server/prisma/schema.prisma, you MUST:
- Run migrations:
cd server && npx prisma migrate dev --name <migration_name> - OR sync directly (development only):
cd server && npx prisma db push - Generate Prisma Client:
cd server && npx prisma generate - Restart the server: If the server is running, restart it to pick up the new Prisma Client. The server process caches the Prisma Client in memory, so changes won't take effect until restart.
Common Issue: "Unknown field" errors after schema changes
If you see errors like "Unknown field fieldName for select statement on model ModelName", this means:
- The Prisma Client is out of sync with the schema
- Solution: Run
npx prisma generateand restart the server - The database may also need syncing: run
npx prisma db push(dev) ornpx prisma migrate deploy(production)
TL;DR:
# 1. Install dependencies
cd server && yarn install
cd ../web && yarn install
# 2. Set up database
cd server
createdb arcos # or use setup-dev-env.sh
yarn prisma migrate deploy # Apply existing migrations
yarn prisma generate # Generate Prisma Client
yarn prisma db seed # Seed demo user + exercises
# 3. Start servers
cd server && yarn dev # Terminal 1
cd web && yarn dev # Terminal 2
# 4. Open http://localhost:3000
# Login: demo@arcos.local / demo123
Docker Setup
docker compose up --build
This starts:
- PostgreSQL on port 5432
- API server on port 3001
- Web app on port 3000
🔧 Troubleshooting
CORS Errors (Access-Control-Allow-Credentials)
Symptom: Browser shows CORS error like:
Access to fetch at 'http://localhost:3001/api/auth/login' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true'
Important: This is usually NOT a CORS configuration problem. CORS errors with empty header values typically indicate the server is not running properly or crashed during request handling.
Debugging Steps:
-
Check if server is running:
curl http://localhost:3001/health
# Should return: {"status":"ok"} -
Check for port conflicts:
lsof -i :3001
# Kill any stale processes: lsof -ti:3001 | xargs kill -9 -
Check server logs for errors:
- Server logs are output with pino-pretty in development
- Look for database connection errors, missing env vars, or startup crashes
-
Restart the server:
cd server
pkill -f "tsx.*index.ts" # Kill any running servers
yarn dev # Start fresh -
Check database connection:
pg_isready -h localhost -p 5432
# Should return: accepting connections -
Run CORS tests to verify configuration:
cd server && yarn test src/routes/__tests__/cors.test.ts
Root Cause: When Fastify encounters an error before CORS headers are set (e.g., during route registration, database connection, or middleware execution), it returns a response without proper CORS headers. The browser interprets missing headers as CORS violations.
Common causes:
- Database not running or connection string wrong
- Port 3001 already in use by another process
- Server crashed during startup
- Missing environment variables (check
.env) - Syntax/import errors in route files
🧪 Testing
⚠️ CRITICAL: This system controls daily life. All code must be tested. See TESTING_REQUIREMENTS.md for strict testing requirements.
Requirements
- 90% minimum code coverage (enforced)
- 100% coverage for critical paths (auth, validation, business rules)
- All tests must pass before merge (CI enforced)
- No new code without tests (mandatory)
- Tests written WITH code, not after (TDD preferred)
Test Categories
- Unit Tests — All services, utilities, business logic
- Integration Tests — All API endpoints with real database
- Component Tests — All React components
- Page Tests — All page components and flows
- E2E Tests — Critical user journeys (Playwright) - MANDATORY - catches React errors before production
See TESTING_REQUIREMENTS.md for complete testing standards.
E2E Testing: See E2E_TESTING.md for Playwright E2E test setup and usage.
📁 Project Structure
/server Backend API
/prisma Prisma schema and migrations
/src
/routes API route handlers (thin, delegate to services)
/services Business logic (pure, testable)
/utils Utilities (auth, response, logger)
/types TypeScript types
/web Frontend React app
/src
/components UI components (Button, Input, Card, etc.)
/pages Page components (Login, Today, Week, Day, etc.)
/styles CSS modules and design tokens
/utils Utilities (API client, auth context)
/docker Dockerfiles and nginx config
/docs Documentation
/api API documentation
/testing Testing standards and processes
/architecture Architecture and design decisions
/project Project planning and TODO
/features Implemented features documentation
🔐 Environment Variables
Server (.env in server/)
DATABASE_URL: PostgreSQL connection stringJWT_SECRET: Secret for JWT token signingPORT: Server port (default: 3001)NODE_ENV: Environment (development/production)CORS_ORIGIN: Frontend origin (default: http://localhost:3000)FILE_STORAGE_ADAPTER: File storage adapter ('disk' or 's3', default: 'disk')FILE_UPLOAD_DIR: Directory for file uploads (disk adapter, default: './uploads')MAX_FILE_SIZE: Maximum file size in bytes (default: 10485760 = 10MB)ALLOWED_IMAGE_TYPES: Comma-separated allowed image MIME typesALLOWED_DOCUMENT_TYPES: Comma-separated allowed document MIME typesIMAGE_PROCESSING_MODE: Image variant generation mode ('eager' or 'lazy', default: 'eager')RATE_LIMIT_MAX: Maximum requests per time window for global rate limit (default: 1000)RATE_LIMIT_TIME_WINDOW: Time window in milliseconds for global rate limit (default: 900000 = 15 minutes)RATE_LIMIT_AUTH_MAX: Maximum requests per time window for auth endpoints (default: 100)RATE_LIMIT_AUTH_TIME_WINDOW: Time window in milliseconds for auth rate limit (default: 900000 = 15 minutes)DISABLE_RATE_LIMIT: Set to 'true' to disable rate limiting (useful for tests, default: false)
API Versioning:
- All API responses include
API-Version: v1header - API endpoints support both versioned (
/api/v1/...) and unversioned (/api/...) paths for backward compatibility - Frontend API client uses versioned paths (
/api/v1/...) by default
Web (.env in web/)
VITE_API_URL: Backend API URL (default: http://localhost:3001)
📚 Documentation
- Coding Standards & Conventions: MANDATORY — React/TypeScript standards, design patterns, testing requirements (READ THIS FIRST)
- TODO.md: Open work only (completed features live in
docs/features/) - TESTING_REQUIREMENTS.md: Strict testing standards
- QUICKSTART.md: Step-by-step setup guide
- USER_GUIDE.md: Complete user guide
- API_DOCUMENTATION.md: API reference
- ENDPOINTS.md: Full HTTP catalog
- ARCHITECTURE.md: System architecture
- DEPLOYMENT.md: Production deployment
- Features: Live feature docs
🎯 For Future Developers & LLMs
⚠️ MANDATORY READING: Before writing any code, you MUST read:
- Coding Standards & Conventions — React/TypeScript standards, design patterns, testing requirements
- Testing Requirements — 90% coverage minimum, 100% for critical paths
- Architecture — Technology stack and design principles
- How It Manages You as a Human — Understanding the domain
These rules are mandatory and non-negotiable. If requirements conflict with these standards, stop and ask for clarification.
What You're Building
You're building a life operating system—not a productivity app, not a fitness tracker, not a calendar. This is a system that manages a human being by:
- Enforcing sustainable patterns through rules
- Tracking the full picture (not just work)
- Correlating data across domains (training → sleep → mood → energy)
- Providing structure and guardrails
- Learning patterns and adapting
Key Principles
- Heavily Relational: Link everything. This enables future analytics and insights.
- Rules Over Suggestions: The system enforces rules (perimeter scope count, lunch slot rule, task deferral requirements).
- Human-Centric: Recognizes humans are biological, emotional, social, learning beings—not machines.
- Data-Rich: Track everything. Even if we don't use it now, we'll need it for future analytics.
- Test Everything: This system controls daily life. Bugs are not acceptable.
When Adding Features
Before implementing, ask yourself:
- Does this help manage the human, not just track data?
- Can we link this to existing data? (Do it.)
- Does this enforce a rule or just suggest? (Prefer enforcement.)
- Is this testable? (Must be — see Testing Requirements)
- Does this fit the monochrome, technical aesthetic? (Should — see Design Consistency)
- Does this follow Coding Standards? (Must — strict typing, component structure, design tokens)
- Are all types explicit? (Must — no
any, no implicit types) - Does this reuse existing components? (Should — Button, Input, Card, etc.)
Domain Language
Use the domain language consistently:
- ARC Day (not "day entry" or "daily log")
- Perimeter Tasks (not "daily goals" or "focus areas") - reusable checklist items
- Minimum Mode (not "low energy mode" or "reduced mode")
- Timebox (not "estimated duration" or "time limit")
- Weekly Split (not "training program" or "workout plan")
📋 Current Status
See TODO.md for remaining external/deferred work.
Product status:
- ✅ Web app and API in production (
https://arcos.corgicy.com) - ✅ Public API, outgoing webhooks, MCP, Brain (including forms)
- ✅ Core life-OS modules (planning, training, nutrition, finance, social, gamification)
- ⏳ Stripe, S3, and live fitness-provider sync remain deferred (see TODO.md)
📄 License
Private project.
Built with the understanding that humans need structure, regulation, and data to thrive—not just productivity hacks.