Self-hosted Docker deployment control panel with admin tooling, operational visibility, backup dry-runs, and release safety checks.
Source-available: PolyForm Noncommercial 1.0.0
Commercial, internal business, client, SaaS, and resale use require a separate commercial license.
Reviewer Package | Architecture | Runbook | Product Strategy
DeployMate is a self-hosted deployment control panel for small teams that need a fast way to ship Docker containers, manage reusable templates, track operational state, and handle lightweight admin workflows from one UI.
It is built for pragmatic operator experience rather than platform complexity.
This repository is source-available, not open source.
- public code license: PolyForm Noncommercial 1.0.0
- commercial/business use: not permitted under the public license
- for business, internal company, client, SaaS, or resale use: request a separate commercial license first
See COMMERCIAL-LICENSE.md for the business-use policy and NOTICE for the short-form repository notice.
Commercial licensing entry points:
- public explanation: COMMERCIAL-LICENSE.md
- owner contact:
mailto:alexgerlitz@users.noreply.github.com - expected first reply: usually within 2 business days
- production contact alias is configurable via
NEXT_PUBLIC_BUSINESS_CONTACT_EMAIL
If you are opening this repository as a hiring reviewer, these are the fastest entry points:
- product preview screenshots: Product Preview
- release notes: docs/releases/v0.1.0.md
- roadmap: ROADMAP.md
- product strategy: PRODUCT-STRATEGY.md
- architecture overview: ARCHITECTURE.md
- production/release discipline: RUNBOOK.md, SAFE-RELEASE.md, SECURITY.md
What to evaluate quickly:
- product depth: deployments, templates, servers, admin users, upgrade requests, backup dry-run
- engineering maturity: scripted preflight, smoke coverage, remote release flow, production docs
- operational thinking: security posture, runtime capability boundaries, release safety checks
If you want the shortest coherent pass through the project:
- start with the screenshots in Product Preview
- read ARCHITECTURE.md for system boundaries
- read RUNBOOK.md and SAFE-RELEASE.md for release and recovery discipline
- inspect docs/releases/v0.1.0.md for the public release shape
- read PRODUCT-STRATEGY.md for the product thesis, ICP, and long-term differentiator
- use the runtime routes below as the reviewer map if a live deployment is available
If you are evaluating whether this is more than a UI shell, the quickest evidence is:
- product screenshots and route map
- release workflow and smoke discipline
- roadmap and documentation continuity from product to operations
The repository includes product screenshots that show the richer operator and admin surfaces:
If a live deployment is available, use this route map:
- open
/appfor the operator overview - open one deployment detail page for runtime state and observability
- open
/app/server-reviewto inspect the dedicated server workspace - open
/app/usersand/app/upgrade-requeststo inspect the richer admin surface - review saved views, bulk actions, audit trail, backup bundle, and restore dry-run tooling
Recommended reviewer order:
/appfor the operator overview/deployments/[deploymentId]for runtime state and observability/app/server-reviewfor live server create/edit/test/diagnostics/delete flow/app/usersfor admin saved views, bulk actions, audit, and recovery tooling/app/upgrade-requestsfor workflow depth, exports, and admin triage surface
- one product surface covers deployments, servers, templates, activity, admin users, upgrade requests, backups, and restore dry-runs
- production release flow is already scripted with preflight and post-deploy smoke checks
- the admin surface has saved views, bulk actions, exports, audit history, and backup tooling
- production security posture was improved with a remote-only deployment profile and strict pinned SSH defaults
| Area | What is already implemented |
|---|---|
| Deployments | create, redeploy, inspect, delete, logs, health, activity |
| Servers | dedicated /app/server-review workspace with saved SSH targets, create/edit/test/diagnostics/delete, and suggested ports |
| Templates | reusable presets, usage tracking, preview, duplicate, filters |
| Admin users | filters, saved views, bulk actions, exports, audit trail |
| Upgrade inbox | filters, saved views, bulk actions, exports, audit trail |
| Recovery | backup bundle export and restore dry-run conflict analysis |
| Release safety | preflight, admin smoke, post-deploy smoke |
- a separate operator-side
Web Terminalexists for direct server work with Codex and tmux - the reference location and maintenance rules live in WEB-TERMINAL.md
- the public proof is the sidecar contract and maintenance model, not a required live sidecar
- create, redeploy, inspect, and delete Docker deployments
- support reusable deployment templates with usage tracking and preview
- inspect logs, health, activity, and external port mappings
- target either local Docker or remote SSH hosts, with production capable of running in remote-only mode
- optional public signup for safe
trialaccounts
- use the dedicated
/app/server-reviewworkspace as the main server surface - register remote servers with SSH-key auth for new targets
- edit, test, diagnose, and delete saved targets from the same review flow
- fetch suggested free ports before runtime work
- manage users, roles, plans, and password-reset state
- process upgrade requests with filters, exports, bulk actions, and audit trail
- use saved views for both users and upgrade inbox workflows
- export admin data and operational snapshots as JSON or CSV
- download a structured backup bundle
- run restore dry-run analysis without applying changes
- inspect conflicts before any future restore workflow
FastAPINext.jsPostgreSQLDocker ComposeCaddy
Browser
-> Next.js frontend
-> FastAPI backend
-> PostgreSQL
-> Docker runtime or remote SSH targets
More detail: see ARCHITECTURE.md. Project focus rules: see PROJECT-RULES.md. Product strategy: see PRODUCT-STRATEGY.md.
For the public release framing, see docs/releases/v0.1.0.md.
backend/FastAPI application and deployment orchestrationfrontend/Next.js application and admin/operator UIscripts/release, smoke, and preflight automationdeploy/production reverse-proxy configdocker-compose.prod.ymlproduction stack definition- AUTOMATION-CORE.md reusable automation-core notes for porting this DX layer into another repo
make export-automation-corebuilds an exportable automation bundle for moving this DX layer into a separate private repositorymake bootstrap-core-init TARGET_DIR=... BOOTSTRAP_CORE_FLAGS="--project-name MyApp --frontend-dir web --backend-dir api"installs the reusable core into another repo and prefills the first adapter config in one shot- PRODUCT-STARTER.md defines the reusable product starter layer for future projects
make bootstrap-product-starter TARGET_DIR=... PRODUCT_STARTER_FLAGS="--project-name MyApp --app-slug myapp --contact-email founder@example.com --frontend-dir web --backend-dir api"renders a starter product skeleton plus automation core into a new repomake scaffold-product-resource TARGET_DIR=... RESOURCE_FLAGS="--name Projects --slug projects --frontend-dir web --backend-dir api"generates the first real feature slice after the starter shellmake scaffold-deploymate-surface SURFACE_FLAGS="--name Review Inbox --slug review-inbox"generates a new DeployMate-specific admin surface page, backend route/service stub, route registration, and API flow test inside this repomake scaffold-deploymate-feature FEATURE_FLAGS="--name Controlled Import Plan --slug controlled-import-plan --feature-kind recovery-workflow"wraps the surface scaffold with a DeployMate-specific feature pack: frontend helper stub, generated smoke checks, and a dedicated smoke runner script
For daily coding, the shortest useful local checks are now:
make start-pr-branch SLUG=my-change
make git-doctor
make ship-pr SLUG=my-change MESSAGE="Describe the change"
make pr-ready
make pr-open
make pr-status
make pr-doctor
make pr-watch
make pr-land
make pr-land-sync
make auto-local
make dev-doctor
make changed
make profile-changed
make profile-frontend
make profile-backend
make profile-fast
make profile-frontend-hot
make profile-fast-hot
make frontend-smoke-server-status
make frontend-smoke-server-stop
make audit-cache-clear
make frontend
make frontend-hot
make backend
make fast
make fast-hot
make scaffold-deploymate-surface SURFACE_FLAGS="--name Review Inbox --slug review-inbox"
make sync-mainTo spend less time on repetitive Git choreography, the repo now also has a compressed flow:
make git-doctor
make ship-pr SLUG=my-change MESSAGE="Describe the change"
make pr-watch
make pr-land-syncWhat these do:
make git-doctortells you the next useful Git command from the current branch statemake ship-pr ...can create the feature branch, commit, run the PR-ready loop, push, and open the PR in one passmake sync-mainfast-forwardsmainfromdevelopmake pr-land-synclands the PR and then syncsmain
Preferred Git cadence for a presentable GitHub history:
- commit per finished logical slice, not per tiny keystroke
- push after one good commit or a small clean series of 2-3 related commits
- avoid noisy
wip/tmp/ broken intermediate commits when a cleaner split is possible - prefer one platform/scaffold commit plus one product-surface commit over one mixed dump commit
For current DeployMate work, the fastest route from idea to a real new surface is now:
make scaffold-deploymate-surface SURFACE_FLAGS="--name Review Inbox --slug review-inbox"That generator creates:
frontend/app/app/<slug>/page.jsbackend/app/routes/<slug>.pybackend/app/services/<slug>.pybackend/tests/test_<slug>_api_flow.pybackend/app/schemas.pylist-response contract- route registration in
backend/app/main.py
It also now starts the page on top of reusable DeployMate review blocks instead of raw duplicated JSX:
AdminSurfaceSummaryAdminSurfaceQueueAdminSurfaceQueueCard
The backend side now also starts closer to a real DeployMate admin slice:
- typed
ListResponsecontract inschemas.py response_modelon the generated route- a built-in
qfilter path - an API flow test that already exercises filtered and unfiltered responses
Use it when the next feature is another admin/resource surface inside DeployMate itself, not when bootstrapping a brand-new product.
For a richer first pass, the same scaffold can also add optional sections:
make scaffold-deploymate-surface \
SURFACE_FLAGS="--name Review Inbox --slug review-inbox --with-table --with-saved-views --with-audit --with-export"These flags let the generator start with:
- base queue-only surface
- queue + table review starter
- queue + saved views
- queue + audit
- queue + export/recovery notes
- or the fuller review shell when the feature genuinely needs all of them
The generated page is now more than a static mock:
- URL/search-param sync for the primary query
- active filter chips
- optional review-table starter for denser scanning across the same queue data
- saved-views manager wiring when
--with-saved-viewsis enabled - audit filter/sort starter wiring when
--with-auditis enabled - working local JSON/CSV starter exports when
--with-exportis enabled - a preset-aware starter action panel with two real local action paths you can replace with the first real mutation
The scaffold is also entity-aware now:
--preset generic--preset users--preset upgrade-requests--preset servers
So the generated sample queue, summary copy, search placeholder, and starter export shape can already look closer to the kind of DeployMate surface you are actually adding.
Those presets now also shape the first real action pattern:
generic: queue triage / escalateusers: password reset / access reviewupgrade-requests: approve / closeservers: run diagnostics / mark SSH ready
So the next screen starts closer to a true DeployMate workflow, not just a list with placeholder cards.
The scaffold is now also entity-aware inside the generated page itself:
- preset-specific workflow/segment filter
- richer sample fields like context/meta instead of only label + status
- dynamic summary cards driven by the current filtered starter slice
- queue cards that already show the extra entity context you will usually need in the first real review pass
- bulk starter actions tied to the visible slice
- mutation payload preview for the first real write path
The generated surface now also ships in a more maintainable shape:
page.jsas the orchestration layerstarter-data.jsfor preset data and stringsstarter-actions.jsfor mutation preview and slice helpersstarter-smoke.jsfor route/check placeholders- backend
*_starter.pymodule for sample items and summary contract - typed backend starter-action request/response + POST endpoint test
starter-api.jsfor the generated frontend read/write bridge
Automation core is no longer the only reusable layer here.
This repo now also contains a reusable product starter for the next project:
- starter landing/auth/app shell
- starter FastAPI backend shell
- starter docs
- optional automation-core bootstrap in the same command
Fastest path for a brand new product repo:
make bootstrap-product-starter TARGET_DIR=/absolute/path/to/project PRODUCT_STARTER_FLAGS="--project-name MyApp --app-slug myapp --contact-email founder@example.com --frontend-dir web --backend-dir api"That is the new shortest route from “empty folder” to “working product skeleton plus automation”.
Then the next shortest route from “starter shell” to “first real product slice” is:
make scaffold-product-resource TARGET_DIR=/absolute/path/to/project RESOURCE_FLAGS="--name Projects --slug projects --frontend-dir web --backend-dir api"What they do:
make changeddetects the changed release surface from the local diff and runs only the lightweight matching gatemake profile-changedruns the same changed-file gate and then prints recent timings, grouped stats, and the latest bottleneck hintmake profile-frontendruns the fast frontend gate and then prints the same timing profile bundlemake profile-backendruns the fast backend gate and then prints the same timing profile bundlemake profile-fastruns the fast full gate and then prints the same timing profile bundlemake profile-frontend-hotruns the frontend profile bundle with the persistent smoke server enabledmake profile-fast-hotruns the full profile bundle with the persistent frontend smoke server enabledmake frontend-smoke-server-statusshows reusable local frontend smoke servers kept alive between commandsmake frontend-smoke-server-stopstops those reusable local frontend smoke servers explicitlymake audit-cache-clearclears the persistent local audit fingerprint cachemake start-pr-branch SLUG=...creates a clean feature branch from localdevelopmake pr-readyruns the recommended local loop for the current feature branch and prints the PR next stepmake pr-openopens a GitHub PR againstdevelopwith the repo template plus local automation contextmake pr-statusshows the current PR state through GitHub CLImake pr-doctorprints PR health, current size class, upstream status, PR status, and whether the last local green loop still matches the branch basemake pr-watchwaits on PR checks and then prints the latest doctor summarymake pr-landmerges the current PR only when doctor is clean, the PR head SHA matches localHEAD, and GitHub checks are greenmake dev-doctorprints the cheapest useful local loop, the latest timing bottleneck, and the current PR doctor summary in one commandmake dev-doctoris also backed by a shell-readablebash scripts/dev_doctor.sh --format shellmode for future automation on top of the coremake pr-doctoralso reads PR CI status from GitHub and gives a split hint from the actual diff mix when the branch gets too largemake pr-doctornow also compares the current localHEAD, the last locally verifiedHEAD, and the PR head SHA on GitHub, so stale local green runs stop being mistaken for current verificationmake frontendruns the fast frontend gatemake frontend-hotruns the same fast frontend gate but keeps the smoke server warm across runsmake backendruns the fast backend gatemake fastruns the fast full gatemake fast-hotruns the fast full gate with the persistent frontend smoke server enabled
Recommended hot frontend loop:
make frontend-hot
make frontend-hot
make frontend-smoke-server-status
make frontend-smoke-server-stopmake fullstill runs the heavier full local release workflow
The fast gate intentionally uses fewer resources:
- frontend: targeted auth/ops/runtime smokes from changed files when possible, otherwise all three
- frontend mixed/shared diffs can now skip fast frontend smokes entirely when no frontend contract changed, instead of always booting the shared smoke server
- backend: targeted tests from changed files when possible, otherwise the focused safety suite
- backend mixed/shared diffs can now skip the fast backend suite entirely when no backend contract changed, instead of paying the safety-suite cost by default
- backend syntax in preflight now narrows to changed backend Python files when possible and skips entirely for frontend-only local diffs
- explicit surface commands like
make frontend,make backend,make profile-frontend, andmake profile-backendnow auto-derive the same local diff context, so scoped audits and syntax checks still stay cheap outsidemake changed - release-workflow and runbook diffs now keep
release_workflow_auditenabled while still lettingsecurity_auditstay on changed-file scope during local explicit surface loops - local
security_auditnow splits cheap secret scanning from runtime-policy scanning, so release/docs/script-heavy diffs keep the relevant checks without paying for unnecessary risky-default scans - successful local secret-scan and runtime-policy results now persist by file fingerprint, so repeating the same loop does not re-run those scans unnecessarily
- repeated local release-contract and runtime-contract audits now also reuse fingerprint-cached results when their inputs did not change
- preflight, release, and profile commands now print a short cache summary so it is obvious when repeated checks were skipped
- repeated fast frontend smoke targets and backend fast test modules now reuse phase-level fingerprint caches when the diff and inputs did not change
- repeated preflight backend syntax checks and local frontend builds now also reuse phase-level fingerprint caches when their inputs did not change
- repeated security audit blocks now also reuse a phase-level fingerprint cache when the diff, scopes, and nested audit inputs did not change
- changed-file security scans now reuse per-file fingerprints for secret and runtime-policy checks, so adding one new file does not force rescanning every unchanged file in the local diff
- repeated local runtime audits now also reuse per-file fingerprints for static runtime-contract files, so one changed deploy/runtime file no longer invalidates every unchanged runtime contract check
- repeated release workflow contract checks now reuse per-file extracted secret lists for
release.yml,staging.yml, andRUNBOOK.md, so changing one contract file does not re-parse the other two - local preflight, release, and profile commands now print family-level cache savings for
security,release_contract, andruntime, so it is obvious which layer still costs the most - local diff-context derivation now handles empty changed-file sets cleanly and prints a family bottleneck hint, so explicit surface commands stay stable and immediately show which verification family still dominates misses
- security secret scans and runtime-policy scans now prefer per-file fingerprint reuse even in wider scopes when the file set is still manageable, so repeat full-scope checks stop rescanning the entire repo unnecessarily
make recommend-local-modenow suggests the cheapest useful loop for the current diff, so you spend less time deciding betweenbackend,frontend-hot,changed, orprofile-changedmake changednow narrows mixed diffs down to an effectivefrontendorbackendfast surface automatically when one side already resolves toskip, so shared-but-one-sided changes stop paying for an unnecessary second halfmake auto-localnow executes the recommended loop directly, including auto-switching between fast and profile modes when the diff looks expensive enough to justify timing and cache contextmake auto-localnow also remembers the last successful loop for the same diff family and prints a cheaper follow-up command for the next tweak, now biased by the last measured bottleneck instead of just the previous mode name- project-specific layout and route assumptions now live behind scripts/project_automation_config.sh, so the reusable automation core is no longer welded directly to DeployMate paths
- project-specific path-to-target rules now live behind scripts/project_automation_targets.sh, so moving this system to another repo no longer means rewriting every
detect_*script - frontend smoke assertions now live behind scripts/project_automation_smoke_checks.sh, so both the fast and heavier smoke runners are no longer welded to DeployMate-specific selectors
- preflight: skips the production frontend build in fast mode
- fast frontend mode now reuses one shared smoke dev server instead of starting a separate
next devprocess per smoke - the repo now has experimental local persistent frontend smoke-server controls, but the default fast loop stays on the safer per-command lifecycle unless
FRONTEND_SMOKE_PERSIST_SERVER=1is set explicitly - the heavier frontend gate also reuses shared smoke servers for the main smoke pack
- repeated local audits are cached within one gate run, so nested security/runtime checks do not repeat unnecessarily
- local changed-file verification now skips runtime-oriented audits automatically when the diff does not touch deploy/runtime contract files
- local changed-file verification now narrows
security_auditto the changed files and skips nested release/credentials audits unless the diff touches those contracts - local preflight and release flows now print a timing summary so the slowest phase is obvious after each run
- local preflight and release flows now append timing data into
.logs/local_gate_timing.csv, so you can compare runs over time make timing-historyprints the latest local timing rows without opening the CSV manuallymake timing-statsprints groupedavg/min/max/latestphase timings from the recent local history- local preflight and release flows now print a short bottleneck hint from recent matching runs, so the next optimization target is obvious
The repository now works best with a PR-first loop into develop:
git switch develop
git pull --ff-only origin develop
make start-pr-branch SLUG=my-changeThen use this daily path:
- code and commit on the feature branch
- run
make pr-ready - push with
git push -u origin $(git branch --show-current) - open the PR with
make pr-open - wait with
make pr-watch - merge with
make pr-land
PRs are not just ceremony here:
- pull requests already run the same CI release gate as
developpushes - auto-staging still happens only after the reviewed PR lands in
develop .github/pull_request_template.mdkeeps the PR body short and consistentmake pr-readyandmake pr-openkeep the branch-to-PR flow aligned with the same automation core used for local verificationmake pr-doctorwarns when the branch has grown into a probably-too-large PR, so review cost stays under controlmake pr-doctornow also surfaces PR check health and a practical split direction, so the next action is clearer than a generic “too big” warningmake pr-doctornow also catches “you already changed the branch after the last green local run” and “the PR head on GitHub is not the same commit you last verified locally”make pr-landcloses the loop safely by refusing to merge a PR whose doctor state, head SHA, or GitHub checks no longer matchmake dev-doctorgives one compact answer to “what should I run next and what is blocking me?”, which is exactly the kind of friction this automation core is supposed to remove
/appoperations dashboard/deployments/[deploymentId]deployment detail view/app/server-reviewdedicated server workspace/app/usersadmin users workspace/app/upgrade-requestsadmin upgrade inbox/loginand/change-passwordauth flow
- scripted preflight in scripts/preflight.sh
- runtime capability contract audit in scripts/runtime_capability_audit.sh
- production env security audit in scripts/production_env_audit.sh
- dedicated CI/manual workflow contract gate in scripts/production_contract_gate.sh
- scripted local release gate in scripts/release_workflow.sh
- scripted remote release helper in scripts/remote_release.sh, with branch plus exact commit deployment support
- GitHub Actions CI runs the same local release gate on
developpushes and pull requests - GitHub Actions CI now also runs a dedicated production-contract job on every PR and push, even when the normal deploy surface resolves to
skip - GitHub Actions staging workflow can auto-promote successful
developbuilds into a staging environment - GitHub Actions manual release workflow can run the remote release helper against a configured host
- GitHub Actions staging and production releases now pin the exact checked-out commit SHA during remote deploy instead of relying on branch drift alone
- both repository-side deploy workflows share a reusable composite action instead of duplicating shell logic
- tracked-file security audit in scripts/security_audit.sh
- release workflow secret-contract audit in scripts/release_workflow_audit.sh
- scripted post-deploy smoke in scripts/post_deploy_smoke.sh
- dedicated admin frontend smoke in scripts/frontend_admin_smoke.sh
- dedicated auth frontend smoke in scripts/frontend_auth_smoke.sh
- dedicated beginner-path frontend smoke in scripts/frontend_beginner_smoke.sh for
/app,/app/server-review, and/app/deployment-workflow - dedicated admin-interactions frontend smoke in scripts/frontend_admin_interactions_smoke.sh for saved views and bulk-action surfaces
- dedicated ops frontend smoke in scripts/frontend_ops_smoke.sh
- dedicated restore-report frontend smoke in scripts/frontend_restore_smoke.sh
- dedicated runtime frontend smoke in scripts/frontend_runtime_smoke.sh
- dedicated servers frontend smoke in scripts/frontend_servers_smoke.sh
- dedicated templates frontend smoke in scripts/frontend_templates_smoke.sh
- deployment detail now includes quick reference, attention overview, and copyable runtime summary ergonomics
- backend local Docker execution is now explicit opt-in; remote-only is the default runtime posture
- operations overview now exposes backend runtime capability posture, including local Docker, SSH trust mode, and credential-key readiness
- preflight and security audit now check that production frontend and backend local-runtime flags stay aligned
- preflight and remote release now also fail on insecure production env overrides such as memory-backed auth throttling, non-strict SSH trust, placeholder admin passwords, or missing pinned
known_hosts - the local release gate now runs auth, admin, admin-interactions, beginner, ops, restore, runtime, servers, and templates frontend smokes before build
- backend unit tests for restore analysis, admin helpers, and SSH option policy
- release and rollback notes in RUNBOOK.md and SAFE-RELEASE.md
For the current main product path walkthrough, use docs/beginner-walkthrough.md first.
If I were demoing the project to a reviewer, I would open it in this order:
/appfor the operations overview/deployments/[deploymentId]for runtime state, logs, and health/app/server-reviewfor the live server-management loop/app/usersfor saved views, bulk actions, audit, and backup tooling/app/upgrade-requestsfor admin workflow depth and export/reporting features
The repository is meant to show not only a UI, but a product plus delivery discipline:
- docs/releases/v0.1.0.md for the initial public release framing
- RUNBOOK.md for local gate, remote release, post-deploy smoke, and workflow contract
- ROADMAP.md for what is intentionally next rather than vaguely planned
- PRODUCT-STRATEGY.md for category, ICP, market angle, and differentiator
cd backend
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reloadcd frontend
npm install
npm run devDefault local URLs:
- frontend:
http://127.0.0.1:3000 - backend:
http://127.0.0.1:8000
Production deployment uses:
docker-compose.prod.yml- PRODUCTION.md
- RUNBOOK.md
Typical release flow:
./scripts/preflight.sh
npm --prefix frontend run smoke:beginner
npm --prefix frontend run smoke:admin
npm --prefix frontend run smoke:runtime
npm --prefix frontend run build
git push origin develop
ssh <deploy-host>
cd /opt/deploymate
git pull --ff-only origin develop
docker compose -f docker-compose.prod.yml --env-file .env.production up -d --build --no-deps frontend
DEPLOYMATE_BASE_URL=https://your-domain DEPLOYMATE_ADMIN_USERNAME=admin DEPLOYMATE_ADMIN_PASSWORD='<secret>' bash scripts/post_deploy_smoke.sh./scripts/preflight.sh now includes both the runtime capability audit and the production env security audit. bash scripts/remote_release.sh ... now runs the same checks on the target host before it calls docker compose up. The GitHub CI and manual release workflows also run bash scripts/production_contract_gate.sh before they touch a remote host.
If the change touches /app, /app/server-review, or /app/deployment-workflow, keep npm --prefix frontend run smoke:beginner in the local loop even when you skip heavier frontend checks.
Or use the single remote helper for prod-like or staging-like deploys:
bash scripts/remote_release.sh \
--host <deploy-host> \
--surface full \
--base-url https://your-domain \
--admin-username admin \
--admin-password '<secret>'There is also a manual GitHub Actions release workflow in .github/workflows/release.yml for teams that prefer a guarded repository-side trigger over running the remote helper from a workstation.
For a safer promotion path, .github/workflows/staging.yml can deploy develop to a dedicated staging environment after CI passes, then production can stay on the manual release gate.
This project is production-usable, but still intentionally closer to a strong MVP than to a finished enterprise platform.
Current strengths:
- user passwords are hashed
- server SSH credentials are encrypted at rest when persisted by the application
- admin audit trail exists for user and upgrade actions
- restore flow is dry-run only
- SSH host key checking now defaults to strict pinned verification
- SSH host key behavior is configurable through environment variables
- strict SSH mode fails fast unless a real non-empty
known_hostsfile is configured - bootstrap
admin/adminis refused unless local-only insecure bootstrap is explicitly acknowledged - auth throttling can use shared database-backed state across workers and restarts
- production now defaults to a remote-only profile without Docker socket access in the backend
- the production frontend can be built with local deployment controls disabled to match the backend capability boundary
- production checks now fail if
.env.productionleaves backend local-runtime policy and frontend deployment controls out of sync - production checks now also fail on insecure env overrides before release or remote rebuild starts
Current tradeoffs:
- server credentials are still application-managed, but they are encrypted at rest and require a stable
DEPLOYMATE_SERVER_CREDENTIALS_KEY - local Docker control is explicit opt-in and disabled by default unless
DEPLOYMATE_LOCAL_DOCKER_ENABLED=true - legacy password-based SSH records may still exist until they are rotated to SSH keys
- local Docker control and remote SSH control still live in the same backend service boundary
These are conscious MVP tradeoffs, not hidden assumptions.
Start here:
- README.md
- ARCHITECTURE.md
- PRODUCTION.md
- RUNBOOK.md
- SAFE-RELEASE.md
- CONTRIBUTING.md
- SECURITY.md
- CHANGELOG.md
Next likely improvements:
- move server credentials to external secret management
- split local Docker execution into a narrower executor boundary
- add first-class known-host management and fingerprint review inside the product
- deepen automated smoke coverage around deployment runtime flows
Longer-term direction: see ROADMAP.md.
The project is actively iterated in develop, with a working production deployment, scripted release checks, and a substantial admin/ops surface already in place.



