# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

`turboci-admin` is a Next.js (Pages Router) admin panel for TurboCI, a CI/CD deployment system. It manages deployments, services, and servers across cloud providers.

## Commands

### Development

```bash
bun run project:init     # Full first-time setup: install deps, init twui submodule, generate DB schema
bun run dev              # Next.js dev server on port 3772 (web only)
bun run pm2:dev          # Start all 3 processes (web + cron + websocket) via PM2 in dev/watch mode
bun run pm2:start        # Start all 3 processes via PM2 in production mode
bun run pm2:kill         # Kill all PM2 processes
```

### Build & Database

```bash
bun run build            # Production Next.js build
bun run db:schema        # Regenerate SQLite types from schema (run after DB changes)
```

### Docker

```bash
bun run docker:start     # Rebuild and start all containers
bun run docker:logs      # Tail Docker logs
```

### Submodule (twui)

```bash
bun run twui:update      # Pull latest twui component library
```

## Architecture

### Process Model

The app runs as **three separate processes**, managed by PM2 (dev) or Docker Compose (prod):

| Process | Entry Point | Description |
|---|---|---|
| `turboci-web` | Next.js (port 3772) | Pages Router app + API routes |
| `turboci-websocket` | `src/websocket/index.ts` | Bun native WebSocket server (port from `WEB_SOCKET_PORT` env) |
| `turboci-cron` | `src/cron/index.ts` | Polls every 30s (`AppData.CronInterval`) to check services |

### Database

- **ORM**: `@moduletrace/nsqlite` — SQLite with Bun
- **Config**: `nsqlite.config.js` — DB name `turboci-admin`, stored in `src/db/`
- **Types**: Auto-generated in `src/db/types.ts` via `bun run db:schema`
- **Tables**: `users`, `users_ports`

### Key Directories

- `src/pages/` — Next.js pages and API routes (`/api/*`)
- `src/websocket/` — Bun WebSocket server; events are dispatched via a switch in `socket-message.ts`
- `src/cron/` — Background cron job (service health checks)
- `src/functions/` — Business logic (auth, deployment users, pages, ttyd)
- `src/utils/` — Utilities including SSH execution, config file access, port management
- `src/components/` — React components organized by page
- `src/types/index.ts` — All shared TypeScript types including `TCIConfig`, `WebSocketEvents`, `PagePropsType`
- `src/data/app-data.ts` — Central constants (`AppData`): cookie names, port ranges, timeouts
- `src/exports/client-exports.ts` — Re-exports from `@moduletrace/datasquirel` (use `_n` for number coercion, `EJSON` for WebSocket serialization)
- `twui/` — Git submodule: internal Tailwind UI component library

### TurboCI Config Files (Runtime)

The app reads deployment config from the host at runtime:

- `/root/.turboci/.config/turboci.json` — Main deployment config (`TCIGlobalConfig` type)
- `/root/.turboci/.ssh/turboci` — SSH private key for connecting to deployment servers
- `/root/.turboci/deployment_id` — Current deployment identifier

Use `grabDirNames()` (`src/utils/grab-dir-names.ts`) to get these paths, never hardcode them.

### WebSocket Event Flow

Client sends EJSON-serialized `WebSocketDataType` → `socket-message.ts` dispatches by `event` field → handler in `src/websocket/events/`. Connected users tracked in `global.WEBSOCKET_CONNECTED_USERS_DATA`.

### Auth

Cookie-based auth using `@moduletrace/datasquirel`. Cookie names are in `AppData` (`AuthCookieName`, `AuthCSRFCookieName`). Use `userAuth` (`src/utils/user-auth.ts`) in API routes and `getServerSideProps`.

### Environment Variables

Required in `.env` (see `test.env` for reference keys):
- `DSQL_ENCRYPTION_PASSWORD` / `DSQL_ENCRYPTION_SALT` — Used by datasquirel for auth token encryption
- `PORT` — Web server port (default 3772)
- `WEB_SOCKET_PORT` — WebSocket server port
- `HOST` — Full host URL (e.g. `http://localhost:3772`)
