Unified Backend Architecture

Comprehensive guide to the consolidated backend architecture, including all services, authentication, database, and deployment.

Created: 1/29/2026

Unified Backend Architecture

This guide provides a comprehensive overview of the consolidated backend architecture (apps/ai), which unifies all backend services into a single, cohesive Express application.

Architecture Overview

The unified backend serves as the central hub for all application services, providing a single deployment target while maintaining clear separation of concerns through route modules.

graph TB
    subgraph "Client Layer"
        Native[Native App]
        Web[Web Apps]
    end

    subgraph "API Gateway Layer"
        Express[Express Server<br/>Port 3005]
    end

    subgraph "Route Modules"
        AI[AI Routes<br/>/api/ai]
        Move[Move Routes<br/>/api/move]
        IPFS[IPFS Routes<br/>/api/ipfs]
        DB[Database Routes<br/>/api/database]
        Notif[Notifications Routes<br/>/api/notifications]
        Auth[Auth Routes<br/>/api/auth]
        HB[Heartbeat Routes<br/>/api/heartbeat]
    end

    subgraph "External Services"
        OpenAI[OpenAI API]
        Movement[Movement Testnet]
        Helia[Helia IPFS Node]
        ExpoPush[Expo Push Service]
        Privy[Privy Auth Service]
    end

    subgraph "Data Layer"
        Postgres[(PostgreSQL)]
    end

    Native --> Express
    Web --> Express

    Express --> AI
    Express --> Move
    Express --> IPFS
    Express --> DB
    Express --> Notif
    Express --> Auth
    Express --> HB

    AI --> OpenAI
    Move --> Movement
    IPFS --> Helia
    Notif --> ExpoPush
    Auth --> Privy

    DB --> Postgres
    AI --> Postgres
    Notif --> Postgres
    Auth --> Postgres

Core Components

Express Server

  • Port: 3005 (configurable via PORT)
  • Framework: Express with TypeScript
  • Middleware: CORS, JSON parsing, timing utilities, authentication
  • Route Structure: Modular routes under /api/* prefixes

Database Layer

  • Engine: PostgreSQL with connection pooling
  • ORM: Drizzle with type-safe queries
  • Security: Row Level Security (RLS) for multi-tenant data isolation
  • Migrations: Automated schema management

Authentication

  • Provider: Privy (server-side token validation)
  • Middleware: validateAuth for route protection
  • Scope: User-based data access across all services

Performance Monitoring

  • Timing Utilities: Request/response timing and logging
  • Middleware: Automatic performance tracking for all routes
  • Storage: Timing data persistence for analysis

Service Integration

How Services Work Together

  1. User Registration Flow:

    App → /api/auth/register → Privy validation → Database user creation → Device registration → Response
    
  2. AI Chat with Data Persistence:

    App → /api/ai/chat → OpenAI streaming → /api/database/entries → User data storage → Response stream
    
  3. Push Notifications:

    App → /api/notifications/devices/register → Token storage → /api/notifications/send → Expo service → Device delivery
    
  4. Blockchain + Storage:

    App → /api/ipfs/upload → CID generation → /api/move/submit-transaction → On-chain storage → Confirmation
    

Environment Configuration

Required Variables

# OpenAI Configuration
OPENAI_API_KEY=sk-your-openai-key

# Privy Authentication
PRIVY_APP_ID=your-privy-app-id
PRIVY_APP_SECRET=your-privy-app-secret

# Database Connection
DATABASE_URL=postgresql://user:password@localhost:5432/cubed

# Server Configuration
PORT=3005
HOST=0.0.0.0
NODE_ENV=production

# Optional: IPFS API Key
IPFS_API_KEY=your-ipfs-api-key

Development vs Production

Development (NODE_ENV=development):

  • Local PostgreSQL database
  • Console logging enabled
  • Detailed error responses
  • Host: localhost

Production (NODE_ENV=production):

  • Production database (e.g., Fly.io PostgreSQL)
  • Structured logging
  • Minimal error details
  • Host: 0.0.0.0

Startup Sequence

The backend follows a specific initialization order:

// 1. Environment validation
console.log('[AI Backend] Script loading...');

// 2. Express app setup
const app = express();
app.use(cors());
app.use(express.json());
app.use(timingMiddleware()); // Performance tracking

// 3. Route mounting
app.use('/api/ai', aiRoutes);
app.use('/api/move', moveRoutes);
// ... other routes

// 4. Helia IPFS initialization (async)
await initializeHelia();

// 5. Activity service startup
activityService.start();

// 6. Server start
app.listen(port, host, () => {
    console.log(`✅ AI Server running at http://${host}:${port}`);
});

Database Schema & Migrations

Schema Overview

-- Users table (Privy integration)
CREATE TABLE users (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  privyUserId TEXT UNIQUE NOT NULL,
  createdAt TIMESTAMP DEFAULT NOW()
);

-- Devices table (multi-device support)
CREATE TABLE devices (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  userId UUID REFERENCES users(id) ON DELETE CASCADE,
  deviceName TEXT,
  deviceModel TEXT,
  osVersion TEXT,
  platform TEXT CHECK (platform IN ('ios', 'android')),
  appVersion TEXT,
  buildVersion TEXT,
  deviceType INTEGER,
  platformApiLevel INTEGER,
  isPhysicalDevice BOOLEAN,
  osName TEXT,
  deviceYearClass INTEGER,
  totalMemory BIGINT,
  isActive BOOLEAN DEFAULT true,
  createdAt TIMESTAMP DEFAULT NOW(),
  updatedAt TIMESTAMP DEFAULT NOW()
);

-- Device tokens (push notifications)
CREATE TABLE deviceTokens (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  deviceId UUID REFERENCES devices(id) ON DELETE CASCADE,
  userId UUID REFERENCES users(id) ON DELETE CASCADE,
  pushToken TEXT UNIQUE NOT NULL,
  isActive BOOLEAN DEFAULT true,
  lastUsedAt TIMESTAMP DEFAULT NOW(),
  createdAt TIMESTAMP DEFAULT NOW(),
  updatedAt TIMESTAMP DEFAULT NOW()
);

-- User entries (data sync)
CREATE TABLE entries (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  userId UUID REFERENCES users(id) ON DELETE CASCADE,
  content TEXT NOT NULL,
  createdAt TIMESTAMP DEFAULT NOW(),
  updatedAt TIMESTAMP DEFAULT NOW(),
  deleted BOOLEAN DEFAULT false
);

Migration Commands

# Generate migrations from schema changes
cd apps/ai
pnpm db:generate

# Apply migrations to database
pnpm db:push

# View current schema
pnpm db:studio

API Endpoints Reference

Authentication Routes (/api/auth)

| Method | Endpoint | Description | Auth Required | |--------|----------|-------------|---------------| | POST | /register | Register user with device info | Privy token | | POST | /logout | Deactivate all user devices | Privy token |

Database Routes (/api/database)

| Method | Endpoint | Description | Auth Required | |--------|----------|-------------|---------------| | GET | /entries | Fetch user entries (with ?since filter) | Yes | | POST | /entries | Create/update entries (upsert) | Yes |

AI Routes (/api/ai)

| Method | Endpoint | Description | Auth Required | |--------|----------|-------------|---------------| | POST | /chat | Streaming AI conversation | Yes |

Move Routes (/api/move)

| Method | Endpoint | Description | Auth Required | |--------|----------|-------------|---------------| | POST | /generate-hash | Generate transaction hash | Yes | | POST | /submit-transaction | Submit signed transaction | Yes | | POST | /faucet | Request test tokens | Yes | | GET | /balance/:address | Get MOVE balance | Yes | | GET | /account-info/:address | Get account info | Yes | | POST | /view | Call view function | Yes | | POST | /get-resource | Get account resource | Yes |

IPFS Routes (/api/ipfs)

| Method | Endpoint | Description | Auth Required | |--------|----------|-------------|---------------| | POST | /upload-image | Upload image to IPFS | Yes + API key | | POST | /upload-json | Upload JSON data | Yes + API key | | POST | /upload | Legacy upload (name/desc/image) | Yes + API key | | GET | /data/:cid | Retrieve JSON data | No | | GET | /image/:cid | Retrieve image | No |

Notifications Routes (/api/notifications)

| Method | Endpoint | Description | Auth Required | |--------|----------|-------------|---------------| | POST | /devices/register | Register push token | Yes | | DELETE | /devices/:tokenId | Deactivate token | Yes | | GET | /devices | List user devices | Yes | | POST | /send | Send to multiple users | Yes | | POST | /send-to-token | Send to specific token | Yes |

Heartbeat Route (/api/heartbeat)

| Method | Endpoint | Description | Auth Required | |--------|----------|-------------|---------------| | POST | / | Update activity status | Yes |

Performance Tracking

Timing Middleware

All routes include automatic performance tracking:

// Automatic timing for every request
app.use(timingMiddleware());

// Example timing output:
// [timing] GET /api/database/entries - 45ms
// [timing] POST /api/move/generate-hash - 120ms

Custom Timing

For complex operations:

import { timeAndLog } from './utils/timing-utils.js';

const result = await timeAndLog(
  'custom_operation',
  async () => performComplexTask(),
  { userId, operationType: 'sync' }
);

Authentication Flow

Privy Token Validation

// Middleware validates tokens on protected routes
const validateAuth = async (req, res, next) => {
  const authHeader = req.headers.authorization;

  if (!authHeader?.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'Missing token' });
  }

  try {
    const token = authHeader.split(' ')[1];
    const verifiedClaims = await privy.utils().auth().verifyAccessToken(token);

    req.userId = verifiedClaims.user_id;
    next();
  } catch (error) {
    res.status(401).json({ error: 'Invalid token' });
  }
};

Row Level Security

Database queries automatically scope to authenticated users:

-- Automatic user filtering
SELECT * FROM entries WHERE userId = $1; -- $1 is req.userId

Deployment Considerations

Fly.io Configuration

# fly.toml
app = "cubed-backend"
primary_region = "ord"

[build]
  dockerfile = "Dockerfile"

[env]
  PORT = "3000"
  NODE_ENV = "production"

[services]
  internal_port = 3000
  protocol = "tcp"

  [[services.ports]]
    port = 80
    handlers = ["http"]
    force_https = true

  [[services.ports]]
    port = 443
    handlers = ["tls", "http"]

Database Setup

# Attach PostgreSQL to Fly app
fly postgres create --name cubed-db
fly postgres attach cubed-db --app cubed-backend

# Run migrations
fly ssh console --app cubed-backend
pnpm db:push

Environment Secrets

# Set production secrets
fly secrets set OPENAI_API_KEY="sk-..."
fly secrets set PRIVY_APP_ID="..."
fly secrets set PRIVY_APP_SECRET="..."
fly secrets set DATABASE_URL="postgresql://..."

Monitoring & Debugging

Health Checks

# Health endpoint (no auth required)
GET /health
# Returns: { "status": "ok" }

Logs

# View application logs
fly logs --app cubed-backend

# View database logs
fly postgres logs --app cubed-db

Performance Analysis

Timing logs help identify bottlenecks:

[timing] POST /api/ai/chat - 2.3s (streaming response)
[timing] GET /api/database/entries - 45ms
[timing] POST /api/move/generate-hash - 120ms

Best Practices

Error Handling

  • Use consistent error response format
  • Log errors with context but don't expose sensitive details
  • Implement graceful degradation for external service failures

Security

  • Always validate input data
  • Use parameterized queries to prevent SQL injection
  • Rotate API keys regularly
  • Implement rate limiting for production

Performance

  • Use connection pooling for database
  • Implement caching where appropriate
  • Monitor memory usage and implement cleanup routines
  • Use streaming for large data transfers

Scalability

  • Design for horizontal scaling
  • Use database indexes for common queries
  • Implement background job processing for heavy operations
  • Monitor service limits and implement queuing

Troubleshooting

Common Issues

Database Connection Failed

  • Verify DATABASE_URL format
  • Check PostgreSQL service status
  • Ensure proper SSL configuration for production

Privy Token Validation Errors

  • Confirm PRIVY_APP_ID and PRIVY_APP_SECRET are set
  • Verify token format in Authorization header
  • Check token expiration

IPFS Upload Failures

  • Ensure Helia node is initialized (check startup logs)
  • Verify API key is provided for uploads
  • Check available disk space

Push Notification Issues

  • Confirm Expo push tokens are registered
  • Verify device platform information
  • Check Expo service status

Debug Mode

Enable detailed logging in development:

NODE_ENV=development DEBUG=* pnpm start:ai

This provides comprehensive request/response logging and error details.