#The Three-Phase Doctrine
Deploying to production is the highest-stakes operation in software engineering. A bad deploy can take down a running system, corrupt data, or expose security vulnerabilities. The Prismatic Platform mitigates this risk through a three-phase deployment pipeline where each phase must pass before the next begins.
#Phase 1: Pre-Deploy Validation
Before any code reaches production, it must pass three categories of checks:
#Quality Gates
mix format --check-formatted # Code formatting
mix compile --warnings-as-errors --force # Zero-warning compilation
mix credo --strict # Static analysis
mix test --cover # Test suite with coverage
mix dialyzer # Type checkingAll quality gates must pass. A single warning, a single failing test, or a type error blocks the deploy.
#Doctrine Compliance
The platformβs 18-pillar doctrine is validated by mix check.doctrines:
| Pillar | Check | Enforcement |
|---|---|---|
| ZERO | No String.to_atom, no bare rescue | Blocking |
| SEAL | No hardcoded secrets, no SQL injection | Blocking |
| PERF | No N+1 queries, no unbounded Repo.all | Blocking |
| TACH | Test files exist for changed modules | Blocking |
| DOCS | @moduledoc, @doc, @spec present | Blocking |
| DEPS | Version constraints, no unstable git deps | Blocking |
| RDME | README.md in every app | Blocking |
| HYGIENE | No stale files, clean git state | Blocking |
| NMND | No placeholders, stubs, or shortcuts | Blocking |
| OTEL | Telemetry in GenServers and controllers | Advisory |
| GITL | Conventional commit format | Advisory |
| KNOW | Glossary coverage for new modules | Advisory |
#Security Scan
A security-specific scan checks for:
- Dependencies with known vulnerabilities (
mix deps.audit) - Secrets accidentally committed to the repository
- Unsafe code patterns that could enable injection attacks
#Health Score Gate
The platformβs health score (computed by mix health.score) must meet the minimum threshold. The health score is a composite metric combining compilation health, test coverage, doctrine compliance, and documentation completeness.
#Phase 2: Deployment via Fly.io
The platform runs on Fly.io, which provides zero-downtime deployments through rolling updates:
#Build Process
# Build the Docker image
fly deploy --build-only
# The Dockerfile:
# 1. Installs Erlang/OTP and Elixir
# 2. Fetches and compiles dependencies
# 3. Compiles the umbrella application
# 4. Builds production assets (esbuild + tailwind)
# 5. Creates the Mix release
# 6. Copies the release to a minimal runtime image#Rolling Update Strategy
Fly.io deploys new instances before shutting down old ones:
- New VM is started with the updated release
- Health check endpoint (
/api/v1/health) is polled - Once the new VM responds with HTTP 200, traffic is routed to it
- Old VM receives a SIGTERM and has 30 seconds to drain connections
- Old VM is shut down
This ensures zero downtime β at no point are zero instances serving traffic.
#Release Configuration
# rel/env.sh.eex
export RELEASE_DISTRIBUTION=name
export RELEASE_NODE=prismatic@${FLY_APP_NAME}.internal
export ERL_AFLAGS="-proto_dist inet6_tcp"The release is configured for IPv6 (required by Fly.ioβs internal network) and uses named distribution for potential clustering.
#Phase 3: Post-Deploy Validation
After deployment, automated checks verify the release is healthy:
#Smoke Tests
Four critical endpoints are tested within 60 seconds of deployment:
# Health endpoint (must respond with 200)
curl -f https://prismatic-prod.fly.dev/api/v1/health
# Landing page (must respond with 200)
curl -f https://prismatic-prod.fly.dev/
# Dashboard (must respond with 200, authenticated)
curl -f https://prismatic-prod.fly.dev/dashboard
# API status (must return valid JSON)
curl -f https://prismatic-prod.fly.dev/api/v1/status#Performance Verification
Response times are measured and compared against baselines:
- Health endpoint: must respond in less than 10ms
- Page load: must complete in less than 250ms
- Server render: must complete in less than 100ms
- LiveView mount: must complete in less than 150ms
If any metric exceeds 2x the baseline, an alert is triggered. If any metric exceeds 5x the baseline, automatic rollback is initiated.
#Functional Verification
Key user journeys are tested end-to-end:
- Can a user log in and reach the dashboard?
- Does the OSINT toolbox load and display adapters?
- Can a DD case be created and viewed?
- Do real-time updates flow through PubSub?
#Rollback Strategy
If post-deploy validation fails, the pipeline initiates automatic rollback:
# Immediate rollback to previous release
fly releases rollback --app prismatic-prod
# Verify rollback succeeded
curl -f https://prismatic-prod.fly.dev/api/v1/healthRollback is fast (typically under 30 seconds) because Fly.io retains the previous release image. The old VMs are restarted from the cached image without requiring a rebuild.
#Rollback Triggers
| Condition | Action | Timing |
|---|---|---|
| Health check fails 3x | Automatic rollback | Within 90 seconds |
| Response time 5x baseline | Automatic rollback | Within 2 minutes |
| Error rate exceeds 5% | Alert + manual review | Within 5 minutes |
| Smoke test failure | Automatic rollback | Within 60 seconds |
#The Deploy Command
The entire pipeline is orchestrated by the /deploy command:
# Full pipeline: validate + deploy + verify
just deploy-validate staging
# Production (requires confirmation)
just deploy-production
# Dry run (preview without executing)
just deploy-dry-run productionThe command provides real-time progress output for each phase, with clear pass/fail indicators and timing information. A typical production deploy takes 4-6 minutes end-to-end: 1-2 minutes for validation, 2-3 minutes for deployment, and 30-60 seconds for post-deploy verification.
#Deployment History
Every deployment is recorded with its validation results, timing, and outcome:
v546: 2026-03-25 14:32 UTC | staging | PASS | 4m 12s
v547: 2026-03-25 15:01 UTC | staging | PASS | 3m 58s
v548: 2026-03-25 15:45 UTC | prod | PASS | 5m 03sThis history enables trend analysis: are deploys getting slower? Are failures increasing? Which phase fails most often?
Ship with confidence. The pipeline catches what humans miss.