# Officer.dev Backend Architecture ## Executive Summary Officer is a full-stack AI-assisted personal backend and frontend for life management. The backend is a **Bun-based monorepo** using: - **Hono** framework for REST API (port 5000) - **PostgreSQL** with Drizzle ORM for persistent data - **WebSockets** for real-time terminal and AI chat functionality - **Multi-workspace** shared libraries for code reuse - **Node.js PTY sidecars** for terminal emulation - **Pi coding agent integration** for AI-powered development assistance This document covers the backend architecture, data flow, and technical patterns. --- ## Table of Contents 1. [Architecture Overview](#architecture-overview) 2. [Technology Stack](#technology-stack) 3. [Directory Structure](#directory-structure) 4. [Core Server](#core-server) 5. [API Architecture](#api-architecture) 6. [Database Design](#database-design) 7. [WebSocket Services](#websocket-services) 8. [Shared Workspaces](#shared-workspaces) 9. [Error Handling](#error-handling) 10. [Development & Deployment](#development--deployment) 11. [Key Features](#key-features) --- ## Architecture Overview ### High-Level Architecture ``` ┌─────────────────────────────────────────────────────────────┐ │ Web Browser (Frontend) │ └──────────────┬──────────────────────────────────────────────┘ │ ├─ HTTP REST API (port 5000) ├─ WebSocket: Terminal (ws://api:5000/api/terminal/ws) ├─ WebSocket: Pi Chat (ws://api:5000/api/pi/chat/ws) └─ Dev Server Proxy (ws://api:5000/api/dev-server-proxy/*) │ ┌──────────────▼──────────────────────────────────────────────┐ │ Bun Server (src/server.tsx + Hono Router) │ ├─────────────────────────────────────────────────────────────┤ │ Middleware: │ │ - CORS handler │ │ - User authentication (JWT + token blacklist) │ │ - Request body parser │ │ │ │ Routes: │ │ - /api/auth → Authentication (login, signup) │ │ - /api/plans → Plans management │ │ - /api/skills → Skills (Pi integration) │ │ - /api/tasks → Tasks & processes │ │ - /api/upload → File uploads │ │ - /api/workspaces → Workspace management │ │ - /api/settings → User settings │ │ - /api/dev-server → Local dev server routing │ │ - WebSocket handlers → Real-time communication │ └──────────────┬──────────────────────────────────────────────┘ │ ┌──────┴──────────────────────┐ │ │ ▼ ▼ ┌──────────────────┐ ┌──────────────────────┐ │ PostgreSQL DB │ │ Node.js PTY Sidecar │ │ (officer_db) │ │ (Terminal Emulation)│ │ │ │ │ │ Users, Plans, │ │ xterm-js │ │ Skills, Tasks, │ │ node-pty │ │ Sessions, etc │ │ Docker container │ └──────────────────┘ └──────────────────────┘ ``` ### Request/Response Flow ``` Client Request ↓ Server Router (Bun) ↓ Authentication Middleware ↓ Protected/Public Handler ↓ Database Query (Drizzle ORM) OR External Service ↓ Response (JSON/WebSocket) ↓ Client ``` --- ## Technology Stack ### Core Runtime & Framework - **Bun** (v1.30+) - Fast JavaScript runtime with built-in tooling - **TypeScript** (v5.9+) - Strict mode enabled - **Hono** (v4.11+) - Lightweight, type-safe web framework - **Node.js** - For PTY sidecar processes ### Database & ORM - **PostgreSQL** - Primary persistent data store - **Drizzle ORM** (v0.45+) - Type-safe SQL query builder - **Drizzle Kit** (v0.31+) - Schema management and migrations ### Real-Time Communication - **WebSockets** (native Bun) - Bidirectional communication - **Redis** (optional) - Session/cache storage ### Authentication & Security - **JWT** - Token-based authentication - **Argon2** - Password hashing (bcrypt alternative) - **SimpleWebAuthn** - WebAuthn/FIDO2 passkey support - **Token Blacklist** - Revocation tracking ### AI & Automation - **@anthropic-ai/claude-agent-sdk** - Claude integration - **Pi Coding Agent** - CLI-based AI development assistant - **Nodemailer** - Email notifications - **Googleapis** - Google integration for services ### Utilities - **node-pty** - Cross-platform pseudoterminal support - **Cron** (v4.3+) - Scheduled task execution - **Date-fns** (v4.1+) - Date manipulation - **Zod** (v4.2+) - Schema validation --- ## Directory Structure ### Complete Backend Layout ``` monorepo/ ├── src/ │ ├── server.tsx # Main Bun server entry point │ │ │ ├── servers/ # Backend core │ │ ├── bootstrap.ts # Server initialization │ │ ├── hono.ts # Hono app & router setup │ │ ├── jwt.ts # JWT token handling │ │ ├── custom-errors.ts # Custom error classes │ │ ├── create-router.ts # Router factory with context │ │ ├── data-path.ts # Path management │ │ │ │ │ ├── _middlewares/ # Shared middleware │ │ │ ├── user-middleware.ts # Auth verification │ │ │ └── body-parser.ts # Request parsing │ │ │ │ │ └── api/ # API routes │ │ ├── auth/ # Authentication routes │ │ │ ├── signin.ts # Login endpoint │ │ │ ├── signup.ts # Registration endpoint │ │ │ ├── signout.ts # Logout endpoint │ │ │ ├── verify.ts # Email verification │ │ │ ├── passkey-router.ts # WebAuthn endpoints │ │ │ ├── reset-password.ts # Password reset │ │ │ └── auth.ts # Core auth logic │ │ │ │ │ ├── terminal/ # Terminal WebSocket │ │ │ ├── websocket.ts # WS handler │ │ │ └── pty-sidecar.mjs # PTY subprocess │ │ │ │ │ ├── pi/ # Pi coding agent integration │ │ │ ├── websocket.ts # Chat WS handler │ │ │ ├── rest.ts # REST endpoints │ │ │ ├── pi-bridge.ts # Pi SDK bridge │ │ │ ├── storage.ts # Chat session storage │ │ │ └── session-manager.ts # Session management │ │ │ │ │ ├── dev-server/ # Local dev server routing │ │ │ └── router.ts # Dev server proxy │ │ │ │ │ ├── plans/ # Plans management │ │ ├── skills/ # Skills routes │ │ ├── tasks/ # Tasks & processes │ │ ├── workspaces/ # Workspace management │ │ ├── settings/ # User settings │ │ ├── upload/ # File upload │ │ ├── file-browser/ # File browser API │ │ ├── scrape/ # Web scraping │ │ ├── sessions/ # Chat sessions │ │ ├── task-logs/ # Task execution logs │ │ ├── server-settings/ # System configuration │ │ └── users/ # User management │ │ │ ├── databases/ # Data layer │ │ └── officer_db/ # Main database package │ │ ├── drizzle.config.ts # Drizzle configuration │ │ ├── migrations/ # Database migrations │ │ ├── src/ │ │ │ ├── schema.ts # Table definitions │ │ │ ├── types.ts # Inferred types │ │ │ └── index.ts # Exports │ │ └── package.json # Workspace manifest │ │ │ └── workspaces/ # Shared libraries │ ├── components/ # React components │ ├── hooks/ # React hooks │ ├── helpers/ # Utility functions │ ├── types/ # Shared types │ ├── state/ # State management │ ├── config/ # Configuration │ ├── definitions/ # Constants │ ├── emailer/ # Email service │ ├── injector/ # Dependency injection │ └── i18n/ # Internationalization │ ├── package.json # Root workspace config ├── bunfig.toml # Bun configuration ├── tsconfig.json # TypeScript config └── .env # Environment variables ``` --- ## Core Server ### Entry Point: `src/server.tsx` The main server file initializes the Bun HTTP server and handles: 1. Route registration (static files, API, WebSockets) 2. WebSocket upgrade logic and authentication 3. Dev server proxy for HMR and local dev environments 4. PI coding agent installation/verification #### Key Responsibilities ```typescript // 1. Static file serving '/static/*' → public/ directory files // 2. HTML fallback for SPA routing '/' and '/*' → officer-web app // 3. API routing '/api/*' → honoServer (REST endpoints) // 4. WebSocket routing with auth '/api/terminal/ws' → Terminal WebSocket '/api/pi/chat/ws' → Pi Chat WebSocket // 5. Dev server proxy '/api/dev-server-proxy/*' → Proxied WS for local dev servers ``` #### WebSocket Authentication Pattern ```typescript async function upgradeWs(req: Request, server: any, provider: 'terminal' | 'pi') { // 1. Extract JWT token from query params const token = new URL(req.url).searchParams.get('token'); // 2. Verify token and extract user const user = await verify(token); // 3. Check token blacklist (for revoked tokens) const blacklisted = await officerdb.query.TokenBlacklist.findFirst({...}); // 4. Extract WS-specific parameters const sessionId = url.searchParams.get('sessionId'); const cwd = url.searchParams.get('cwd'); const cols = url.searchParams.get('cols'); // terminal dimensions // 5. Upgrade connection with authenticated data server.upgrade(req, { data: { userId, email, role, provider, ... } }); } ``` ### Hono Server: `src/servers/hono.ts` Hono is a lightweight web framework perfect for edge computing and Bun. #### Server Initialization ```typescript const honoServer = new Hono<{ Variables: HonoVariables }>(); honoServer.use(cors({ origin: '*', allowMethods: [...] })); // Public routes honoServer.get('/api', (ctx) => ctx.json({ officerAPI: 'ok' })); honoServer.route('/api/auth', authRouter); honoServer.route('/api/server-settings', serverSettingsRouter); // Protected routes const protectedRouter = createRouter(); protectedRouter.use(bodyParser()); protectedRouter.use(userMiddleware); protectedRouter.route('/plans', plansRouter); protectedRouter.route('/tasks', tasksRouter); // ... other routes honoServer.route('/api', protectedRouter); // Error handling honoServer.onError((error, ctx) => { if (error instanceof CustomError) { return ctx.json(error.returnValue, error.statusCode); } return ctx.text('Internal Server Error', 500); }); ``` #### Hono Variables Context ```typescript type HonoVariables = { userId: number; email: string; role: 'admin' | 'user'; // Accessible in all routes via ctx.get('userId') }; ``` --- ## API Architecture ### Route Organization The API is organized by feature domain: ``` /api/ ├── auth/ # User authentication (public) │ ├── POST /signin │ ├── POST /signup │ ├── POST /signout │ ├── GET /verify │ ├── POST /passkeys (WebAuthn) │ └── ... │ ├── plans/ # Plans management (protected) ├── skills/ # Skills endpoints ├── tasks/ # Task operations ├── workspaces/ # Workspace operations ├── settings/ # User preferences ├── upload/ # File uploads ├── file-browser/ # File system access ├── terminal/ws # Terminal emulation (WS) ├── pi/ # AI assistant integration │ ├── /ws # Chat (WebSocket) │ └── /rest # REST endpoints │ └── dev-server/ # Local dev server routing ``` ### Router Creation Pattern: `src/servers/create-router.ts` ```typescript // Factory function for creating contextualized routers export function createRouter() { return new Hono<{ Variables: HonoVariables }>(); } // Usage in route handlers: const router = createRouter(); router.get('/endpoint', (ctx) => { const userId = ctx.get('userId'); // Route logic }); ``` ### Error Handling: `src/servers/custom-errors.ts` ```typescript class CustomError extends Error { constructor( public statusCode: number, message: string, public returnValue?: Record | string, ) { super(message); } } // Usage patterns throw new CustomError(400, 'Bad request', { error: 'Invalid input' }); throw new CustomError(401, 'Unauthorized'); throw new CustomError(500, 'Internal error', { error: 'Database failed' }); ``` --- ## Database Design ### Primary Database: `officer_db` Located in `src/databases/officer_db/`, this is the main persistent data store. #### Drizzle Configuration ```typescript // drizzle.config.ts import { defineConfig } from 'drizzle-kit'; export default defineConfig({ schema: './src/schema.ts', out: './migrations', dialect: 'postgresql', dbCredentials: { url: process.env.DATABASE_URL!, }, }); ``` #### Schema Structure The schema defines all tables and their relationships: ```typescript // src/databases/officer_db/src/schema.ts // Core tables export const Users = pgTable('users', { id: serial('id').primaryKey(), email: text('email').unique().notNull(), password: text('password'), role: text('role').$type<'admin' | 'user'>().default('user'), verified: boolean('verified').default(false), createdAt: timestamp('created_at').defaultNow(), updatedAt: timestamp('updated_at').defaultNow(), }); export const Plans = pgTable('plans', { id: serial('id').primaryKey(), userId: integer('user_id').references(() => Users.id), title: text('title').notNull(), description: text('description'), // ... other fields }); export const Skills = pgTable('skills', { id: serial('id').primaryKey(), userId: integer('user_id').references(() => Users.id), name: text('name').notNull(), content: text('content'), // ... other fields }); // ... many more tables for tasks, sessions, workspaces, etc. // Relations export const usersRelations = relations(Users, ({ many }) => ({ plans: many(Plans), skills: many(Skills), })); ``` #### Type Generation Types are automatically inferred from schema: ```typescript // src/databases/officer_db/src/types.ts // Simple table types export type User = typeof Users.$inferSelect; export type UserInsert = typeof Users.$inferInsert; // Extended types for API responses export type UserWithRelations = User & { plans: Plan[]; skills: Skill[]; }; ``` #### Database Operations in Routes ```typescript import { officerdb, eq, Users } from 'officerdb'; // Simple query const user = await officerdb.query.Users.findFirst({ where: eq(Users.id, userId), }); // Query with relations const user = await officerdb.query.Users.findFirst({ where: eq(Users.id, userId), with: { plans: true, skills: true, }, }); // Insert with returning const [newUser] = await officerdb.insert(Users).values({ email: 'user@example.com', password: hashedPassword, }).returning(); // Update await officerdb.update(Users).set({ verified: true, }).where(eq(Users.id, userId)); ``` #### Token Blacklist Table ```typescript export const TokenBlacklist = pgTable('token_blacklist', { id: serial('id').primaryKey(), jti: text('jti').unique().notNull(), // JWT ID expiresAt: timestamp('expires_at').notNull(), createdAt: timestamp('created_at').defaultNow(), }); // Used for token revocation (logout, password change, etc.) ``` ### Database Migrations Migrations are generated by Drizzle and stored in `src/databases/officer_db/migrations/`: ```bash # Generate new migration bun run db:gen # Apply migrations bun run db:push # Open Drizzle Studio for visual management bun run db:studio ``` --- ## WebSocket Services ### 1. Terminal WebSocket: `src/servers/api/terminal/` Provides an interactive terminal emulator in the browser using xterm.js. #### Architecture ``` Browser (xterm.js) ↓ WebSocket Officer Server (websocket.ts) ↓ IPC/Stdio PTY Sidecar (pty-sidecar.mjs) ↓ Shell Process System Shell (bash/zsh) ``` #### Handler: `websocket.ts` ```typescript export const terminalWebsocket = { // Connection established open(ws: ServerWebSocket) { const { userId, cwd, cols, rows, sandboxed } = ws.data; // 1. Spawn or reuse PTY sidecar // 2. Set terminal dimensions // 3. Send initial prompt }, // Client sends data (typing, etc.) message(ws: ServerWebSocket, raw: string | Buffer) { // 1. Parse message type (input, resize, etc.) // 2. Forward to PTY process }, // Connection closed close(ws: ServerWebSocket) { // 1. Kill PTY process // 2. Cleanup resources }, }; ``` #### PTY Sidecar: `pty-sidecar.mjs` A Node.js subprocess that manages the actual pseudoterminal: ```javascript // Uses node-pty for cross-platform terminal support const pty = require('node-pty'); const term = pty.spawn('bash', [], { name: 'xterm-color', cols: 120, rows: 40, cwd: process.env.CWD, }); // stdout → send to client term.on('data', (data) => { process.stdout.write(JSON.stringify({ type: 'output', data })); }); // stdin from client → write to terminal process.stdin.on('data', (chunk) => { const msg = JSON.parse(chunk); if (msg.type === 'input') term.write(msg.data); if (msg.type === 'resize') term.resize(msg.cols, msg.rows); }); ``` #### Sandboxed vs. Real Terminals - **Sandboxed**: Limited to specific directories, no system access - **Real**: Full system access from user's working directory ### 2. Pi Coding Agent WebSocket: `src/servers/api/pi/` Integrates the Pi coding agent for AI-assisted development. #### Architecture ``` Browser (Chat UI) ↓ WebSocket Officer Server (pi/websocket.ts) ↓ SDK Pi Coding Agent (pi-bridge.ts) ↓ RPC/Tools LLM API (Claude, GPT, etc.) ``` #### Components **websocket.ts**: WebSocket message handler - Routes incoming chat messages to Pi - Streams responses back to client - Manages session state **pi-bridge.ts**: SDK integration layer ```typescript export async function createPiSession( cwd: string, userEmail: string, sessionId?: string, ) { // 1. Initialize Pi SDK const { session } = await createAgentSession({ cwd, model: selectedModel, tools: createCodingTools(cwd), }); // 2. Subscribe to events session.subscribe((event) => { // Stream events back to client via WS }); // 3. Return session for messaging return session; } ``` **rest.ts**: REST endpoints for Pi operations - Create new sessions - List sessions - Get session details - Export conversations **storage.ts**: Chat session persistence ```typescript // Store conversation history in database interface PiSession { id: string; userId: number; cwd: string; model: string; createdAt: timestamp; messages: PiMessage[]; } // Retrieve from database when resuming ``` **session-manager.ts**: Session lifecycle management #### Message Flow ``` Client: "ls -la" → WebSocket to Officer → Pi process stdin → Pi executes bash tool → Tool output → Stream back to client ``` #### Integration with Tools Pi can execute: - `read` - Read files - `bash` - Run shell commands - `edit` - Modify files - `write` - Create files - Custom tools via extensions --- ## Shared Workspaces Shared code is organized in `src/workspaces/` as Bun workspace packages: ### Key Workspaces **types/** - TypeScript type definitions - Centralized, exported via `'types'` alias - Shared by frontend and backend - Database types imported and re-exported **helpers/** - Utility functions - Formatters, validators, converters - Pure functions with no side effects **hooks/** - React hooks - Frontend-only - `useAuth`, `useQuery`, `useMutation`, etc. **state/** - State management - Global state stores - Context providers - Zustand/React Context usage **components/** - React components - UI components (buttons, inputs, etc.) - Complex feature components - Reusable across apps **config/** - Configuration - Constants - Environment-specific settings **definitions/** - Enum and constant definitions - User roles - Status values - Feature flags **emailer/** - Email service ```typescript // Nodemailer-based email sending export async function sendEmail(to: string, subject: string, html: string) { const transporter = nodemailer.createTransport({...}); return transporter.sendMail({ to, subject, html }); } ``` **injector/** - Dependency injection - Service locator pattern - Configuration management **i18n/** - Internationalization - Multi-language support - Locale management **sounds/** - Audio assets - Notification sounds - UI feedback audio **widgets/** - Complex UI widgets - Feature-rich components - Composed from basic components ### Workspace Configuration Each workspace has a `package.json`: ```json { "name": "components", "version": "0.1.0", "type": "module", "exports": { ".": "./index.ts" }, "main": "./index.ts" } ``` ### Import Pattern in Code ```typescript // In any app (frontend/backend) import { User, Plan } from 'types'; import { formatDate } from 'helpers'; import { useAuth } from 'hooks'; import { useGlobalState } from 'state'; import { Button } from 'components'; ``` --- ## Error Handling ### Error Classification ```typescript // Custom error hierarchy class CustomError extends Error { constructor( public statusCode: number, message: string, public returnValue?: any, ) {} } // Usage patterns throw new CustomError(400, 'Bad request', { field: 'email', error: 'Invalid' }); throw new CustomError(401, 'Unauthorized'); throw new CustomError(403, 'Forbidden'); throw new CustomError(404, 'Not found', { resource: 'Plan' }); throw new CustomError(409, 'Conflict', { error: 'Email already exists' }); throw new CustomError(500, 'Internal server error'); ``` ### Middleware Error Handling ```typescript honoServer.onError((error, ctx) => { // CustomError → formatted response if (error instanceof CustomError) { return ctx.json(error.returnValue || error.message, error.statusCode); } // Unexpected error → 500 console.error('Unexpected error:', error.message); return ctx.text('Internal Server Error', 500); }); ``` ### Try/Catch Pattern ```typescript // In route handlers router.post('/endpoint', async (ctx) => { try { const body = await ctx.req.json(); // Validation if (!body.email) { throw new CustomError(400, 'Email required', { field: 'email' }); } // Database operation const user = await officerdb.insert(Users).values({...}).returning(); if (!user) throw new CustomError(500, 'Failed to create user'); return ctx.json({ success: true, user }); } catch (error) { // Re-throw CustomErrors, let middleware handle if (error instanceof CustomError) throw error; // Unexpected error console.error('Route error:', error); throw new CustomError(500, 'Internal server error'); } }); ``` --- ## Authentication System ### JWT Flow ``` User Login ↓ Verify credentials (email + password) ↓ Generate JWT token { "sub": userId, "email": email, "role": "user", "iat": timestamp, "exp": timestamp, "jti": unique-token-id } ↓ Return token to client ↓ Client stores in localStorage ↓ Client sends in Authorization header ↓ Server verifies signature & expiration ↓ Grant access ``` ### Token Verification: `src/servers/jwt.ts` ```typescript export async function verify(token: string) { try { // 1. Verify signature and expiration const decoded = jwt.verify(token, JWT_SECRET) as JWTPayload; // 2. Check token blacklist (for revoked tokens) if (decoded.jti) { const blacklisted = await officerdb.query.TokenBlacklist.findFirst({ where: eq(TokenBlacklist.jti, decoded.jti), }); if (blacklisted) return null; // Token revoked } return { id: decoded.sub, email: decoded.email, role: decoded.role }; } catch { return null; // Invalid token } } ``` ### Logout with Token Blacklist ```typescript router.post('/signout', async (ctx) => { const token = ctx.req.header('Authorization')?.replace('Bearer ', ''); const decoded = jwt.decode(token) as JWTPayload; // Add to blacklist await officerdb.insert(TokenBlacklist).values({ jti: decoded.jti, expiresAt: new Date(decoded.exp * 1000), }); return ctx.json({ success: true }); }); ``` ### WebAuthn/Passkey Support ```typescript // Registration router.post('/passkeys/register/options', async (ctx) => { const user = ctx.get('userId'); const options = await generateRegistrationOptions({ rpID: 'officer.dev', rpName: 'Officer', userID: Buffer.from(String(user.id)), userName: user.email, }); return ctx.json(options); }); // Verification router.post('/passkeys/register/verify', async (ctx) => { const credential = await ctx.req.json(); const verification = await verifyRegistrationResponse({ credential, expectedOrigin: 'https://officer.dev', expectedRPID: 'officer.dev', }); if (verification.verified) { // Store passkey await officerdb.insert(Passkeys).values({...}); } return ctx.json({ verified: verification.verified }); }); ``` --- ## Development & Deployment ### Development Server ```bash # Start with hot reload bun dev # Server runs on http://localhost:5000 # Frontend available at http://localhost:5000/ ``` ### Database Operations ```bash # Generate migration from schema changes bun run db:gen # Apply pending migrations bun run db:push # Open Drizzle Studio (UI for database) bun run db:studio ``` ### Build & Production ```bash # Full build bun run build # Production server NODE_ENV=production bun src/server.tsx # Runs on port specified by PORT env var (default 5000) ``` ### Environment Variables ```bash # .env DATABASE_URL=postgresql://user:pass@localhost:5432/officer JWT_SECRET=your-secret-key NODE_ENV=development PORT=5000 ``` --- ## Key Features ### 1. Real-Time Terminal - Interactive shell in browser - File operations - Code execution - Multi-session support - Sandboxed mode option ### 2. AI-Powered Development with Pi - Chat interface with Claude - File reading/writing capabilities - Shell command execution - Session persistence - Model selection ### 3. Task Management - Create and track tasks - Task dependencies - Scheduled execution (cron) - Task logs and history - Process management ### 4. Workspace Management - Multi-workspace support - Project organization - Settings per workspace - Resource management ### 5. File Management - File browser with preview - Upload support (50GB max) - Web scraping - Export/import ### 6. Skills System - Pi agent skills - Custom task templates - Reusable automation ### 7. Settings & Configuration - User preferences - System configuration - Integration settings - Resource limits --- ## Performance Considerations ### Connection Pooling PostgreSQL connections are managed by Drizzle ORM with configurable pool size. ### Caching - Redis support for session data (optional) - Database query result caching - Static asset caching ### Rate Limiting - Per-user API limits (todo) - WebSocket message throttling - File upload size limits (50GB max) ### Database Optimization - Proper indexing on foreign keys - Query optimization with relations - Pagination for large datasets --- ## Security ### CORS ```typescript honoServer.use(cors({ origin: '*', allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], allowHeaders: ['Content-Type', 'Authorization'], })); ``` ### JWT Security - Secret stored in env variables - Token expiration enforced - Token blacklist for revocation - jti (JWT ID) for tracking ### Password Security - Argon2 hashing (modern, secure) - No plain-text storage - Email verification required - Password reset via email ### WebAuthn/FIDO2 - Hardware key support - Phishing-resistant - No passwords stored for passkeys --- ## Monitoring & Logging ### Current Logging - Console.log for debugging - Error stack traces printed to console ### Future Monitoring (Signoz Integration) - Distributed tracing - Performance monitoring - Error tracking - Log aggregation --- ## Testing ### Current Test Setup - `@testing-library/react` for component tests - `@playwright/test` for E2E tests - `happy-dom` for DOM testing ### Test Command ```bash # Not yet fully configured bun test ``` --- ## Related Documentation - **Frontend Architecture**: See `OFFICERDEV_FRONTEND.md` - **CONVENTIONS.md**: Detailed code patterns and style guide - **CLAUDE.md**: Project overview and patterns - **Each folder CLAUDE.md**: Feature-specific documentation --- ## Summary Officer's backend is a modern, type-safe Bun monorepo with: - RESTful API using Hono framework - Real-time capabilities via WebSockets - PostgreSQL persistence with Drizzle ORM - AI integration through Pi coding agent - Modular architecture with shared workspaces - Strong TypeScript support throughout - Robust authentication with JWT and WebAuthn The architecture prioritizes developer experience, type safety, and maintainability while providing powerful real-time and AI-powered features to users.