The problem was not Docker Compose
The mistake would have been to treat Docker Compose as the enemy. Production was working, the tooling was familiar, and the operating model was understandable. The real problem was that the deployment knowledge lived in too many places: environment files, service names, build targets, secret scripts, admin status pages, and human memory.
A platform abstraction is not a different runtime. It is a shared contract that describes what ChatFlow needs, what the target platform provides, and which safety gates must pass before a deploy is allowed to touch production.
The profile is the new source of truth
The profile describes the current production binding: Docker Compose adapter, required backing services, secret render state, health checks, image/runtime expectations, and operator-facing metadata. That profile feeds scripts, validation, deployment status, and the Admin Deployment page.
Once this exists, an OpenShift adapter no longer starts from a blank page. It has to satisfy the same profile contract: where secrets come from, which services are internal or managed, which routes expose HTTP, and what a healthy deployment means.
Secrets moved out of the raw env file
The visible operator change is simple: plain environment files no longer carry raw platform secrets. Those values live encrypted in the repository, are decrypted only on the production host, and are rendered into the runtime environment during the deployment flow.
This gives the repository back its role as the place for configuration, not leaked credentials. The operator interface stayed intact: if no secret values changed, deploying is still one command. The difference is that the deploy now checks rendered secret freshness and refuses stale state before it restarts services.
pull the latest release render + audit secrets # only when secrets changed deploy # preflights, health checks, restart
The Admin Deployment page is not decoration
The platform page now shows the active deployment profile, secret render freshness, health/readiness results, service bindings, and an architecture map that connects the generic layer to the concrete production adapter. That matters because enterprise operators do not want a blog post. They want to see what the running system thinks it is.
The page is intentionally read-heavy. Some settings can become editable later, but only where a browser write can be made safe. Deployment targets, secrets, and managed-service bindings still belong to controlled operational flows.
- Profile visible to operators
- Secret freshness visible before deploy
- Docker Compose remains the production adapter
- Browser writes directly to production secret material
What this buys for OpenShift
OpenShift is still not a checkbox. It brings routes, SCC constraints, registry policy, secret operators, managed backing services, and platform team preferences. The deployment profile does not erase that work. It makes it measurable.
The first real OpenShift rollout should start by filling the provider infrastructure matrix, deciding which databases and queues are managed, rendering manifests, and comparing them against the same contract that production already uses today.