Skip to content

Commit 8a43c18

Browse files
authored
Merge pull request #26 from OmniBioAI/release/v0.7.0-production-stabilization
release(studio): prepare v0.7.0-beta production release
2 parents 391144e + 4356fe2 commit 8a43c18

14 files changed

Lines changed: 238 additions & 54 deletions

.env.web

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
# ignored by the Electron scripts (dev, build:ui, build:linux, etc.),
44
# which never pass --mode.
55
VITE_WEB_MODE=true
6-
VITE_VERSION=0.5.0-beta
6+
VITE_VERSION=0.7.0
77
VITE_APP_NAME=OmniBioAI Studio Web

CHANGELOG.md

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,38 @@ Format: [Keep a Changelog](https://keepachangelog.com)
99
- 🌐 Public web domain moved from app.omnibioai.org to webstudio.omnibioai.org (old domain kept working during the transition period)
1010

1111
---
12-
## v0.7.0-beta (2026-07-18)
12+
## v0.7.0 (2026-08-07)
13+
14+
### New Features
15+
- 🔐 Unified license key system (OMNI-XXXX-XXXX-XXXX-XXXX)
16+
→ One key works for web + desktop
17+
→ Auto-creates user on first validation
18+
→ Same JWT as OAuth login
19+
- 🌐 webstudio.omnibioai.org fully working
20+
→ License key login enforced
21+
→ All workbench pages loading correctly
22+
→ Service worker fixed
23+
→ nginx routes fixed (/license/, /roles/)
24+
→ Control Center JWT cookie fallback
25+
- 👥 Team expansion
26+
→ Dr. Rajnish Kumar (Scientific Consultant, SR University)
27+
→ Praveen C.V. Raghavulu (Scientific Advisor, KUMC)
28+
→ About page restructured as company team page
29+
- 🛠 12,110 bioinformatics tools (up from 11,577)
30+
→ 100+ new HTTP API tools added
31+
→ All tools validated (100% clean)
32+
→ 0 duplicates, 0 ToolSpec errors
33+
- 🤖 Tool selection AI improved
34+
→ GPU enabled for Ollama (57x faster: 120s → 2.1s)
35+
→ Accuracy: 0% → 60%
36+
→ Recall@K: 60% → 85%
37+
- 📦 1,000 ARM64 SIF images
38+
- 🔧 Control Center web service added
39+
- 💰 Billing service integrated
40+
- 🔧 Admin Console at admin.omnibioai.org
41+
42+
---
43+
## v0.6.0-beta (2026-07-18)
1344

1445
### New Features
1546
- 🌐 Web version at app.omnibioai.org
@@ -131,34 +162,3 @@ Format: [Keep a Changelog](https://keepachangelog.com)
131162
- LLM configuration: Ollama + Claude API + OpenAI
132163
- Cloud execution: AWS/Azure/GCP Batch + Kubernetes
133164
- HPC execution: Slurm / PBS / LSF via TES
134-
135-
136-
## v0.7.0 (2026-08-07)
137-
138-
### New Features
139-
- 🔐 Unified license key system (OMNI-XXXX-XXXX-XXXX-XXXX)
140-
→ One key works for web + desktop
141-
→ Auto-creates user on first validation
142-
→ Same JWT as OAuth login
143-
- 🌐 webstudio.omnibioai.org fully working
144-
→ License key login enforced
145-
→ All workbench pages loading correctly
146-
→ Service worker fixed
147-
→ nginx routes fixed (/license/, /roles/)
148-
→ Control Center JWT cookie fallback
149-
- 👥 Team expansion
150-
→ Dr. Rajnish Kumar (Scientific Consultant, SR University)
151-
→ Praveen C.V. Raghavulu (Scientific Advisor, KUMC)
152-
→ About page restructured as company team page
153-
- 🛠 12,110 bioinformatics tools (up from 11,577)
154-
→ 100+ new HTTP API tools added
155-
→ All tools validated (100% clean)
156-
→ 0 duplicates, 0 ToolSpec errors
157-
- 🤖 Tool selection AI improved
158-
→ GPU enabled for Ollama (57x faster: 120s → 2.1s)
159-
→ Accuracy: 0% → 60%
160-
→ Recall@K: 60% → 85%
161-
- 📦 1,000 ARM64 SIF images
162-
- 🔧 Control Center web service added
163-
- 💰 Billing service integrated
164-
- 🔧 Admin Console at admin.omnibioai.org

DEPLOYMENT.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,17 @@ AUTH_SECRET_KEY=<generate: python3 -c "import secrets; print(secrets.token_urlsa
7777
7878
# ── Container registry ────────────────────────────────────────────────────────
7979
GITHUB_TOKEN=<PAT with read:packages scope — for ghcr.io pull>
80+
GHCR_PULL_TOKEN=<PAT with read:packages scope — BuildKit secret for image builds that need @man4ish/ui, and for license-server/tes/model-registry/lims/rag image pulls>
81+
82+
# ── License (unified OMNI-XXXX flow) ───────────────────────────────────────────
83+
LICENSE_SECRET=<random-token — used by the legacy standalone license-server, :8099>
84+
85+
# ── Neo4j (RAG knowledge graph) ─────────────────────────────────────────────────
86+
NEO4J_PASSWORD=<strong-password> # defaults to "omnibioai" if unset — override in production
87+
88+
# ── Telemetry ────────────────────────────────────────────────────────────────
89+
# SENTRY_RELEASE is set automatically per-service to the app version (currently "0.7.0")
90+
# in docker-compose.yml / docker-compose.release.yml; no action needed unless overriding.
8091
8192
# ── Paths ─────────────────────────────────────────────────────────────────────
8293
HOST_IP=0.0.0.0 # or specific NIC IP
@@ -244,6 +255,33 @@ Expected dashboard titles: `OmniBioAI Platform Overview`, `OmniBioAI LIMS`, `Omn
244255

245256
---
246257

258+
## Production Domains
259+
260+
The steps above describe the local/on-prem docker-compose runbook (everything on
261+
`localhost:<port>`). In the hosted production deployment, the same stack sits behind
262+
`docker/nginx-router.conf` and is reachable at three public domains:
263+
264+
| Domain | Serves | Notes |
265+
|---|---|---|
266+
| `webstudio.omnibioai.org` | Web build of Studio (`web-ui` service, built via `Dockerfile.web` / `npm run web:build`) | License-key login (`OMNI-XXXX-XXXX-XXXX-XXXX`) enforced; same backend as desktop |
267+
| `workbench.omnibioai.org` | Same nginx-router stack, workbench-focused entry point | Routes `/api`, `/_tes`, `/_svc/rag`, `/_svc/modelregistry`, `/_svc/workflows` etc. through to their respective upstreams — see `docker/nginx-router.conf` |
268+
| `admin.omnibioai.org` | Control Center Admin Console (`/_svc/control`, JWT-gated except a small public health/summary allowlist) | Port 7070 upstream; bound to localhost on the container host, only reachable externally through the nginx router |
269+
270+
Health verification against the public domains (adjust for your DNS/TLS setup):
271+
272+
```bash
273+
curl -sf https://webstudio.omnibioai.org/ && echo "webstudio reachable"
274+
curl -sf https://workbench.omnibioai.org/api/health && echo "workbench API reachable"
275+
curl -sf https://admin.omnibioai.org/_svc/control/health && echo "admin console reachable"
276+
```
277+
278+
**Known gap:** the Billing/Subscriptions/Entitlements/Usage/Invoices UI (`control-center-web`,
279+
the `cc-ui` frontend) is not currently served by any production compose file or routed by
280+
`nginx-router.conf` — see Known Issues in `README.md`. The `billing-service` backend itself
281+
is deployed and reachable only indirectly through Control Center's own backend proxy.
282+
283+
---
284+
247285
## Rollback Procedure
248286

249287
### Using Git Tags
@@ -271,6 +309,36 @@ docker compose up -d
271309
docker compose up -d --no-deps <service-name>
272310
```
273311

312+
### Locally-built services (e.g. web-ui): tag-based rollback
313+
314+
`web-ui` (and other services using `build:` rather than `image:` in `docker-compose.yml`)
315+
have no registry digest to pin — they're built and tagged locally
316+
(`<compose-project>-<service>:latest`, e.g. `omnibioai-studio-web-ui:latest`), so digest
317+
pinning doesn't apply. Before rebuilding one of these, tag the currently-running image
318+
so it survives the rebuild (which overwrites `:latest` in place):
319+
320+
```bash
321+
# Before rebuilding — capture a named rollback point
322+
docker tag omnibioai-studio-web-ui:latest omnibioai-studio-web-ui:rollback
323+
324+
# Rebuild + redeploy (only this service; --no-deps avoids restarting anything else)
325+
docker compose -f docker-compose.yml build web-ui
326+
docker compose -f docker-compose.yml up -d --no-deps --force-recreate web-ui
327+
328+
# If it needs to be rolled back:
329+
docker tag omnibioai-studio-web-ui:rollback omnibioai-studio-web-ui:latest
330+
docker compose -f docker-compose.yml up -d --no-deps --force-recreate web-ui
331+
```
332+
333+
**Note**: recreating a service changes its container IP on the Docker bridge network.
334+
`nginx-router`'s `upstream` blocks cache that IP at nginx's own startup (see the
335+
"nginx-router returning 502" entry under Troubleshooting) — Docker *may* hand the
336+
recreated container back its previous IP if nothing else claimed it in the meantime, in
337+
which case no further action is needed (verify with `docker inspect <container>
338+
--format '{{json .NetworkSettings.Networks}}'` before assuming so), but this is not
339+
guaranteed. If the IP changes, `nginx-router` needs `--no-deps --force-recreate` too, or
340+
that route will 502 again.
341+
274342
---
275343

276344
## Backup and Restore
@@ -420,6 +488,39 @@ docker compose restart control-center
420488
docker compose exec control-center curl -sf http://workbench:8000/health/
421489
```
422490

491+
### nginx-router returning 502 for a service that's actually healthy
492+
493+
`nginx-router.conf`'s `upstream { server <name>:<port>; }` blocks resolve each backend
494+
hostname to a Docker bridge-network IP **once**, at nginx startup/reload — not per
495+
request. If a backend container is later recreated (redeploy, rebuild, crash-restart),
496+
it gets a new IP from Docker, but `nginx-router` keeps sending traffic to the old one
497+
until it is itself reloaded or recreated. The symptom is `502 Bad Gateway` with
498+
`connect() failed (111: Connection refused)` in `nginx-router`'s logs, naming an IP that
499+
`docker inspect <backend-container> --format '{{.NetworkSettings.Networks}}'` shows no
500+
longer belongs to that service (sometimes it now belongs to a *different* container
501+
entirely — the stale IP got reassigned). This can affect one route or many at once,
502+
depending on how many backends were recreated since `nginx-router`'s last (re)start.
503+
504+
```bash
505+
# Confirm: does the IP in the error log match the backend's current IP?
506+
docker logs --tail 50 omnibioai-studio-nginx-router-1 | grep "Connection refused"
507+
docker inspect omnibioai-studio-<service>-1 \
508+
--format '{{.NetworkSettings.Networks.omnibioai-studio_default.IPAddress}}'
509+
510+
# Fix: force nginx-router to re-resolve every upstream hostname and pick up the
511+
# current on-disk config (a plain `nginx -s reload` is not reliable here — see the
512+
# bind-mount inode GOTCHA documented at the top of docker/nginx-router.conf, which
513+
# can leave a running container serving a config file from days earlier even after
514+
# a reload). Recreating only nginx-router does not restart or otherwise affect any
515+
# other service:
516+
docker compose -f docker-compose.yml up -d --no-deps --force-recreate nginx-router
517+
```
518+
519+
Root-caused and fixed this way for the `webstudio.omnibioai.org` 502 incident,
520+
2026-08-08 (PR G) — `nginx-router` had not been restarted since 2026-08-07, while
521+
`web-ui` and several other services had been recreated since then and picked up new
522+
IPs nginx-router never learned about.
523+
423524
### Celery workers not picking up tasks
424525

425526
```bash

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
- 💰 **Billing service** integrated
1919
- 🛡️ **Admin Console** live at admin.omnibioai.org
2020

21-
### v0.7.0-beta ✅
21+
### v0.6.0-beta ✅
2222
- 🌐 Web version at webstudio.omnibioai.org — no installation required
2323
- 🔐 SSO & OAuth2 — Google, GitHub, and Microsoft sign-in
2424
- 🛡️ Cloudflare Access — secure invite-only email whitelist
@@ -632,7 +632,7 @@ Reports are sent to our dashboard. Response within 24 hours during beta. Disable
632632
| v0.3.0-beta | ✅ Released | IDE Services, Grafana observability, auto-secrets, npm security |
633633
| v0.4.0-beta | ✅ Released | Version unification, 23 services, 7 execution servers, Claude Sonnet 4 |
634634
| v0.5.0-beta | ✅ Released | 225+ plugins, 36M-abstract RAG index, 1,120+ container images, full beta launch |
635-
| v0.7.0-beta | ✅ Released | Web version (`webstudio.omnibioai.org`), SSO/OAuth2 (Google/GitHub/Microsoft), Cloudflare Access, 800 ARM64 SIF images, 12,000+ tools, Hugging Face integration, Model Registry HF push button |
635+
| v0.6.0-beta | ✅ Released | Web version (`webstudio.omnibioai.org`), SSO/OAuth2 (Google/GitHub/Microsoft), Cloudflare Access, 800 ARM64 SIF images, 12,000+ tools, Hugging Face integration, Model Registry HF push button |
636636
| **v0.7.0** |**Current** | Unified License Key (one `OMNI-XXXX` key for web + desktop, auto-creates user, same JWT as OAuth login), `webstudio.omnibioai.org` fully working end-to-end, 12,110 tools (100+ new HTTP API tools), Tool Selection AI 57x faster with GPU-enabled Ollama (accuracy 0%→60%, Recall@K 60%→85%), 1,000 ARM64 SIF images, Control Center web service, Billing service integrated, **Admin Console** at `admin.omnibioai.org`, team expansion (Dr. Rajnish Kumar, Praveen C.V. Raghavulu) |
637637
| **v0.8.0** | 🔜 Planned | **Enterprise Platform** — expand the ML portfolio to **20 trained ML models on Hugging Face**, HIPAA compliance reporting, SAML/enterprise SSO, multi-user workspaces, team management, usage analytics, mobile-responsive UI, and **Omni Assistant v2** (tool-aware responses, agentic workflow suggestions, multi-step reasoning, context-aware analysis) |
638638
| **v0.9.0** | 🔜 Planned | **Enterprise Admin Console expansion** — advanced organization administration, enterprise governance, deeper billing and subscription management, advanced usage analytics, administrative workflows, platform operations, security administration, and enterprise-scale management capabilities |
@@ -650,6 +650,8 @@ Reports are sent to our dashboard. Response within 24 hours during beta. Disable
650650
- cAdvisor requires privileged mode and `/dev/kmsg` device access
651651
- Prometheus not exposed directly — access only via `/_svc/prometheus`
652652
- Control Center (`/_svc/control`) requires valid JWT; port 7070 bound to localhost only
653+
- Billing service backend (`billing-service`, :8005) is deployed and DB-backed, but has no served production frontend — `control-center-web` (the billing/subscriptions/entitlements UI) is not wired into any docker-compose file or nginx route in this deployment yet
654+
- Two license-validation backends currently coexist: the legacy standalone `license_server.py` (`license-server`, :8099, its own MySQL DB) and the unified `/license/validate` endpoint on `omnibioai-auth` (:8001), which is what web and desktop actually call for the OMNI-XXXX login flow. The legacy server is still built and deployed but appears superseded — pending a decision on formal decommission
653655

654656
---
655657

docker-compose-release.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,10 @@ services:
628628
- prometheus
629629
restart: unless-stopped
630630

631+
web-ui:
632+
image: ghcr.io/omnibioai/omnibioai-web:latest
633+
restart: unless-stopped
634+
631635
# ---------------------------------------------------------------------------
632636
# Router
633637
# ---------------------------------------------------------------------------
@@ -640,6 +644,7 @@ services:
640644
- ./docker/nginx-router.conf:/etc/nginx/conf.d/default.conf:ro
641645
depends_on:
642646
- workbench
647+
- web-ui
643648
- lims
644649
- rag
645650
- api-gateway

docker-compose.release.yml

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# OmniBioAI Studio - Release configuration
22
# Uses pre-built images from ghcr.io
3-
# Version: v0.4.0-beta
3+
# Version: v0.7.0
44
#
55
# Setup:
66
# cp .env.example .env
@@ -128,6 +128,13 @@ services:
128128
environment:
129129
PYTHONUNBUFFERED: "1"
130130
REDIS_URL: redis://redis:6379
131+
# SSO Phase 2 PR2 (JWT consumer audit): same shared secret
132+
# auth-service signs with and api-gateway/control-center already
133+
# verify with (all AUTH_SECRET_KEY) -- previously unset here, so
134+
# api/deps.py::require_platform_admin and
135+
# audit/identity.py::validate_identity_token both fell back to the
136+
# public literal "change-me" instead of the real secret.
137+
JWT_SECRET: ${AUTH_SECRET_KEY:-change-me-in-production}
131138
depends_on:
132139
redis:
133140
condition: service_healthy
@@ -210,7 +217,7 @@ services:
210217
SINGULARITY_TMPDIR: /tmp/singularity_tmp
211218
SENTRY_DSN: ${SENTRY_DSN:-}
212219
SENTRY_ENVIRONMENT: ${SENTRY_ENVIRONMENT:-beta}
213-
SENTRY_RELEASE: "0.4.0-beta"
220+
SENTRY_RELEASE: "0.7.0"
214221
volumes:
215222
- ${WORKSPACE_HOST}:/workspace
216223
- /var/run/docker.sock:/var/run/docker.sock
@@ -278,7 +285,7 @@ services:
278285
LIMS_API_TOKEN: ""
279286
SENTRY_DSN: ${SENTRY_DSN:-}
280287
SENTRY_ENVIRONMENT: ${SENTRY_ENVIRONMENT:-beta}
281-
SENTRY_RELEASE: "0.4.0-beta"
288+
SENTRY_RELEASE: "0.7.0"
282289
volumes:
283290
- ${WORKSPACE_HOST}:/workspace
284291
- ${WORK_DIR}/runs:/app/work/runs
@@ -419,7 +426,14 @@ services:
419426
TOOL_IMAGES_BASE: /workspace/tool-images
420427
SENTRY_DSN: ${SENTRY_DSN:-}
421428
SENTRY_ENVIRONMENT: ${SENTRY_ENVIRONMENT:-beta}
422-
SENTRY_RELEASE: "0.4.0-beta"
429+
SENTRY_RELEASE: "0.7.0"
430+
# SSO Phase 2 PR1: same shared secret auth-service signs with and
431+
# api-gateway already verifies with (both above, AUTH_SECRET_KEY) --
432+
# this was previously unset here, so core/auth.py::require_admin's
433+
# os.environ.get("JWT_SECRET", "change-me") fallback silently
434+
# verified tokens against the public literal "change-me" instead of
435+
# the real secret.
436+
JWT_SECRET: ${AUTH_SECRET_KEY:-change-me-in-production}
423437
volumes:
424438
- ${DATA_DIR}:/workspace
425439
- /var/run/docker.sock:/var/run/docker.sock

0 commit comments

Comments
 (0)