Flow A

Developer submits form → Cloud Build → new Cloud Run service + DNS.

Flow B

End user query path: auth, embeddings, vector search, LLM stream, tracing.

Flow C

Sight kill-switch: Firestore update + hot config reload (~seconds).

Flow D

Observe dashboard: parallel fetch from Logging, Monitoring, Langfuse, BQ.

Flow E

Traffic shift rollback to a prior Cloud Run revision.

Flow F

Persona edit — lists affected apps; redeploy required for propagation.

Flow G · Admin

Invite developers, portal settings, global audit — admin role only.

Flow A: Developer deploys a new app

From the portal form through immutable config snapshot, Secret Manager, Cloud Build, Artifact Registry, Cloud Run deploy, domain mapping, and live URL back to the developer.

sequenceDiagram
    autonumber
    participant Dev as Developer
(browser) participant FE as Portal Frontend participant BE as Portal Backend participant FS as Firestore
(portal-state) participant SM as Secret Manager participant CB as Cloud Build participant AR as Artifact Registry participant CR as Cloud Run participant DNS as Cloud DNS participant App as RAG App
(new revision) Dev->>FE: Fill "New App" form
(name, slug, persona, LLM/RAG cfg) FE->>BE: POST /api/apps (Firebase JWT) BE->>FS: create apps/{app_id} BE->>FS: write config_snapshots/{snap_id}
(immutable copy) BE->>SM: create per-app secrets
(OPENAI_API_KEY, etc.) BE->>CB: trigger build
subs: _APP_ID, _TEMPLATE_VERSION, _SNAPSHOT_ID BE-->>FE: 202 Accepted (build_id) FE-->>Dev: "Deploying… (3-8 min)" CB->>BE: GET /internal/snapshots/{snap_id} BE-->>CB: snapshot JSON CB->>CB: git checkout vertexai-rag @ tag CB->>CB: docker build CB->>AR: docker push rag:{app_id}-{sha} CB->>CR: gcloud run deploy rag-{app_id}
--set-env-vars APP_ID, PORTAL_API_URL
--set-secrets ... CR->>App: cold start App->>BE: GET /internal/apps/{app_id}/config
(OIDC token) BE-->>App: snapshot config App->>App: cache config, ready CR-->>CB: revision live CB->>DNS: domain mapping {slug}.apps.yourdomain.com CB->>BE: POST /internal/builds/{build_id}/complete
(revision name) BE->>FS: update apps/{app_id}.current_revision
+ deployment_events BE-->>FE: SSE / poll: status=live, url=... FE-->>Dev: "Live at https://{slug}.apps.yourdomain.com"

Flow B: End user hits a deployed app (runtime serving path)

Technician opens the app subdomain. Sight middleware gates availability; authenticated RAG queries flow through Vertex embeddings, Firestore vector search, streamed LLM response, Langfuse traces, and structured Cloud Logging.

sequenceDiagram
    autonumber
    participant EU as End User
(technician) participant DNS as DNS / LB participant App as RAG App
(rag-technician) participant Sight as Sight
Middleware participant Auth as Firebase
Identity Platform participant RAG as RAG Service participant VAI as Vertex AI
(embeddings) participant LLM as OpenAI / Gemini participant FS as Firestore
(shared) participant LF as Langfuse participant CL as Cloud Logging EU->>DNS: GET technician.apps.yourdomain.com DNS->>App: route to rag-technician revision App->>Sight: check sight_enabled alt sight off Sight-->>EU: 503 "App offline" else sight on App->>Auth: verify ID token (tenant: technician-abc) Auth-->>App: claims (uid, email) EU->>App: POST /api/rag/query {q, conversation_id} App->>RAG: query() RAG->>VAI: embed query VAI-->>RAG: vector RAG->>FS: vector search (filter app_id + tenant_id) FS-->>RAG: chunks RAG->>LLM: chat completion
(@observe -> Langfuse trace) LLM-->>RAG: tokens (streamed) RAG-->>App: SSE stream App-->>EU: SSE stream RAG->>LF: trace {app_id, user_id_hash, conv_id} App->>CL: structured log {app_id, request_id} end

Flow C: Sight toggle (hot config update, no rebuild)

Developer disables Sight from the portal. Backend updates Firestore and pushes config to the live app via OIDC-authenticated reload — no Cloud Build required.

sequenceDiagram
    autonumber
    participant Dev as Developer
    participant FE as Portal FE
    participant BE as Portal Backend
    participant FS as Firestore
    participant App as RAG App
(live) Dev->>FE: Toggle "Sight" OFF on app detail page FE->>BE: POST /api/apps/{app_id}/sight {enabled: false} BE->>FS: update apps/{app_id}.sight_enabled = false BE->>FS: write deployment_events (type=config_update) BE->>App: POST https://rag-{app_id}.../admin/reload-config
(OIDC token, audience=app URL) App->>BE: GET /internal/apps/{app_id}/config BE-->>App: updated config (sight_enabled=false) App->>App: swap cache atomically App-->>BE: 200 OK BE-->>FE: 200 OK, latency FE-->>Dev: "Sight disabled in 1.2s" Note over App: subsequent requests return 503

Flow D: Observability aggregation (developer views one app)

Single observe page fans out in parallel to Cloud Monitoring, Logging, Error Reporting, Langfuse, and BigQuery billing export — aggregated by the portal backend.

sequenceDiagram
    autonumber
    participant Dev as Developer
    participant FE as Portal FE
    participant BE as Portal Backend
    participant LOG as Cloud Logging API
    participant ERR as Error Reporting API
    participant MON as Cloud Monitoring API
    participant LF as Langfuse API
    participant BQ as BigQuery
(billing export) Dev->>FE: Open /apps/technician/observe par Health FE->>BE: GET /api/apps/technician/health BE->>MON: uptime_check_result filter=rag-technician MON-->>BE: ok/fail series BE-->>FE: 200 OK and Logs FE->>BE: GET /api/apps/technician/logs?level=ERROR&window=1h BE->>LOG: entries.list
filter: resource.labels.service_name="rag-technician" LOG-->>BE: log entries BE-->>FE: log entries and Crashes FE->>BE: GET /api/apps/technician/errors BE->>ERR: groupStats.list filter=service:rag-technician ERR-->>BE: error groups BE-->>FE: error groups and Metrics FE->>BE: GET /api/apps/technician/metrics?type=latency_p95 BE->>MON: timeSeries.list metric=request_latencies MON-->>BE: time series BE-->>FE: chart data and AI traces FE->>BE: GET /api/apps/technician/traces?tag=app_id:technician BE->>LF: GET /api/public/traces?tags=app_id:technician LF-->>BE: traces BE-->>FE: traces and Cost FE->>BE: GET /api/apps/technician/cost?range=30d BE->>BQ: SELECT cost FROM billing_export WHERE service=rag-technician BQ-->>BE: rows BE-->>FE: cost summary end FE-->>Dev: render dashboard

Flow E: Rollback to previous revision

One-click rollback shifts 100% traffic to a prior Cloud Run revision and records the event in Firestore deployment history.

sequenceDiagram
    autonumber
    participant Dev as Developer
    participant FE as Portal FE
    participant BE as Portal Backend
    participant CR as Cloud Run Admin API
    participant FS as Firestore

    Dev->>FE: Click "Rollback to rag-technician-00041"
    FE->>BE: POST /api/apps/technician/rollback {revision: "00041"}
    BE->>CR: services.patch traffic=100%->00041
    CR-->>BE: ok (new revision config)
    BE->>FS: update apps/technician.current_revision = 00041
+ deployment_events(type=rollback) BE-->>FE: 200 OK FE-->>Dev: "Rolled back in 18s"

Flow F: Persona update propagates to apps using it

Editing a shared persona updates Firestore and returns affected app IDs. Changes do not auto-deploy — developers must redeploy (or hot-reload prompt-only changes).

sequenceDiagram
    autonumber
    participant Dev as Developer
    participant FE as Portal FE
    participant BE as Portal Backend
    participant FS as Firestore

    Dev->>FE: Edit persona "Field Technician" system prompt
    FE->>BE: PATCH /api/personas/field-technician
    BE->>FS: update personas/field-technician
    BE->>FS: find apps where persona_id=field-technician
    FS-->>BE: [technician, technician-eu]
    BE-->>FE: 200 OK + affected_apps:[...]
    FE-->>Dev: "2 apps use this persona. Redeploy now?"
    Note over Dev,BE: Persona edits do NOT auto-propagate.
Developer must explicitly redeploy each app
(or hot-reload if change is prompt-only).

Flow G: Portal admin operations

Admins sign in via Firebase (invite-only portal-developers tenant). The backend loads developers/{uid}.role and exposes admin APIs only when role === admin. Developers see apps and personas; admins additionally manage team access, portal-wide integrations, and cross-app audit.

RBAC (v1)Developer: CRUD own apps, deploy, observe, personas. Admin: everything above + invite/revoke users, change roles, edit /settings (GCP project link, Langfuse, billing export), view global audit, force Sight off on any app.
sequenceDiagram
    autonumber
    participant Admin as Portal Admin
(browser) participant FE as Portal Frontend participant Auth as Firebase Auth participant BE as Portal Backend participant FS as Firestore
(developers, settings) participant SM as Secret Manager Admin->>FE: Open portal.yourdomain.com FE->>Auth: signInWithEmailLink / SSO Auth-->>FE: ID token (JWT) FE->>BE: GET /api/me Authorization Bearer JWT BE->>FS: developers/{uid} FS-->>BE: role=admin BE-->>FE: { role: admin, permissions } FE-->>Admin: Admin nav + dashboard Admin->>FE: Settings → Developers → Invite FE->>BE: POST /api/admin/developers/invite {email, role} BE->>BE: assert role=admin BE->>FS: create developers/{pending_uid} invited BE->>Auth: send invite email BE-->>FE: 201 Created FE-->>Admin: Invite sent Admin->>FE: Settings → Portal → Save FE->>BE: PATCH /api/admin/settings BE->>FS: portal_settings/global BE->>SM: rotate portal secrets if keys changed BE-->>FE: 200 OK FE-->>Admin: Settings saved Admin->>FE: Audit → all apps, last 7d FE->>BE: GET /api/admin/audit?from=... BE->>FS: query deployment_events FS-->>BE: events BE-->>FE: audit rows FE-->>Admin: deploy / rollback / config_update table

Admin UI — wireframe screens

Low-fidelity mockups for the admin slice of the portal. Same shell as developer views; extra nav items appear only after GET /api/me returns role: admin.

1 · Login
portal.yourdomain.com/login
Developer Portal
Invite-only · Firebase Auth
No public signup
2 · Admin home
/admin
DashboardAppsPersonasAdmin
24Live apps
3Deploying
8Developers
1Sight off
Failed deploys (24h)2
3 · Developers
/admin/developers
Team
EmailRole
admin@coadmin
dev@codeveloper
4 · Invite modal
/admin/developers
Invite developer
5 · Portal settings
/admin/settings
Portal settings
GCP projectvertexai-rag-portal
Langfuse hostcloud.langfuse.com
Billing BQ datasetbilling_export
6 · All apps (oversight)
/admin/apps
All applications
technicianlive
saleslive
warehousesight off
7 · Global audit
/admin/audit
Audit log
TimeAppEvent
10:02techdeploy_success
09:41salesrollback
09:15whconfig_update
8 · Role denied
/admin/settings
403 — Admin only

Shown when a developer hits an admin URL. Nav hides Admin section.