@nextsparkjs/ai-workflow 0.1.0-beta.100
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/LICENSE +21 -0
- package/README.md +115 -0
- package/claude/_docs/workflows-optimizations.md +359 -0
- package/claude/agents/api-tester.md +634 -0
- package/claude/agents/architecture-supervisor.md +1351 -0
- package/claude/agents/backend-developer.md +997 -0
- package/claude/agents/backend-validator.md +417 -0
- package/claude/agents/bdd-docs-writer.md +737 -0
- package/claude/agents/block-developer.md +677 -0
- package/claude/agents/code-reviewer.md +1432 -0
- package/claude/agents/db-developer.md +721 -0
- package/claude/agents/db-validator.md +407 -0
- package/claude/agents/demo-video-generator.md +493 -0
- package/claude/agents/documentation-writer.md +1268 -0
- package/claude/agents/frontend-developer.md +1234 -0
- package/claude/agents/frontend-validator.md +777 -0
- package/claude/agents/functional-validator.md +630 -0
- package/claude/agents/mock-analyst.md +387 -0
- package/claude/agents/product-manager.md +963 -0
- package/claude/agents/qa-automation.md +1762 -0
- package/claude/agents/release-manager.md +634 -0
- package/claude/agents/selectors-translator.md +262 -0
- package/claude/agents/unit-test-writer.md +785 -0
- package/claude/agents/visual-comparator.md +329 -0
- package/claude/agents/workflow-maintainer.md +352 -0
- package/claude/commands/do/README.md +88 -0
- package/claude/commands/do/create-api.md +64 -0
- package/claude/commands/do/create-entity.md +66 -0
- package/claude/commands/do/create-migration.md +64 -0
- package/claude/commands/do/create-plugin.md +56 -0
- package/claude/commands/do/create-theme.md +70 -0
- package/claude/commands/do/mock-data.md +67 -0
- package/claude/commands/do/reset-db.md +71 -0
- package/claude/commands/do/setup-scheduled-action.md +75 -0
- package/claude/commands/do/sync-code-review.md +117 -0
- package/claude/commands/do/update-selectors.md +112 -0
- package/claude/commands/do/use-skills.md +90 -0
- package/claude/commands/do/validate-blocks.md +69 -0
- package/claude/commands/how-to/README.md +261 -0
- package/claude/commands/how-to/add-metadata.md +692 -0
- package/claude/commands/how-to/add-taxonomies.md +806 -0
- package/claude/commands/how-to/add-translations.md +571 -0
- package/claude/commands/how-to/create-api.md +577 -0
- package/claude/commands/how-to/create-block.md +575 -0
- package/claude/commands/how-to/create-child-entities.md +771 -0
- package/claude/commands/how-to/create-entity.md +597 -0
- package/claude/commands/how-to/create-migrations.md +605 -0
- package/claude/commands/how-to/create-plugin.md +654 -0
- package/claude/commands/how-to/customize-app.md +481 -0
- package/claude/commands/how-to/customize-dashboard.md +553 -0
- package/claude/commands/how-to/customize-theme.md +438 -0
- package/claude/commands/how-to/define-features-flows.md +632 -0
- package/claude/commands/how-to/deploy.md +507 -0
- package/claude/commands/how-to/handle-file-uploads.md +746 -0
- package/claude/commands/how-to/implement-search.md +1001 -0
- package/claude/commands/how-to/install-plugins.md +352 -0
- package/claude/commands/how-to/manage-test-coverage.md +984 -0
- package/claude/commands/how-to/run-tests.md +400 -0
- package/claude/commands/how-to/set-app-languages.md +601 -0
- package/claude/commands/how-to/set-plans-and-permissions.md +575 -0
- package/claude/commands/how-to/set-scheduled-actions.md +527 -0
- package/claude/commands/how-to/set-user-roles-and-permissions.md +550 -0
- package/claude/commands/how-to/setup-authentication.md +388 -0
- package/claude/commands/how-to/setup-claude-code.md +440 -0
- package/claude/commands/how-to/setup-database.md +274 -0
- package/claude/commands/how-to/setup-email-providers.md +598 -0
- package/claude/commands/how-to/setup-mobile-dev.md +627 -0
- package/claude/commands/how-to/start.md +500 -0
- package/claude/commands/how-to/use-devtools.md +639 -0
- package/claude/commands/how-to/use-superadmin.md +622 -0
- package/claude/commands/session/README.md +193 -0
- package/claude/commands/session/block-create.md +190 -0
- package/claude/commands/session/block-list.md +203 -0
- package/claude/commands/session/block-update.md +192 -0
- package/claude/commands/session/block-validate.md +218 -0
- package/claude/commands/session/changelog.md +115 -0
- package/claude/commands/session/close.md +225 -0
- package/claude/commands/session/commit.md +174 -0
- package/claude/commands/session/db-entity.md +206 -0
- package/claude/commands/session/db-fix.md +212 -0
- package/claude/commands/session/db-sample.md +206 -0
- package/claude/commands/session/demo.md +178 -0
- package/claude/commands/session/doc-bdd.md +207 -0
- package/claude/commands/session/doc-feature.md +218 -0
- package/claude/commands/session/doc-read.md +225 -0
- package/claude/commands/session/execute.md +204 -0
- package/claude/commands/session/explain.md +202 -0
- package/claude/commands/session/fix-bug.md +210 -0
- package/claude/commands/session/fix-build.md +182 -0
- package/claude/commands/session/fix-test.md +189 -0
- package/claude/commands/session/pending.md +232 -0
- package/claude/commands/session/refine.md +188 -0
- package/claude/commands/session/resume.md +192 -0
- package/claude/commands/session/review.md +192 -0
- package/claude/commands/session/scope-change.md +181 -0
- package/claude/commands/session/start-blocks.md +347 -0
- package/claude/commands/session/start.md +604 -0
- package/claude/commands/session/status.md +169 -0
- package/claude/commands/session/test-fix.md +221 -0
- package/claude/commands/session/test-run.md +203 -0
- package/claude/commands/session/test-write.md +242 -0
- package/claude/commands/session/validate.md +162 -0
- package/claude/config/context.json +40 -0
- package/claude/config/github.json +69 -0
- package/claude/config/github.schema.json +106 -0
- package/claude/config/team.json +46 -0
- package/claude/config/team.schema.json +106 -0
- package/claude/config/workspace.json +43 -0
- package/claude/config/workspace.schema.json +75 -0
- package/claude/skills/README.md +228 -0
- package/claude/skills/accessibility/SKILL.md +573 -0
- package/claude/skills/api-bypass-layers/SKILL.md +550 -0
- package/claude/skills/asana-integration/SKILL.md +499 -0
- package/claude/skills/better-auth/SKILL.md +666 -0
- package/claude/skills/billing-subscriptions/SKILL.md +660 -0
- package/claude/skills/block-decision-matrix/SKILL.md +359 -0
- package/claude/skills/clickup-integration/SKILL.md +434 -0
- package/claude/skills/core-theme-responsibilities/SKILL.md +485 -0
- package/claude/skills/create-plugin/SKILL.md +425 -0
- package/claude/skills/create-theme/SKILL.md +331 -0
- package/claude/skills/cypress-api/SKILL.md +511 -0
- package/claude/skills/cypress-api/scripts/generate-api-controller.py +329 -0
- package/claude/skills/cypress-api/scripts/generate-api-test.py +930 -0
- package/claude/skills/cypress-e2e/SKILL.md +526 -0
- package/claude/skills/cypress-e2e/scripts/extract-selectors.py +383 -0
- package/claude/skills/cypress-e2e/scripts/generate-uat-test.py +788 -0
- package/claude/skills/cypress-selectors/SKILL.md +309 -0
- package/claude/skills/cypress-selectors/scripts/extract-missing.py +243 -0
- package/claude/skills/cypress-selectors/scripts/generate-block-selectors.py +283 -0
- package/claude/skills/cypress-selectors/scripts/validate-selectors.py +145 -0
- package/claude/skills/database-migrations/SKILL.md +335 -0
- package/claude/skills/database-migrations/scripts/generate-sample-data.py +284 -0
- package/claude/skills/database-migrations/scripts/validate-migration.py +323 -0
- package/claude/skills/design-system/SKILL.md +682 -0
- package/claude/skills/documentation/SKILL.md +540 -0
- package/claude/skills/entity-api/SKILL.md +482 -0
- package/claude/skills/entity-system/SKILL.md +635 -0
- package/claude/skills/entity-system/scripts/generate-child-migration.py +298 -0
- package/claude/skills/entity-system/scripts/generate-metas-migration.py +233 -0
- package/claude/skills/entity-system/scripts/generate-migration.py +382 -0
- package/claude/skills/entity-system/scripts/generate-sample-data.py +418 -0
- package/claude/skills/entity-system/scripts/scaffold-entity.py +661 -0
- package/claude/skills/github/SKILL.md +467 -0
- package/claude/skills/i18n-nextintl/SKILL.md +302 -0
- package/claude/skills/i18n-nextintl/scripts/add-translation.py +243 -0
- package/claude/skills/i18n-nextintl/scripts/extract-hardcoded.py +246 -0
- package/claude/skills/i18n-nextintl/scripts/validate-translations.py +260 -0
- package/claude/skills/impact-analysis/SKILL.md +203 -0
- package/claude/skills/jest-unit/SKILL.md +306 -0
- package/claude/skills/jest-unit/references/component-testing.md +371 -0
- package/claude/skills/jest-unit/references/mocking-patterns.md +380 -0
- package/claude/skills/jest-unit/references/service-hook-testing.md +454 -0
- package/claude/skills/jira-integration/SKILL.md +539 -0
- package/claude/skills/media-library/SKILL.md +743 -0
- package/claude/skills/mock-analysis/SKILL.md +276 -0
- package/claude/skills/monorepo-architecture/SKILL.md +162 -0
- package/claude/skills/nextjs-api-development/SKILL.md +364 -0
- package/claude/skills/nextjs-api-development/scripts/generate-crud-tests.py +456 -0
- package/claude/skills/nextjs-api-development/scripts/scaffold-endpoint.py +481 -0
- package/claude/skills/nextjs-api-development/scripts/validate-api.py +283 -0
- package/claude/skills/notion-integration/SKILL.md +641 -0
- package/claude/skills/npm-development-workflow/SKILL.md +480 -0
- package/claude/skills/page-builder-blocks/SKILL.md +530 -0
- package/claude/skills/page-builder-blocks/scripts/scaffold-block.py +444 -0
- package/claude/skills/permissions-system/SKILL.md +619 -0
- package/claude/skills/plugins/SKILL.md +340 -0
- package/claude/skills/plugins/references/plugin-templates.md +414 -0
- package/claude/skills/plugins/references/plugin-testing.md +353 -0
- package/claude/skills/plugins/references/plugin-types.md +198 -0
- package/claude/skills/plugins/scripts/scaffold-plugin.py +443 -0
- package/claude/skills/pom-patterns/SKILL.md +452 -0
- package/claude/skills/pom-patterns/scripts/generate-pom.py +392 -0
- package/claude/skills/rate-limiting/SKILL.md +342 -0
- package/claude/skills/react-best-practices/AGENTS.md +2410 -0
- package/claude/skills/react-best-practices/README.md +123 -0
- package/claude/skills/react-best-practices/SKILL.md +125 -0
- package/claude/skills/react-best-practices/metadata.json +15 -0
- package/claude/skills/react-best-practices/rules/_sections.md +46 -0
- package/claude/skills/react-best-practices/rules/_template.md +28 -0
- package/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/claude/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
- package/claude/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/claude/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/claude/skills/react-best-practices/rules/async-dependencies.md +36 -0
- package/claude/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/claude/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/claude/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/claude/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/claude/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/claude/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/claude/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/claude/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/claude/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/claude/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/claude/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/claude/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/claude/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/claude/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/claude/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/claude/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/claude/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/claude/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/claude/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/claude/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/claude/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/claude/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/claude/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/claude/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/claude/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/claude/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/claude/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/claude/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/claude/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/claude/skills/react-best-practices/rules/server-cache-react.md +76 -0
- package/claude/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/claude/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/claude/skills/react-patterns/SKILL.md +688 -0
- package/claude/skills/registry-system/SKILL.md +331 -0
- package/claude/skills/scheduled-actions/SKILL.md +671 -0
- package/claude/skills/scope-enforcement/SKILL.md +542 -0
- package/claude/skills/scope-enforcement/scripts/validate-scope.py +357 -0
- package/claude/skills/server-actions/SKILL.md +493 -0
- package/claude/skills/service-layer/SKILL.md +587 -0
- package/claude/skills/session-management/SKILL.md +266 -0
- package/claude/skills/session-management/scripts/create-session.py +166 -0
- package/claude/skills/session-management/scripts/iteration-close.sh +105 -0
- package/claude/skills/session-management/scripts/iteration-init.sh +180 -0
- package/claude/skills/session-management/scripts/session-archive.sh +87 -0
- package/claude/skills/session-management/scripts/session-close.sh +133 -0
- package/claude/skills/session-management/scripts/session-init.sh +225 -0
- package/claude/skills/session-management/scripts/session-list.sh +163 -0
- package/claude/skills/session-management/scripts/split-plan.sh +116 -0
- package/claude/skills/shadcn-components/SKILL.md +586 -0
- package/claude/skills/shadcn-theming/SKILL.md +446 -0
- package/claude/skills/suspense-loading/SKILL.md +280 -0
- package/claude/skills/tailwind-theming/SKILL.md +507 -0
- package/claude/skills/tanstack-query/SKILL.md +608 -0
- package/claude/skills/test-coverage/SKILL.md +239 -0
- package/claude/skills/web-design-guidelines/SKILL.md +39 -0
- package/claude/skills/zod-validation/SKILL.md +537 -0
- package/claude/templates/blocks/progress.md +86 -0
- package/claude/templates/iteration/changes.md +61 -0
- package/claude/templates/iteration/progress.md +55 -0
- package/claude/templates/log.md +31 -0
- package/claude/templates/story/context.md +77 -0
- package/claude/templates/story/pendings.md +37 -0
- package/claude/templates/story/plan.md +299 -0
- package/claude/templates/story/requirements.md +109 -0
- package/claude/templates/story/scope.json +10 -0
- package/claude/templates/story/tests.md +91 -0
- package/claude/templates/task/progress.md +58 -0
- package/claude/templates/task/requirements.md +54 -0
- package/claude/workflows/README.md +154 -0
- package/claude/workflows/blocks.md +614 -0
- package/claude/workflows/story.md +1207 -0
- package/claude/workflows/task.md +927 -0
- package/claude/workflows/tweak.md +527 -0
- package/cursor/.gitkeep +0 -0
- package/package.json +35 -0
- package/scripts/postinstall.mjs +198 -0
- package/scripts/setup.mjs +282 -0
- package/scripts/sync.mjs +209 -0
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
# /how-to:create-migrations
|
|
2
|
+
|
|
3
|
+
Interactive guide to create database migrations in NextSpark.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Required Skills
|
|
8
|
+
|
|
9
|
+
Before executing, these skills provide deeper context:
|
|
10
|
+
- `.claude/skills/database-migrations/SKILL.md` - PostgreSQL migration patterns
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Syntax
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
/how-to:create-migrations
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Behavior
|
|
23
|
+
|
|
24
|
+
Guides the user through creating database migrations with RLS, relations, and sample data.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Tutorial Overview
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
STEPS OVERVIEW (4 steps)
|
|
32
|
+
|
|
33
|
+
Step 1: Understanding Migrations
|
|
34
|
+
└── Migration structure and naming
|
|
35
|
+
|
|
36
|
+
Step 2: Create Entity Migration
|
|
37
|
+
└── Tables with RLS policies
|
|
38
|
+
|
|
39
|
+
Step 3: Add Relations and Indexes
|
|
40
|
+
└── Foreign keys and performance
|
|
41
|
+
|
|
42
|
+
Step 4: Create Sample Data Migration
|
|
43
|
+
└── Seed data for testing
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Step 1: Understanding Migrations
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
52
|
+
📚 HOW TO: CREATE MIGRATIONS
|
|
53
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
54
|
+
|
|
55
|
+
STEP 1 OF 4: Understanding Migrations
|
|
56
|
+
|
|
57
|
+
NextSpark uses SQL migrations with automatic execution:
|
|
58
|
+
|
|
59
|
+
┌─────────────────────────────────────────────┐
|
|
60
|
+
│ MIGRATION TYPES │
|
|
61
|
+
│ ───────────────────────────────────────── │
|
|
62
|
+
│ │
|
|
63
|
+
│ 1. CORE MIGRATIONS │
|
|
64
|
+
│ core/migrations/ │
|
|
65
|
+
│ → Auth tables, base schema │
|
|
66
|
+
│ │
|
|
67
|
+
│ 2. ENTITY MIGRATIONS │
|
|
68
|
+
│ themes/{theme}/entities/*/migrations/ │
|
|
69
|
+
│ → Entity tables with RLS │
|
|
70
|
+
│ │
|
|
71
|
+
│ 3. PLUGIN MIGRATIONS │
|
|
72
|
+
│ plugins/*/migrations/ │
|
|
73
|
+
│ → Plugin-specific tables │
|
|
74
|
+
│ │
|
|
75
|
+
└─────────────────────────────────────────────┘
|
|
76
|
+
|
|
77
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
78
|
+
|
|
79
|
+
📋 Migration File Naming:
|
|
80
|
+
|
|
81
|
+
Format: YYYYMMDDHHMMSS_description.sql
|
|
82
|
+
|
|
83
|
+
Examples:
|
|
84
|
+
• 20240115100000_create_products.sql
|
|
85
|
+
• 20240115100001_add_products_indexes.sql
|
|
86
|
+
• 20240115100002_seed_products_data.sql
|
|
87
|
+
|
|
88
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**📂 Migration Location:**
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
contents/themes/your-theme/entities/products/
|
|
96
|
+
└── migrations/
|
|
97
|
+
├── 20240115100000_create_products.sql
|
|
98
|
+
├── 20240115100001_add_products_meta.sql
|
|
99
|
+
└── 20240115100002_seed_products.sql
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**📋 Migration Commands:**
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Run all pending migrations
|
|
106
|
+
pnpm db:migrate
|
|
107
|
+
|
|
108
|
+
# Create new migration (generates timestamp)
|
|
109
|
+
pnpm db:migrate:create "create_products"
|
|
110
|
+
|
|
111
|
+
# Rollback last migration
|
|
112
|
+
pnpm db:migrate:rollback
|
|
113
|
+
|
|
114
|
+
# Reset entire database (WARNING)
|
|
115
|
+
pnpm db:reset
|
|
116
|
+
|
|
117
|
+
# Check migration status
|
|
118
|
+
pnpm db:migrate:status
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
123
|
+
|
|
124
|
+
What would you like to do?
|
|
125
|
+
|
|
126
|
+
[1] Continue to Step 2 (Entity Migration)
|
|
127
|
+
[2] Show me the migration tracking table
|
|
128
|
+
[3] How do I rollback safely?
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Step 2: Create Entity Migration
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
137
|
+
STEP 2 OF 4: Create Entity Migration
|
|
138
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
139
|
+
|
|
140
|
+
Create the main entity table with RLS:
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**📋 Main Table Migration:**
|
|
144
|
+
|
|
145
|
+
```sql
|
|
146
|
+
-- 20240115100000_create_products.sql
|
|
147
|
+
|
|
148
|
+
-- ============================================
|
|
149
|
+
-- CREATE PRODUCTS TABLE
|
|
150
|
+
-- ============================================
|
|
151
|
+
|
|
152
|
+
CREATE TABLE IF NOT EXISTS "products" (
|
|
153
|
+
-- Primary key (UUID)
|
|
154
|
+
"id" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
155
|
+
|
|
156
|
+
-- Team ownership (required for RLS)
|
|
157
|
+
"teamId" UUID NOT NULL REFERENCES "team"("id") ON DELETE CASCADE,
|
|
158
|
+
|
|
159
|
+
-- Entity fields (use camelCase!)
|
|
160
|
+
"name" VARCHAR(255) NOT NULL,
|
|
161
|
+
"description" TEXT,
|
|
162
|
+
"price" DECIMAL(10,2) NOT NULL DEFAULT 0,
|
|
163
|
+
"sku" VARCHAR(100),
|
|
164
|
+
"stock" INTEGER NOT NULL DEFAULT 0,
|
|
165
|
+
"status" VARCHAR(50) NOT NULL DEFAULT 'draft',
|
|
166
|
+
"categoryId" UUID REFERENCES "categories"("id") ON DELETE SET NULL,
|
|
167
|
+
|
|
168
|
+
-- Audit fields
|
|
169
|
+
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
170
|
+
"updatedAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
171
|
+
"createdBy" UUID REFERENCES "user"("id") ON DELETE SET NULL,
|
|
172
|
+
"updatedBy" UUID REFERENCES "user"("id") ON DELETE SET NULL
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
-- ============================================
|
|
176
|
+
-- ROW LEVEL SECURITY (RLS)
|
|
177
|
+
-- ============================================
|
|
178
|
+
|
|
179
|
+
-- Enable RLS
|
|
180
|
+
ALTER TABLE "products" ENABLE ROW LEVEL SECURITY;
|
|
181
|
+
|
|
182
|
+
-- Policy: Team members can view their team's products
|
|
183
|
+
CREATE POLICY "products_select_policy" ON "products"
|
|
184
|
+
FOR SELECT
|
|
185
|
+
USING ("teamId" = current_setting('app.current_team_id', true)::UUID);
|
|
186
|
+
|
|
187
|
+
-- Policy: Team members can insert products
|
|
188
|
+
CREATE POLICY "products_insert_policy" ON "products"
|
|
189
|
+
FOR INSERT
|
|
190
|
+
WITH CHECK ("teamId" = current_setting('app.current_team_id', true)::UUID);
|
|
191
|
+
|
|
192
|
+
-- Policy: Team members can update their team's products
|
|
193
|
+
CREATE POLICY "products_update_policy" ON "products"
|
|
194
|
+
FOR UPDATE
|
|
195
|
+
USING ("teamId" = current_setting('app.current_team_id', true)::UUID);
|
|
196
|
+
|
|
197
|
+
-- Policy: Team members can delete their team's products
|
|
198
|
+
CREATE POLICY "products_delete_policy" ON "products"
|
|
199
|
+
FOR DELETE
|
|
200
|
+
USING ("teamId" = current_setting('app.current_team_id', true)::UUID);
|
|
201
|
+
|
|
202
|
+
-- ============================================
|
|
203
|
+
-- INDEXES
|
|
204
|
+
-- ============================================
|
|
205
|
+
|
|
206
|
+
CREATE INDEX "idx_products_teamId" ON "products"("teamId");
|
|
207
|
+
CREATE INDEX "idx_products_status" ON "products"("status");
|
|
208
|
+
CREATE INDEX "idx_products_categoryId" ON "products"("categoryId");
|
|
209
|
+
CREATE UNIQUE INDEX "idx_products_sku_team" ON "products"("teamId", "sku")
|
|
210
|
+
WHERE "sku" IS NOT NULL;
|
|
211
|
+
|
|
212
|
+
-- ============================================
|
|
213
|
+
-- UPDATED_AT TRIGGER
|
|
214
|
+
-- ============================================
|
|
215
|
+
|
|
216
|
+
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
|
217
|
+
RETURNS TRIGGER AS $$
|
|
218
|
+
BEGIN
|
|
219
|
+
NEW."updatedAt" = NOW();
|
|
220
|
+
RETURN NEW;
|
|
221
|
+
END;
|
|
222
|
+
$$ language 'plpgsql';
|
|
223
|
+
|
|
224
|
+
CREATE TRIGGER "products_updated_at"
|
|
225
|
+
BEFORE UPDATE ON "products"
|
|
226
|
+
FOR EACH ROW
|
|
227
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**📋 CRITICAL RULES:**
|
|
231
|
+
|
|
232
|
+
1. **camelCase field names** - NOT snake_case
|
|
233
|
+
2. **teamId is required** - For RLS to work
|
|
234
|
+
3. **TIMESTAMPTZ for dates** - Always timezone-aware
|
|
235
|
+
4. **UUID for IDs** - Never use SERIAL/BIGSERIAL
|
|
236
|
+
5. **RLS policies are mandatory** - For multi-tenant security
|
|
237
|
+
|
|
238
|
+
**📋 Common Field Types:**
|
|
239
|
+
|
|
240
|
+
| Field Type | PostgreSQL | Example |
|
|
241
|
+
|------------|------------|---------|
|
|
242
|
+
| String | VARCHAR(n) | name VARCHAR(255) |
|
|
243
|
+
| Text | TEXT | description TEXT |
|
|
244
|
+
| Number | INTEGER | stock INTEGER |
|
|
245
|
+
| Decimal | DECIMAL(10,2) | price DECIMAL(10,2) |
|
|
246
|
+
| Boolean | BOOLEAN | isActive BOOLEAN |
|
|
247
|
+
| Date | TIMESTAMPTZ | createdAt TIMESTAMPTZ |
|
|
248
|
+
| UUID | UUID | id UUID |
|
|
249
|
+
| JSON | JSONB | metadata JSONB |
|
|
250
|
+
| Enum | VARCHAR(50) | status VARCHAR(50) |
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
254
|
+
|
|
255
|
+
What would you like to do?
|
|
256
|
+
|
|
257
|
+
[1] Continue to Step 3 (Relations)
|
|
258
|
+
[2] Show me metadata table pattern
|
|
259
|
+
[3] How does RLS work?
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Step 3: Add Relations and Indexes
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
268
|
+
STEP 3 OF 4: Relations and Indexes
|
|
269
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**📋 Parent-Child Relations:**
|
|
273
|
+
|
|
274
|
+
```sql
|
|
275
|
+
-- 20240115100001_create_product_variants.sql
|
|
276
|
+
|
|
277
|
+
-- Child table (variants belong to products)
|
|
278
|
+
CREATE TABLE IF NOT EXISTS "productVariants" (
|
|
279
|
+
"id" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
280
|
+
|
|
281
|
+
-- Parent reference (NOT teamId for children)
|
|
282
|
+
"productId" UUID NOT NULL REFERENCES "products"("id") ON DELETE CASCADE,
|
|
283
|
+
|
|
284
|
+
-- Variant fields
|
|
285
|
+
"name" VARCHAR(255) NOT NULL,
|
|
286
|
+
"sku" VARCHAR(100),
|
|
287
|
+
"price" DECIMAL(10,2),
|
|
288
|
+
"stock" INTEGER NOT NULL DEFAULT 0,
|
|
289
|
+
"attributes" JSONB DEFAULT '{}',
|
|
290
|
+
|
|
291
|
+
-- Audit
|
|
292
|
+
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
293
|
+
"updatedAt" TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
-- RLS for child tables (through parent)
|
|
297
|
+
ALTER TABLE "productVariants" ENABLE ROW LEVEL SECURITY;
|
|
298
|
+
|
|
299
|
+
-- Select via parent's team
|
|
300
|
+
CREATE POLICY "productVariants_select_policy" ON "productVariants"
|
|
301
|
+
FOR SELECT
|
|
302
|
+
USING (
|
|
303
|
+
EXISTS (
|
|
304
|
+
SELECT 1 FROM "products" p
|
|
305
|
+
WHERE p."id" = "productVariants"."productId"
|
|
306
|
+
AND p."teamId" = current_setting('app.current_team_id', true)::UUID
|
|
307
|
+
)
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
-- Insert via parent's team
|
|
311
|
+
CREATE POLICY "productVariants_insert_policy" ON "productVariants"
|
|
312
|
+
FOR INSERT
|
|
313
|
+
WITH CHECK (
|
|
314
|
+
EXISTS (
|
|
315
|
+
SELECT 1 FROM "products" p
|
|
316
|
+
WHERE p."id" = "productVariants"."productId"
|
|
317
|
+
AND p."teamId" = current_setting('app.current_team_id', true)::UUID
|
|
318
|
+
)
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
-- Update via parent's team
|
|
322
|
+
CREATE POLICY "productVariants_update_policy" ON "productVariants"
|
|
323
|
+
FOR UPDATE
|
|
324
|
+
USING (
|
|
325
|
+
EXISTS (
|
|
326
|
+
SELECT 1 FROM "products" p
|
|
327
|
+
WHERE p."id" = "productVariants"."productId"
|
|
328
|
+
AND p."teamId" = current_setting('app.current_team_id', true)::UUID
|
|
329
|
+
)
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
-- Delete via parent's team
|
|
333
|
+
CREATE POLICY "productVariants_delete_policy" ON "productVariants"
|
|
334
|
+
FOR DELETE
|
|
335
|
+
USING (
|
|
336
|
+
EXISTS (
|
|
337
|
+
SELECT 1 FROM "products" p
|
|
338
|
+
WHERE p."id" = "productVariants"."productId"
|
|
339
|
+
AND p."teamId" = current_setting('app.current_team_id', true)::UUID
|
|
340
|
+
)
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
-- Indexes
|
|
344
|
+
CREATE INDEX "idx_productVariants_productId" ON "productVariants"("productId");
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**📋 Metadata Table Pattern:**
|
|
348
|
+
|
|
349
|
+
```sql
|
|
350
|
+
-- 20240115100002_create_products_meta.sql
|
|
351
|
+
|
|
352
|
+
CREATE TABLE IF NOT EXISTS "productsMeta" (
|
|
353
|
+
"id" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
354
|
+
"productId" UUID NOT NULL REFERENCES "products"("id") ON DELETE CASCADE,
|
|
355
|
+
"key" VARCHAR(255) NOT NULL,
|
|
356
|
+
"value" TEXT,
|
|
357
|
+
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
358
|
+
"updatedAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
359
|
+
|
|
360
|
+
UNIQUE("productId", "key")
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
ALTER TABLE "productsMeta" ENABLE ROW LEVEL SECURITY;
|
|
364
|
+
|
|
365
|
+
-- RLS through parent product
|
|
366
|
+
CREATE POLICY "productsMeta_select_policy" ON "productsMeta"
|
|
367
|
+
FOR SELECT
|
|
368
|
+
USING (
|
|
369
|
+
EXISTS (
|
|
370
|
+
SELECT 1 FROM "products" p
|
|
371
|
+
WHERE p."id" = "productsMeta"."productId"
|
|
372
|
+
AND p."teamId" = current_setting('app.current_team_id', true)::UUID
|
|
373
|
+
)
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
-- Similar policies for INSERT, UPDATE, DELETE...
|
|
377
|
+
|
|
378
|
+
CREATE INDEX "idx_productsMeta_productId" ON "productsMeta"("productId");
|
|
379
|
+
CREATE INDEX "idx_productsMeta_key" ON "productsMeta"("key");
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**📋 Many-to-Many Relations:**
|
|
383
|
+
|
|
384
|
+
```sql
|
|
385
|
+
-- 20240115100003_create_product_tags.sql
|
|
386
|
+
|
|
387
|
+
-- Junction table for products <-> tags
|
|
388
|
+
CREATE TABLE IF NOT EXISTS "productTags" (
|
|
389
|
+
"productId" UUID NOT NULL REFERENCES "products"("id") ON DELETE CASCADE,
|
|
390
|
+
"tagId" UUID NOT NULL REFERENCES "tags"("id") ON DELETE CASCADE,
|
|
391
|
+
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
392
|
+
|
|
393
|
+
PRIMARY KEY ("productId", "tagId")
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
ALTER TABLE "productTags" ENABLE ROW LEVEL SECURITY;
|
|
397
|
+
|
|
398
|
+
-- RLS through product's team
|
|
399
|
+
CREATE POLICY "productTags_all_policy" ON "productTags"
|
|
400
|
+
FOR ALL
|
|
401
|
+
USING (
|
|
402
|
+
EXISTS (
|
|
403
|
+
SELECT 1 FROM "products" p
|
|
404
|
+
WHERE p."id" = "productTags"."productId"
|
|
405
|
+
AND p."teamId" = current_setting('app.current_team_id', true)::UUID
|
|
406
|
+
)
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
CREATE INDEX "idx_productTags_tagId" ON "productTags"("tagId");
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
**📋 Performance Indexes:**
|
|
413
|
+
|
|
414
|
+
```sql
|
|
415
|
+
-- Composite index for common queries
|
|
416
|
+
CREATE INDEX "idx_products_team_status"
|
|
417
|
+
ON "products"("teamId", "status");
|
|
418
|
+
|
|
419
|
+
-- Partial index for active products only
|
|
420
|
+
CREATE INDEX "idx_products_active"
|
|
421
|
+
ON "products"("teamId", "createdAt")
|
|
422
|
+
WHERE "status" = 'active';
|
|
423
|
+
|
|
424
|
+
-- Text search index
|
|
425
|
+
CREATE INDEX "idx_products_search"
|
|
426
|
+
ON "products" USING gin(to_tsvector('english', "name" || ' ' || COALESCE("description", '')));
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
```
|
|
430
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
431
|
+
|
|
432
|
+
What would you like to do?
|
|
433
|
+
|
|
434
|
+
[1] Continue to Step 4 (Sample Data)
|
|
435
|
+
[2] Show me more index patterns
|
|
436
|
+
[3] How do I handle soft deletes?
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## Step 4: Create Sample Data Migration
|
|
442
|
+
|
|
443
|
+
```
|
|
444
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
445
|
+
STEP 4 OF 4: Sample Data Migration
|
|
446
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
447
|
+
|
|
448
|
+
Create realistic sample data for development and testing:
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
**📋 Sample Data Migration:**
|
|
452
|
+
|
|
453
|
+
```sql
|
|
454
|
+
-- 20240115100010_seed_products.sql
|
|
455
|
+
|
|
456
|
+
-- ============================================
|
|
457
|
+
-- SAMPLE DATA FOR PRODUCTS
|
|
458
|
+
-- ============================================
|
|
459
|
+
|
|
460
|
+
-- First, get a valid team ID (from dev keyring user's team)
|
|
461
|
+
DO $$
|
|
462
|
+
DECLARE
|
|
463
|
+
v_team_id UUID;
|
|
464
|
+
v_user_id UUID;
|
|
465
|
+
v_category_id UUID;
|
|
466
|
+
BEGIN
|
|
467
|
+
-- Get the first team (created by dev keyring)
|
|
468
|
+
SELECT "id" INTO v_team_id FROM "team" LIMIT 1;
|
|
469
|
+
SELECT "id" INTO v_user_id FROM "user" LIMIT 1;
|
|
470
|
+
|
|
471
|
+
-- Create sample category first
|
|
472
|
+
INSERT INTO "categories" ("id", "teamId", "name", "slug", "createdBy")
|
|
473
|
+
VALUES
|
|
474
|
+
(gen_random_uuid(), v_team_id, 'Electronics', 'electronics', v_user_id),
|
|
475
|
+
(gen_random_uuid(), v_team_id, 'Clothing', 'clothing', v_user_id),
|
|
476
|
+
(gen_random_uuid(), v_team_id, 'Home & Garden', 'home-garden', v_user_id)
|
|
477
|
+
ON CONFLICT DO NOTHING;
|
|
478
|
+
|
|
479
|
+
-- Get electronics category
|
|
480
|
+
SELECT "id" INTO v_category_id FROM "categories"
|
|
481
|
+
WHERE "teamId" = v_team_id AND "slug" = 'electronics' LIMIT 1;
|
|
482
|
+
|
|
483
|
+
-- Insert sample products
|
|
484
|
+
INSERT INTO "products" (
|
|
485
|
+
"teamId", "name", "description", "price", "sku", "stock",
|
|
486
|
+
"status", "categoryId", "createdBy"
|
|
487
|
+
) VALUES
|
|
488
|
+
-- Electronics
|
|
489
|
+
(v_team_id, 'Wireless Bluetooth Headphones',
|
|
490
|
+
'Premium noise-canceling headphones with 30-hour battery life',
|
|
491
|
+
149.99, 'ELEC-001', 50, 'active', v_category_id, v_user_id),
|
|
492
|
+
|
|
493
|
+
(v_team_id, 'Smart Watch Pro',
|
|
494
|
+
'Advanced fitness tracking with heart rate monitor and GPS',
|
|
495
|
+
299.99, 'ELEC-002', 30, 'active', v_category_id, v_user_id),
|
|
496
|
+
|
|
497
|
+
(v_team_id, 'Portable Charger 20000mAh',
|
|
498
|
+
'High-capacity power bank with fast charging support',
|
|
499
|
+
49.99, 'ELEC-003', 100, 'active', v_category_id, v_user_id),
|
|
500
|
+
|
|
501
|
+
(v_team_id, 'Wireless Earbuds',
|
|
502
|
+
'True wireless earbuds with active noise cancellation',
|
|
503
|
+
89.99, 'ELEC-004', 75, 'active', v_category_id, v_user_id),
|
|
504
|
+
|
|
505
|
+
(v_team_id, '4K Webcam',
|
|
506
|
+
'Professional webcam for streaming and video calls',
|
|
507
|
+
129.99, 'ELEC-005', 25, 'active', v_category_id, v_user_id),
|
|
508
|
+
|
|
509
|
+
-- Draft product
|
|
510
|
+
(v_team_id, 'VR Headset (Coming Soon)',
|
|
511
|
+
'Next-generation virtual reality headset',
|
|
512
|
+
499.99, 'ELEC-006', 0, 'draft', v_category_id, v_user_id),
|
|
513
|
+
|
|
514
|
+
-- Inactive product
|
|
515
|
+
(v_team_id, 'MP3 Player (Discontinued)',
|
|
516
|
+
'Classic portable music player',
|
|
517
|
+
29.99, 'ELEC-007', 5, 'inactive', v_category_id, v_user_id)
|
|
518
|
+
ON CONFLICT DO NOTHING;
|
|
519
|
+
|
|
520
|
+
-- Add product variants
|
|
521
|
+
INSERT INTO "productVariants" ("productId", "name", "sku", "price", "stock", "attributes")
|
|
522
|
+
SELECT
|
|
523
|
+
p."id",
|
|
524
|
+
'Black',
|
|
525
|
+
p."sku" || '-BLK',
|
|
526
|
+
p."price",
|
|
527
|
+
p."stock" / 2,
|
|
528
|
+
'{"color": "black"}'::jsonb
|
|
529
|
+
FROM "products" p
|
|
530
|
+
WHERE p."teamId" = v_team_id AND p."status" = 'active'
|
|
531
|
+
ON CONFLICT DO NOTHING;
|
|
532
|
+
|
|
533
|
+
-- Add metadata
|
|
534
|
+
INSERT INTO "productsMeta" ("productId", "key", "value")
|
|
535
|
+
SELECT
|
|
536
|
+
p."id",
|
|
537
|
+
'warranty',
|
|
538
|
+
'2 years'
|
|
539
|
+
FROM "products" p
|
|
540
|
+
WHERE p."teamId" = v_team_id AND p."status" = 'active'
|
|
541
|
+
ON CONFLICT DO NOTHING;
|
|
542
|
+
|
|
543
|
+
END $$;
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
**📋 Sample Data Best Practices:**
|
|
547
|
+
|
|
548
|
+
1. **Use DO $$ blocks** for variables
|
|
549
|
+
2. **ON CONFLICT DO NOTHING** for idempotency
|
|
550
|
+
3. **Reference existing teams** from dev keyring
|
|
551
|
+
4. **Create related data** (categories before products)
|
|
552
|
+
5. **Include various states** (active, draft, inactive)
|
|
553
|
+
6. **Realistic quantities** (50+ records for pagination testing)
|
|
554
|
+
|
|
555
|
+
**📋 Run Migrations:**
|
|
556
|
+
|
|
557
|
+
```bash
|
|
558
|
+
# Run all migrations
|
|
559
|
+
pnpm db:migrate
|
|
560
|
+
|
|
561
|
+
# Verify data
|
|
562
|
+
psql $DATABASE_URL -c "SELECT COUNT(*) FROM products"
|
|
563
|
+
|
|
564
|
+
# Check sample data
|
|
565
|
+
psql $DATABASE_URL -c "SELECT name, status, price FROM products LIMIT 10"
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
**📋 Migration Checklist:**
|
|
569
|
+
|
|
570
|
+
- [ ] Migration files use correct timestamp format
|
|
571
|
+
- [ ] Table uses camelCase field names
|
|
572
|
+
- [ ] teamId column exists with FK to team
|
|
573
|
+
- [ ] RLS is enabled with proper policies
|
|
574
|
+
- [ ] Indexes created for common queries
|
|
575
|
+
- [ ] updatedAt trigger is set up
|
|
576
|
+
- [ ] Sample data references existing team
|
|
577
|
+
- [ ] ON CONFLICT handles re-runs
|
|
578
|
+
|
|
579
|
+
```
|
|
580
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
581
|
+
|
|
582
|
+
✅ TUTORIAL STORY!
|
|
583
|
+
|
|
584
|
+
You've learned:
|
|
585
|
+
• Migration file structure and naming
|
|
586
|
+
• Creating tables with RLS policies
|
|
587
|
+
• Parent-child relationships
|
|
588
|
+
• Sample data generation
|
|
589
|
+
|
|
590
|
+
📚 Related tutorials:
|
|
591
|
+
• /how-to:setup-database - Database setup
|
|
592
|
+
• /how-to:create-entity - Entity configuration
|
|
593
|
+
|
|
594
|
+
🔙 Back to menu: /how-to:start
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
## Related Commands
|
|
600
|
+
|
|
601
|
+
| Command | Action |
|
|
602
|
+
|---------|--------|
|
|
603
|
+
| `/how-to:setup-database` | Database setup |
|
|
604
|
+
| `/how-to:create-entity` | Create entities |
|
|
605
|
+
| `/session:db:fix` | Fix migration issues |
|