From 2abcdd7c58b607b1d089342fc574452987bde9f5 Mon Sep 17 00:00:00 2001 From: Ryan Westfall Date: Sun, 6 Sep 2026 06:35:48 -0700 Subject: [PATCH] Register print_forge for django deploy (closes #27) (#28) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Closes [#27](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/27). - Register `print_forge` in `app_catalog` (`type: django`, repo `ai_ml_operations/print_forge`, default branch `master`). - Add `host_apps` prod `:8007` / beta `:8019` on **adama**, **roslin**, **starbuck**, **apollo**, and **ai-server-4080**. - dj-queue **worker singleton on adama** only (`compose_profiles: [worker]`); other hosts web-only. - Document ports, NPM hosts, Postgres DBs, secrets, Nominatim (`10.0.0.128:8089`), and the app-repo companion ([print_forge#1](https://git.aimloperations.com/ai_ml_operations/print_forge/issues/1)). - Update `scripts/deploy.sh` `--app` help. - Move unused `abc_be` prod port reserve **8007 → 8009** so it does not collide with `print_forge`. ## Test plan - [ ] Confirm `print_forge` appears in `app_catalog` and `--app print_forge` is listed in `deploy.sh --help` - [ ] Confirm beta `host_apps` on all five hosts (port **8019**); adama has `compose_profiles: [worker]` - [ ] Confirm prod port **8007** reserved on those hosts (no NPM until launch) - [ ] After merge (ops, not this PR): create Postgres DBs `print_forge_beta` + `print_forge` on `10.0.0.230`, grant `westfarn` - [ ] After merge (ops): write `~/Documents/secrets/print_forge/print_forge_{beta,prod}.env` from app `.env.prod.example`; add `print_forge:` to `SHORTENER_API_TOKENS` (beta first) - [ ] After merge (ops): NPM `print-forge-preview.aimloperations.com` → `:8019` active/active; do **not** NPM-route `printforgeprints.com` until launch - [ ] After secrets + DBs: `~/Documents/repos/server-infra/scripts/deploy.sh --app print_forge --env beta --ref master` and hit `/healthz/` Reviewed-on: https://git.aimloperations.com/ai_ml_operations/server-infra/pulls/28 --- IMPLEMENTATION.md | 35 +++++++++++++++++++++----- inventory/group_vars/all.yml | 9 +++++++ inventory/host_vars/adama.yml | 2 ++ inventory/host_vars/ai-server-4080.yml | 4 ++- inventory/host_vars/apollo.yml | 4 ++- inventory/host_vars/roslin.yml | 4 ++- inventory/host_vars/starbuck.yml | 4 ++- roles/app-deploy/tasks/django.yml | 2 +- scripts/deploy.sh | 2 +- 9 files changed, 54 insertions(+), 12 deletions(-) diff --git a/IMPLEMENTATION.md b/IMPLEMENTATION.md index 3a224df..01688b6 100644 --- a/IMPLEMENTATION.md +++ b/IMPLEMENTATION.md @@ -217,6 +217,7 @@ After Docker install, re-SSH so the `docker` group membership takes effect. | `monica_site` | django (docker) | all webservers | beta + prod | active/active behind NPM; no bundled Postgres (like `scha`); dj-queue **worker singleton on adama** only (`compose --profile worker`); Ollama social drafting via `10.0.0.128:11434` | | `url_shortening_service` | django (docker) | all webservers | beta + prod | active/active behind NPM; no bundled Postgres; **no worker**. Two public hosts, same container: short domain (`GET /`, `GET /` 302) and API host (`/api/links/`, Bearer required). | | `college_craft` | django (docker) | all webservers | beta + prod | active/active behind NPM; no bundled Postgres (like `scha` / `monica_site`); dj-queue **worker singleton on adama** only (`compose --profile worker`); Ollama social drafting via `10.0.0.128:11434`; Nominatim `http://10.0.0.128:8089`; prod `SITE_UNDER_CONSTRUCTION=true` until launch | +| `print_forge` | django (docker) | all webservers | beta + prod | active/active behind NPM; no bundled Postgres (like `scha` / `monica_site` / `college_craft`); dj-queue **worker singleton on adama** only (`compose --profile worker`); Nominatim `http://10.0.0.128:8089`; prod `SITE_UNDER_CONSTRUCTION=true` until launch; prod NPM waits until launch | | `abc_be` | django (docker) | all webservers | **beta only** | AI Benefits Coach API; no bundled Postgres; Ollama `http://10.0.0.128:11434`; shares DB `abc_be_beta` with `abc_worker` | | `abc_worker` | django-type compose (FastAPI) | all webservers | **beta only** | same Postgres as `abc_be`; `migrate_cmd: true`; WS on host port 8018 | | `abc_fe` | node-static (Vite) | all webservers | **beta only** | built to `/var/www/.abc.aimloperations/html`; no prod `host_apps` row | @@ -230,7 +231,7 @@ a DB. - `app_catalog` (`group_vars/all.yml`) — how each app is built (repo, type, compose file, migrate cmd). - `host_apps` (`host_vars/.yml`) — which app+env+port runs on that host. Optional `compose_profiles: [worker]` activates docker compose profiles on that - host only (used for `monica_site` / `college_craft` dj-queue singleton on adama). + host only (used for `monica_site` / `college_craft` / `print_forge` dj-queue singleton on adama). - Django app = one compose project per env: project name `_`, host port from `host_apps`. Ports match across app hosts so NPM can balance `adama:PORT` + `roslin:PORT` + `starbuck:PORT` + `apollo:PORT`. @@ -249,7 +250,8 @@ future beta replica. | monica_site | 8014 | 8004 | all webservers | | url_shortening_service | 8015 | 8005 | all webservers | | college_craft | 8016 | 8006 | all webservers | -| abc_be | **8017** | 8007 (*not deployed*) | all webservers | +| print_forge | **8019** | **8007** | all webservers | +| abc_be | **8017** | 8009 (*not deployed*) | all webservers | | abc_worker | **8018** | 8008 (*not deployed*) | all webservers | | dta_webapp (nginx) | 8081 | 8080 | all webservers | | chat_web_app (nginx) | 8083 | 8082 | all webservers | @@ -261,7 +263,7 @@ Host-local services on ai-server-4080 (not balanced by NPM): | Service | Port | Notes | |---------|------|-------| | Ollama | 11434 | Not Ansible-managed today; GPU host (`monica_site` / `college_craft` social drafting) | -| Nominatim | 8089 | Not Ansible-managed today; LAN address autocomplete for `college_craft` | +| Nominatim | 8089 | Not Ansible-managed today; LAN address autocomplete for `college_craft` / `print_forge` | | SearxNG | 8088 | `roles/searxng` (#10); JSON API for chat_backend grounded search | | Loki | 3100 | `roles/observability` | | Prometheus | 9090 | `roles/observability` | @@ -287,7 +289,7 @@ chat_backend secrets must use `SEARXNG_BASE_URL=http://10.0.0.128:8088`. to host `{{ apps_env_dir }}` → git checkout at ref → copy `.env` into checkout → `docker compose build` → `up -d` (with `COMPOSE_PROFILES` from optional `host_apps.compose_profiles`) → migrate (run once, shared DB). - **`monica_site` / `college_craft` worker:** adama `host_apps` sets + **`monica_site` / `college_craft` / `print_forge` worker:** adama `host_apps` sets `compose_profiles: [worker]` so deploy starts dj-queue with web. Other hosts omit profiles (web only). - **node-static**: git checkout at ref → `npm ci` → `npm run build:` @@ -320,6 +322,7 @@ point each domain at the backend(s): | url_shortening_service (short) | `aiml.pw` and/or `cidinn.li` (pick when DNS is ready); `short-beta.aimloperations.com` (beta). Proxy `/` + `/[a-z0-9]{4,8}` only — 404 `/api/`, `/admin/`, `/debug/` | `adama:8005` / `8015` + same on roslin / starbuck / apollo / ai-server-4080 | | url_shortening_service (API) | `shortener.aimloperations.com`; `shortener-beta.aimloperations.com` (beta). Proxy `/api/` only — 404 `/admin/` | same ports as short host (one container) | | college_craft | `collegecraft.com` (+ www); `college-craft-preview.aimloperations.com` (beta) | `adama:8006` / `8016` + same on roslin / starbuck / apollo / ai-server-4080 | +| print_forge | `printforgeprints.com` (+ www) — **do not NPM-route prod until launch**; `print-forge-preview.aimloperations.com` (beta) | `adama:8007` / `8019` + same on roslin / starbuck / apollo / ai-server-4080 | | abc_fe | `beta.abc.aimloperations.com` (beta only) | `adama:8085` + same on roslin / starbuck / apollo / ai-server-4080 | | abc_be | `beta.abc.be.aimloperations.com` (beta only) | `adama:8017` + same on roslin / starbuck / apollo / ai-server-4080 | | abc_worker | `beta.abc.worker.aimloperations.com` (beta only; HTTP + WebSocket upgrade) | `adama:8018` + same on roslin / starbuck / apollo / ai-server-4080 | @@ -361,6 +364,8 @@ do not). | url_shortening_service | beta | `url_shortener_beta` | `postgres://westfarn:@10.0.0.230:5432/url_shortener_beta` | | college_craft | prod | `college_craft` | `postgres://westfarn:@10.0.0.230:5432/college_craft` | | college_craft | beta | `college_craft_beta` | `postgres://westfarn:@10.0.0.230:5432/college_craft_beta` | +| print_forge | prod | `print_forge` | `postgres://westfarn:@10.0.0.230:5432/print_forge` | +| print_forge | beta | `print_forge_beta` | `postgres://westfarn:@10.0.0.230:5432/print_forge_beta` | | abc_be | beta | `abc_be_beta` | `postgres://westfarn:@10.0.0.230:5432/abc_be_beta` | | abc_worker | beta | *(same `abc_be_beta`)* | worker uses `DB_*` pointing at `abc_be_beta` — do **not** create a second DB | @@ -390,6 +395,23 @@ App-repo companion (`college_craft`, not this repo): deploy workflows still call `--app client_site` (template leftover). They must become `--app college_craft` before CI deploy will hit this catalog entry. Default branch is `master` (not `main`). +`print_forge` extra env (control-node secrets, not in git): +`~/Documents/secrets/print_forge/print_forge_prod.env` and +`print_forge_beta.env`. Template: app repo `.env.prod.example`. +`DJANGO_ENV` / `DJANGO_ALLOWED_HOSTS` / `DATABASE_URL` / `WEB_PORT` / +`PUBLIC_SITE_URL` differ per env (prod `printforgeprints.com` / `:8007`; +beta `print-forge-preview.aimloperations.com` / `:8019`). +`SITE_UNDER_CONSTRUCTION=true` on prod (holding page until launch), `false` on beta. +Purchased flags: `FEATURE_EMAIL_SMS`, `FEATURE_PAYMENTS`, `FEATURE_SHOP`, +`FEATURE_SHIPPING`. Other `FEATURE_*` stay false. Add a `print_forge:` +entry to `SHORTENER_API_TOKENS` on `url_shortening_service` (beta token first). +`SHORTENER_BASE_URL` is prod shortener on prod, `https://shortener-beta.aimloperations.com` +on beta. Default branch is `master`. + +Companion app ticket: [print_forge#1](https://git.aimloperations.com/ai_ml_operations/print_forge/issues/1) +([#27](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/27)). +App Gitea workflow deploys beta on push to `master` (`--app print_forge`). + `abc_be` / `abc_worker` / `abc_fe` (GIS org, not this repo) — **beta only** ([#26](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/26)): Control-node secrets (never git, mode `600`): @@ -404,7 +426,7 @@ Templates: `GIS/abc_be` `.env.beta.example`, `GIS/abc_worker` `.env.beta.example Create Postgres DB `abc_be_beta` and grant `westfarn` before first deploy. NPM: `beta.abc.aimloperations.com` → `:8085`, `beta.abc.be.aimloperations.com` → `:8017`, `beta.abc.worker.aimloperations.com` → `:8018` (enable WebSocket). No prod ABC -`host_apps` rows; ports 8007 / 8008 / 8084 reserved. +`host_apps` rows; ports **8009** / 8008 / 8084 reserved (`print_forge` took prod **8007**). Companion workflows: [abc_be#22](https://git.aimloperations.com/GIS/abc_be/issues/22), [abc_worker#27](https://git.aimloperations.com/GIS/abc_worker/issues/27), @@ -487,7 +509,8 @@ Store vault password for CI in a file readable only by the Act runner (e.g. `~/. | 10f | Add starbuck + apollo as app hosts (same workloads as roslin) | Done ([#20](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/20)) | | 10g | Register + deploy `url_shortening_service` (django, ports 8005/8015) | Done ([#22](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/22)) | | 10h | Register + deploy `college_craft` (django, ports 8006/8016) | Done ([#24](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/24)) | -| 10i | Register + deploy ABC beta (`abc_be` 8017, `abc_worker` 8018, `abc_fe` 8085) | This PR ([#26](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/26)) | +| 10i | Register + deploy ABC beta (`abc_be` 8017, `abc_worker` 8018, `abc_fe` 8085) | Done ([#26](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/26)) | +| 10j | Register + deploy `print_forge` (django, ports 8007/8019) | This PR ([#27](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/27)) | | 11 | Gitea container registry (optional) | Future | ## Open Decisions diff --git a/inventory/group_vars/all.yml b/inventory/group_vars/all.yml index 49307fc..f740bde 100644 --- a/inventory/group_vars/all.yml +++ b/inventory/group_vars/all.yml @@ -129,6 +129,15 @@ app_catalog: migrate_cmd: "uv run python manage.py migrate --noinput" # dj-queue worker = compose profile `worker` (singleton). Deploy starts it # via host_apps.compose_profiles on adama only (see host_vars/adama.yml). + print_forge: + type: django + repo: "{{ git_base_url }}/ai_ml_operations/print_forge.git" + default_branch: master + compose_file: docker-compose.prod.yml + web_service: web + migrate_cmd: "uv run python manage.py migrate --noinput" + # dj-queue worker = compose profile `worker` (singleton). Deploy starts it + # via host_apps.compose_profiles on adama only (see host_vars/adama.yml). abc_be: type: django repo: "{{ git_base_url }}/GIS/abc_be.git" diff --git a/inventory/host_vars/adama.yml b/inventory/host_vars/adama.yml index 04c815a..71d8cb0 100644 --- a/inventory/host_vars/adama.yml +++ b/inventory/host_vars/adama.yml @@ -24,6 +24,8 @@ host_apps: - { name: url_shortening_service, env: beta, port: 8015 } - { name: college_craft, env: prod, port: 8006, compose_profiles: [worker] } - { name: college_craft, env: beta, port: 8016, compose_profiles: [worker] } + - { name: print_forge, env: prod, port: 8007, compose_profiles: [worker] } + - { name: print_forge, env: beta, port: 8019, compose_profiles: [worker] } - { name: abc_be, env: beta, port: 8017 } - { name: abc_worker, env: beta, port: 8018 } - { name: abc_fe, env: beta, port: 8085 } diff --git a/inventory/host_vars/ai-server-4080.yml b/inventory/host_vars/ai-server-4080.yml index fbb895e..56e0a8c 100644 --- a/inventory/host_vars/ai-server-4080.yml +++ b/inventory/host_vars/ai-server-4080.yml @@ -34,13 +34,15 @@ host_apps: - { name: chat_web_app, env: beta, port: 8083 } - { name: chat_backend, env: prod, port: 8003 } - { name: chat_backend, env: beta, port: 8013 } - # monica_site / college_craft workers NOT here — adama sets compose_profiles: [worker]. + # monica_site / college_craft / print_forge workers NOT here — adama sets compose_profiles: [worker]. - { name: monica_site, env: prod, port: 8004 } - { name: monica_site, env: beta, port: 8014 } - { name: url_shortening_service, env: prod, port: 8005 } - { name: url_shortening_service, env: beta, port: 8015 } - { name: college_craft, env: prod, port: 8006 } - { name: college_craft, env: beta, port: 8016 } + - { name: print_forge, env: prod, port: 8007 } + - { name: print_forge, env: beta, port: 8019 } - { name: abc_be, env: beta, port: 8017 } - { name: abc_worker, env: beta, port: 8018 } - { name: abc_fe, env: beta, port: 8085 } \ No newline at end of file diff --git a/inventory/host_vars/apollo.yml b/inventory/host_vars/apollo.yml index 2e3c4cf..c594086 100644 --- a/inventory/host_vars/apollo.yml +++ b/inventory/host_vars/apollo.yml @@ -13,13 +13,15 @@ host_apps: - { name: chat_web_app, env: beta, port: 8083 } - { name: chat_backend, env: prod, port: 8003 } - { name: chat_backend, env: beta, port: 8013 } - # monica_site / college_craft workers NOT here — adama sets compose_profiles: [worker]. + # monica_site / college_craft / print_forge workers NOT here — adama sets compose_profiles: [worker]. - { name: monica_site, env: prod, port: 8004 } - { name: monica_site, env: beta, port: 8014 } - { name: url_shortening_service, env: prod, port: 8005 } - { name: url_shortening_service, env: beta, port: 8015 } - { name: college_craft, env: prod, port: 8006 } - { name: college_craft, env: beta, port: 8016 } + - { name: print_forge, env: prod, port: 8007 } + - { name: print_forge, env: beta, port: 8019 } - { name: abc_be, env: beta, port: 8017 } - { name: abc_worker, env: beta, port: 8018 } - { name: abc_fe, env: beta, port: 8085 } diff --git a/inventory/host_vars/roslin.yml b/inventory/host_vars/roslin.yml index faa2cca..0234b71 100644 --- a/inventory/host_vars/roslin.yml +++ b/inventory/host_vars/roslin.yml @@ -13,13 +13,15 @@ host_apps: - { name: chat_web_app, env: beta, port: 8083 } - { name: chat_backend, env: prod, port: 8003 } - { name: chat_backend, env: beta, port: 8013 } - # monica_site / college_craft workers NOT here — adama sets compose_profiles: [worker]. + # monica_site / college_craft / print_forge workers NOT here — adama sets compose_profiles: [worker]. - { name: monica_site, env: prod, port: 8004 } - { name: monica_site, env: beta, port: 8014 } - { name: url_shortening_service, env: prod, port: 8005 } - { name: url_shortening_service, env: beta, port: 8015 } - { name: college_craft, env: prod, port: 8006 } - { name: college_craft, env: beta, port: 8016 } + - { name: print_forge, env: prod, port: 8007 } + - { name: print_forge, env: beta, port: 8019 } - { name: abc_be, env: beta, port: 8017 } - { name: abc_worker, env: beta, port: 8018 } - { name: abc_fe, env: beta, port: 8085 } diff --git a/inventory/host_vars/starbuck.yml b/inventory/host_vars/starbuck.yml index f2dadf6..b9e2b0a 100644 --- a/inventory/host_vars/starbuck.yml +++ b/inventory/host_vars/starbuck.yml @@ -13,13 +13,15 @@ host_apps: - { name: chat_web_app, env: beta, port: 8083 } - { name: chat_backend, env: prod, port: 8003 } - { name: chat_backend, env: beta, port: 8013 } - # monica_site / college_craft workers NOT here — adama sets compose_profiles: [worker]. + # monica_site / college_craft / print_forge workers NOT here — adama sets compose_profiles: [worker]. - { name: monica_site, env: prod, port: 8004 } - { name: monica_site, env: beta, port: 8014 } - { name: url_shortening_service, env: prod, port: 8005 } - { name: url_shortening_service, env: beta, port: 8015 } - { name: college_craft, env: prod, port: 8006 } - { name: college_craft, env: beta, port: 8016 } + - { name: print_forge, env: prod, port: 8007 } + - { name: print_forge, env: beta, port: 8019 } - { name: abc_be, env: beta, port: 8017 } - { name: abc_worker, env: beta, port: 8018 } - { name: abc_fe, env: beta, port: 8085 } diff --git a/roles/app-deploy/tasks/django.yml b/roles/app-deploy/tasks/django.yml index edcba0a..0879bc7 100644 --- a/roles/app-deploy/tasks/django.yml +++ b/roles/app-deploy/tasks/django.yml @@ -104,7 +104,7 @@ - _legacy_systemd_probe.stdout | default('') | length > 0 # Optional host_apps.compose_profiles (e.g. [worker]) activates compose profiles -# on this host only. Used for monica_site / college_craft dj-queue singleton on +# on this host only. Used for monica_site / college_craft / print_forge dj-queue singleton on # adama — without it, plain up --remove-orphans can drop a manually started worker. - name: "django[{{ _project }}] start containers" ansible.builtin.command: diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 14767e1..72967f0 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -17,7 +17,7 @@ Deploy applications with deploy-apps.yml. HOST Optional. Limit to one host: adama, roslin, starbuck, apollo, or ai-server-4080. Options: - --app NAME App to deploy (company_site, dta_service, dta_webapp, scha, chat_web_app, chat_backend, monica_site, url_shortening_service, college_craft, abc_be, abc_worker, abc_fe) + --app NAME App to deploy (company_site, dta_service, dta_webapp, scha, chat_web_app, chat_backend, monica_site, url_shortening_service, college_craft, print_forge, abc_be, abc_worker, abc_fe) --env ENV Environment: beta or prod --ref REF Git ref/sha to deploy (default: master) --check Dry run