# Cibello — drift & uppdaterings-runbook Så uppdaterar vi prod **säkert och repeterbart**. Gäller EC2 `cibello-prod-app` (eu-north-1). Koden hämtas från Gitea (`git.aamos.systems/platform-admin/Cibello-app`, gren `master`) via en **read-only** deploy-koppling. Secrets (`.env`, `secrets/*.env`) är otrackade i git och rörs aldrig. ## Karta | Del | Var | |-----|-----| | Kod på servern | `/opt/cibello-platform` (symlänk `/opt/app-platform`) | | Compose | `infrastructure/docker/docker-compose.production.yml` | | Tjänster | `app-api` (:4100→4000), `app-worker`, `app-admin` (:4180→8080), `app-redis` | | Ops-container | `app-tools` (profile `tools`, startar ej med `up`) — migrera/seed | | Databas | RDS Postgres 16, databas `cibello` | Kör docker-kommandon som root (eller `sudo`). Git körs som ägaren `ubuntu`. Nedan förkortas `-f infrastructure/docker/docker-compose.production.yml` till `-f $C`. --- ## 1. Vanlig uppdatering (buggfix / ny funktion / ändrad kod) **På din maskin:** committa och pusha till Gitea `master`. **På servern:** ett kommando — hämtar, bygger, migrerar, startar om, healthcheckar, och **rullar tillbaka automatiskt** om API:t inte svarar: ```bash sudo bash /opt/cibello-platform/infrastructure/deployment/deploy.sh ``` Klart när det står `DEPLOY KLAR: (healthz OK)`. --- ## 2. Lägga till / uppdatera recept (och andra seed-data) Recept, ingredienser och översättningar ligger i `packages/database/src/seed/data/`. Seed är **idempotent** (upsert) och **rör aldrig `users`** — den lägger bara till/uppdaterar katalogen. Den kan aldrig radera prod-data (TRUNCATE kräver `--test` + databasnamn som slutar på `_test`; prod heter `cibello`). 1. Uppdatera seed-datan i repot, committa, pusha till Gitea. 2. Kör en vanlig deploy (steg 1) så koden är i synk. 3. Kör seed via tools-containern: ```bash C=/opt/cibello-platform/infrastructure/docker/docker-compose.production.yml sudo docker compose -f "$C" build app-tools sudo docker compose -f "$C" --profile tools run --rm app-tools \ tsx packages/database/src/seed/run.ts ``` 4. Verifiera antal (ändrar inget): ```bash sudo docker exec -i app-api node -e 'const{Client}=require("pg");const u=(process.env.DATABASE_URL||"").replace(/[?&]sslmode=[^&]+/g,"").replace(/\?$/,"");const c=new Client({connectionString:u,ssl:/localhost|127\.0\.0\.1/.test(u)?false:{rejectUnauthorized:false}});c.connect().then(()=>c.query("select (select count(*) from recipes) recipes,(select count(*) from canonical_ingredients) ingredients,(select count(*) from users) users")).then(r=>{console.log(r.rows[0]);return c.end()}).catch(e=>{console.error(e.message);process.exit(1)})' ``` > **Rekommendation:** ta en RDS-snapshot före en stor seed, som extra skyddsnät. --- ## 3. Lägga till ett nytt språk i18n-verktygen finns i `apps/mobile/scripts/` och `apps/worker/scripts/` (`i18n-add-language`, `translate-recipes`, `verify-translations` m.fl.). 1. Kör i18n-add-language för det nya språket, generera + verifiera översättningar lokalt. 2. Committa (locale-filer + ev. `recipe_translations`/`ingredient_translations`-seed), pusha. 3. Deploy (steg 1) + seed (steg 2) så översättningarna hamnar i prod-DB. 4. Mobilappen: släpp en ny build med det nya språket (App Store / Google Play). --- ## 4. Schema-ändringar (migreringar) Migreringar körs **automatiskt i `deploy.sh`** (steg 1) via tools-containern. `migrate.ts` applicerar bara journal-poster nyare än det som redan är kört — klart no-op om inget nytt finns, och rör bara schema, aldrig data. Kör en migrering separat (utan full deploy): ```bash C=/opt/cibello-platform/infrastructure/docker/docker-compose.production.yml sudo docker compose -f "$C" build app-tools sudo docker compose -f "$C" --profile tools run --rm app-tools \ tsx packages/database/src/migrate.ts ``` > **Alltid RDS-snapshot före migreringar** som lägger till/ändrar kolumner. --- ## 5. Admin-panelen Admin byggs **inte** av `deploy.sh` (den har en build-arg `VITE_API_BASE_URL` som bakas in vid bygget). Bygg om admin separat när dess kod ändras: ```bash C=/opt/cibello-platform/infrastructure/docker/docker-compose.production.yml sudo docker compose -f "$C" build app-admin # build-arg sätts i compose till https://api.cibello.app sudo docker compose -f "$C" up -d app-admin ``` --- ## 6. Rollback `deploy.sh` rullar tillbaka **automatiskt** om healthz inte svarar efter en deploy. Manuell rollback till föregående commit: ```bash sudo -H -u ubuntu git -C /opt/cibello-platform reset --hard C=/opt/cibello-platform/infrastructure/docker/docker-compose.production.yml sudo docker compose -f "$C" build app-api app-worker sudo docker compose -f "$C" up -d app-api app-worker ``` Databas: återställ från RDS-snapshot (konsolen) om en migrering behöver rullas tillbaka. --- ## 7. Snabb hälsokoll ```bash curl -s -o /dev/null -w "internt: %{http_code}\n" http://127.0.0.1:4100/healthz curl -s -o /dev/null -w "externt: %{http_code}\n" https://api.cibello.app/healthz sudo docker compose -f /opt/cibello-platform/infrastructure/docker/docker-compose.production.yml ps ``` --- ## 8. Nollställa användardata (försiktigt) Använd **`DELETE FROM users`**, aldrig `TRUNCATE users CASCADE`. Recept har en FK `creator_user_id → users` med `ON DELETE SET NULL`: `DELETE` respekterar det och **behåller receptkatalogen** (nollställer bara skaparen), medan `TRUNCATE ... CASCADE` ignorerar `SET NULL` och sveper med hela recept-tabellen. Ta alltid en RDS-snapshot först, och kör SQL:en via samma `docker exec app-api node`-mönster som db-koll-scripten.