Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

DEPLOY.md

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

DEPLOY.mdBlame145 lines · 1 contributor
988380aClaude1# Deploying Gluecron
8ade77bClaude2
90fa787Claude3Gluecron is a standalone product. It runs anywhere Bun runs. The repo ships a `fly.toml` for Fly.io as the documented primary target, and a `Dockerfile` for any other container host.
3644238Claude4
988380aClaude5---
3644238Claude6
988380aClaude7## 1. Prerequisites
3644238Claude8
988380aClaude91. **Neon Postgres** — create a project at https://neon.tech and copy the pooled connection string. This becomes `DATABASE_URL`.
90fa787Claude102. **Fly.io account** (or any Docker-compatible host) — `flyctl` installed locally if you're using Fly.
988380aClaude113. **(Recommended) Anthropic API key** — https://console.anthropic.com. Everything AI-flavoured degrades to safe fallbacks without it, but you'll want this for the differentiator features.
3644238Claude12
988380aClaude13---
8ade77bClaude14
90fa787Claude15## 2. Deploy to Fly.io
8ade77bClaude16
90fa787Claude17The repo includes a ready `fly.toml`. First-time setup:
8ade77bClaude18
90fa787Claude19```bash
20fly launch # adopts the existing fly.toml; pick an app name and region
21fly deploy # builds via the in-repo Dockerfile and releases
22```
23
24The shipped `fly.toml` already wires up:
25
26- **Release command:** `bun run db:migrate` (runs before each deploy cuts over)
27- **Persistent volume:** `gluecron_repos` mounted at `/app/repos` (bare git repos live on disk)
28- **HTTP service** on port 3000 with forced HTTPS
8ade77bClaude29
90fa787Claude30Set secrets before the first deploy:
8ade77bClaude31
90fa787Claude32```bash
33fly secrets set DATABASE_URL="..." APP_BASE_URL="https://your-app.fly.dev" ANTHROPIC_API_KEY="..."
34```
35
36Route a custom domain via `fly certs add your-domain.com` if you want something other than `*.fly.dev`.
37
38### Other Docker hosts
39
40Any platform that runs the in-repo `Dockerfile` works. Required wiring:
41
42- **Build:** `docker build .`
43- **Release (pre-start):** `bun run db:migrate`
44- **Start:** `bun run src/index.ts`
45- **Port:** `3000`
46- **Persistent volume:** mount the path set by `GIT_REPOS_PATH` (default `/app/repos`)
8ade77bClaude47
988380aClaude48---
8ade77bClaude49
988380aClaude50## 3. Environment variables
8ade77bClaude51
988380aClaude52Full reference is in [`.env.example`](./.env.example); cross-reference BUILD_BIBLE §5.2 for anything not listed here.
8ade77bClaude53
988380aClaude54### Required
55| Variable | Purpose |
56|---|---|
57| `DATABASE_URL` | Neon Postgres connection string (pooled). |
58| `GIT_REPOS_PATH` | Where bare repos live on disk (e.g. `/data/repos`). |
59| `PORT` | HTTP port. Default `3000`. |
60| `APP_BASE_URL` | Canonical public URL, used when composing outbound emails and webhooks. |
8ade77bClaude61
988380aClaude62### Strongly recommended
63| Variable | Purpose |
64|---|---|
65| `ANTHROPIC_API_KEY` | Unlocks AI review, triage, chat, incident responder, auto-repair, completions. |
66| `EMAIL_PROVIDER` | `log` (default, writes to stderr) or `resend` (production). |
67| `EMAIL_FROM` | Sender identity on outbound mail. |
68| `RESEND_API_KEY` | Required when `EMAIL_PROVIDER=resend`. |
69| `VOYAGE_API_KEY` | Upgrades semantic search to Voyage `voyage-code-3` embeddings; without it, a deterministic hashing embedder is used. |
70
90fa787Claude71### Integrations (all optional)
988380aClaude72| Variable | Purpose |
73|---|---|
90fa787Claude74| `GATETEST_URL` | Outbound push webhook to the GateTest third-party security scanner. Default `https://gatetest.ai/api/events/push`. |
988380aClaude75| `GATETEST_API_KEY` | Bearer sent on outbound GateTest posts. |
76| `GATETEST_CALLBACK_SECRET` | Inbound bearer GateTest must present on result callbacks. See `GATETEST_HOOK.md`. |
77| `GATETEST_HMAC_SECRET` | HMAC secret for inbound GateTest callbacks (alternative to bearer). |
90fa787Claude78| `CRONTECH_DEPLOY_URL` | Optional outbound deploy webhook. When set, pushes to the default branch POST here. |
79| `GLUECRON_WEBHOOK_SECRET` | Bearer sent on the outbound deploy webhook above. |
80| `CRONTECH_EVENT_TOKEN` | Bearer an external deploy service must present on `deploy.succeeded` / `deploy.failed` callbacks to `POST /api/events/deploy`. |
81| `CRONTECH_STATUS_URL` / `GLUECRON_STATUS_URL` / `GATETEST_STATUS_URL` | Third-party platform-status endpoints surfaced in the `/admin/platform` widget. |
8ade77bClaude82
988380aClaude83### Operational flags
84| Variable | Purpose |
85|---|---|
86| `AUTOPILOT_DISABLED=1` | Opt out of the 5-minute autopilot ticker (mirror sync, merge-queue processing, weekly digests, advisory rescans). Default: enabled. |
87| `DEMO_SEED_ON_BOOT=1` | Idempotently create a `demo` user plus three public sample repos (`hello-python`, `todo-api`, `design-docs`) on server start. Safe to leave enabled — a second run is a near-instant no-op. Site admins can also trigger a reseed manually from `/admin`. |
88
89---
90
91## 4. Database migrations
92
93Migrations are checked into `drizzle/` and run via:
8ade77bClaude94
95```bash
988380aClaude96bun run db:migrate
8ade77bClaude97```
98
90fa787Claude99Hook this into your host's release phase so every deploy self-migrates. On Fly.io the in-repo `fly.toml` already wires this up via `[deploy].release_command`. First-time bootstrap: the release command will pick up `0000_init.sql` through the latest migration in order.
8ade77bClaude100
988380aClaude101---
8ade77bClaude102
988380aClaude103## 5. Post-deploy checklist
8ade77bClaude104
988380aClaude105Verify these in order after the first deploy:
8ade77bClaude106
90fa787Claude107- [ ] **Release command ran successfully** — `bun run db:migrate` reported success in the release logs.
988380aClaude108- [ ] **`/healthz` is green** — returns `{"ok": true, ...}` with a 200.
109- [ ] **`/readyz` is green** — returns `{"ok": true}`, confirming DB connectivity.
110- [ ] **`/metrics` responds** — basic process snapshot is emitted.
111- [ ] **First admin bootstrap** — register the first account at `/register`. Per `src/lib/admin.ts`, while `site_admins` is empty the **oldest user** is treated as site admin. Register the intended admin account first so the bootstrap rule applies; subsequent admins can then be granted from `/admin/users`.
112- [ ] **Smart HTTP works** — create a repo at `/new`, then `git clone https://<your-host>/<user>/<repo>.git` round-trips.
90fa787Claude113- [ ] **Push triggers the pipeline** — a `git push` fires the secret scanner, webhook fan-out, and (if configured) the outbound GateTest post (check `/:owner/:repo/gates` and `/:owner/:repo/settings/audit`).
988380aClaude114- [ ] **Custom domain TLS** — certificate issued and `APP_BASE_URL` reflects the canonical host.
115- [ ] **Autopilot state** — if you want the background ticker off, confirm `AUTOPILOT_DISABLED=1` is set; otherwise expect mirror syncs and weekly digests to fire on schedule.
8ade77bClaude116
988380aClaude117---
8ade77bClaude118
988380aClaude119## 6. Operations
8ade77bClaude120
988380aClaude121### Logs
90fa787Claude122Your host streams stdout/stderr from `bun run src/index.ts` (on Fly.io: `fly logs`). Every request carries an `X-Request-Id` header; grep logs by that ID when tracing a report.
988380aClaude123
124### Restarts
90fa787Claude125Trigger from your host's dashboard or CLI (on Fly.io: `fly apps restart`). Rate-limit counters are in-memory and reset on restart — that is intentional.
988380aClaude126
127### Rollbacks
90fa787Claude128Roll back via your host's release history (on Fly.io: `fly releases` + `fly deploy --image <previous>`). Database migrations are additive; rolling back the service does not roll back the schema. If a migration needs reverting, write a new forward-migration.
988380aClaude129
130### Backups
90fa787Claude131Neon handles PITR + branch snapshots — configure retention in the Neon console. The bare repos on the persistent volume must be backed up separately (filesystem snapshot of the mount at `GIT_REPOS_PATH`; on Fly.io, snapshot the `gluecron_repos` volume). See BUILD_BIBLE §2.6 for what still needs wiring on the observability side.
988380aClaude132
133---
8ade77bClaude134
988380aClaude135## 7. Graceful-degradation matrix
8ade77bClaude136
988380aClaude137| Missing secret | Effect |
138|---|---|
139| `DATABASE_URL` | App boots, `/healthz` returns 200, any DB-backed route returns 500. Do not deploy without it. |
140| `ANTHROPIC_API_KEY` | AI review, chat, triage, incident, completions, explain, test-gen, merge resolver all return deterministic fallback strings. Site remains fully usable as a plain git host. |
141| `GATETEST_API_KEY` | Outbound GateTest integration silently skipped. Local secret scanner + gate runner still execute. |
142| `RESEND_API_KEY` (with `EMAIL_PROVIDER=resend`) | `sendEmail()` still never throws; emails are logged instead of delivered. |
143| `VOYAGE_API_KEY` | Semantic search falls back to the deterministic hashing embedder. Quality drops; feature still works. |
8ade77bClaude144
988380aClaude145Every missing integration follows the same rule: **never break the primary request path**. See BUILD_BIBLE §4.9 for the full invariant list.