Cloudron deployment plan
This commit is contained in:
@@ -15,6 +15,11 @@
|
||||
|
||||
Use `npx prisma studio` to inspect the database.
|
||||
|
||||
Deploying to staging or production (MEDLab Cloudron) — see
|
||||
[docs/guides/ops-backend-deploy.md](docs/guides/ops-backend-deploy.md)
|
||||
for the admin handoff and the linked Linear tickets for the actual
|
||||
deployment-pipeline work.
|
||||
|
||||
### Prisma migrations
|
||||
|
||||
- **Never edit** a migration that has already been applied to staging,
|
||||
|
||||
@@ -23,6 +23,7 @@ These will be deleted once the backend services are stood up:
|
||||
- [guides/backend-roadmap.md](./guides/backend-roadmap.md)
|
||||
- [guides/backend-linear-tickets.md](./guides/backend-linear-tickets.md)
|
||||
- [guides/template-recommendation-matrix.md](./guides/template-recommendation-matrix.md)
|
||||
- [guides/ops-backend-deploy.md](./guides/ops-backend-deploy.md) — admin handoff for deploying to MEDLab's Cloudron.
|
||||
|
||||
## Cursor rules
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ A backend review was merged into **[docs/backend-roadmap.md](backend-roadmap.md)
|
||||
### Audit note (Linear CR-72+ vs repo, 2026-04)
|
||||
|
||||
- **Done in Linear and shipped:** **CR-72–CR-76**, **CR-77** (publish from create flow), **CR-78** (template seed), **CR-79**, **CR-88**, **CR-89**. The **CR-72 → CR-83** numbering is the original **sequential plan**, not current blocking order; the **core product vertical** through publish + templates is effectively complete in-repo.
|
||||
- **Backlog (still open):** **CR-80** (web vitals — file-based route remains), **CR-81** (public rule detail — no `GET /api/rules/[id]` or marketing detail page yet), **CR-82** (CI migrate smoke), **CR-83** (no `docs/ops-backend-deploy.md` yet), **CR-84** / **CR-85** (parallel hygiene), **CR-86** (profile + account + draft resume — UI mostly placeholder), **CR-90** / **CR-91**, **CR-93** (template grid facets on marketing).
|
||||
- **Backlog (still open):** **CR-80** (web vitals — file-based route remains), **CR-81** (public rule detail — no `GET /api/rules/[id]` or marketing detail page yet), **CR-82** (CI migrate smoke), **CR-84** / **CR-85** (parallel hygiene), **CR-86** (profile + account + draft resume — UI mostly placeholder), **CR-90** / **CR-91**, **CR-93** (template grid facets on marketing).
|
||||
- **CR-83 Done (admin handoff scope):** [`docs/guides/ops-backend-deploy.md`](ops-backend-deploy.md) shipped as the **admin handoff sheet** (access, env vars, platform settings, open decisions). The full deploy runbook is intentionally split out — see the new follow-up tickets in [Ticket 12 / CR-83 follow-ups](#follow-up-tickets-filed-under-cr-83) below.
|
||||
- **CR-86** is **no longer blocked** by publish — **CR-77** is **Done**; profile work is gated by **implementation**, not waiting on publish wiring.
|
||||
- **Not in this ticket list** but called out in **[docs/backend-roadmap.md](backend-roadmap.md):** shared **rate-limit store** (e.g. Redis) before multi-instance; **`GET /api/create-flow/methods`** exists for facet scoring (Ticket 16 / CR-88) but is not duplicated as a separate doc ticket.
|
||||
|
||||
@@ -535,29 +536,58 @@ _Section B — Final Review screen `+` button per category:_
|
||||
|
||||
---
|
||||
|
||||
## Ticket 12 — Staging / production runbook (operator checklist)
|
||||
## Ticket 12 — Staging / production admin handoff (Cloudron at MEDLab)
|
||||
|
||||
**Depends on:** Tickets 1–8 complete enough to deploy a vertical slice.
|
||||
|
||||
**Server / admin:** **This is the main ticket where you need the admin.** You draft the runbook; **admin fills in real hostnames, DB endpoint, SMTP, backup tooling, and who runs `migrate deploy`.** Without their input, you cannot complete production-ready deploy steps.
|
||||
**Server / admin:** **This is the handoff ticket.** Scope is **narrowed** vs. the original "full operator runbook" framing: the deliverable is the **admin-handoff sheet** — exactly what access, env vars, and platform decisions to ask MEDLab's Cloudron admin for. The full deploy runbook (build / push / install / migrate / smoke / rollback) is **split out into a follow-up ticket** so CR-83 isn't blocked on access we don't have yet.
|
||||
|
||||
**Goal:** Single doc for admin: env vars, TLS, DB backups, migrations, Docker, SMTP, health checks.
|
||||
**Goal:** Single short doc the admin can read end-to-end and respond to in one round-trip: required access, Cloudron-injected vs. manually-set env vars, platform settings to confirm (`httpPort`, `healthCheckPath`, addons, memory, backups), and the open product decisions only admin can answer (subdomains, sender address, registry choice, cutover overlap, retention).
|
||||
|
||||
**Implementation:**
|
||||
**Platform context:** Target is **Cloudron at MEDLab** (same host as the legacy [`CommunityRule/CommunityRuleBackend`](https://git.medlab.host/CommunityRule/CommunityRuleBackend), which is Express + MySQL with a 30-min `run.sh` watchdog). New app is a properly packaged Cloudron app (Docker image + `CloudronManifest.json`), uses the **postgresql + sendmail + localstorage** addons, and replaces the legacy service entirely — **no data migration**. Cloudron's container supervisor replaces the old watchdog.
|
||||
|
||||
1. Add `docs/ops-backend-deploy.md` (or similar) with numbered steps:
|
||||
- Required env: `DATABASE_URL`, `SESSION_SECRET`, `SMTP_URL`, `SMTP_FROM`, optional `NEXT_PUBLIC_ENABLE_BACKEND_SYNC`.
|
||||
- `docker compose` vs `Dockerfile` deploy; `prisma migrate deploy` before traffic.
|
||||
- Reverse proxy: `GET /api/health` for LB health.
|
||||
- Backups and restore drill for Postgres.
|
||||
- SMTP DNS (SPF/DKIM).
|
||||
2. Cross-link [docs/backend-roadmap.md](docs/backend-roadmap.md) §11 (environments) and §8 (migrations policy); note **never rewrite applied migrations** and where application logs go.
|
||||
**Implementation (shipped):**
|
||||
|
||||
1. [`docs/guides/ops-backend-deploy.md`](ops-backend-deploy.md) — admin handoff sheet (~1 page):
|
||||
- **§2 Access checklist** (Cloudron admin login, registry creds, DNS, `cloudron` CLI, log access, read of legacy app config).
|
||||
- **§3 Env vars** split into Cloudron auto-injected (`CLOUDRON_POSTGRESQL_URL`, `CLOUDRON_MAIL_SMTP_*`) vs. manually-set (`SESSION_SECRET`, `SMTP_FROM`, `NEXT_PUBLIC_ENABLE_BACKEND_SYNC`).
|
||||
- **§4 Platform settings** (`httpPort: 3000`, `healthCheckPath: /api/health`, memory, backups, TLS).
|
||||
- **§5 Decisions** (subdomains, sender, registry, cutover, retention).
|
||||
- **§7 Old vs new deltas** (addons, watchdog, OTP→magic link, sender, API surface — all reasons not to reuse legacy infra).
|
||||
- **§8 Follow-up tickets** (the six tickets below).
|
||||
2. Cross-links: [`docs/guides/backend-roadmap.md`](backend-roadmap.md) §11 (environments — names Cloudron at MEDLab) and §8 (migrations policy — never rewrite applied migrations).
|
||||
|
||||
**Acceptance criteria:**
|
||||
|
||||
- [ ] Someone who did not write the code can deploy and roll back migrations with only the doc.
|
||||
- [x] Admin can grant the right access + answer the open decisions in one pass without further back-and-forth.
|
||||
- [x] Doc is ~1 page and explicitly lists what is **not** in scope so admin doesn't expect a full deploy walkthrough.
|
||||
- [x] Six follow-up tickets enumerated and linked (see below).
|
||||
|
||||
**Files:** new `docs/ops-backend-deploy.md`.
|
||||
**Files:** [`docs/guides/ops-backend-deploy.md`](ops-backend-deploy.md), [`docs/guides/backend-roadmap.md`](backend-roadmap.md), [`docs/README.md`](../README.md), [`CONTRIBUTING.md`](../../CONTRIBUTING.md).
|
||||
|
||||
**Status:** [CR-83](https://linear.app/community-rule/issue/CR-83/backend-stagingproduction-runbook-admin-handoff-docsops-backend) **Done** (admin handoff scope). Deployment-pipeline implementation tracked in the follow-up tickets below.
|
||||
|
||||
### Follow-up tickets filed under CR-83
|
||||
|
||||
All six are titled `[Backend] …`, assigned to Vinod, in the **community-rule** team, **Backlog** state. IDs filled in once filed via Linear MCP.
|
||||
|
||||
| # | Linear | Title | Depends on |
|
||||
| - | ------ | ----- | ---------- |
|
||||
| 1 | [CR-96](https://linear.app/community-rule/issue/CR-96/backend-bridge-cloudron-env-vars-to-canonical-names) | `[Backend] Bridge CLOUDRON_* env vars to canonical names` | none — can ship now |
|
||||
| 2 | [CR-97](https://linear.app/community-rule/issue/CR-97/backend-container-image-registry-choose-build-push) | `[Backend] Container image registry: choose, build, push` | registry decision (handoff §5) |
|
||||
| 3 | [CR-98](https://linear.app/community-rule/issue/CR-98/backend-cloudron-staging-install-smoke) | `[Backend] Cloudron staging install + smoke` | CR-96 + CR-97 + Cloudron CLI access + staging DNS |
|
||||
| 4 | [CR-99](https://linear.app/community-rule/issue/CR-99/backend-cloudron-production-install-dns-cutover) | `[Backend] Cloudron production install + DNS cutover` | CR-98 green for the agreed overlap window |
|
||||
| 5 | [CR-100](https://linear.app/community-rule/issue/CR-100/backend-steady-state-operator-runbook) | `[Backend] Steady-state operator runbook` | CR-98 (write what we actually did) |
|
||||
| 6 | [CR-101](https://linear.app/community-rule/issue/CR-101/backend-decommission-legacy-expressmysql-backend) | `[Backend] Decommission legacy Express/MySQL backend` | CR-99 + sign-off window |
|
||||
|
||||
**Per-ticket detail:**
|
||||
|
||||
1. **Bridge `CLOUDRON_*` env vars to canonical names.** Cloudron injects `CLOUDRON_POSTGRESQL_URL` and `CLOUDRON_MAIL_SMTP_SERVER/PORT/USERNAME/PASSWORD`; the app reads `DATABASE_URL` / `SMTP_URL`. Recommended approach: read both names in [`lib/server/env.ts`](../../lib/server/env.ts) and assemble `SMTP_URL` from the four parts in [`lib/server/mail.ts`](../../lib/server/mail.ts) when only the Cloudron names are present. Alternative: a `start.sh` shim in the image. Acceptance: with only `CLOUDRON_*` set, app connects to DB and sends mail; with only canonical names set (current behavior), unchanged; unit tests cover both.
|
||||
2. **Container image registry: choose, build, push.** Acceptance: `docker pull <registry>/communityrule:<tag>` works from a Cloudron-reachable network. CI builds and pushes on merge to `main` (stretch).
|
||||
3. **Cloudron staging install + smoke.** Acceptance: `curl https://<staging>/api/health` returns `{"ok":true,"database":"connected"}`; magic-link request → click link → `GET /api/auth/session` returns a user; publishing a rule succeeds.
|
||||
4. **Cloudron production install + DNS cutover.** Acceptance: production subdomain resolves to the new app; old subdomain still works during overlap; sign-in + publish succeed against production; backups confirmed.
|
||||
5. **Steady-state operator runbook.** Lives at `docs/guides/ops-runbook.md` (sibling to the handoff). Covers deploy a new version, rollback, restore drill cadence, multi-instance limitations from [`backend-roadmap.md`](backend-roadmap.md) §5/§7. Acceptance: a fresh reader can deploy + roll back using only this doc.
|
||||
6. **Decommission legacy Express/MySQL backend.** Acceptance: old Cloudron app stopped + uninstalled; old MySQL addon backed up once and removed; legacy Gitea repo README updated to point at this app. Priority: Low.
|
||||
|
||||
---
|
||||
|
||||
@@ -661,7 +691,7 @@ _Section B — Final Review screen `+` button per category:_
|
||||
| 9 | 9 | Web vitals persistence |
|
||||
| 10 | 10 | Public rule detail (optional) |
|
||||
| 11 | 11 | CI migrate smoke (optional) |
|
||||
| 12 | 12 | Ops runbook |
|
||||
| 12 | 12 | Ops admin handoff (Cloudron) **Done** |
|
||||
| 13 | 13 | API errors + request-id logging |
|
||||
| 14 | 14 | Session lifecycle + cleanup |
|
||||
| 15 | 15 | Profile + account (Figma profile) |
|
||||
@@ -678,7 +708,7 @@ Tickets **10–11** can be deferred without blocking the core “auth + drafts +
|
||||
|
||||
## Linear (Community-rule team)
|
||||
|
||||
**Main chain (historical):** **CR-72 → CR-83** was the original **strict sequence**; **repo + Linear status today:** **CR-72–CR-79**, **CR-88**, **CR-89** are **Done**; **CR-77** (publish) **Done**; **CR-80–CR-83** remain **Backlog** (web vitals, public rule detail, CI migrate smoke, ops runbook — optional / ops tail). **Parallel:** **CR-84**, **CR-85** (**Backlog**); **CR-86** / Ticket 15 (**Backlog** — publish **not** a blocker); **CR-93** (**Backlog**); **CR-90** / Ticket 18 (stakeholder invites); **CR-91** / Ticket 19 (`Add` button behavior).
|
||||
**Main chain (historical):** **CR-72 → CR-83** was the original **strict sequence**; **repo + Linear status today:** **CR-72–CR-79**, **CR-83**, **CR-88**, **CR-89** are **Done**; **CR-77** (publish) **Done**; **CR-80–CR-82** remain **Backlog** (web vitals, public rule detail, CI migrate smoke). **CR-83** (admin handoff) shipped as a narrow handoff sheet; the actual Cloudron deployment pipeline is split into the **`[Backend]` follow-up tickets** filed under it (env-var bridging → image registry → staging → production cutover → operator runbook → legacy decommission). **Parallel:** **CR-84**, **CR-85** (**Backlog**); **CR-86** / Ticket 15 (**Backlog** — publish **not** a blocker); **CR-93** (**Backlog**); **CR-90** / Ticket 18 (stakeholder invites); **CR-91** / Ticket 19 (`Add` button behavior).
|
||||
|
||||
| Doc ticket | Linear | Title (short) |
|
||||
| ---------: | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
|
||||
@@ -693,7 +723,13 @@ Tickets **10–11** can be deferred without blocking the core “auth + drafts +
|
||||
| 9 | [CR-80](https://linear.app/community-rule/issue/CR-80/backend-persist-web-vitals-outside-next-db-or-external-rum) | Web vitals (prefer external) |
|
||||
| 10 | [CR-81](https://linear.app/community-rule/issue/CR-81/backend-public-rule-detail-page-get-apirulesid-optional) | Public rule detail (optional) |
|
||||
| 11 | [CR-82](https://linear.app/community-rule/issue/CR-82/backend-ci-postgres-migration-smoke-optional) | CI migrate smoke (optional) |
|
||||
| 12 | [CR-83](https://linear.app/community-rule/issue/CR-83/backend-stagingproduction-runbook-admin-handoff-docsops-backend) | Ops runbook / admin handoff |
|
||||
| 12 | [CR-83](https://linear.app/community-rule/issue/CR-83/backend-stagingproduction-runbook-admin-handoff-docsops-backend) | Ops admin handoff (Cloudron) **Done** |
|
||||
| 12.1 | [CR-96](https://linear.app/community-rule/issue/CR-96/backend-bridge-cloudron-env-vars-to-canonical-names) | `[Backend] Bridge CLOUDRON_* env vars to canonical names` |
|
||||
| 12.2 | [CR-97](https://linear.app/community-rule/issue/CR-97/backend-container-image-registry-choose-build-push) | `[Backend] Container image registry: choose, build, push` |
|
||||
| 12.3 | [CR-98](https://linear.app/community-rule/issue/CR-98/backend-cloudron-staging-install-smoke) | `[Backend] Cloudron staging install + smoke` |
|
||||
| 12.4 | [CR-99](https://linear.app/community-rule/issue/CR-99/backend-cloudron-production-install-dns-cutover) | `[Backend] Cloudron production install + DNS cutover` |
|
||||
| 12.5 | [CR-100](https://linear.app/community-rule/issue/CR-100/backend-steady-state-operator-runbook) | `[Backend] Steady-state operator runbook` |
|
||||
| 12.6 | [CR-101](https://linear.app/community-rule/issue/CR-101/backend-decommission-legacy-expressmysql-backend) | `[Backend] Decommission legacy Express/MySQL backend` |
|
||||
| 13 | [CR-84](https://linear.app/community-rule/issue/CR-84/backend-api-error-contract-request-id-logging) | API errors + request-id logging |
|
||||
| 14 | [CR-85](https://linear.app/community-rule/issue/CR-85/backend-custom-session-lifecycle-cleanup-invalidation-policy) | Session lifecycle + cleanup |
|
||||
| 15 | [CR-86](https://linear.app/community-rule/issue/CR-86/backend-profile-dashboard-account-figma-profile) | Profile + account (Figma 22143:900069) |
|
||||
|
||||
@@ -206,13 +206,15 @@ npm run dev
|
||||
|
||||
**Optional QA:** Run automated tests against an **ephemeral** database in CI instead of maintaining a fourth long-lived server.
|
||||
|
||||
**Target platform:** **Cloudron at MEDLab** — same host as the legacy [`CommunityRule/CommunityRuleBackend`](https://git.medlab.host/CommunityRule/CommunityRuleBackend) (Express + MySQL). The new app is packaged as a proper Cloudron app (Docker image + `CloudronManifest.json`, **postgresql + sendmail + localstorage** addons). Cloudron's container supervisor replaces the legacy 30-min `run.sh` watchdog. Admin handoff (access, env vars, platform settings, open decisions): [`docs/guides/ops-backend-deploy.md`](ops-backend-deploy.md). Note: Cloudron injects `CLOUDRON_POSTGRESQL_URL` and `CLOUDRON_MAIL_SMTP_*`; the app reads `DATABASE_URL` / `SMTP_URL`, so a small env-var bridge in [`lib/server/env.ts`](../../lib/server/env.ts) / [`lib/server/mail.ts`](../../lib/server/mail.ts) is needed (tracked in [**CR-96**](https://linear.app/community-rule/issue/CR-96/backend-bridge-cloudron-env-vars-to-canonical-names), filed under CR-83 — see [backend-linear-tickets.md](backend-linear-tickets.md) Ticket 12 follow-ups).
|
||||
|
||||
**Admin / infra (coordinate with whoever runs the server):**
|
||||
|
||||
1. TLS certificates and hostnames.
|
||||
2. PostgreSQL backups and restore drill.
|
||||
3. SMTP DNS (SPF, DKIM).
|
||||
4. Health check URL for reverse proxy (`/api/health`).
|
||||
5. Log retention and alerts for 5xx errors.
|
||||
1. TLS certificates and hostnames. _On Cloudron: handled by the platform per chosen subdomain._
|
||||
2. PostgreSQL backups and restore drill. _On Cloudron: daily snapshots; configure retention in admin UI._
|
||||
3. SMTP DNS (SPF, DKIM). _On Cloudron: handled for the platform-managed domain._
|
||||
4. Health check URL for reverse proxy (`/api/health`). _On Cloudron: set `healthCheckPath` in `CloudronManifest.json`._
|
||||
5. Log retention and alerts for 5xx errors. _On Cloudron: app log viewer; export off-platform if longer retention is needed._
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
# Backend deploy — admin handoff
|
||||
|
||||
This is the list of access, environment variables, and platform decisions
|
||||
needed to deploy CommunityRule (the new Next.js + Postgres app in this
|
||||
repo) onto MEDLab's Cloudron. Hand it to the Cloudron admin; once they
|
||||
confirm what is checked below, the actual deploy happens in the
|
||||
follow-up tickets listed in §8.
|
||||
|
||||
## 1. Context
|
||||
|
||||
- This app **replaces** the old Express + MySQL backend at
|
||||
[`CommunityRule/CommunityRuleBackend`](https://git.medlab.host/CommunityRule/CommunityRuleBackend).
|
||||
- It is packaged as a real Cloudron app (Docker image +
|
||||
`CloudronManifest.json`). No `/app/data` drop-in. No `run.sh`
|
||||
watchdog — Cloudron's container supervisor handles restarts.
|
||||
- **Greenfield Postgres.** No data migration from the old MySQL addon.
|
||||
Old auth (4-digit OTP in `email_otp`) is replaced by hashed
|
||||
magic-link tokens; old API and `rules` / `version_history` tables do
|
||||
not map to anything in the new app.
|
||||
|
||||
## 2. Access I need
|
||||
|
||||
Check off as granted:
|
||||
|
||||
- [ ] **Cloudron admin login** for the MEDLab instance, or "deploy
|
||||
app" capability scoped to one app slot.
|
||||
- [ ] **Container registry credentials** — read/write to wherever
|
||||
images get pushed (Docker Hub, GHCR, MEDLab self-hosted registry —
|
||||
admin's choice; see §6).
|
||||
- [ ] **DNS** — ability to add/edit a subdomain record pointing at the
|
||||
Cloudron host, or confirmation that admin will add the records I
|
||||
specify.
|
||||
- [ ] **`cloudron` CLI access** from my workstation (token-based; no
|
||||
SSH needed for normal ops).
|
||||
- [ ] **Cloudron app log access** — web UI is fine; SSH only if web
|
||||
logs aren't enough.
|
||||
- [ ] **Read access to the existing legacy app's Cloudron config** so
|
||||
I can confirm domain / cert / SMTP setup before cutover.
|
||||
|
||||
## 3. Environment variables
|
||||
|
||||
### Cloudron auto-injects (admin: confirm the addons are enabled)
|
||||
|
||||
- `CLOUDRON_POSTGRESQL_URL` — from the **postgresql** addon. The app
|
||||
reads `DATABASE_URL`; bridging is a small in-app code change (see
|
||||
§8 ticket 1).
|
||||
- `CLOUDRON_MAIL_SMTP_SERVER` / `_PORT` / `_USERNAME` / `_PASSWORD` —
|
||||
from the **sendmail** addon. The app reads `SMTP_URL`; bridged the
|
||||
same way.
|
||||
|
||||
### I set manually via `cloudron configure --app <id> --set-env`
|
||||
|
||||
- `SESSION_SECRET` — long random (`openssl rand -hex 32`). Required,
|
||||
≥ 16 chars. Rotating it logs everyone out.
|
||||
- `SMTP_FROM` — visible "From:" address on sign-in emails. Cloudron
|
||||
does **not** inject this. Recommend `hello@communityrule.info` (same
|
||||
as the old service) unless admin wants a new address.
|
||||
- `NEXT_PUBLIC_ENABLE_BACKEND_SYNC=true` — turns on Postgres draft
|
||||
persistence for signed-in users. Recommended for production.
|
||||
|
||||
## 4. Platform settings to confirm
|
||||
|
||||
- Container `httpPort`: **3000** (matches [`Dockerfile`](../../Dockerfile)
|
||||
`ENV PORT=3000`).
|
||||
- Health-check path: **`/api/health`**
|
||||
([`app/api/health/route.ts`](../../app/api/health/route.ts) returns
|
||||
`200 {"ok":true,"database":"connected"}` when healthy, `503`
|
||||
otherwise).
|
||||
- Memory limit: start at **512 MB**; raise if Next.js standalone OOMs
|
||||
under load.
|
||||
- Backups: confirm Cloudron's daily snapshot is on for both this app
|
||||
and its postgresql addon.
|
||||
- TLS, DNS, SPF/DKIM: handled by Cloudron for the chosen subdomain —
|
||||
confirm.
|
||||
|
||||
## 5. Decisions I need from admin
|
||||
|
||||
1. **Subdomains** for staging and production. Default proposal:
|
||||
`staging-app.communityrule.info` + `app.communityrule.info`.
|
||||
2. **Sender address** — reuse legacy `hello@communityrule.info`, or
|
||||
pick a new one?
|
||||
3. **Container registry** — MEDLab self-hosted, Docker Hub (under
|
||||
what org), or GHCR?
|
||||
4. **Cutover overlap** — how many days should the old service keep
|
||||
running in parallel before we uninstall it?
|
||||
5. **Backup retention** beyond Cloudron defaults? (If "defaults are
|
||||
fine," say so.)
|
||||
|
||||
## 6. What is intentionally NOT in this doc
|
||||
|
||||
So admin doesn't expect more than this scope:
|
||||
|
||||
- The deploy runbook itself (build / push / install / migrate / smoke
|
||||
/ rollback) — written **after** access in §2 is granted; see §8
|
||||
ticket 5.
|
||||
- Code changes to bridge `CLOUDRON_*` env vars to `DATABASE_URL` /
|
||||
`SMTP_URL` — I do those locally and ship the image with bridging
|
||||
built in; see §8 ticket 1.
|
||||
- Decommissioning the legacy Express/MySQL service — does not happen
|
||||
until the new app is green in production; see §8 ticket 6.
|
||||
|
||||
## 7. Old vs new backend deltas
|
||||
|
||||
So nothing surprises admin or users at cutover:
|
||||
|
||||
- Old addons: **MySQL + sendmail**. New addons: **postgresql +
|
||||
sendmail + localstorage**. Different DB addon entirely; do not
|
||||
reuse the old one.
|
||||
- Old service ran from `/app/data/public/communityRuleBackend` with a
|
||||
30-min `lsof`-based `run.sh` watchdog — not a packaged Cloudron
|
||||
app. New app is a proper Cloudron app; Cloudron supervises it.
|
||||
- Old auth = plaintext 4-digit OTP. New auth = magic **link** in
|
||||
email. If users report "I'm not getting a code," remind them to
|
||||
look for a link.
|
||||
- Old code hardcoded `from: 'hello@communityrule.info'` in
|
||||
[`controllers/emailController.js`](https://git.medlab.host/CommunityRule/CommunityRuleBackend/raw/branch/master/controllers/emailController.js)
|
||||
because Cloudron does not inject a `MAIL_FROM`. New app reads
|
||||
`SMTP_FROM` — see §3.
|
||||
- Old API surface (`/api/send_otp`, `/api/publish_rule`, etc.) and
|
||||
schema (`rules` + `version_history` tables, soft-delete via
|
||||
`deleted` column) **do not overlap**. No data migration.
|
||||
|
||||
## 8. Follow-up tickets
|
||||
|
||||
All filed in Linear, titled `[Backend] …`, assigned to me, in the
|
||||
**Community-rule** team, **Backlog** state.
|
||||
|
||||
1. [**CR-96**](https://linear.app/community-rule/issue/CR-96/backend-bridge-cloudron-env-vars-to-canonical-names)
|
||||
— `[Backend] Bridge CLOUDRON_* env vars to canonical names`. No
|
||||
admin dependency; can land now.
|
||||
2. [**CR-97**](https://linear.app/community-rule/issue/CR-97/backend-container-image-registry-choose-build-push)
|
||||
— `[Backend] Container image registry: choose, build, push`.
|
||||
Depends on registry decision (§5).
|
||||
3. [**CR-98**](https://linear.app/community-rule/issue/CR-98/backend-cloudron-staging-install-smoke)
|
||||
— `[Backend] Cloudron staging install + smoke`. Blocked by CR-96
|
||||
+ CR-97; needs Cloudron CLI access + staging DNS.
|
||||
4. [**CR-99**](https://linear.app/community-rule/issue/CR-99/backend-cloudron-production-install-dns-cutover)
|
||||
— `[Backend] Cloudron production install + DNS cutover`. Blocked
|
||||
by CR-98 green for the agreed overlap window.
|
||||
5. [**CR-100**](https://linear.app/community-rule/issue/CR-100/backend-steady-state-operator-runbook)
|
||||
— `[Backend] Steady-state operator runbook`. Blocked by CR-98
|
||||
(we write it after we've actually done it).
|
||||
6. [**CR-101**](https://linear.app/community-rule/issue/CR-101/backend-decommission-legacy-expressmysql-backend)
|
||||
— `[Backend] Decommission legacy Express/MySQL backend`. Blocked
|
||||
by CR-99 + sign-off window. Priority: Low.
|
||||
|
||||
## 9. Related docs
|
||||
|
||||
- [`docs/guides/backend-roadmap.md`](backend-roadmap.md) §11
|
||||
(environments) and §8 (Prisma migrations policy).
|
||||
- [`docs/guides/backend-linear-tickets.md`](backend-linear-tickets.md)
|
||||
Ticket 12 / CR-83 — this doc satisfies it.
|
||||
- [`CONTRIBUTING.md`](../../CONTRIBUTING.md) — local dev setup
|
||||
(Postgres, magic-link, draft sync).
|
||||
Reference in New Issue
Block a user