Files
community-rule/docs/guides/ops-backend-deploy.md
T
2026-04-22 18:54:32 -06:00

7.1 KiB

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.
  • 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 ENV PORT=3000).
  • Health-check path: /api/health (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 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[Backend] Bridge CLOUDRON_* env vars to canonical names. No admin dependency; can land now.
  2. CR-97[Backend] Container image registry: choose, build, push. Depends on registry decision (§5).
  3. CR-98[Backend] Cloudron staging install + smoke. Blocked by CR-96
    • CR-97; needs Cloudron CLI access + staging DNS.
  4. CR-99[Backend] Cloudron production install + DNS cutover. Blocked by CR-98 green for the agreed overlap window.
  5. CR-100[Backend] Steady-state operator runbook. Blocked by CR-98 (we write it after we've actually done it).
  6. CR-101[Backend] Decommission legacy Express/MySQL backend. Blocked by CR-99 + sign-off window. Priority: Low.