# 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, any> | 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<WSData>) {
    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<WSData>, raw: string | Buffer) {
    // 1. Parse message type (input, resize, etc.)
    // 2. Forward to PTY process
  },
  
  // Connection closed
  close(ws: ServerWebSocket<WSData>) {
    // 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.
