migraguard 0.5.4 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/COMMANDS.md CHANGED
@@ -9,8 +9,17 @@ Create a new migration SQL file with a local-timezone timestamp prefix.
9
9
  ```bash
10
10
  migraguard new add_users_email_index
11
11
  # → db/migrations/20260301_120000__add_users_email_index.sql
12
+
13
+ migraguard new --expand-contract rename_username_to_handle
14
+ # → db/migrations/20260301_120000__rename_username_to_handle/
15
+ # 1_expand.sql
16
+ # 2_backfill.sql
17
+ # 3_switch.sql
18
+ # 4_contract.sql
12
19
  ```
13
20
 
21
+ `--expand-contract` creates a Migration Group directory with four phase templates. See [docs/expand-contract.md](docs/expand-contract.md) for details.
22
+
14
23
  ### `migraguard squash`
15
24
 
16
25
  Squash multiple new (unrecorded in metadata.json) migration files into a single file. Run before merging to a release branch.
@@ -121,7 +130,7 @@ Show the diff between the current DB schema and the saved `schema.sql`.
121
130
  migraguard diff
122
131
  ```
123
132
 
124
- ## Dependency analysis (extension)
133
+ ## Dependency analysis
125
134
 
126
135
  ### `migraguard deps`
127
136
 
@@ -131,3 +140,62 @@ Analyze and display the dependency graph between migration files.
131
140
  migraguard deps
132
141
  migraguard deps --html deps.html # output as HTML with GitGraph.js visualization
133
142
  ```
143
+
144
+ ## Expand/Contract commands
145
+
146
+ Commands for managing long-running Migration Groups. See [docs/expand-contract.md](docs/expand-contract.md) for the full guide.
147
+
148
+ ### `migraguard group-status [group]`
149
+
150
+ Show the current state of Migration Groups (expand/contract phases).
151
+
152
+ ```bash
153
+ migraguard group-status # all groups
154
+ migraguard group-status 20260315_100000__rename_username_to_handle # specific group
155
+ ```
156
+
157
+ ### `migraguard advance <group> <phase> <status>`
158
+
159
+ Record a phase state transition. Used by external executors to report progress.
160
+
161
+ Valid phases: `expand`, `backfill`, `switch`, `contract`.
162
+ Valid statuses: `running`, `completed`, `failed`.
163
+
164
+ ```bash
165
+ migraguard advance 20260315_100000__rename_username_to_handle backfill running
166
+ migraguard advance 20260315_100000__rename_username_to_handle backfill completed
167
+ migraguard advance 20260315_100000__rename_username_to_handle backfill failed
168
+ ```
169
+
170
+ ### `migraguard apply-phase <group> <phase>`
171
+
172
+ Apply a specific phase of a Migration Group via `psql`. Validates prerequisites and acquires advisory lock.
173
+
174
+ ```bash
175
+ migraguard apply-phase 20260315_100000__rename_username_to_handle expand
176
+ migraguard apply-phase 20260315_100000__rename_username_to_handle switch
177
+ migraguard apply-phase 20260315_100000__rename_username_to_handle contract
178
+ ```
179
+
180
+ ### `migraguard gate`
181
+
182
+ Evaluate deployment gate conditions against current Migration Group states. Exit code 0 = pass, 1 = fail.
183
+
184
+ ```bash
185
+ migraguard gate \
186
+ --require "group:rename_username_to_handle.expand_applied" \
187
+ --forbid "group:rename_username_to_handle.contract_completed"
188
+
189
+ migraguard gate --contract-file schema-requirements.json
190
+ ```
191
+
192
+ ### `migraguard baseline`
193
+
194
+ Squash applied migrations into `schema.sql`. Removes squashed files from disk and records the baseline in `metadata.json`.
195
+
196
+ ```bash
197
+ migraguard baseline # squash all except leaves
198
+ migraguard baseline --keep-since 20260315_100000__rename_username_to_handle # keep from cutpoint
199
+ ```
200
+
201
+ Open Migration Groups are excluded from baseline. Requires DB connection.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/migraguard.svg)](https://www.npmjs.com/package/migraguard) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
4
 
5
- An incident-prevention migration tool for PostgreSQL. Enforces safe operational policies via CI gates and DB state tracking, so that common migration accidents are structurally impossible.
5
+ PostgreSQL schema-aware deployment control. Idempotent SQL migrations with CI-enforced integrity checks, expand/contract migration orchestration, schema drift detection, and unified gating across database, application, and infrastructure rollouts.
6
6
 
7
7
  **Prevented accidents:**
8
8
 
@@ -161,14 +161,33 @@ Production deploy completes → all environments have S → the next migration c
161
161
 
162
162
  See [docs/state-model.md](docs/state-model.md) for detailed apply, check, resolve, and squash flows.
163
163
 
164
+ ## Expand/Contract Pattern (Class B Migrations)
165
+
166
+ For long-running schema changes — column renames, type migrations, table splits — migraguard supports the **expand/contract pattern** as a first-class concept. A Migration Group is a directory containing phased SQL files (`expand` → `backfill` → `switch` → `contract`) with a dedicated state machine, deployment gate, and executor commands.
167
+
168
+ ```bash
169
+ # Create a migration group
170
+ migraguard new --expand-contract rename_username_to_handle
171
+
172
+ # Check group state
173
+ migraguard group-status
174
+
175
+ # Deployment gate (CI/CD integration)
176
+ migraguard gate --require "group:rename_username_to_handle.expand_applied"
177
+ ```
178
+
179
+ See [docs/expand-contract.md](docs/expand-contract.md) for the complete guide: file structure, state machine, CI/CD integration patterns, TypeScript API, and idempotency examples.
180
+
164
181
  ## Commands
165
182
 
166
183
  | Command | Description |
167
184
  |---------|-------------|
168
185
  | `new <name>` | Generate a new migration SQL file |
186
+ | `new --expand-contract <name>` | Create an expand/contract migration group |
169
187
  | `squash` | Merge pending files into one for release |
170
188
  | `apply` | Execute pending migrations via `psql` |
171
189
  | `apply --with-drift-check` | Local: drift check → apply → dump update |
190
+ | `apply --from-baseline` | Apply `schema.sql` baseline, then remaining migrations |
172
191
  | `resolve <file>` | Mark a failed migration as skipped (explicit judgment) |
173
192
  | `status` | Display migration status per file |
174
193
  | `editable` | List currently editable files (tail / leaf) |
@@ -179,6 +198,11 @@ See [docs/state-model.md](docs/state-model.md) for detailed apply, check, resolv
179
198
  | `diff` | Show schema diff (DB vs saved dump) |
180
199
  | `deps` | Display dependency graph |
181
200
  | `deps --html <path>` | Generate HTML dependency visualization |
201
+ | `group-status [group]` | Show Migration Group phase states |
202
+ | `advance <group> <phase> <status>` | Record phase state transition (executor) |
203
+ | `apply-phase <group> <phase>` | Apply a specific phase via `psql` |
204
+ | `gate` | Evaluate deployment gate conditions |
205
+ | `baseline` | Squash applied migrations into `schema.sql` |
182
206
 
183
207
  See [COMMANDS.md](COMMANDS.md) for detailed usage, options, and examples.
184
208
 
@@ -382,8 +406,12 @@ UPDATE users SET status = 'active' WHERE status IS NULL;
382
406
  | `ban-reindex` | REINDEX (heavy locks — run as operational job) |
383
407
  | `ban-alter-system` | ALTER SYSTEM (cluster-wide config change) |
384
408
  | `ban-set-session-replication-role` | SET session_replication_role (disables triggers/FK) |
409
+ | `expand-requires-idempotent-pattern` | CREATE without IF NOT EXISTS in expand phase *(expand only)* |
410
+ | `backfill-requires-where-clause` | UPDATE/DELETE without WHERE in backfill phase *(backfill only)* |
411
+ | `backfill-ban-ddl` | DDL statements in backfill phase *(backfill only)* |
412
+ | `contract-requires-allow-directive` | DROP without migraguard:allow in contract phase *(contract only)* |
385
413
 
386
- Each rule can be set to `"error"` (default — fail lint), `"warn"` (report but pass), or `"off"` (skip). Per-file exceptions use a comment directive:
414
+ Each rule can be set to `"error"` (default — fail lint), `"warn"` (report but pass), or `"off"` (skip). Phase-specific rules (marked above) only activate for the corresponding expand/contract phase file. Per-file exceptions use a comment directive:
387
415
 
388
416
  ```sql
389
417
  -- migraguard:allow ban-drop-column, ban-alter-column-type
@@ -399,8 +427,13 @@ project-root/
399
427
  ├── migraguard.config.json
400
428
  ├── db/
401
429
  │ ├── migrations/
402
- │ │ ├── 20260301_120000__create_users_table.sql
430
+ │ │ ├── 20260301_120000__create_users_table.sql ← Class A (single file)
403
431
  │ │ ├── 20260302_093000__add_email_index.sql
432
+ │ │ ├── 20260315_100000__rename_username_to_handle/ ← Class B (directory)
433
+ │ │ │ ├── 1_expand.sql
434
+ │ │ │ ├── 2_backfill.sql
435
+ │ │ │ ├── 3_switch.sql
436
+ │ │ │ └── 4_contract.sql
404
437
  │ │ └── ...
405
438
  │ ├── schema.sql # Normalized schema dump (generated)
406
439
  │ └── .migraguard/
@@ -513,3 +546,4 @@ No. `verify` creates a temporary shadow DB, applies migrations twice, then drops
513
546
  - [docs/state-model.md](docs/state-model.md) — Apply/check/resolve/squash flows, INSERT-only design, regression detection
514
547
  - [docs/dag-internals.md](docs/dag-internals.md) — Dependency analysis, explicit declarations, DAG migration compatibility
515
548
  - [docs/safe-ddl.md](docs/safe-ddl.md) — Safe DDL patterns for PostgreSQL (lock timeout, CONCURRENTLY, batch backfills)
549
+ - [docs/expand-contract.md](docs/expand-contract.md) — Expand/contract pattern: phased migrations, state machine, CI/CD deployment gate, TypeScript API