Files
platform/OFFICERDEV_BACKEND.md
T
2026-02-22 16:49:30 +00:00

31 KiB

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
  2. Technology Stack
  3. Directory Structure
  4. Core Server
  5. API Architecture
  6. Database Design
  7. WebSocket Services
  8. Shared Workspaces
  9. Error Handling
  10. Development & Deployment
  11. 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

// 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

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

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

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

// 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

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

// 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:

// 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:

// 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

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

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/:

# 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

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:

// 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

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

// 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

// 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:

{
  "name": "components",
  "version": "0.1.0",
  "type": "module",
  "exports": {
    ".": "./index.ts"
  },
  "main": "./index.ts"
}

Import Pattern in Code

// 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

// 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

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

// 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

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

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

// 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

# Start with hot reload
bun dev

# Server runs on http://localhost:5000
# Frontend available at http://localhost:5000/

Database Operations

# 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

# 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

# .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

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

# Not yet fully configured
bun test

  • 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.