Repository navigation
Releases: btcneves/AutoFlowOps
Release list
v1.2.0
Release Notes — v1.2.0
Release date: 2026-05-20
Overview
v1.2.0 introduces conditional alert rules for per-job operational thresholds, hardens workspace isolation on resource-specific endpoints and notification dispatch, expands the deployment documentation for the notification encryption key, and ships a production-ready observability stack (Prometheus metrics, structured JSON logging, and an optional Prometheus + Grafana compose stack with a pre-built dashboard).
All changes are backward-compatible. Deployments that do not use the X-Workspace-ID header are unaffected by the membership enforcement.
What's New
Conditional alert rules
Jobs can now define enabled/disabled alert rules that create internal alerts from:
- HTTP status thresholds (
http_status_gte) - Execution duration thresholds (
duration_ms_gte) - Response body text matches (
response_body_contains) - Consecutive failure counts (
consecutive_failures_gte)
Rules are managed through GET, POST, PATCH and DELETE /api/jobs/{job_id}/alert-rules, and the job detail page includes a rules section for operators and admins. The Celery worker evaluates these rules after final retry handling so queued/scheduled jobs behave the same as inline executions.
Workspace membership enforcement (security)
Prior to this release, any authenticated user could access another workspace's data by supplying an arbitrary workspace UUID in the X-Workspace-ID header. Starting with v1.2.0, the get_active_workspace dependency validates that the requesting user is a member of the target workspace before returning any data.
- Admin users (role level 3) bypass the check and retain cross-workspace access.
- Non-member requests return
403 Forbiddenwith the messageNot a member of this workspace. - The workspace object is not returned at all for non-members, preventing information leakage.
- 5 new backend tests cover member access, non-member rejection, and the admin bypass path.
This resolves the known limitation documented in v1.1.0 that stated workspace isolation was not a security boundary.
Encryption key documentation and rotation guide
The NOTIFICATION_ENCRYPTION_KEY Fernet key was absent from the deployment guide's environment variable reference table and production checklist. Both have been updated.
docs/deployment.mdnow listsNOTIFICATION_ENCRYPTION_KEYin the environment variable reference and includes a checklist item requiring the key to be backed up before first use.docs/security.mdnow includes an "Encryption key — backup and rotation" section with the key generation command, backup requirements, and a five-step rotation procedure.
Prometheus metrics endpoint
The backend exposes a /metrics endpoint in Prometheus text format, powered by prometheus-fastapi-instrumentator.
- HTTP metrics are auto-instrumented:
http_request_duration_secondshistogram withhandler,method, andstatus_codelabels. - Two business metrics counters:
autoflowops_job_executions_total— labelled bystatus(success,failure,timeout) andtrigger_type(manual,scheduled).autoflowops_alerts_created_total— labelled byseverity.
- The
/metricsendpoint is excluded from HTTP instrumentation to avoid self-referential noise.
Structured logging
Application logs now use structlog with context-variable injection.
- Development: human-readable coloured output (default when
APP_ENV != production). - Production: one JSON object per line when
APP_ENV=production. - Every HTTP request automatically binds
request_id(UUID) to the log context via middleware. - Authenticated requests bind
user_id; workspace-scoped requests bindworkspace_id. - Fully compatible with existing
logging.getLogger()usage throughout the codebase.
Log aggregation
Structured logs can now be shipped directly to Loki or Elasticsearch in addition to printing to stdout.
LOG_SINKselects the active shipping mode:stdout(default),loki,elasticsearch, or a comma-separated combination for dual shipping.LOKI_URLandELASTICSEARCH_URLconfigure target endpoints for direct-push mode.docker-compose.observability.ymlupdated with a Loki + Promtail stack for agent-based log collection from Docker container stdout — the recommended mode for standard self-hosted deployments.- All log streams carry a consistent label schema (
app,service,env,level,logger) plus structured metadata fields (job_id,execution_id,workspace_id,request_id). - Direct-push and agent-based modes can be active simultaneously.
- Full configuration reference and local setup instructions in
docs/log-aggregation.md.
Notification provider extensions
PagerDuty and OpsGenie delivery now supports additional provider-specific fields.
dedup_keyon PagerDuty channels for alert deduplication across the Events API v2 lifecycle.priorityon OpsGenie channels (P1–P5) for routing to on-call schedules by severity.payload_templateon both channel types for fully custom JSON payloads when the built-in format does not match provider expectations.
Prometheus + Grafana stack
A ready-to-run observability compose stack is provided in docker-compose.observability.yml.
- Prometheus v2.53.0 scrapes
/metricsevery 15 seconds. - Grafana v11.1.0 with a pre-configured Prometheus datasource and an auto-provisioned dashboard.
- The AutoFlowOps dashboard (uid:
autoflowops-main) ships with 7 panels: HTTP Request Rate, HTTP Latency P95, HTTP Error Rate (5xx), Job Executions rate, Alerts Created rate, Total Job Executions (stat), and Total Alerts Created (stat). - Data is persisted in Docker volumes
prometheus_dataandgrafana_data. - Three new Makefile targets:
obs-up,obs-down,obs-logs.
Upgrade Steps
Run the database migration included in this release. It creates the alert_rules table.
cd backend
alembic upgrade headPull from registry
make pull IMAGE_TAG=v1.2.0
make registry-down
make registry-up IMAGE_TAG=v1.2.0Build from source
git pull origin main
docker compose up -d --buildOptional: start the observability stack
# The main stack must be running first
docker compose up -d
make obs-upGrafana is available at http://localhost:3001 (default credentials: admin / admin). Change the admin password after first login.
Production Safety Checklist
All items from previous releases apply. Additional considerations for v1.2.0:
- Workspace membership — users without a
workspace_membershipsrow for a given workspace will receive403when that workspace is requested. Ensure all workspace members are recorded in theworkspace_membershipstable before deploying. NOTIFICATION_ENCRYPTION_KEYbackup — seedocs/security.mdfor the backup and rotation procedure. The key must be available for decryption of existing channel credentials; losing it renders all stored channel configurations unrecoverable.- Grafana credentials — the observability stack defaults to
admin/admin. Set a strong password immediately after first login.
Validation Plan
- Backend lint:
cd backend && ruff check . - Backend tests:
cd backend && PYTHONPATH=. pytest(260 tests) - Frontend lint:
cd frontend && npm run lint - Frontend tests:
cd frontend && npm test(76 tests) - Frontend build:
cd frontend && npm run build - Full local lint/test:
make lint && make test - Local Docker build:
docker compose build - Smoke tests: send a request with an unknown
X-Workspace-IDfrom a non-member user and verify403; start the observability stack and confirm metrics appear in Grafana.
Known Limitations
- Workspace membership enforcement is applied at the API layer. Direct database access is not affected.
- The observability stack requires the main
autoflowops_defaultDocker network to exist (created bydocker compose up). If the project name differs in your deployment, updatenetworks.autoflowops_default.nameindocker-compose.observability.ymlor setCOMPOSE_PROJECT_NAME=autoflowopsbefore starting the main stack. - Prometheus data retention defaults to 15 days. Adjust
--storage.tsdb.retention.timeindocker-compose.observability.ymlif longer retention is required.
v1.1.0 — PagerDuty/OpsGenie channels, PDF reports and multi-workspace support
Overview
v1.1.0 extends AutoFlowOps with two new notification providers (PagerDuty and OpsGenie), PDF export for operational reports, and multi-workspace support for namespace isolation within a single instance.
All changes are backward-compatible. Existing deployments without the X-Workspace-ID header continue to operate exactly as before.
What's New
PagerDuty notification channel
A new pagerduty channel type integrates with the PagerDuty Events API v2.
routing_keyis the only required credential; encrypted at rest using the existing Fernet mechanism.- Alerts dispatch a
triggerevent with severity mapped from the internal alert severity. - The
routing_keyis masked in all API responses and delivery error records. - The channel can be tested via
POST /api/notification-channels/{id}/test.
OpsGenie notification channel
A new opsgenie channel type integrates with the OpsGenie Alerts API.
- Supports US (
api.opsgenie.com) and EU (api.eu.opsgenie.com) regions via aregionfield (usby default). api_keyis the required credential; encrypted at rest and masked in API responses.- Optional
responderslist accepts any structure supported by the OpsGenie API (teams, users, escalations, schedules). - The channel can be tested via
POST /api/notification-channels/{id}/test.
PDF report export
Operational reports can now be downloaded as PDF in addition to JSON, Markdown and CSV.
- Endpoint:
GET /api/reports/{id}/download?format=pdf - Generated with
reportlab(pure-Python, no OS-level dependencies). - PDF sections: title, period, summary metrics, top failed jobs, alerts, recommendations.
- The
ReportFormattype in the frontend now includespdf; the Reports page exposes a PDF download button alongside the existing format options.
Multi-workspace
Resources can now be scoped to a workspace using the X-Workspace-ID request header.
- New tables:
workspaces,workspace_memberships. - A default workspace (
Default/ slugdefault) is created automatically on first startup. - All domain resources (jobs, executions, alerts, webhooks, notification channels, notification templates, escalation policies, reports) accept the header and filter results accordingly.
- When the header is absent, no filtering is applied — full backward compatibility.
- Workspace CRUD:
GET /api/workspaces,POST /api/workspaces,PATCH /api/workspaces/{id},DELETE /api/workspaces/{id}(admin-only for write operations). - Member management:
GET /api/workspaces/{id}/members,POST /api/workspaces/{id}/members,DELETE /api/workspaces/{id}/members/{user_id}. - The default workspace cannot be deleted.
- Frontend workspace selector in the sidebar persists the active workspace to
localStorageand injects theX-Workspace-IDheader into all API requests. - Admin-only Workspaces settings page at
/workspaces.
Upgrade Steps
A database migration is required to add the workspaces and workspace_memberships tables and the workspace_id column to domain tables.
Pull from registry
make pull IMAGE_TAG=v1.1.0
make registry-down
make registry-up IMAGE_TAG=v1.1.0Build from source
git pull origin main
docker compose up -d --buildFor production environments with existing data, run the Alembic migration explicitly:
docker compose exec backend alembic upgrade headProduction Safety Notes
- PagerDuty/OpsGenie credentials —
routing_keyandapi_keyare encrypted at rest. EnsureNOTIFICATION_ENCRYPTION_KEYis set and backed up before adding channels. - Workspace isolation — the
X-Workspace-IDheader is a convenience filter, not a security boundary. Use RBAC roles for access control. - Default workspace — all resources created before v1.1.0 have
workspace_id = NULL. They remain visible when no workspace header is sent.
Known Limitations
- PagerDuty and OpsGenie channel tests require valid credentials; the test endpoint returns a delivery failure for placeholder keys.
- Workspace filtering does not enforce data access control; RBAC remains the access control mechanism.
v1.0.0 — stable self-hosted release
Release Notes — v1.0.0
Release date: 2026-05-20
Overview
v1.0.0 is the first stable self-hosted release of AutoFlowOps. It consolidates the full platform built from v0.1.0 through v0.9.0: FastAPI backend, React/TypeScript frontend, PostgreSQL persistence, Redis and Celery worker execution, Jobs, Executions, Webhooks, Alerts, Reports, Notification Channels, Templates, Escalation Policies, RBAC, Audit Log, WebSocket real-time events, Docker Compose deployment, GHCR image publishing and setup scripts.
This release is intended as the official baseline for self-hosted operation.
Included Capabilities
Core automation
- Jobs CRUD with HTTP methods, headers, bodies, timeouts and schedule controls.
- Manual, interval and cron execution paths.
- Persistent execution history with statuses, timings, masked request metadata and response previews.
- Redis-backed Celery worker for manual and scheduled job processing.
- Automatic alerts for failed executions and webhook failures.
Integrations and operations
- Webhook CRUD, token validation, event history and reprocessing.
- Reports exportable as JSON, Markdown and CSV.
- Dashboard metrics for active jobs, recent executions, failures and success rate.
- External notifications through Discord, Telegram, SMTP email and custom webhooks.
- Notification templates and multi-step escalation policies.
Security and governance
- JWT authentication on protected API routes.
- Admin, operator and viewer roles enforced server-side.
- Admin-only user management.
- Audit log for sensitive actions with actor, resource, IP address, user agent and masked metadata.
- SSRF protection for HTTP job targets.
- Webhook token hashing.
- Notification credentials encrypted at rest with Fernet.
- Secrets masked in execution records, API responses, delivery errors and audit metadata.
Real-time experience
- WebSocket endpoint at
/ws/eventswith JWT validation. - Redis Pub/Sub fan-out for execution and alert events.
- Frontend live indicators and query invalidation for executions, jobs and alerts.
- Polling fallback remains available when the WebSocket stream is unavailable.
Distribution and deployment
- Local Docker Compose stack for development and validation.
- Production Docker Compose stack with Caddy reverse proxy.
- Backend and frontend images published to GHCR on release tags.
- Registry compose file for running pre-built images without a local build.
scripts/setup.shfor first-time setup and non-interactive scripted installs.- Makefile targets for tests, lint, local stack, production stack and registry stack.
Version and Packaging Changes
- Backend package metadata and
/api/versionnow report1.0.0. - Frontend package metadata and lockfile now report
1.0.0. - GHCR publish workflow now emits:
v1.0.01.0.01.0latest
- Setup examples now use
IMAGE_TAG=v1.0.0.
Upgrade Steps
No database migration is required for the v0.9.0 to v1.0.0 version consolidation.
Pull from registry
make pull IMAGE_TAG=v1.0.0
make registry-down
make registry-up IMAGE_TAG=v1.0.0Build from source
git pull origin main
docker compose up -d --buildProduction Safety Checklist
- Set strong, unique
APP_SECRET_KEYandJWT_SECRET_KEYvalues before deployment. - Set
NOTIFICATION_ENCRYPTION_KEYexplicitly for production notification credentials. - Change the initial admin password immediately after first login.
- Keep
.env,.env.productionand database backups outside version control. - Run behind HTTPS in production, especially when using the WebSocket endpoint.
- Restrict PostgreSQL and Redis to the internal Docker network.
- Keep
ENABLE_SSRF_PROTECTION=trueunless private-network job targets are intentionally required. - Review RBAC assignments before adding operators or viewers.
- Monitor audit logs for sensitive administrative activity.
Validation Plan
- Backend lint:
cd backend && ruff check . - Backend tests:
cd backend && PYTHONPATH=. pytest - Frontend lint:
cd frontend && npm run lint - Frontend tests:
cd frontend && npm test - Frontend build:
cd frontend && npm run build - Full local lint/test:
make lint && make test - Local Docker build:
docker compose build - Local smoke: backend health/version, Redis ping, Celery worker ping, job success/failure, alert creation, RBAC checks, audit log entries, WebSocket event stream.
- Registry smoke after release: pull
v1.0.0GHCR images, runIMAGE_TAG=v1.0.0 bash scripts/setup.sh, verify backend, frontend, worker and health endpoints.
Known Limitations
- The frontend image uses
vite preview; for high-traffic production environments, prefer the documented production stack with a dedicated reverse proxy. - WebSocket authentication uses a query parameter because browser WebSocket clients cannot send custom headers during the handshake. Use HTTPS/WSS and short-lived tokens in production.
- Webhook rate limiting is in-memory per API process.
- Audit logs are append-only by application convention; direct database access can bypass application controls.
- Notification credential encryption depends on protecting the configured encryption key.
- Multi-workspace isolation, PDF exports and advanced retry controls remain planned future work.
Next Steps
- Add advanced retry policy controls to the frontend.
- Add optional PDF report export.
- Expand notification providers.
- Document multi-replica deployment patterns for the WebSocket subscriber and worker scaling.
v0.9.0 — Docker image registry and simplified setup
Release Notes — v0.9.0
Release date: 2026-05-20
Overview
v0.9.0 adds a Docker image registry to AutoFlowOps. Backend and frontend images are now published to GitHub Container Registry (GHCR) on every release tag. A new setup script and a dedicated docker-compose.registry.yml let anyone run the full stack from a single command — no local build or clone required.
All existing features (RBAC, audit log, WebSocket real-time stream, notifications, Celery worker) remain unchanged.
What's New
Docker images on GHCR
Two images are published on every v*.*.* tag:
| Image | Registry path |
|---|---|
| Backend | ghcr.io/btcneves/autoflowops-backend |
| Frontend | ghcr.io/btcneves/autoflowops-frontend |
Each release produces three tags:
| Tag | Example | Meaning |
|---|---|---|
vX.Y.Z |
v0.9.0 |
Exact release — pinned, immutable |
X.Y |
0.9 |
Minor stream — updates on patch releases |
latest |
latest |
Latest stable release |
Images include OCI metadata labels (title, description, source, licenses, version, revision).
docker-compose.registry.yml
A new compose file that starts the full stack — backend, worker, frontend, PostgreSQL, Redis — using GHCR images. The IMAGE_TAG environment variable controls the version (default: latest).
# Start with latest
docker compose -f docker-compose.registry.yml up -d
# Pin to a specific release
IMAGE_TAG=v0.9.0 docker compose -f docker-compose.registry.yml up -dscripts/setup.sh
An interactive setup script for first-time installation:
- Checks that Docker and Docker Compose are installed
- Copies
.env.exampleto.env(if not already present) - Prompts for an image tag (default:
latest; skipped whenIMAGE_TAGis set) - Pulls backend and frontend images from GHCR
- Starts the stack via
docker-compose.registry.yml - Waits for the backend health endpoint (
/api/health) and frontend to respond - Prints service URLs and credentials reminder
# Interactive
bash scripts/setup.sh
# Non-interactive (CI / scripted environments)
IMAGE_TAG=v0.9.0 bash scripts/setup.shMakefile targets
| Target | Description |
|---|---|
make pull |
Pull backend + frontend images from GHCR (IMAGE_TAG=latest) |
make registry-up |
Start stack using GHCR images |
make registry-down |
Stop registry-based stack |
make registry-logs |
Stream logs from registry-based stack |
Override the tag: IMAGE_TAG=v0.9.0 make registry-up
docker-publish.yml workflow
A new GitHub Actions workflow (publish-backend + publish-frontend jobs) triggered on v*.*.* tag push:
- Logs in to GHCR using
GITHUB_TOKEN(no secrets to configure) - Builds each image with
docker/build-push-action@v5 - Uses GitHub Actions build cache (
type=gha) — subsequent builds of unchanged layers complete in seconds - Applies OCI metadata labels automatically via
docker/metadata-action@v5 - Can also be triggered manually via
workflow_dispatch
Dockerfile improvements
Backend:
- Added
curlto the image (required for theHEALTHCHECKinstruction) - Added
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3using/api/health - Added OCI labels
- Non-root user (
appuser, UID 1000) created early in the build .dockerignoreextended:tests/,*.egg-info/,*.sqlite,*.pyd,.env.*
Frontend:
- Added OCI labels
.dockerignoreextended:src/tests/,coverage/
Upgrade Steps
No database migration is required. No new environment variables are required.
From v0.8.0 (build from source)
- Pull the latest code:
git pull origin main - Rebuild:
docker compose up -d --build
Switch to registry images
# Pull the v0.9.0 images
make pull IMAGE_TAG=v0.9.0
# Stop any existing stack
docker compose down
# Start from registry
make registry-up IMAGE_TAG=v0.9.0Known Limitations
- GHCR packages start private — after the first
docker-publish.ymlrun, go to the repository → Packages → make the packages public (or authenticate withdocker login ghcr.iousing a personal access token withread:packagesscope). vite previewin production — the frontend image usesvite previewto serve the built assets. For high-traffic deployments, replace with a dedicated static server (nginx, Caddy). The productiondocker-compose.prod.ymlflow (with Caddy) is unaffected and recommended for production.IMAGE_TAGnot propagated todocker-compose.registry.ymlautomatically — always pass it explicitly (IMAGE_TAG=v0.9.0 make registry-up) or export it in the shell.- No Windows support for
scripts/setup.sh— the setup script is a Bash script and requires WSL2 or Git Bash on Windows.
v0.8.0 — Real-time WebSocket event stream
Release Notes — v0.8.0
Release date: 2026-05-20
Overview
v0.8.0 adds real-time push notifications to the AutoFlowOps frontend via a WebSocket event stream. Job executions and new alerts now appear in the UI as they happen, without waiting for the next polling cycle.
All WebSocket events contain only safe, pre-masked data — no credentials, headers or secrets are ever forwarded to browser clients.
What's New
WebSocket event stream (GET /ws/events)
A new WebSocket endpoint accepts JWT-authenticated connections and pushes domain events in real time:
| Event | Trigger |
|---|---|
execution.started |
An HTTP execution transitions to running |
execution.completed |
An execution reaches a terminal state (success, failure, timeout) or retrying |
alert.created |
A job failure creates a new alert |
Authentication uses the existing JWT access token passed as a query parameter (?token=<JWT>). The server rejects missing or invalid tokens with WebSocket close code 1008 (Policy Violation). No new credentials or configuration are required.
Redis Pub/Sub fan-out
The backend starts a long-running asyncio task at startup that subscribes to the autoflowops:events Redis channel and fans out messages to all connected WebSocket clients. The task fails gracefully if Redis is unavailable — the WebSocket endpoint still accepts connections and the frontend falls back to polling.
useWebSocket frontend hook
The hook manages the WebSocket lifecycle:
- Automatic reconnect with exponential backoff (max 30s delay)
- Stops reconnecting on authentication failure (code 1008)
- Cleans up on component unmount
- Falls back silently when no access token is present
LiveIndicator component
A small status badge is shown in the top-right area of the Jobs, Executions and Alerts pages:
- Green pulsing dot — WebSocket connected, real-time updates active
- Grey dot — Connecting…
- Nothing — Closed or auth failure (polling still active)
Pages updated
| Page | Real-time trigger |
|---|---|
| Jobs | execution.completed — refreshes last_run_at |
| Executions | execution.started, execution.completed |
| Alerts | alert.created |
Test Coverage
| Suite | Before | After |
|---|---|---|
| Backend pytest | 209 | 216 (+7) |
| Frontend Vitest | 65 | 75 (+10) |
New backend tests (tests/test_ws.py)
- No token → rejected (code 1008)
- Invalid token → rejected (code 1008)
- JWT for non-existent user → rejected (code 1008)
- Valid admin token → connected message received
- Ping/pong keepalive
ConnectionManager.broadcastdelivers to registered connectionsConnectionManagersilently removes dead connections
New frontend tests (tests/useWebSocket.test.ts)
- Connection created on mount
- Initial status is
connecting - Auth error when no token stored
- Status transitions to
openon successful connection - Incoming messages parsed as
WSEvent pongandconnectedframes do not updatelastEvent- Code 1008 sets
auth_errorand prevents reconnect - Normal close schedules reconnect
- Socket closed on unmount
Architecture Changes
New files
| File | Purpose |
|---|---|
backend/app/services/event_publisher.py |
publish_event() (sync) and publish_event_async() — write to Redis Pub/Sub channel autoflowops:events |
backend/app/api/ws.py |
WebSocket endpoint, ConnectionManager singleton, redis_subscriber background task |
backend/tests/test_ws.py |
WS endpoint and connection manager tests |
frontend/src/hooks/useWebSocket.ts |
Hook with auto-reconnect and auth-error detection |
frontend/src/components/ui/LiveIndicator.tsx |
Connection status badge |
frontend/src/tests/useWebSocket.test.ts |
Hook unit tests |
Modified files
| File | Change |
|---|---|
backend/app/main.py |
Includes WS router; starts redis_subscriber asyncio task in lifespan |
backend/app/services/http_runner.py |
Publishes execution.started, execution.completed, alert.created |
backend/app/worker/tasks.py |
Publishes execution.completed (incl. retrying), alert.created synchronously |
frontend/src/pages/ExecutionsPage.tsx |
Wires useWebSocket; invalidates query on exec events |
frontend/src/pages/JobsPage.tsx |
Wires useWebSocket; invalidates jobs query on completion |
frontend/src/pages/AlertsPage.tsx |
Wires useWebSocket; invalidates alerts query on new alert |
Known Limitations
- Token in URL — The JWT is sent as a query parameter during the WebSocket handshake. Use HTTPS/WSS in production to keep it encrypted in transit. It will appear in server access logs; use short token lifetimes.
- Single subscriber per replica — Each backend replica independently subscribes and fans out. In a multi-replica deployment, a client connected to replica A will not receive events published only on replica B's Redis subscriber (but both subscribers connect to the same Redis channel, so this is not an issue in practice — the event is published once and both subscribers relay it).
- No history replay — WebSocket clients only receive events that occur after connection; historical executions are loaded via the REST API.
- No per-user filtering — All authenticated users receive the same event stream. Fine-grained filtering (e.g. viewer sees only their own job events) is not yet implemented.
Upgrade Steps
No database migration is required. No new environment variables are required.
-
Pull the latest code.
-
Rebuild Docker images:
docker compose up -d --build -
Verify the backend log shows:
INFO app.api.ws Redis WS subscriber ready on channel autoflowops:events -
Open the Jobs, Executions or Alerts page in the browser; the Live indicator should appear within a few seconds.
v0.7.0 — RBAC and Audit Log
Release Notes — v0.7.0
Released: 2026-05-20
Overview
v0.7.0 adds role-based access control and a full audit trail, making AutoFlowOps suitable for small teams where different members need different levels of access and where a history of sensitive operations is required for accountability.
What's New
Role-Based Access Control
Three roles are now enforced server-side on every endpoint:
| Role | Who it's for |
|---|---|
admin |
Full access — user management, audit logs, all configuration |
operator |
Day-to-day work — create/run jobs, manage webhooks, ack alerts, test channels, generate reports |
viewer |
Read-only visibility into all domain data |
Role checks use FastAPI dependency injection (require_admin, require_operator) applied per-endpoint. The frontend reflects these boundaries through AdminRoute (blocks non-admins from /users and /audit-logs) and computed isAdmin/isOperator booleans in AuthContext.
User Management
Admins can now manage all user accounts through the UI or API:
- List users —
GET /api/users - Create user —
POST /api/users(sets email, name, password, role) - Update user —
PATCH /api/users/{id}(role, active status, name) - Reset password —
POST /api/users/{id}/reset-password - Delete user —
DELETE /api/users/{id}
Self-protection: the API refuses to deactivate or delete the last active admin account.
The Users page in the frontend provides all of the above through a table with inline controls.
Audit Log
Every sensitive action now produces an audit record in the audit_logs database table. Each record captures:
- Who performed the action (
user_id, nullable for failed logins) - What was done (
action— e.g.job.create,auth.login_failure) - What resource was affected (
resource_type,resource_id) - Whether it succeeded (
status) - Where the request came from (
ip_address,user_agent) - Additional context (
metadata) — with sensitive fields replaced by"[redacted]"
Admins can view and filter the log at GET /api/audit-logs (filters: user_id, action, resource_type, status, since, until, limit) or through the Audit Logs page in the frontend.
Audit Coverage
The following actions are logged automatically:
auth.login_success/auth.login_failurejob.create/job.update/job.delete/job.runwebhook.create/webhook.update/webhook.delete/webhook.reprocessalert.acknowledge/alert.resolvenotification_channel.create/.update/.delete/.activate/.deactivate/.testnotification_template.create/.update/.deleteescalation_policy.create/.update/.delete/.add_step/.delete_stepreport.generateuser.create/user.update/user.delete/user.reset_password
Last Login Tracking
The users table now records last_login_at, updated on every successful login. This is visible in the Users page.
Frontend Changes
- Users page (
/users) — admin-only; user table with name, email, role selector, status badge, last login, created date; inline password reset form; activate/deactivate; delete - Audit Logs page (
/audit-logs) — admin-only; filter controls for action, resource type, status and date range; paginated log table showing timestamp, actor, action, resource, status and IP - Sidebar — Users and Audit Logs navigation items visible only to admins; role label shown in the footer for the signed-in user
AdminRoute— route guard that redirects non-authenticated users to/loginand authenticated non-admins to/
Test Coverage
| Suite | Tests | Status |
|---|---|---|
| RBAC tests (backend) | 20 | Passing |
| Audit log tests (backend) | 5 | Passing |
| User management tests (backend) | 9 | Passing |
| UsersPage tests (frontend) | 4 | Passing |
| AuditLogsPage tests (frontend) | 4 | Passing |
| Total backend | 209 | Passing |
| Total frontend | 65 | Passing |
Migration Notes
New table: audit_logs
The audit_logs table is created automatically by Base.metadata.create_all on backend startup. No manual step is required for fresh deployments.
New column: users.last_login_at
create_all does not add columns to existing tables. If upgrading an existing deployment without Alembic:
ALTER TABLE users ADD COLUMN last_login_at TIMESTAMPTZ;Run this against your PostgreSQL database before starting the new backend version.
Default role change
New users created via POST /api/users default to "viewer". If your deployment previously relied on the internal "user" role string, update any references to use "viewer".
Upgrade Steps
- Pull the new image or rebuild:
docker compose build - If upgrading an existing database, run the
ALTER TABLEstatement above. - Start services:
docker compose up -d - Log in as admin, verify the Users and Audit Logs pages are accessible.
- Create an
operatoraccount for day-to-day work if desired. - Verify audit log entries appear after performing a sensitive action.
Known Limitations
- The audit log is append-only by convention. Direct database access bypasses the trail.
last_login_atrequires a manualALTER TABLEon existing deployments (see above).- JWT tokens issued before this upgrade remain valid until expiry; no token invalidation is performed during upgrade.
Release Notes — v0.6.0
Release Notes — v0.6.0
Release date: 2026-05-20
Overview
v0.6.0 strengthens the notification system introduced in v0.5.0 with two new channel providers (Slack and Telegram), customisable message templates, multi-step escalation policies, and Fernet-based credential encryption for all channel configurations stored in the database.
New features
Slack webhook channel
A new slack_webhook channel type posts messages to any Slack incoming webhook URL using the Slack attachments format. Severity is colour-coded: red for error, amber for warning, green for everything else.
Telegram channel
A new telegram_message channel type sends formatted messages to a Telegram chat using the Bot API. The bot_token is encrypted at rest and masked in all API responses ({numeric_prefix}:***).
Notification templates
The notification_templates table stores per-severity (or catch-all) templates with title_template and body_template fields. Variables: {title}, {severity}, {message}, {alert_id}, {source_type}, {source_id}.
Template resolution order:
- Exact match on
severity_filter - Catch-all template (
severity_filter IS NULL), preferringis_default=true - Built-in fallback
Manage templates via the API (/api/notification-templates) or the new Templates page in the frontend.
Escalation policies
An EscalationPolicy groups ordered EscalationStep records. Each step names a channel and a delay in minutes:
- delay_minutes = 0 → channel is notified immediately when the alert fires
- delay_minutes > 0 → an
EscalationEventrecord is created with a futurescheduled_at; a 60-second APScheduler job dispatches overdue events and cancels them when the alert is resolved or acknowledged
Manage policies via /api/escalation-policies or the new Escalation page in the frontend.
Credential encryption at rest
All channel config_encrypted values are now stored as Fernet ciphertexts. The encryption key comes from:
NOTIFICATION_ENCRYPTION_KEYenvironment variable (recommended for production)- Derived from
APP_SECRET_KEYvia SHA-256 (dev/test fallback — logs a WARNING)
Existing plain-JSON records from v0.5.0 are detected by their leading { character and handled transparently on read; they are re-encrypted on the next write.
Security
- Slack webhook URLs are masked to
scheme://netloc/***in all API responses and delivery error messages - Telegram
bot_tokenvalues are masked to{numeric_prefix}:***in API responses; errors from the Telegram API contain***in place of the real token NOTIFICATION_ENCRYPTION_KEYshould be set before the first production deployment; rotating the key requires re-saving all existing channels
Migration
This release adds four new tables: notification_templates, escalation_policies, escalation_steps, escalation_events. The Alembic migration a1b2c3d4e5f6 runs automatically on backend startup. No data loss occurs for existing channels; their config_encrypted values are still readable as plain JSON until they are next saved.
To generate a new Fernet key:
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"Add NOTIFICATION_ENCRYPTION_KEY=<output> to your .env or .env.production before starting.
Test coverage
| Suite | Result |
|---|---|
| Backend lint (ruff) | Clean |
| Backend tests (pytest) | 172 passing |
| Frontend tests (Vitest) | 57 passing |
| Frontend lint (ESLint) | Clean |
| Frontend TypeScript | No errors |
Release Notes — AutoFlowOps v0.5.0
Release Notes — AutoFlowOps v0.5.0
Release date: 2026-05-20
Summary
AutoFlowOps v0.5.0 adds external notification channels for critical operational alerts. Teams can now send job and webhook failure alerts to Discord webhooks, SMTP email inboxes or custom HTTP webhooks while keeping channel secrets masked in API responses, UI output and delivery error records.
Main Features
Notification Channels
- Create, edit, activate, pause, test and delete notification channels
- Supported types:
discord_webhook,smtp_emailandcustom_webhook - Frontend page added at
/notifications
Alert Delivery
- Critical job failure alerts dispatch notifications through all active channels
- Webhook token validation failures and paused webhook deliveries create critical alerts
- Notification sends use a short retry loop and never block alert persistence
Delivery History
- New delivery records capture channel, alert, status, timestamp and masked error details
- Test sends create delivery records with
alert_id: null - API responses return only masked channel configuration
Upgrade Notes
- Pull the release and rebuild the backend image.
- Run database migrations with
alembic upgrade heador start the Docker stack so the backend entrypoint runs migrations automatically. - Log in and open Notification Channels.
- Add a Discord webhook, SMTP email or custom webhook channel.
- Use the channel test action before relying on production alerts.
This release adds two tables:
notification_channelsnotification_deliveries
Security Notes
- Channel secrets are masked in API responses and UI output.
- Delivery errors are scrubbed before persistence.
- Custom webhook URLs are checked by the SSRF guard when SSRF protection is enabled.
- Notification credentials must be stored for delivery and are not database-encrypted yet; protect database access and backups accordingly.
Known Limitations
- Slack and Telegram providers are not implemented yet.
- Delivery retry uses a simple short retry loop.
- Advanced templates, escalation policies and RBAC are not included in this release.
- Notification credentials are masked but not encrypted at the database layer.
Release Notes — AutoFlowOps v0.4.0
Release Notes — AutoFlowOps v0.4.0
Release date: 2026-05-20
Summary
AutoFlowOps v0.4.0 separates job execution from the API process. Manual and scheduled HTTP jobs are now queued in Redis and executed by a dedicated Celery worker, improving reliability and preparing the platform for heavier self-hosted workloads.
Main Features
Celery Worker
- New worker process runs HTTP job executions outside FastAPI
- Worker reuses the existing HTTP runner, SSRF protection, masking, timeout handling and alert creation
- Final failures and timeouts still create internal alerts
Redis Queue
- Redis is configured as Celery broker and result backend via
REDIS_URL - Development and production Compose files include Redis and worker services
- Redis remains internal in production and is not published to the host
Queued Execution Flow
- Manual runs now create an execution with
status: "queued"and return immediately - APScheduler still owns schedule timing but dispatches scheduled work to the queue
- Worker updates the same execution through
running,retrying,success,failureortimeout
Retry Preparation
- Existing
retry_countandretry_delay_secondsjob fields now drive Celery retries - Failed or timed-out attempts move to
retryinguntil attempts are exhausted - Alerts are created only after the final failed attempt
Upgrade Notes
- Rebuild containers so the backend image includes Celery and Redis dependencies.
- Ensure
REDIS_URL=redis://redis:6379/0is present in.envor.env.production. - Start the full stack with
docker compose up --buildormake prod-up. - Verify backend, Redis and worker containers are healthy.
- Trigger a manual job and confirm the execution appears first as
queued, then as a terminal status.
No database migration is required. The existing executions.status string column stores the new queue statuses.
Known Limitations
- APScheduler still runs in the API process and should be kept to one API replica.
- Redis-backed rate limiting is not implemented; webhook rate limiting remains in-memory per API process.
- The frontend shows queue statuses but does not yet expose detailed retry history.
- Published container images remain future work.
Release Notes — AutoFlowOps v0.3.0
Release Notes — AutoFlowOps v0.3.0
Release date: 2026-05-20
Summary
AutoFlowOps v0.3.0 focuses on production readiness for single-host VPS deployments. It adds a hardened Docker Compose production stack, Caddy HTTPS reverse proxy, production environment template, config validation CI and complete deployment documentation.
Main Features
Production Docker Compose
docker-compose.prod.ymlruns Caddy, backend, frontend and PostgreSQL- Only Caddy publishes host ports (
80,443and443/udp) - Backend, frontend and PostgreSQL stay on the private Docker network
- Service healthchecks and
restart: alwaysare configured for production operations
Caddy Reverse Proxy
- Automatic HTTPS certificate provisioning and renewal
/api/*,/docs,/redocand/openapi.jsonroute to the FastAPI backend- All other paths route to the frontend
- Baseline security headers and JSON logs are enabled
Production Documentation
- Full VPS guide with DNS, Docker installation, environment setup and Caddy configuration
- Backup and restore commands for PostgreSQL
- Update procedure with migration notes
- Troubleshooting table for common deployment issues
- Production hardening guidance in the security documentation
Observability and CI
/api/healthnow reports database connectivity withdatabase: "ok"ordatabase: "error"make prod-validatevalidates the production compose file and Caddyfile- Production Config CI validates
docker-compose.prod.ymlandCaddyfileon pull requests
Upgrade Notes
- Copy
.env.production.exampleto.env.production. - Replace every placeholder secret and credential.
- Edit
Caddyfilewith your real domain and email. - Run
make prod-validate. - Start with
make prod-up.
Production deploys should verify:
curl https://your-domain.example/api/healthExpected response includes "database":"ok".
Known Limitations
- The production stack is designed for one backend replica while APScheduler remains in-process.
- Rate limiting remains in memory and is not shared across replicas.
- Caddy is configured from a checked-in template; operators must replace the example domain and email before deployment.
- Published container images are still future work.
See docs/deployment.md for the full production guide.