Skip to content

Bringing an existing system

Most organizations already run systems when they adopt a platform, and those systems rarely look like a fresh product from Airframe’s template. This page says plainly what Airframe can take in today, what a product gives up when it skips the template, and which parts of the adoption path are designed but not built, so you can plan without surprises.

The short version: the catalog can register an existing system, and the platform then builds its cloud side, but nothing built today moves its code, its data or its deployment onto the platform. The working path today is a new product from the template, with the existing application brought into it.

A product entry can say template: none, meaning “do not render a repository for me”, together with one of two fields:

  • source_repo, the address of the one repository the system lives in today;
  • repos, a list of the system’s repositories, each with a role: infra, service, worker, frontend or migration.

The catalog’s lint refuses template: none without one of them (enforced). An entry may also carry conformance_level, from 1 to 3, how far along the platform’s adoption ladder the product is. The schema accepts it, and nothing reads it yet.

The reconcilers treat it like any other product. The project factory creates its two projects and its identities, and bills them once the product is listed in the factory’s billed_products. The domain’s GitLab root creates a repository at the product’s path in its context group, with its protected main.

That repository stays empty. The platform’s render job, the only account allowed to push a product repository’s first commit, renders entries that say template: fullstack and skips the rest. Nothing reads source_repo or repos yet. So today template: none gives a system a place in the catalog and its cloud projects, and leaves its code where it is.

A product rendered from the golden path’s template starts with:

  • a working application for its stack, with JSON logs, traces and a health endpoint already wired to the platform’s telemetry;
  • its Terraform roots, infra/np, infra/sandbox, infra/prod, infra/eph for previews and infra/grafana, composed from the platform’s modules;
  • a pipeline made only of the platform’s components;
  • .airframe/ with the list of images the trusted builder builds and the seeds for the sandbox and previews;
  • a file that names the product’s secrets and never holds a value, a runbook, a CODEOWNERS file that names the context’s group as owner of the paths the ownership model protects, and instructions for a coding agent.

A product without the template has to bring each of these itself, and the platform’s build and test jobs know only the three template stacks. A product on another stack runs none of them, and its merge requests fail the test coverage check until its entry sets quality.minimum_coverage to zero, a change a team lead or a domain lead approves.

  1. Register the system as a new product with template: fullstack and the closest stack, following the first product.
  2. Replace the rendered application in apps/ with the existing code, through ordinary merge requests in the new repository. The team may change the Dockerfile or add more, as long as each one starts from one of the platform’s base images and is listed in .airframe/images.yaml, as any stack explains.
  3. Recreate the system’s cloud resources through the product’s roots. Existing data has to be moved by the team: the import of existing databases and Terraform state into the product’s roots is part of the adoption design below, and is designed.

Landing-zone’s ADR-0016 and ADR-0017 describe how the platform will take in the most common shape of an existing system. Both decisions are still proposals, and the catalog’s schema has only their first fields.

  • Products spread over several repositories (designed). A product keeps one repository per application, plus a repository that changes its database schema and a new infra repository rendered by the template for what the product decides. Each repository has its own Terraform state, images and preview hostname, <product>-<repo>-eph-<iid>, and the migration repository’s identity owns the database schema.
  • Adoption by moving the group (designed). A product joins the platform when its GitLab group is transferred under projectairframe/<journey>/<domain>/<context>/<product>/, one recorded transfer per product under the exceptional procedure. The entry would carry source_group, the group’s old path, until the move.
  • Hostname aliases (designed). An adopted product’s existing hostnames, listed in the entry’s hostnames, would be served by the shared edge as aliases of its canonical hostname. The catalog’s schema does not accept the field yet, so the lint refuses an entry that uses it.
  • Dependencies kept outside (designed). A data store the product keeps running elsewhere, such as a MongoDB, would be a dependencies entry: the network opens the way to it, and the policy pack warns.
  • GKE as a second place to run (designed). A product could say runtime: gke and run in its own namespaces on one shared Autopilot cluster per edition, deployed by Argo CD from what the product’s root applies, with no cluster credential in any pipeline. No cluster root exists yet.
  • The adoption ladder and airframe adopt (designed). Level 1 registers a product, level 2 hosts its repositories and infrastructure on the platform, and level 3 adopts the template’s layout; conformance_level records the level, and nothing acts on it yet. A command, airframe adopt, would draft the entry and the merge requests; it is planned last, after the manual path has been rehearsed.

Until these are built, an existing system on Airframe is a new product that the team moves its application into.

Where it lives

In the landing-zone repository:

In the catalog repository:

In the golden-path repository:

In the control-plane repository:

MIT license. Copyright Airframe contributors.

This site describes platform release 2026.10.20-1.