red64-cli 0.1.0 → 0.3.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.
Files changed (125) hide show
  1. package/README.md +1 -2
  2. package/dist/cli/parseArgs.d.ts.map +1 -1
  3. package/dist/cli/parseArgs.js +5 -0
  4. package/dist/cli/parseArgs.js.map +1 -1
  5. package/dist/components/init/CompleteStep.d.ts.map +1 -1
  6. package/dist/components/init/CompleteStep.js +2 -2
  7. package/dist/components/init/CompleteStep.js.map +1 -1
  8. package/dist/components/init/TestCheckStep.d.ts +16 -0
  9. package/dist/components/init/TestCheckStep.d.ts.map +1 -0
  10. package/dist/components/init/TestCheckStep.js +120 -0
  11. package/dist/components/init/TestCheckStep.js.map +1 -0
  12. package/dist/components/init/index.d.ts +1 -0
  13. package/dist/components/init/index.d.ts.map +1 -1
  14. package/dist/components/init/index.js +1 -0
  15. package/dist/components/init/index.js.map +1 -1
  16. package/dist/components/init/types.d.ts +9 -0
  17. package/dist/components/init/types.d.ts.map +1 -1
  18. package/dist/components/screens/InitScreen.d.ts.map +1 -1
  19. package/dist/components/screens/InitScreen.js +69 -6
  20. package/dist/components/screens/InitScreen.js.map +1 -1
  21. package/dist/components/screens/ListScreen.d.ts.map +1 -1
  22. package/dist/components/screens/ListScreen.js +28 -3
  23. package/dist/components/screens/ListScreen.js.map +1 -1
  24. package/dist/components/screens/StartScreen.d.ts.map +1 -1
  25. package/dist/components/screens/StartScreen.js +212 -13
  26. package/dist/components/screens/StartScreen.js.map +1 -1
  27. package/dist/components/ui/ArtifactsSidebar.d.ts +19 -0
  28. package/dist/components/ui/ArtifactsSidebar.d.ts.map +1 -0
  29. package/dist/components/ui/ArtifactsSidebar.js +51 -0
  30. package/dist/components/ui/ArtifactsSidebar.js.map +1 -0
  31. package/dist/components/ui/FeatureSidebar.d.ts.map +1 -1
  32. package/dist/components/ui/FeatureSidebar.js +1 -1
  33. package/dist/components/ui/FeatureSidebar.js.map +1 -1
  34. package/dist/components/ui/index.d.ts +1 -0
  35. package/dist/components/ui/index.d.ts.map +1 -1
  36. package/dist/components/ui/index.js +1 -0
  37. package/dist/components/ui/index.js.map +1 -1
  38. package/dist/services/ClaudeErrorDetector.js +3 -3
  39. package/dist/services/ClaudeErrorDetector.js.map +1 -1
  40. package/dist/services/ConfigService.d.ts +1 -0
  41. package/dist/services/ConfigService.d.ts.map +1 -1
  42. package/dist/services/ConfigService.js.map +1 -1
  43. package/dist/services/ProjectDetector.d.ts +28 -0
  44. package/dist/services/ProjectDetector.d.ts.map +1 -0
  45. package/dist/services/ProjectDetector.js +236 -0
  46. package/dist/services/ProjectDetector.js.map +1 -0
  47. package/dist/services/TestRunner.d.ts +46 -0
  48. package/dist/services/TestRunner.d.ts.map +1 -0
  49. package/dist/services/TestRunner.js +85 -0
  50. package/dist/services/TestRunner.js.map +1 -0
  51. package/dist/services/index.d.ts +2 -0
  52. package/dist/services/index.d.ts.map +1 -1
  53. package/dist/services/index.js +2 -0
  54. package/dist/services/index.js.map +1 -1
  55. package/dist/types/index.d.ts +13 -0
  56. package/dist/types/index.d.ts.map +1 -1
  57. package/dist/types/index.js.map +1 -1
  58. package/framework/.red64/settings/templates/specs/gap-analysis.md +163 -0
  59. package/framework/agents/claude/.claude/agents/red64/spec-impl.md +131 -2
  60. package/framework/agents/claude/.claude/agents/red64/validate-gap.md +13 -7
  61. package/framework/agents/claude/.claude/commands/red64/spec-impl.md +24 -0
  62. package/framework/agents/claude/.claude/commands/red64/validate-gap.md +4 -0
  63. package/framework/agents/codex/.codex/agents/red64/spec-impl.md +131 -2
  64. package/framework/agents/codex/.codex/agents/red64/validate-gap.md +13 -7
  65. package/framework/agents/codex/.codex/commands/red64/spec-impl.md +24 -0
  66. package/framework/agents/codex/.codex/commands/red64/validate-gap.md +4 -0
  67. package/framework/stacks/generic/feedback.md +80 -0
  68. package/framework/stacks/nextjs/accessibility.md +437 -0
  69. package/framework/stacks/nextjs/api.md +431 -0
  70. package/framework/stacks/nextjs/coding-style.md +282 -0
  71. package/framework/stacks/nextjs/commenting.md +226 -0
  72. package/framework/stacks/nextjs/components.md +411 -0
  73. package/framework/stacks/nextjs/conventions.md +333 -0
  74. package/framework/stacks/nextjs/css.md +310 -0
  75. package/framework/stacks/nextjs/error-handling.md +442 -0
  76. package/framework/stacks/nextjs/feedback.md +124 -0
  77. package/framework/stacks/nextjs/migrations.md +332 -0
  78. package/framework/stacks/nextjs/models.md +362 -0
  79. package/framework/stacks/nextjs/queries.md +410 -0
  80. package/framework/stacks/nextjs/responsive.md +338 -0
  81. package/framework/stacks/nextjs/tech-stack.md +177 -0
  82. package/framework/stacks/nextjs/test-writing.md +475 -0
  83. package/framework/stacks/nextjs/validation.md +467 -0
  84. package/framework/stacks/python/api.md +468 -0
  85. package/framework/stacks/python/authentication.md +342 -0
  86. package/framework/stacks/python/code-quality.md +283 -0
  87. package/framework/stacks/python/code-refactoring.md +315 -0
  88. package/framework/stacks/python/coding-style.md +462 -0
  89. package/framework/stacks/python/conventions.md +399 -0
  90. package/framework/stacks/python/error-handling.md +512 -0
  91. package/framework/stacks/python/feedback.md +92 -0
  92. package/framework/stacks/python/implement-ai-llm.md +468 -0
  93. package/framework/stacks/python/migrations.md +388 -0
  94. package/framework/stacks/python/models.md +399 -0
  95. package/framework/stacks/python/python.md +232 -0
  96. package/framework/stacks/python/queries.md +451 -0
  97. package/framework/stacks/python/structure.md +245 -58
  98. package/framework/stacks/python/tech.md +92 -35
  99. package/framework/stacks/python/testing.md +380 -0
  100. package/framework/stacks/python/validation.md +471 -0
  101. package/framework/stacks/rails/authentication.md +176 -0
  102. package/framework/stacks/rails/code-quality.md +287 -0
  103. package/framework/stacks/rails/code-refactoring.md +299 -0
  104. package/framework/stacks/rails/feedback.md +130 -0
  105. package/framework/stacks/rails/implement-ai-llm-with-rubyllm.md +342 -0
  106. package/framework/stacks/rails/rails.md +301 -0
  107. package/framework/stacks/rails/rails8-best-practices.md +498 -0
  108. package/framework/stacks/rails/rails8-css.md +573 -0
  109. package/framework/stacks/rails/structure.md +140 -0
  110. package/framework/stacks/rails/tech.md +108 -0
  111. package/framework/stacks/react/code-quality.md +521 -0
  112. package/framework/stacks/react/components.md +625 -0
  113. package/framework/stacks/react/data-fetching.md +586 -0
  114. package/framework/stacks/react/feedback.md +110 -0
  115. package/framework/stacks/react/forms.md +694 -0
  116. package/framework/stacks/react/performance.md +640 -0
  117. package/framework/stacks/react/product.md +22 -9
  118. package/framework/stacks/react/state-management.md +472 -0
  119. package/framework/stacks/react/structure.md +351 -44
  120. package/framework/stacks/react/tech.md +219 -30
  121. package/framework/stacks/react/testing.md +690 -0
  122. package/package.json +1 -1
  123. package/framework/stacks/node/product.md +0 -27
  124. package/framework/stacks/node/structure.md +0 -82
  125. package/framework/stacks/node/tech.md +0 -63
@@ -0,0 +1,388 @@
1
+ # Database Migration Patterns
2
+
3
+ Alembic migration best practices for Python projects with SQLAlchemy.
4
+
5
+ ---
6
+
7
+ ## Philosophy
8
+
9
+ - **Reversible by default**: Every migration must have a working downgrade path
10
+ - **Small and atomic**: One logical change per migration file
11
+ - **Zero-downtime aware**: Schema changes must not lock tables or break running code
12
+ - **Schema separate from data**: Never mix DDL and DML in the same migration
13
+
14
+ ---
15
+
16
+ ## Alembic Setup
17
+
18
+ ### Configuration
19
+
20
+ ```python
21
+ # alembic/env.py
22
+ from app.models.base import Base
23
+ from app.config import settings
24
+
25
+ target_metadata = Base.metadata
26
+
27
+ def run_migrations_online():
28
+ connectable = create_engine(settings.database_url)
29
+ with connectable.connect() as connection:
30
+ context.configure(
31
+ connection=connection,
32
+ target_metadata=target_metadata,
33
+ compare_type=True, # Detect column type changes
34
+ compare_server_default=True, # Detect default value changes
35
+ render_as_batch=True, # SQLite compatibility
36
+ )
37
+ with context.begin_transaction():
38
+ context.run_migrations()
39
+ ```
40
+
41
+ ### Naming Conventions
42
+
43
+ Alembic auto-generates revision IDs. Use descriptive `--message` values:
44
+
45
+ ```bash
46
+ # Schema changes
47
+ uv run alembic revision --autogenerate -m "add_users_table"
48
+ uv run alembic revision --autogenerate -m "add_email_index_to_users"
49
+ uv run alembic revision --autogenerate -m "add_role_column_to_users"
50
+
51
+ # Data migrations (never autogenerate)
52
+ uv run alembic revision -m "backfill_user_display_names"
53
+ ```
54
+
55
+ **Pattern**: `{verb}_{noun}[_detail]` -- `add_users_table`, `drop_legacy_flags`, `rename_content_slug`.
56
+
57
+ ---
58
+
59
+ ## Reversible Migrations
60
+
61
+ ### Always Implement Downgrade
62
+
63
+ ```python
64
+ """add_users_table
65
+
66
+ Revision ID: a1b2c3d4
67
+ """
68
+
69
+ def upgrade() -> None:
70
+ op.create_table(
71
+ "users",
72
+ sa.Column("id", sa.Integer(), primary_key=True),
73
+ sa.Column("email", sa.String(255), nullable=False, unique=True),
74
+ sa.Column("name", sa.String(255), nullable=False),
75
+ sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
76
+ )
77
+ op.create_index("ix_users_email", "users", ["email"])
78
+
79
+ def downgrade() -> None:
80
+ op.drop_index("ix_users_email", table_name="users")
81
+ op.drop_table("users")
82
+ ```
83
+
84
+ ### Irreversible Migrations
85
+
86
+ When a migration truly cannot be reversed (data loss), make it explicit:
87
+
88
+ ```python
89
+ def downgrade() -> None:
90
+ raise NotImplementedError(
91
+ "This migration drops the legacy_flags column and cannot be reversed. "
92
+ "Restore from backup if needed."
93
+ )
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Small, Atomic Changes
99
+
100
+ ### One Concern Per Migration
101
+
102
+ ```python
103
+ # GOOD: Single logical change
104
+ # Migration 1: add_posts_table
105
+ def upgrade() -> None:
106
+ op.create_table("posts", ...)
107
+
108
+ # Migration 2: add_posts_published_at_index
109
+ def upgrade() -> None:
110
+ op.create_index("ix_posts_published_at", "posts", ["published_at"])
111
+ ```
112
+
113
+ ```python
114
+ # BAD: Multiple unrelated changes
115
+ def upgrade() -> None:
116
+ op.create_table("posts", ...)
117
+ op.add_column("users", sa.Column("bio", sa.Text()))
118
+ op.create_index("ix_posts_published_at", "posts", ["published_at"])
119
+ ```
120
+
121
+ ---
122
+
123
+ ## Zero-Downtime Migrations
124
+
125
+ ### Safe Column Addition
126
+
127
+ Adding a nullable column with no default is always safe:
128
+
129
+ ```python
130
+ def upgrade() -> None:
131
+ op.add_column("users", sa.Column("display_name", sa.String(255), nullable=True))
132
+ ```
133
+
134
+ ### Unsafe Operations and Alternatives
135
+
136
+ | Operation | Problem | Safe Alternative |
137
+ |---|---|---|
138
+ | Add NOT NULL column | Locks table, fails on existing rows | Add nullable, backfill, then alter |
139
+ | Drop column | Running code may reference it | Deploy code removal first, then drop |
140
+ | Rename column | Breaks running queries | Add new column, backfill, deploy code, drop old |
141
+ | Add index on large table | Locks table for duration | Use `CREATE INDEX CONCURRENTLY` (PostgreSQL) |
142
+ | Change column type | May require table rewrite | Add new column, backfill, swap |
143
+
144
+ ### Multi-Step Column Rename
145
+
146
+ ```python
147
+ # Step 1: Add new column (deploy migration)
148
+ def upgrade() -> None:
149
+ op.add_column("users", sa.Column("display_name", sa.String(255), nullable=True))
150
+
151
+ # Step 2: Backfill data (data migration)
152
+ def upgrade() -> None:
153
+ op.execute("UPDATE users SET display_name = name WHERE display_name IS NULL")
154
+
155
+ # Step 3: Deploy code using display_name instead of name
156
+
157
+ # Step 4: Drop old column (after code is deployed)
158
+ def upgrade() -> None:
159
+ op.drop_column("users", "name")
160
+ ```
161
+
162
+ ### Concurrent Index Creation (PostgreSQL)
163
+
164
+ ```python
165
+ from alembic import op
166
+
167
+ def upgrade() -> None:
168
+ # Must run outside a transaction for CONCURRENTLY
169
+ op.execute("CREATE INDEX CONCURRENTLY ix_posts_user_id ON posts (user_id)")
170
+
171
+ def downgrade() -> None:
172
+ op.drop_index("ix_posts_user_id", table_name="posts")
173
+ ```
174
+
175
+ Add to the migration file:
176
+
177
+ ```python
178
+ # Disable transaction wrapping for this migration
179
+ from alembic import context
180
+ context.configure(transaction_per_migration=False)
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Schema vs Data Migrations
186
+
187
+ ### Schema Migration (DDL)
188
+
189
+ ```python
190
+ """add_status_column_to_posts
191
+
192
+ Autogenerated: yes
193
+ """
194
+
195
+ def upgrade() -> None:
196
+ op.add_column(
197
+ "posts",
198
+ sa.Column("status", sa.String(20), nullable=True, server_default="draft"),
199
+ )
200
+
201
+ def downgrade() -> None:
202
+ op.drop_column("posts", "status")
203
+ ```
204
+
205
+ ### Data Migration (DML)
206
+
207
+ ```python
208
+ """backfill_post_status
209
+
210
+ Autogenerated: no
211
+ """
212
+ from sqlalchemy import table, column, String
213
+
214
+ def upgrade() -> None:
215
+ # Use lightweight table references, not ORM models
216
+ posts = table("posts", column("status", String))
217
+ op.execute(
218
+ posts.update()
219
+ .where(posts.c.status.is_(None))
220
+ .values(status="draft")
221
+ )
222
+
223
+ def downgrade() -> None:
224
+ # Data backfills are generally not reversible
225
+ pass
226
+ ```
227
+
228
+ **Rule**: Never import ORM models in migrations. Models change over time; migrations must remain stable. Use `sa.table()` / `sa.column()` or raw SQL.
229
+
230
+ ---
231
+
232
+ ## Autogenerate Pitfalls
233
+
234
+ ### What Autogenerate Detects
235
+
236
+ | Detected | Not Detected |
237
+ |---|---|
238
+ | Table creation/removal | Table or column renames (shows as drop+create) |
239
+ | Column addition/removal | Changes to constraints names |
240
+ | Column type changes (with `compare_type=True`) | Data migrations |
241
+ | Nullable changes | Custom CHECK constraints (sometimes) |
242
+ | Index creation/removal | PostgreSQL ENUM type changes |
243
+ | Foreign key changes | Trigger or function changes |
244
+
245
+ ### Always Review Generated Migrations
246
+
247
+ ```bash
248
+ # Generate
249
+ uv run alembic revision --autogenerate -m "add_feature_x"
250
+
251
+ # ALWAYS review the generated file before running
252
+ # Check for:
253
+ # 1. Unintended drops (renames detected as drop+create)
254
+ # 2. Missing downgrade operations
255
+ # 3. Correct column types and constraints
256
+ # 4. Index naming consistency
257
+
258
+ # Then run
259
+ uv run alembic upgrade head
260
+ ```
261
+
262
+ ### Custom Enum Handling
263
+
264
+ Alembic does not handle PostgreSQL ENUMs well. Manage them manually:
265
+
266
+ ```python
267
+ from alembic import op
268
+ import sqlalchemy as sa
269
+
270
+ def upgrade() -> None:
271
+ # Create enum type first
272
+ role_enum = sa.Enum("admin", "member", "viewer", name="user_role")
273
+ role_enum.create(op.get_bind(), checkfirst=True)
274
+
275
+ op.add_column("users", sa.Column("role", role_enum, nullable=True))
276
+
277
+ def downgrade() -> None:
278
+ op.drop_column("users", "role")
279
+ sa.Enum(name="user_role").drop(op.get_bind(), checkfirst=True)
280
+ ```
281
+
282
+ ---
283
+
284
+ ## Migration Testing
285
+
286
+ ### Test Migrations in CI
287
+
288
+ ```python
289
+ # tests/test_migrations.py
290
+ import subprocess
291
+
292
+ def test_migrations_up_down():
293
+ """Verify all migrations can run forward and backward."""
294
+ result = subprocess.run(
295
+ ["uv", "run", "alembic", "upgrade", "head"],
296
+ capture_output=True, text=True,
297
+ )
298
+ assert result.returncode == 0, f"Upgrade failed: {result.stderr}"
299
+
300
+ result = subprocess.run(
301
+ ["uv", "run", "alembic", "downgrade", "base"],
302
+ capture_output=True, text=True,
303
+ )
304
+ assert result.returncode == 0, f"Downgrade failed: {result.stderr}"
305
+ ```
306
+
307
+ ### Test Migration Idempotency
308
+
309
+ ```python
310
+ def test_no_pending_migrations():
311
+ """Ensure models and migrations are in sync."""
312
+ result = subprocess.run(
313
+ ["uv", "run", "alembic", "check"],
314
+ capture_output=True, text=True,
315
+ )
316
+ assert result.returncode == 0, (
317
+ "Models and migrations are out of sync. "
318
+ "Run: uv run alembic revision --autogenerate -m 'sync_models'"
319
+ )
320
+ ```
321
+
322
+ ---
323
+
324
+ ## Rollback Strategies
325
+
326
+ ### Alembic Downgrade
327
+
328
+ ```bash
329
+ # Roll back one migration
330
+ uv run alembic downgrade -1
331
+
332
+ # Roll back to specific revision
333
+ uv run alembic downgrade a1b2c3d4
334
+
335
+ # Roll back to base (empty database)
336
+ uv run alembic downgrade base
337
+
338
+ # Show current state
339
+ uv run alembic current
340
+ uv run alembic history --verbose
341
+ ```
342
+
343
+ ### Production Rollback Procedure
344
+
345
+ 1. **Verify**: Check current revision with `alembic current`
346
+ 2. **Test**: Run downgrade in staging first
347
+ 3. **Downgrade**: Run `alembic downgrade -1` in production
348
+ 4. **Deploy**: Roll back application code to match schema
349
+ 5. **Verify**: Confirm application health after rollback
350
+
351
+ ### When Downgrade Is Not Enough
352
+
353
+ For destructive migrations (dropped columns, deleted data):
354
+
355
+ - Restore from database backup
356
+ - Use point-in-time recovery (PostgreSQL WAL)
357
+ - Never deploy destructive migrations on Friday
358
+
359
+ ---
360
+
361
+ ## Commands Reference
362
+
363
+ ```bash
364
+ # Generate migration from model changes
365
+ uv run alembic revision --autogenerate -m "description"
366
+
367
+ # Create empty migration (for data migrations)
368
+ uv run alembic revision -m "description"
369
+
370
+ # Apply all pending migrations
371
+ uv run alembic upgrade head
372
+
373
+ # Roll back last migration
374
+ uv run alembic downgrade -1
375
+
376
+ # Show migration history
377
+ uv run alembic history --verbose
378
+
379
+ # Show current revision
380
+ uv run alembic current
381
+
382
+ # Check if models and migrations are in sync
383
+ uv run alembic check
384
+ ```
385
+
386
+ ---
387
+
388
+ _Migrations are permanent artifacts. Review every generated file. Never modify a migration after it has been applied in any shared environment._