$ rathvan new ./your-product  →  done. now what?

After the scaffold

You have a repository that compiles, migrates and runs, with identity, tenancy, forced row-level security, audit and tests already in it. What you do not have yet is a product. This is the order that wastes the least time — and an honest account of which parts are yours.

  1. already works

    See it running, before you read a line of it

    One command. Database up, application up, URL printed. This is the answer to “how do I look at the actual product rather than the platform”.

    $ rathvan run

    Four things are live immediately, and each proves something different:

    Open thisWhat it proves
    /actuator/healthThe app booted and reached its database. Read the body, not the status code — a health check that only returns 200 has told you nothing.
    /console.htmlA status page in your product’s own design tokens, so the theme is real rather than a mock.
    /ui.htmlEvery component you inherited, on one page. A catalogue, not your application — see step 4.
    /api/v1/_metaYour tables, through a read-only API. Needs the bearer token printed at startup.

    That token is generated per run and never written down. It is not a credential to keep — a deployment has to set its own, deliberately, which is why the API is closed until someone does.

  2. already written

    Read SCAFFOLD.md — it records what was chosen

    In a finished repository a decision and a default look identical. This file is the only place that distinction survives, and it is worth four minutes now rather than an argument later.

    It lists the bands you took and — more usefully — what was deliberately left out and why. If there is no integrations table, this is where it says the INTEGRATION band was not selected, rather than leaving you to conclude the scaffold forgot.

    scaffold.lock beside it records a SHA-256 per generated file plus the builder and kernel versions, so “where did this file come from?” still has an answer in eighteen months.

  3. yours

    Define the PRODUCT band. It is the only one that is yours

    Everything else — identity, tenancy, audit, security, the data plane — is inherited and should not be rebuilt. PRODUCT is the band with nothing in it, because it is the part only you know.

    Start with the nouns: what a record represents, who owns it, who may read it. Then one additive migration with a rollback note in its header. The gate tests already enforce the parts people forget:

    • Row-level security enabled and forced on anything holding user data — enabled-but-not-forced does not apply to the role your app connects as, and it looks enforced.
    • One writer per table. A second writer is how invariants drift, undetectably by any test that exercises only one of them.
    • No cross-capability joins. The cheapest coupling to write and the most expensive to unpick.
  4. yours — and yes, use an agent

    Build the interface. This is where a coding agent belongs

    Be clear about what you were given: ui.css and ui.html are a component catalogue and a set of design tokens, not an application. There is no customer-facing UI in the scaffold and there was never meant to be — a generated interface for a product nobody has described yet is scaffolding you would delete.

    So point your coding agent at this repository and build the screens. That is not a workaround; it is the intended division of labour.

    Rathvan is not a replacement for a coding agent — it is what decides whether the agent’s output is allowed to become your product.

    What makes that safe here is that the checks are executable rather than advisory. An agent that writes a table without forced RLS, edits an applied migration, or imports a vendor SDK into core does not get a polite review comment — the build stops. So give the agent the repository and the gates:

    $ ./gradlew testCounts   # never bare `test` — see step 7

    Two things worth stating to the agent explicitly, because they are house rules it cannot infer: money is an integer in the smallest unit and priced on the server, never client-supplied; and government identifiers, salaries, bank details, phone numbers and raw user notes are never logged or sent to a model.

  5. yours

    Integrations: a port first, an adapter second

    Every external service goes behind an interface in your own code, with a stub beside the real adapter so tests run without credentials. No vendor import belongs in core. This is the rule that keeps a vendor decision revisitable instead of permanent.

    If you did not select the INTEGRATION band, the provider and connection tables are not there — a choice recorded in SCAFFOLD.md, not an omission. Adding them later is a new migration, never an edit to an applied one.

  6. already works

    Deploy it — staging first, and verify against the host

    deploy/ holds a script, a README and scaling.env with the instances-times-pool arithmetic. The script does not create your VPC, subnets or security groups: those are supplied, deliberately, because inheriting a network nobody chose is expensive to undo.

    $ ./deploy/deploy.sh

    The valuable part is not the deploy. It is the numbered checks that run after it — rollout landed, host answers, correct revision serving, and a real request against the deployed thing. Each exists because a deploy once reported success while still serving the old build.

    Never trust the exit code. A deploy tool saying “complete” and a host serving your change are two different claims — check the second one with a real request.

  7. already works

    Keep the gates green, and read counts rather than success lines

    An up-to-date test task prints BUILD SUCCESSFUL having run nothing, which is indistinguishable from having run everything. testCounts never goes up-to-date and fails when the count drops — a fall is as serious as a failure, because it is the only signal that catches a suite which quietly stopped running.

    Two habits worth keeping from day one: a filtered run that matched nothing reports success, so finish with the full count; and a conditionally-skipped suite reports the same comfortable number whether it is healthy or has been broken for months.

“Should we convert it to microservices?”

Not yet — and the useful thing is knowing what would tell you otherwise. What you have is a modular monolith: one deployable, one database, with capability boundaries enforced by structure and tests rather than by network calls. Around sixty capability packages run this way in the reference platform, and that is correct for its size.

When you want evidence rather than an opinion, ask:

$ rathvan split

It reports, per capability, whether anything imports it, what would have to travel with it, and how many call sites would become network calls — cheapest first. The valuable output is usually the caller list, because converting those is work worth doing whether or not you ever split.

What genuinely forces a split

Two release cadences that actually conflict. A resource profile starving its neighbours on a shared box. A compliance boundary needing separate custody. A team that cannot merge without queueing behind another’s tests.

What does not

The size of the codebase. A diagram that looks tidier. A buyer asking whether the architecture is microservices. Splitting before the coupling is gone only adds latency and partial failure to coupling you still have.

One thing the report cannot see, and says so itself every time it runs: it reads import edges only. Joins across capability tables, two writers to one table, and code that publishes an event expecting the subscriber to have finished are all invisible to it. READY means the import graph does not object — never that extraction is safe.

What you do not have, stated plainly

A customer-facing UI

A component catalogue and design tokens. The screens are yours.

A write API

The generated data API is read-only on purpose. A generated write path would be a guess about your invariants.

Business logic

The PRODUCT band is empty by design — the part the intake could not answer for you.

Anything hosted

Self-hosted from the first day. Your code, your keys, your database — and your uptime.

If a command here disagrees with your own SCAFFOLD.md, trust SCAFFOLD.md: it was generated from your answers, and this page was not.