Local development
Local development
Section titled “Local development”Sencai is an event-driven microservices architecture managed with Docker Compose. This guide teaches you how to run it locally.
Prerequisites
Section titled “Prerequisites”- Docker ≥ 20.10
- Docker Compose ≥ 2.0
- Git
- Node.js ≥ 18 (for local service development)
- Minimum 8 GB RAM (recommended 12 GB)
- Minimum 20 GB free space
Cloning the repository
Section titled “Cloning the repository”git clone https://github.com/sencai-ai/sencai.space.gitcd codeSetup environment
Section titled “Setup environment”- Copy the template:
cd orchestrationcp .env.example .env- Fill critical variables:
JWT_SECRET=$(openssl rand -base64 32)API_MANAGER_ENCRYPTION_KEY=$(openssl rand -base64 32)APP_KEYS=$(openssl rand -hex 16),$(openssl rand -hex 16),$(openssl rand -hex 16),$(openssl rand -hex 16)ADMIN_ENCRYPTION_KEY=$(openssl rand -hex 32)- Edit
.envand fill remaining values (cloud tokens, SMTP, etc.)
Running the stack
Section titled “Running the stack”Basic command:
cd orchestration./run-local.sh [profiles...]Profiles
Section titled “Profiles”run-local.sh with no arguments starts the default profile set (orchestration/run-local.sh DEFAULT_PROFILES):
core,traefik,backend,backend-db,auth,git,mq,webhook,monitoring,frontend,web,cloud,docs,admin,audit,agent,vault,billing,watchdog,glitchtip,posthog,opsloop,llm,backup,cell,bootstrap| Profile | Services |
|---|---|
core | API Manager + ssh-proxy-service + workspace-connector (+ Traefik) |
backend / backend-db | Strapi backend / its MySQL |
frontend | Nuxt platform frontend (auth + gravity) |
web | Public marketing web (sencai-web, nginx SSG) |
admin | Admin dashboard (sencai-admin) |
audit | Sencai Audit viewer (port 3300, audit.sencai.localhost) |
auth | Keycloak + keycloak-db + auth-service-consumer |
mq | RabbitMQ (sencai-mq) + notification-service + event-store-consumer |
webhook | Webhook Publisher |
cloud | Cloud Connector + worker + PostgreSQL |
git | Gitea Apps + MySQL + act-runner + Git Connector |
docs | Documentation (Astro 5 + Starlight — this site) |
agent | agent-gateway (fleet C2 gateway, port 4400) |
billing | billing-adapter (Lago/Stripe, port 3600) |
watchdog | sencai-watchdog (dunning microservice — payment-failure suspend/archive cron, port 3700) |
llm | llm-service (LLM facade, port 4430) |
opsloop | opsloop-consumer (intelligence loop, port 3005) |
backup | backup-scheduler (MySQL → S3/GCS) |
cell | cell-metadata (region/cell routing) |
vault | HashiCorp Vault |
monitoring | Prometheus, Grafana, Loki, Tempo, OTEL collector, exporters, Alertmanager, uptime-kuma |
bootstrap | One-shot seed of Strapi data |
forum | Sencai Forum (Lemmy backend + UI + Postgres + pict-rs + oauth2-proxy) — not in the default set, start explicitly |
all | Everything |
Examples
Section titled “Examples”# Backend + auth only./run-local.sh core backend auth mq
# Everything./run-local.sh allLocal URLs
Section titled “Local URLs”Once running, access services through Traefik at their *.sencai.localhost hostnames — this is the primary access method for the whole stack (direct-port access is a debugging fallback, see below):
| Service | URL | Notes |
|---|---|---|
| App / Frontend | http://app.sencai.localhost/ | Nuxt platform (auth + gravity dashboard) |
| Backend API | http://app.sencai.localhost/api | Strapi |
| Strapi Admin | http://app.sencai.localhost/admin | Create admin on first login |
| Keycloak | http://app.sencai.localhost/kc | see note below — bare PathPrefix, no Host() |
| Cloud Console | http://app.sencai.localhost/cloud | Cloud Connector — bare PathPrefix, no Host() |
| Gitea Apps | http://app.sencai.localhost/gitea-apps | bare PathPrefix, no Host() |
| Dozzle (container logs) | http://app.sencai.localhost/dozzle | bare PathPrefix, no Host() |
| Admin Dashboard | http://admin.sencai.localhost/ | sencai-admin |
| Audit Viewer | http://audit.sencai.localhost/ | port 3300 |
| Marketing Web | http://sencai.localhost/ | sencai-web |
| Docs (this site) | http://docs.sencai.localhost/ | |
| GraphQL Gateway | http://graphql.sencai.localhost/ | |
| RabbitMQ UI | http://mq.sencai.localhost/ | admin / admin |
| Grafana | http://grafana.sencai.localhost/ | admin / admin |
| Prometheus | http://prometheus.sencai.localhost/ | |
| Alertmanager | http://alertmanager.sencai.localhost/ | |
| Status / Uptime Kuma | http://status.sencai.localhost/ | first run: create admin |
| Traefik Dashboard | http://localhost:8080 | not behind Traefik itself |
| Lago Billing | http://lago.sencai.localhost/ | profile: billing |
| Vault | http://vault.sencai.localhost/ | profile: vault |
| GlitchTip | http://glitchtip.sencai.localhost/ | profile: glitchtip, first run: create admin |
| PostHog | http://posthog.sencai.localhost/ | profile: posthog, first run: create admin |
| Agent Gateway (Fleet C2) | http://agent-gateway.sencai.localhost/ | profile: agent |
| Opsloop Consumer | http://opsloop.sencai.localhost/ | profile: opsloop |
| LLM Service | http://llm.sencai.localhost/ | profile: llm |
| Notification Service | http://notify.sencai.localhost/ | profile: mq |
| Workspace Connector | http://workspace-connector.sencai.localhost/ | profile: core |
| SSH Proxy (browser terminal) | http://ssh-proxy.sencai.localhost/ | profile: core |
| Cell Metadata | http://cell.sencai.localhost/ | profile: cell |
| Sencai Forum | http://forum.sencai.space/ or http://forum.localhost/ | profile: forum |
Add to /etc/hosts
Section titled “Add to /etc/hosts”127.0.0.1 app.sencai.localhost admin.sencai.localhost audit.sencai.localhost sencai.localhost docs.sencai.localhost graphql.sencai.localhost mq.sencai.localhost grafana.sencai.localhost prometheus.sencai.localhost alertmanager.sencai.localhost status.sencai.localhost lago.sencai.localhost vault.sencai.localhost glitchtip.sencai.localhost posthog.sencai.localhost agent-gateway.sencai.localhost notify.sencai.localhost opsloop.sencai.localhost llm.sencai.localhost workspace-connector.sencai.localhost ssh-proxy.sencai.localhost cell.sencai.localhost forum.localhostNo-Host() routes:
keycloak(/kc),cloud-connector(/cloud),gitea-apps(/gitea-apps) anddozzle(/dozzle) are registered in Traefik as barePathPrefix(...)rules with noHost()restriction. They respond behind any hostname that reaches Traefik on the web entrypoint — not onlyapp.sencai.localhost— sohttp://sencai.localhost/kcorhttp://docs.sencai.localhost/dozzlewill also route to those services. Don’t rely on the hostname alone to isolate them.Port 80 already taken: on machines where port 80 is occupied (e.g. a local k3s cluster’s ServiceLB/klipper-lb), set
TRAEFIK_WEB_HOST_PORTin.env(e.g.8088) and append:PORTto every URL above (http://app.sencai.localhost:8088/,http://grafana.sencai.localhost:8088/, …). The Traefik Dashboard on port 8080 is unaffected.
Bypassing Traefik (direct-port debugging)
Section titled “Bypassing Traefik (direct-port debugging)”Every service that has a ports: mapping in docker-compose.ports.yml can also be reached directly on its container port, bypassing Traefik host-routing entirely — useful when isolating whether an issue is in the app or in the reverse-proxy layer:
http://localhost:1337/admin # Strapi admin, directhttp://localhost:15672 # RabbitMQ UI, directThis is a fallback for debugging only — the *.sencai.localhost URLs above are the standard way to use the stack.
Running services locally
Section titled “Running services locally”For faster development, run services outside Docker:
# Backend (Strapi)cd sencai.space && npm run develop
# Frontend (Nuxt)cd sencai.space-frontend && npm run dev
# API Managercd api-manager && npm run devDatabases
Section titled “Databases”MySQL access
Section titled “MySQL access”mysql -h 127.0.0.1 -P 3306 -u root -pPostgreSQL access
Section titled “PostgreSQL access”psql -h localhost -p 5434 -U cloud_user -d cloud_connector# All servicesdocker compose -f orchestration/docker-compose.yml logs -f
# Single servicedocker compose -f orchestration/docker-compose.yml logs -f backendCleanup
Section titled “Cleanup”# Stop stackcd orchestration && ./run-local.sh stop
# Remove everything (including data!)docker compose -f orchestration/docker-compose.yml down -vTroubleshooting
Section titled “Troubleshooting”| Issue | Cause | Solution |
|---|---|---|
| ”Port already in use” | Port is occupied | Change port in .env |
| Strapi won’t start | MySQL not ready | Wait 30s and restart |
| RabbitMQ connection refused | Not ready | Check logs |
| Keycloak 503 | Slow startup (normal) | Wait 30–90s |
See Root CLAUDE.md for complete reference.