Skip to content

openapi:import — OpenAPI 3.1 \xe2\x86\x92 runnable Univeros project (epic) #160

@tonydspaniard

Description

@tonydspaniard

Goal

Ship bin/altair openapi:import — one command that turns an existing OpenAPI 3.1 document into a directory of Altair YAML specs, and (with --scaffold) into a runnable Univeros project: Actions, Inputs, Responders, tests, entity + migration + repository (when persistence is requested), and a typed client SDK.

The forward chain today is Altair YAML → OpenAPI → SDK. This epic closes the reverse chain: OpenAPI → Altair YAML → working project.

Why

Most teams arriving at Univeros already have an OpenAPI document — generated by their current framework, hand-written, or supplied by a partner. Today the only path into Univeros is to translate every operation into an Altair YAML spec by hand. For a human that's hours of busywork. For an agent it's a token sink the framework can eliminate.

Two concrete wins:

  1. Adoption. "Port my existing service to Univeros" becomes a one-command operation instead of a manual translation exercise.
  2. Benchmark. Adds a credible variant to the tokens-to-ship task: agents handed an OpenAPI doc up-front (a realistic porting scenario) skip spec-authoring entirely. This is exactly the kind of CRUD-with-plumbing work the framework is built for.

It also leans on infrastructure that already exists: Altair\Scaffold\Sdk\Model\OpenApiParser already parses OpenAPI 3.1 into a neutral in-memory model (OpenApiDocument, OperationModel, SchemaType) for SDK emission. Half the work is done.

CLI surface

# Library / no-scaffold
bin/altair openapi:import openapi.yaml                        # → ./api/, specs only
bin/altair openapi:import openapi.yaml --out=specs/

# Full pipeline
bin/altair openapi:import openapi.yaml --scaffold
bin/altair openapi:import openapi.yaml --scaffold --persistence=cycle --queue=redis

# Agent-friendly
bin/altair openapi:import openapi.yaml --dry-run              # report, write nothing
bin/altair openapi:import openapi.yaml --format=json          # structured receipt
bin/altair openapi:import openapi.yaml --force                # clobber existing files

Sub-issues

Docs page (docs/openapi/import.md) + a benchmark task variant ("import-then-scaffold") ship as part of #162's acceptance.

Acceptance criteria

  • bin/altair openapi:import petstore.yaml --out=api/ --scaffold produces a runnable Univeros project that serves every operation in the doc
  • Imported specs pass spec:lint without manual editing
  • spec:emit-openapi against the imported specs reproduces the original doc within documented normalization (see openapi:roundtrip \xe2\x80\x94 drift gate for openapi \xe2\x86\x92 spec \xe2\x86\x92 openapi #164)
  • An OpenAPI doc carrying x-altair-persistence + x-altair-queue extensions imports with persistence + queue artifacts in place
  • A journal:rewind after an --scaffold import cleanly undoes the whole import
  • One mutation event per import lands in .altair/events.jsonl
  • Determinism: same input → byte-identical output (specs + JSON receipt)

Out of scope

  • OpenAPI 2.0 (Swagger). 3.1 only. Users convert first.
  • Custom auth schemes beyond bearerHttpAuthentication and API-key-in-header in v1.
  • Frontend / UI generation.
  • Importing from non-OpenAPI DSLs (gRPC, GraphQL) — separate epics.
  • The webhook + idempotency primitives themselves. This epic only defines the extension keys that point at them.

Dependencies

  • Altair\Scaffold\Sdk\Model\OpenApiParser (already shipped)
  • Altair\Scaffold\Journal\Journal (already shipped)
  • Altair\Events\Contracts\RecorderInterface (already shipped)

Notes for whoever picks this up

Naming convention: openapi:* namespace (not spec:*) because OpenAPI is the source here, not the target. Keep that distinction — it's the only signal that the data flow runs the other way.

The library piece (#161) is the only non-trivial code. The CLI (#162), journal hookup, and events recording are all wiring against existing infrastructure.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions