Package the app as a Cloudron app: CloudronManifest.json, production Dockerfile, scripts/start.sh (migrate + privilege drop), and scripts/docker-release.sh (buildx push to Gitea).
Document the closed registry decision (Gitea Container Registry on git.medlab.host) and the operator build/push/install workflow in docs/guides/ops-backend-deploy.md §9.
Drop legacy Storybook peer deps: remove @storybook/addon-interactions, import interaction helpers from storybook/test, and bump next-intl to v4 so npm ci stays clean inside the Docker build.
Run container locally with CLOUDRON_POSTGRESQL_URL + SESSION_SECRET; confirm GET /api/health returns {"ok":true,"database":"connected"} after migrations
npm run storybook — interaction stories still run
npx vitest run — unit/component suite passes
## Summary
- Package the app as a Cloudron app: `CloudronManifest.json`, production `Dockerfile`, `scripts/start.sh` (migrate + privilege drop), and `scripts/docker-release.sh` (buildx push to Gitea).
- Document the closed registry decision (Gitea Container Registry on `git.medlab.host`) and the operator build/push/install workflow in `docs/guides/ops-backend-deploy.md` §9.
- Drop legacy Storybook peer deps: remove `@storybook/addon-interactions`, import interaction helpers from `storybook/test`, and bump `next-intl` to v4 so `npm ci` stays clean inside the Docker build.
## What changed
### Cloudron packaging (CR-97)
- **`CloudronManifest.json`** — declares `httpPort 3000`, `healthCheckPath /api/health`, 768 MiB memory limit, and `postgresql + sendmail + localstorage` addons; pins image ref `git.medlab.host/communityrule/community-rule:0.1.0`.
- **`Dockerfile`** — production-oriented multi-stage build:
- `npm ci --ignore-scripts` in deps stage (schema not present yet; `prisma generate` runs in builder).
- Reuses base image `node` user (uid 1000) for Cloudron localstorage mount compatibility.
- Copies Prisma CLI into the runner so `start.sh` can run `prisma migrate deploy`.
- Symlinks `.next/cache → /tmp/next-cache` so ISR works on Cloudron's read-only rootfs.
- **`scripts/start.sh`** — chowns `/app/data` and `/tmp/next-cache`, drops to `node:node` via `gosu`, runs migrations, execs Next.js standalone server.
- **`scripts/docker-release.sh`** + **`npm run docker:release`** — cross-platform `linux/amd64` buildx push to the Gitea registry.
### Docs
- **`docs/guides/ops-backend-deploy.md`** — registry decision closed (§6.3); new §9 build/push/install runbook; CR-97 status updated. Staging install (CR-98) remains blocked on CR-96 env bridging.
### Storybook / deps cleanup
- Remove `@storybook/addon-interactions` (merged into Storybook 8+ core); stories import from `storybook/test`.
- Bump `next-intl` to `^4.0.0`; refresh lockfile.
## Test plan
- [x] `npx tsc --noEmit`
- [x] `./scripts/docker-release.sh` — builds and pushes to `git.medlab.host/communityrule/community-rule:<tag>` (requires Gitea PAT + `docker login`)
- [x] `docker logout git.medlab.host && docker pull git.medlab.host/communityrule/community-rule:<tag>` — anonymous pull succeeds (Cloudron simulation)
- [x] Run container locally with `CLOUDRON_POSTGRESQL_URL` + `SESSION_SECRET`; confirm `GET /api/health` returns `{"ok":true,"database":"connected"}` after migrations
- [x] `npm run storybook` — interaction stories still run
- [x] `npx vitest run` — unit/component suite passes
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
CloudronManifest.json, productionDockerfile,scripts/start.sh(migrate + privilege drop), andscripts/docker-release.sh(buildx push to Gitea).git.medlab.host) and the operator build/push/install workflow indocs/guides/ops-backend-deploy.md§9.@storybook/addon-interactions, import interaction helpers fromstorybook/test, and bumpnext-intlto v4 sonpm cistays clean inside the Docker build.What changed
Cloudron packaging (CR-97)
CloudronManifest.json— declareshttpPort 3000,healthCheckPath /api/health, 768 MiB memory limit, andpostgresql + sendmail + localstorageaddons; pins image refgit.medlab.host/communityrule/community-rule:0.1.0.Dockerfile— production-oriented multi-stage build:npm ci --ignore-scriptsin deps stage (schema not present yet;prisma generateruns in builder).nodeuser (uid 1000) for Cloudron localstorage mount compatibility.start.shcan runprisma migrate deploy..next/cache → /tmp/next-cacheso ISR works on Cloudron's read-only rootfs.scripts/start.sh— chowns/app/dataand/tmp/next-cache, drops tonode:nodeviagosu, runs migrations, execs Next.js standalone server.scripts/docker-release.sh+npm run docker:release— cross-platformlinux/amd64buildx push to the Gitea registry.Docs
docs/guides/ops-backend-deploy.md— registry decision closed (§6.3); new §9 build/push/install runbook; CR-97 status updated. Staging install (CR-98) remains blocked on CR-96 env bridging.Storybook / deps cleanup
@storybook/addon-interactions(merged into Storybook 8+ core); stories import fromstorybook/test.next-intlto^4.0.0; refresh lockfile.Test plan
npx tsc --noEmit./scripts/docker-release.sh— builds and pushes togit.medlab.host/communityrule/community-rule:<tag>(requires Gitea PAT +docker login)docker logout git.medlab.host && docker pull git.medlab.host/communityrule/community-rule:<tag>— anonymous pull succeeds (Cloudron simulation)CLOUDRON_POSTGRESQL_URL+SESSION_SECRET; confirmGET /api/healthreturns{"ok":true,"database":"connected"}after migrationsnpm run storybook— interaction stories still runnpx vitest run— unit/component suite passes