# PostgreSQL model migrations

Recorded migrations are Cicadel's standard schema workflow. GORM handles runtime
queries; it never replaces history with `AutoMigrate`. The first-party
`contrib/migrations` module supplies generation, historical state, version
dependencies, execution, verification and recovery. Standard management commands
use this implementation.

## Ask your agent

```text
Read https://cicadel.fauzaanu.com/en/dev/topics/migrations/index.md.
Add [model or schema change] through the application's registered Models and
recorded PostgreSQL history. Generate and review SQL, test against a disposable
database, and report the plan before touching an existing production database.
Do not use AutoMigrate or rewrite applied migration files.
```

## Standard workflow

`startproject` includes accounts, formsets, migration commands and typed query
generation. `startapp blog` creates an app with `Models()`, `MigrationDirectory`
and an embedded migration filesystem. Register `blog.New()` in
`project/apps.go`, retaining the existing first-party registrations.

Add and register a model in `apps/blog/models.go`:

<!-- example: migrations/apps/blog/models.go -->
```go
package blog

import "github.com/fauzaanu/cicadel"

type Note struct {
    ID int64 `gorm:"primaryKey"`
    Title string `gorm:"not null"`
}

func (Note) TableName() string { return "blog_notes" }

func Models() []cicadel.Model {
    return []cicadel.Model{cicadel.ModelOf[Note]("note", "blog_notes")}
}
```

From the project root:

```sh
go run manage.go makemigrations blog --name initial
go run manage.go makemigrations blog --check
go run manage.go generatequeries
DATABASE_URL='postgres://.../app' go run manage.go migrate plan
DATABASE_URL='postgres://.../app' go run manage.go migrate
DATABASE_URL='postgres://.../app' go run manage.go migrate verify
DATABASE_URL='postgres://.../app' go run manage.go showmigrations
```

Generation and typed query generation run offline, even if `DATABASE_URL` points
to an unavailable server. App factories used by `InstalledApps(nil)` must remain
free of database work. Runtime commands require PostgreSQL. Generation compares
registered models with recorded historical state, never a developer's database.
Review and commit generated SQL and query files. `--check` does not write files.
Build the application again after generating SQL so its embedded history is current.

Model names, types and table ownership use the same public `ModelOf` registry for
migrations and typed queries. Declared tables must agree with GORM's table names.
Configure pinned cross-app historical references, naming strategies and custom
type mappings in `project/migrations.go` through `management.ModelMigrationOptions`.
Explicit rename, removal, conversion and backfill declarations use
`makemigrations APP --changes changes.json`; see the [operation contract](https://cicadel.fauzaanu.com/en/dev/ref/migrations/index.md).

## Core module composition

The migration engine is a core default distributed through an installable Go
module. Standard projects already include its management commands. Register
models and migration sources through the app contract, and generate package-owned
migrations in the package source checkout. Application builds load that recorded
history from the embedded filesystem.

Cicadel has no releases. These instructions describe the current development
implementation; use the same framework revision for the CLI and application.

## Recovery

Management commands load all registered migration sources into one dependency
catalog and use the runner's shared PostgreSQL lock. Applications must register
every app whose applied history they manage. Use `migrate plan --target APP=VERSION`
to review a target, then `migrate apply --target APP=VERSION --allow-data-loss` for
a deliberately reviewed rollback. `migrate baseline --reason TEXT` verifies an
eligible pre-existing initial schema. Nontransactional index recovery uses
`migrate recover --migration APP:VERSION --recovery retry|complete`.

Migration history is not a data backup. Unsupported changes fail explicitly; see
[the supported PostgreSQL operations](https://cicadel.fauzaanu.com/en/dev/ref/migrations/index.md) and
[acceptance evidence](https://cicadel.fauzaanu.com/en/dev/sources/contrib/migrations/ACCEPTANCE.md).
