db-migration-kit 1.0.0__tar.gz
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.
- db_migration_kit-1.0.0/PKG-INFO +393 -0
- db_migration_kit-1.0.0/README.md +367 -0
- db_migration_kit-1.0.0/db_migration_kit/__init__.py +16 -0
- db_migration_kit-1.0.0/db_migration_kit/bootstrap.py +12 -0
- db_migration_kit-1.0.0/db_migration_kit/cli.py +155 -0
- db_migration_kit-1.0.0/db_migration_kit/config.py +35 -0
- db_migration_kit-1.0.0/db_migration_kit/inspector.py +151 -0
- db_migration_kit-1.0.0/db_migration_kit/loader.py +15 -0
- db_migration_kit-1.0.0/db_migration_kit/project.py +41 -0
- db_migration_kit-1.0.0/db_migration_kit/providers/__init__.py +13 -0
- db_migration_kit-1.0.0/db_migration_kit/providers/base.py +56 -0
- db_migration_kit-1.0.0/db_migration_kit/providers/registry.py +18 -0
- db_migration_kit-1.0.0/db_migration_kit/providers/sqlalchemy_base.py +699 -0
- db_migration_kit-1.0.0/db_migration_kit/providers/sqlalchemy_postgres.py +5 -0
- db_migration_kit-1.0.0/db_migration_kit/providers/sqlalchemy_sqlite.py +8 -0
- db_migration_kit-1.0.0/db_migration_kit/py.typed +1 -0
- db_migration_kit-1.0.0/db_migration_kit/runner.py +233 -0
- db_migration_kit-1.0.0/db_migration_kit/scaffold.py +255 -0
- db_migration_kit-1.0.0/db_migration_kit/schema.py +86 -0
- db_migration_kit-1.0.0/db_migration_kit/snapshots.py +96 -0
- db_migration_kit-1.0.0/db_migration_kit/sources/__init__.py +9 -0
- db_migration_kit-1.0.0/db_migration_kit/sources/base.py +15 -0
- db_migration_kit-1.0.0/db_migration_kit/sources/metadata.py +90 -0
- db_migration_kit-1.0.0/db_migration_kit/sources/persistence_kit_registry.py +176 -0
- db_migration_kit-1.0.0/pyproject.toml +53 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: db-migration-kit
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Reusable Postgres migration bootstrap and execution toolkit
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: postgres,alembic,migration,rds,ecs
|
|
7
|
+
Author: Andres Felipe Serrano Barrios
|
|
8
|
+
Author-email: andresfserrano1@gmail.com
|
|
9
|
+
Requires-Python: >=3.11,<4.0
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Topic :: Database
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Dist: alembic (>=1.15.2,<2.0.0)
|
|
21
|
+
Requires-Dist: psycopg[binary] (>=3.2.0,<4.0.0)
|
|
22
|
+
Requires-Dist: sqlalchemy[asyncio] (>=2.0.43,<3.0.0)
|
|
23
|
+
Requires-Dist: typing-extensions (>=4.12.0,<5.0.0)
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# db_migration_kit
|
|
27
|
+
|
|
28
|
+
Kit reutilizable para revisar y ejecutar migraciones de esquema de base de datos en proyectos Python.
|
|
29
|
+
|
|
30
|
+
## Objetivo
|
|
31
|
+
|
|
32
|
+
Este paquete busca separar tres responsabilidades:
|
|
33
|
+
|
|
34
|
+
- describir el esquema deseado
|
|
35
|
+
- revisar el impacto antes de aplicarlo
|
|
36
|
+
- ejecutar migraciones de forma controlada
|
|
37
|
+
|
|
38
|
+
La idea central es que el flujo normal no sea `aplicar y ya`, sino:
|
|
39
|
+
|
|
40
|
+
1. `synth`: sintetizar el estado deseado
|
|
41
|
+
2. `diff`: comparar estado actual vs. estado deseado
|
|
42
|
+
3. `review`: explicar qué cambia
|
|
43
|
+
4. `upgrade`: aplicar cambios aceptados
|
|
44
|
+
|
|
45
|
+
## Principios
|
|
46
|
+
|
|
47
|
+
- reutilizable entre proyectos
|
|
48
|
+
- documentación y salida orientadas a revisión humana
|
|
49
|
+
- desacoplado del arranque de la aplicación
|
|
50
|
+
- desacoplado de un motor específico
|
|
51
|
+
- extensible mediante providers
|
|
52
|
+
|
|
53
|
+
## Providers
|
|
54
|
+
|
|
55
|
+
El kit no asume una base de datos concreta.
|
|
56
|
+
|
|
57
|
+
Cada proyecto utiliza un provider que conoce:
|
|
58
|
+
|
|
59
|
+
- cómo inspeccionar el esquema actual
|
|
60
|
+
- cómo construir el esquema deseado
|
|
61
|
+
- cómo calcular diferencias
|
|
62
|
+
- cómo ejecutar migraciones para ese backend
|
|
63
|
+
|
|
64
|
+
Providers disponibles en esta versión:
|
|
65
|
+
|
|
66
|
+
- `sqlalchemy-sqlite`
|
|
67
|
+
- `sqlalchemy-postgres`
|
|
68
|
+
|
|
69
|
+
Ambos comparten una base común en SQLAlchemy y Alembic, pero el comportamiento de inspección puede variar por dialecto. Por ejemplo, `postgres` permite revisar enums nativos con más precisión que `sqlite`.
|
|
70
|
+
|
|
71
|
+
## Flujo local
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
poetry run python -m db_migration_kit.cli inspect-project --root .
|
|
75
|
+
poetry run python -m db_migration_kit.cli bootstrap --root .
|
|
76
|
+
poetry run python -m db_migration_kit.cli doctor --project-module migration_project
|
|
77
|
+
poetry run python -m db_migration_kit.cli review --project-module migration_project
|
|
78
|
+
poetry run python -m db_migration_kit.cli diff --project-module migration_project
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Flujo generico de integracion
|
|
82
|
+
|
|
83
|
+
Para integrar el kit en un proyecto Python como paquete publicado:
|
|
84
|
+
|
|
85
|
+
1. instalar `db-migration-kit` desde PyPI
|
|
86
|
+
2. correr `inspect-project` para detectar provider, source y puntos de integracion
|
|
87
|
+
3. correr `bootstrap` para generar `migration_project.py` y `migrations/*`
|
|
88
|
+
4. revisar el `migration_project.py` generado y confirmar la forma correcta de construir la URL de la base
|
|
89
|
+
5. correr `doctor` para validar que el proyecto de migracion es cargable
|
|
90
|
+
6. correr `review` y `diff` contra una base real
|
|
91
|
+
|
|
92
|
+
Ejemplo de instalacion:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
poetry add db-migration-kit
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Comandos base:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
poetry run python -m db_migration_kit.cli inspect-project --root .
|
|
102
|
+
poetry run python -m db_migration_kit.cli bootstrap --root .
|
|
103
|
+
poetry run python -m db_migration_kit.cli doctor --project-module migration_project
|
|
104
|
+
poetry run python -m db_migration_kit.cli review --project-module migration_project
|
|
105
|
+
poetry run python -m db_migration_kit.cli diff --project-module migration_project
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Como leer el resultado
|
|
109
|
+
|
|
110
|
+
El kit no usa una sola categoria de cambio.
|
|
111
|
+
|
|
112
|
+
Lecturas principales:
|
|
113
|
+
|
|
114
|
+
- `agregar`, `modificar`, `eliminar`: drift real entre la base y el esquema deseado
|
|
115
|
+
- `riesgo`: el kit detecto un caso ambiguo que requiere revision manual
|
|
116
|
+
- `pendiente`: diferencia esperable pero todavia no materializada
|
|
117
|
+
|
|
118
|
+
En proyectos con `persistence_kit`, una tabla puede aparecer como:
|
|
119
|
+
|
|
120
|
+
- `pendiente / tabla-lazy`: el repositorio esta registrado y forma parte del esquema deseado, pero la tabla aun no existe fisicamente porque `persistence_kit` la crea de forma lazy en el primer uso
|
|
121
|
+
|
|
122
|
+
Eso no debe interpretarse automaticamente como una migracion obligatoria.
|
|
123
|
+
|
|
124
|
+
## Primera snapshot
|
|
125
|
+
|
|
126
|
+
La primera snapshot no significa necesariamente "aplicar cambios ya". Significa capturar una linea base entendible del proyecto.
|
|
127
|
+
|
|
128
|
+
El flujo recomendado para una primera snapshot es:
|
|
129
|
+
|
|
130
|
+
1. levantar una base controlada del proyecto
|
|
131
|
+
2. correr `review`
|
|
132
|
+
3. separar hallazgos en tres grupos:
|
|
133
|
+
- drift real
|
|
134
|
+
- objetos legacy
|
|
135
|
+
- materializacion lazy pendiente
|
|
136
|
+
4. usar `diff` como salida estructurada de esa primera linea base
|
|
137
|
+
|
|
138
|
+
Ejemplo:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
poetry run python -m db_migration_kit.cli review --project-module migration_project
|
|
142
|
+
poetry run python -m db_migration_kit.cli diff --project-module migration_project
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Si el resultado contiene solo `pendiente / tabla-lazy`, la lectura correcta es:
|
|
146
|
+
|
|
147
|
+
- el esquema deseado ya quedo bien identificado
|
|
148
|
+
- no hay drift duro relevante
|
|
149
|
+
- solo faltan tablas que el sistema crea cuando realmente usa esos repositorios
|
|
150
|
+
|
|
151
|
+
## Recomendacion para proyectos con persistence_kit
|
|
152
|
+
|
|
153
|
+
Si el proyecto usa `persistence_kit`, la expectativa correcta es:
|
|
154
|
+
|
|
155
|
+
- el schema source describe lo que deberia existir segun `register_entity`
|
|
156
|
+
- la base puede no tener aun todas las tablas si algunos repositorios nunca se han usado
|
|
157
|
+
- `review` no deberia forzar a cambiar ese comportamiento
|
|
158
|
+
|
|
159
|
+
Por eso el kit distingue entre:
|
|
160
|
+
|
|
161
|
+
- drift estructural real
|
|
162
|
+
- materializacion lazy pendiente
|
|
163
|
+
|
|
164
|
+
La primera snapshot debe preservar esa distincion, no borrarla.
|
|
165
|
+
|
|
166
|
+
## Snapshots versionadas
|
|
167
|
+
|
|
168
|
+
El kit guarda snapshots versionadas por proyecto en:
|
|
169
|
+
|
|
170
|
+
```text
|
|
171
|
+
migrations/snapshots/
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Esa ruta se deriva automaticamente desde `migrations_dir`, asi que el kit sabe siempre donde buscarlas.
|
|
175
|
+
|
|
176
|
+
Comandos:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
poetry run python -m db_migration_kit.cli snapshot-create --project-module migration_project
|
|
180
|
+
poetry run python -m db_migration_kit.cli snapshot-create --project-module migration_project --label baseline
|
|
181
|
+
poetry run python -m db_migration_kit.cli snapshot-list --project-module migration_project
|
|
182
|
+
poetry run python -m db_migration_kit.cli snapshot-show --project-module migration_project --version-id v001
|
|
183
|
+
poetry run python -m db_migration_kit.cli snapshot-delete --project-module migration_project --version-id v001
|
|
184
|
+
poetry run python -m db_migration_kit.cli snapshot-apply --project-module migration_project --version-id v001
|
|
185
|
+
poetry run python -m db_migration_kit.cli snapshot-rollback --project-module migration_project --version-id v001
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Convencion:
|
|
189
|
+
|
|
190
|
+
- `v001`, `v002`, `v003`: snapshots secuenciales
|
|
191
|
+
- `v001-baseline`, `v002-post-auth`: snapshots con etiqueta opcional
|
|
192
|
+
|
|
193
|
+
Cada snapshot guarda:
|
|
194
|
+
|
|
195
|
+
- `review`
|
|
196
|
+
- `diff`
|
|
197
|
+
- `desired_snapshot`
|
|
198
|
+
- `alembic_revision`
|
|
199
|
+
- metadatos de proyecto, provider, fecha y version
|
|
200
|
+
|
|
201
|
+
### Como crear la primera snapshot
|
|
202
|
+
|
|
203
|
+
Si ya validaste el proyecto con `doctor`, la primera snapshot versionada se crea asi:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
poetry run python -m db_migration_kit.cli snapshot-create --project-module migration_project --label baseline
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Luego puedes listar y revisar:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
poetry run python -m db_migration_kit.cli snapshot-list --project-module migration_project
|
|
213
|
+
poetry run python -m db_migration_kit.cli snapshot-show --project-module migration_project --version-id v001-baseline
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
La primera snapshot no reemplaza `review` ni `diff`. Los conserva como baseline versionado.
|
|
217
|
+
|
|
218
|
+
## Aplicar una snapshot
|
|
219
|
+
|
|
220
|
+
Si el proyecto ya tiene revisiones Alembic reales, el kit puede aplicar o volver a una snapshot usando la revision asociada guardada dentro de la snapshot.
|
|
221
|
+
|
|
222
|
+
Comandos:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
poetry run python -m db_migration_kit.cli snapshot-apply --project-module migration_project --version-id v003
|
|
226
|
+
poetry run python -m db_migration_kit.cli snapshot-rollback --project-module migration_project --version-id v001-baseline
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Semantica:
|
|
230
|
+
|
|
231
|
+
- `snapshot-apply`: mueve la base a la revision Alembic asociada a la snapshot elegida
|
|
232
|
+
- `snapshot-rollback`: usa la misma resolucion pero con intencion semantica de volver a una version anterior
|
|
233
|
+
|
|
234
|
+
El usuario trabaja con snapshots. Alembic se usa por detras como motor de upgrade/downgrade.
|
|
235
|
+
|
|
236
|
+
## Que significa que una snapshot sea "ejecutable"
|
|
237
|
+
|
|
238
|
+
Una snapshot puede estar en dos estados:
|
|
239
|
+
|
|
240
|
+
- semantica: describe el esquema esperado, pero no tiene una revision Alembic asociada distinta
|
|
241
|
+
- ejecutable: tiene una `alembic_revision` real y el kit puede mover la base hacia esa version usando `snapshot-apply` o `snapshot-rollback`
|
|
242
|
+
|
|
243
|
+
Ejemplo:
|
|
244
|
+
|
|
245
|
+
- `v001-baseline -> alembic_revision = base`
|
|
246
|
+
- `v002-after-phone -> alembic_revision = c3afdddecb7e`
|
|
247
|
+
|
|
248
|
+
En ese escenario:
|
|
249
|
+
|
|
250
|
+
- `v001-baseline` describe el baseline inicial
|
|
251
|
+
- `v002-after-phone` ya representa una version ejecutable del esquema
|
|
252
|
+
|
|
253
|
+
## Flujo recomendado para crear una primera version ejecutable
|
|
254
|
+
|
|
255
|
+
1. integrar el kit
|
|
256
|
+
2. validar el proyecto con `doctor`
|
|
257
|
+
3. revisar el estado actual con `review` y `diff`
|
|
258
|
+
4. crear la baseline inicial
|
|
259
|
+
5. introducir un cambio real de esquema en una entidad ya materializada
|
|
260
|
+
6. volver a correr `review` y `diff`
|
|
261
|
+
7. crear una nueva snapshot
|
|
262
|
+
8. dejar que el kit genere una revision Alembic y la asocie a esa snapshot
|
|
263
|
+
9. aplicar esa snapshot con `snapshot-apply`
|
|
264
|
+
|
|
265
|
+
Comandos tipicos:
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
poetry run python -m db_migration_kit.cli snapshot-create --project-module migration_project --label baseline
|
|
269
|
+
poetry run python -m db_migration_kit.cli review --project-module migration_project
|
|
270
|
+
poetry run python -m db_migration_kit.cli diff --project-module migration_project
|
|
271
|
+
poetry run python -m db_migration_kit.cli snapshot-create --project-module migration_project --label after-change
|
|
272
|
+
poetry run python -m db_migration_kit.cli snapshot-list --project-module migration_project
|
|
273
|
+
poetry run python -m db_migration_kit.cli snapshot-apply --project-module migration_project --version-id v002-after-change
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Como interpretar review y diff
|
|
277
|
+
|
|
278
|
+
El significado operativo de la salida es:
|
|
279
|
+
|
|
280
|
+
- `agregar`, `modificar`, `eliminar`: drift real o cambio de esquema aplicable
|
|
281
|
+
- `pendiente / tabla-lazy`: el esquema deseado incluye esa tabla, pero el proyecto la materializa lazy y todavia no existe fisicamente
|
|
282
|
+
- `riesgo`: el kit detecto algo ambiguo y requiere revision manual
|
|
283
|
+
|
|
284
|
+
Entonces:
|
|
285
|
+
|
|
286
|
+
- si `review` queda vacio, la base esta alineada con el esquema deseado
|
|
287
|
+
- si solo queda `pendiente / tabla-lazy`, la base esta alineada salvo la materializacion lazy esperada
|
|
288
|
+
- si hay `agregar/modificar/eliminar`, existe drift o cambio real de esquema
|
|
289
|
+
|
|
290
|
+
## Modo de trabajo en desarrollo local
|
|
291
|
+
|
|
292
|
+
Si estas desarrollando el kit mismo, puedes iterar localmente antes de publicar una nueva version:
|
|
293
|
+
|
|
294
|
+
1. actualizar el codigo del paquete
|
|
295
|
+
2. reconstruir o reinstalar el entorno local del proyecto consumidor
|
|
296
|
+
3. usar snapshots para versionar el estado esperado
|
|
297
|
+
4. usar `snapshot-apply` para probar upgrades reales
|
|
298
|
+
|
|
299
|
+
## Modo de trabajo en un entorno persistente
|
|
300
|
+
|
|
301
|
+
Si el entorno tiene datos y no debe reiniciarse desde cero:
|
|
302
|
+
|
|
303
|
+
- no destruir volumenes como rutina
|
|
304
|
+
- crear una snapshot antes de actualizar codigo
|
|
305
|
+
- hacer pull del codigo
|
|
306
|
+
- reconstruir imagen
|
|
307
|
+
- revisar `review/diff`
|
|
308
|
+
- aplicar la snapshot objetivo
|
|
309
|
+
- volver a validar el esquema
|
|
310
|
+
|
|
311
|
+
Secuencia recomendada:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
poetry run python -m db_migration_kit.cli snapshot-create --project-module migration_project --label pre-pull
|
|
315
|
+
git pull
|
|
316
|
+
poetry install
|
|
317
|
+
poetry run python -m db_migration_kit.cli review --project-module migration_project
|
|
318
|
+
poetry run python -m db_migration_kit.cli diff --project-module migration_project
|
|
319
|
+
poetry run python -m db_migration_kit.cli snapshot-apply --project-module migration_project --version-id <objetivo>
|
|
320
|
+
poetry run python -m db_migration_kit.cli review --project-module migration_project
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Integracion con CI/CD
|
|
324
|
+
|
|
325
|
+
El kit puede integrarse en CI/CD de dos formas:
|
|
326
|
+
|
|
327
|
+
1. validacion
|
|
328
|
+
- correr `doctor`
|
|
329
|
+
- correr `diff`
|
|
330
|
+
- fallar si hay drift real inesperado
|
|
331
|
+
|
|
332
|
+
2. despliegue controlado
|
|
333
|
+
- aplicar una snapshot ejecutable
|
|
334
|
+
- validar con `review`
|
|
335
|
+
- desplegar la aplicacion solo si el esquema queda alineado
|
|
336
|
+
|
|
337
|
+
Ejemplo de validacion:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
python -m db_migration_kit.cli doctor --project-module migration_project
|
|
341
|
+
python -m db_migration_kit.cli diff --project-module migration_project
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Ejemplo de despliegue:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
python -m db_migration_kit.cli snapshot-apply --project-module migration_project --version-id v003-release
|
|
348
|
+
python -m db_migration_kit.cli review --project-module migration_project
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## Limites actuales
|
|
352
|
+
|
|
353
|
+
El kit ya puede:
|
|
354
|
+
|
|
355
|
+
- inspeccionar el esquema actual
|
|
356
|
+
- sintetizar el esquema deseado
|
|
357
|
+
- generar snapshots versionadas
|
|
358
|
+
- asociar snapshots con revisiones Alembic
|
|
359
|
+
- aplicar snapshots usando Alembic por detras
|
|
360
|
+
|
|
361
|
+
Pero aun hay que revisar manualmente:
|
|
362
|
+
|
|
363
|
+
- cambios destructivos delicados
|
|
364
|
+
- migraciones de datos
|
|
365
|
+
- cambios que requieren backfill
|
|
366
|
+
- escenarios no lineales de ramas Alembic
|
|
367
|
+
|
|
368
|
+
## Estructura mínima por proyecto
|
|
369
|
+
|
|
370
|
+
Cada proyecto solo necesita:
|
|
371
|
+
|
|
372
|
+
- una carpeta de migraciones
|
|
373
|
+
- un archivo `migration_project.py`
|
|
374
|
+
- un objeto `project` que implemente el contrato de `MigrationProject`
|
|
375
|
+
|
|
376
|
+
El kit puede generar estos archivos automáticamente a partir de un escaneo inicial del proyecto.
|
|
377
|
+
|
|
378
|
+
## Estado actual
|
|
379
|
+
|
|
380
|
+
La versión actual deja listo:
|
|
381
|
+
|
|
382
|
+
- contrato de provider
|
|
383
|
+
- snapshots y diff de esquema
|
|
384
|
+
- revisión de columnas, índices, foreign keys y enums
|
|
385
|
+
- detección básica de posibles renombres
|
|
386
|
+
- inspección inicial del proyecto
|
|
387
|
+
- bootstrap automático de archivos mínimos
|
|
388
|
+
- runner reusable
|
|
389
|
+
- scaffold inicial
|
|
390
|
+
- comandos `synth`, `diff`, `review`, `upgrade`, `downgrade`, `stamp`
|
|
391
|
+
|
|
392
|
+
La parte de migraciones reales puede crecer por provider sin acoplar el kit a un proyecto particular.
|
|
393
|
+
|