Deployment Lock Overlay
Overview
Section titled “Overview”When a Coolify deployment is running for a user-facing Logrite service, every logged-in user of app.logrite.ai sees a non-dismissable full-screen overlay that blocks all interaction and shows live progress. The overlay auto-closes 1 minute after the deploy completes (to let traffic settle), then the app unlocks.
This replaces the earlier read-only /deployments dashboard (reverted because it polled Coolify continuously even when nothing was happening).
Gated services
Section titled “Gated services”The lock triggers only for these services:
frontend-mainbackend-mainanalyzer-main,analyzer-devai-service
Infrastructure and pipeline deploys (OpenSearch, OpenSearch Dashboards, Data Prepper, Docs, Webhook) do NOT lock the UI. The gated-set is defined at the top of Logrite-UI/src/components/DeploymentLock/useDeploymentLock.js.
Architecture
Section titled “Architecture”Coolify API (cicd.logrite.ai) ▲ │ Bearer COOLIFY_API_TOKEN │AI Service (aiservice.logrite.ai, port 9300) │ │ 1. GET /api/v1/deployments/signal ← cheap, cached 5s server-side │ 2. GET /api/v1/deployments ← expensive, only while active ▼Browser (app.logrite.ai — DeploymentLockOverlay.jsx)Polling strategy
Section titled “Polling strategy”| Frontend phase | Endpoint | Cadence | Coolify calls per request |
|---|---|---|---|
idle | /api/v1/deployments/signal | every 5 min | 1 (+ shared 5s cache) |
active | /api/v1/deployments/signal + /api/v1/deployments | 5 min signal, 2 s detail | 1 + 26 |
cooldown | none (local 1-minute timer) | — | 0 |
Trade-off: 5-minute idle cadence is deliberately slow to keep idle traffic near zero (~12 calls/hr/user). Short-lived deploys that start and finish between polls may not surface the overlay. For near-instant reaction without polling, migrate to Coolify outbound webhooks → SSE (see Future direction below).
The /signal endpoint responds in ~0.5 s and returns:
{ "active": true, "count": 1, "activeServices": ["analyzer-dev"], "fetchedAt": "2026-04-21T05:19:18.538Z"}When active=false, the overlay stays dormant. When active=true and activeServices intersects the gated set, the overlay mounts and switches to fast-poll mode for per-service percent + stage enrichment.
Overlay behavior
Section titled “Overlay behavior”- Full-screen backdrop (
fixed inset-0 z-[9999]) with blur — covers sidebar, content, everything. - Body scroll locked via
document.body.style.overflow = 'hidden'while visible. - Keyboard blocked —
Tab,Escape,EnterallpreventDefault-ed on the overlay. - Per-service progress bars update every 2 s: display name, commit SHA (7-char), percent, stage text (e.g., “Building image”, “Deploying container”).
- Cooldown — when all gated deploys clear, overlay shows a
MM:SScountdown from 1:00 before unlocking. A new deploy during cooldown re-opens the active state.
Failure modes
Section titled “Failure modes”| Scenario | Behavior |
|---|---|
| Signal endpoint 500s or times out | Overlay keeps last known state; retries on the next poll tick. Won’t falsely mount. |
| Detail endpoint fails mid-active | Overlay stays up with stale percent/stage until next successful detail poll. |
| AI Service container itself redeploys | Signal calls fail during the swap window; frontend can’t detect a self-referential ai-service deploy. Accepted limitation. |
| Frontend container itself redeploys | Old frontend served until new one swaps in — old bundle can’t lock for its own deploy. Accepted limitation. |
Coolify returns unmapped application_id | /signal falls back to empty activeServices; overlay stays down. Extend coolify-apps.ts with the new UUID to enable locking. |
Source files
Section titled “Source files”- Backend:
logrite-ai-service/src/routes/deployments.routes.ts(signal endpoint + cache) - Backend:
logrite-ai-service/src/services/coolify.service.ts(Coolify client) - Backend config:
logrite-ai-service/src/config/coolify-apps.ts(service-key → UUID map) - Frontend hook:
Logrite-UI/src/components/DeploymentLock/useDeploymentLock.js - Frontend UI:
Logrite-UI/src/components/DeploymentLock/DeploymentLockOverlay.jsx - Mount point:
Logrite-UI/src/App.jsx(mounted inside<Router>, sibling to<AppContent>)
Extending
Section titled “Extending”To gate another service: add its key to the GATED_SERVICES Set in useDeploymentLock.js. Make sure the key also exists in coolify-apps.ts.
To change the cooldown: adjust COOLDOWN_MS (default 60 * 1000) in useDeploymentLock.js.
To change the idle poll cadence: adjust SIGNAL_INTERVAL_MS (default 5 * 60 * 1000) in useDeploymentLock.js.
To tune the signal cache: adjust SIGNAL_CACHE_MS (default 5000) in deployments.routes.ts.
Future direction: Move from polling to Coolify outbound webhooks → AI Service state → SSE push to browsers. That eliminates all idle polling. Not required at current scale; noted for future iteration.