The gate framework

Svitrio’s schema and data layer is built on gate — a small declarative schema language (.gate files) and gate-go, an in-house toolkit that turns those files into SQL and Go at build time. Understanding gate explains a lot about why svitrio behaves the way it does.

What it is

A .gate file declares types, fields, relations and constraints. From one schema, gate-go emits both the SQL DDL (CREATE TABLE IF NOT EXISTS + indexes + foreign keys) and the Go store (the struct, a row scanner, and a full scoped CRUD).

type ai_provider {
  @index(project_id, is_default)
  project_id:   ref<project> @external @on_delete(cascade) @scoped(project_id)
  name:         string  @required
  kind:         string  @required
  api_key:      string  @default("") @sealed
  is_default:   bool    @default(false) @exclusive
}

Annotations carry behaviour: @scoped injects WHERE project_id = ? into every query; @sealed encrypts a field at rest (seal on write, open on read); @exclusive keeps at most one row true per scope inside a transaction; @external + @on_delete(cascade) FKs into another module’s table and cleans up when a tenant is deleted.

How svitrio uses it

Each module co-locates its .gate schema with its Go code and embeds it. go generate produces a *_generated.go store (a drift guard in CI fails the build if it goes stale). At boot the host loads every module’s schema and runs CREATE TABLE IF NOT EXISTS — so composing the whole schema is idempotent and the binary starts from a blank database. Adding a new module is: ship its .gate, its gen.go, and a blank import — no central SQL file is ever edited.

What you get

  • Single source of truth — the .gate file drives both the table and the typed store; they can’t drift.

  • Near-zero boilerplate — a ~30-line type yields a struct, scanner, five CRUD methods, transactional sealing and the exclusive-default invariant.

  • No migration dance — every migration is IF NOT EXISTS; additive columns use AddColumnIfMissing. No version table, no up/down scripts.

  • Multi-tenancy for free@scoped + a cascading ref<project> means every module is tenant-isolated by construction.

  • The foundation of the product layer — the admin already builds UI from a .gate schema plus a presentation layer. Turning “author a schema” into a surface a customer can use to model their own product is the natural next step.