@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.
Files changed (272) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -0
  3. package/claude/_docs/workflows-optimizations.md +359 -0
  4. package/claude/agents/api-tester.md +634 -0
  5. package/claude/agents/architecture-supervisor.md +1351 -0
  6. package/claude/agents/backend-developer.md +997 -0
  7. package/claude/agents/backend-validator.md +417 -0
  8. package/claude/agents/bdd-docs-writer.md +737 -0
  9. package/claude/agents/block-developer.md +677 -0
  10. package/claude/agents/code-reviewer.md +1432 -0
  11. package/claude/agents/db-developer.md +721 -0
  12. package/claude/agents/db-validator.md +407 -0
  13. package/claude/agents/demo-video-generator.md +493 -0
  14. package/claude/agents/documentation-writer.md +1268 -0
  15. package/claude/agents/frontend-developer.md +1234 -0
  16. package/claude/agents/frontend-validator.md +777 -0
  17. package/claude/agents/functional-validator.md +630 -0
  18. package/claude/agents/mock-analyst.md +387 -0
  19. package/claude/agents/product-manager.md +963 -0
  20. package/claude/agents/qa-automation.md +1762 -0
  21. package/claude/agents/release-manager.md +634 -0
  22. package/claude/agents/selectors-translator.md +262 -0
  23. package/claude/agents/unit-test-writer.md +785 -0
  24. package/claude/agents/visual-comparator.md +329 -0
  25. package/claude/agents/workflow-maintainer.md +352 -0
  26. package/claude/commands/do/README.md +88 -0
  27. package/claude/commands/do/create-api.md +64 -0
  28. package/claude/commands/do/create-entity.md +66 -0
  29. package/claude/commands/do/create-migration.md +64 -0
  30. package/claude/commands/do/create-plugin.md +56 -0
  31. package/claude/commands/do/create-theme.md +70 -0
  32. package/claude/commands/do/mock-data.md +67 -0
  33. package/claude/commands/do/reset-db.md +71 -0
  34. package/claude/commands/do/setup-scheduled-action.md +75 -0
  35. package/claude/commands/do/sync-code-review.md +117 -0
  36. package/claude/commands/do/update-selectors.md +112 -0
  37. package/claude/commands/do/use-skills.md +90 -0
  38. package/claude/commands/do/validate-blocks.md +69 -0
  39. package/claude/commands/how-to/README.md +261 -0
  40. package/claude/commands/how-to/add-metadata.md +692 -0
  41. package/claude/commands/how-to/add-taxonomies.md +806 -0
  42. package/claude/commands/how-to/add-translations.md +571 -0
  43. package/claude/commands/how-to/create-api.md +577 -0
  44. package/claude/commands/how-to/create-block.md +575 -0
  45. package/claude/commands/how-to/create-child-entities.md +771 -0
  46. package/claude/commands/how-to/create-entity.md +597 -0
  47. package/claude/commands/how-to/create-migrations.md +605 -0
  48. package/claude/commands/how-to/create-plugin.md +654 -0
  49. package/claude/commands/how-to/customize-app.md +481 -0
  50. package/claude/commands/how-to/customize-dashboard.md +553 -0
  51. package/claude/commands/how-to/customize-theme.md +438 -0
  52. package/claude/commands/how-to/define-features-flows.md +632 -0
  53. package/claude/commands/how-to/deploy.md +507 -0
  54. package/claude/commands/how-to/handle-file-uploads.md +746 -0
  55. package/claude/commands/how-to/implement-search.md +1001 -0
  56. package/claude/commands/how-to/install-plugins.md +352 -0
  57. package/claude/commands/how-to/manage-test-coverage.md +984 -0
  58. package/claude/commands/how-to/run-tests.md +400 -0
  59. package/claude/commands/how-to/set-app-languages.md +601 -0
  60. package/claude/commands/how-to/set-plans-and-permissions.md +575 -0
  61. package/claude/commands/how-to/set-scheduled-actions.md +527 -0
  62. package/claude/commands/how-to/set-user-roles-and-permissions.md +550 -0
  63. package/claude/commands/how-to/setup-authentication.md +388 -0
  64. package/claude/commands/how-to/setup-claude-code.md +440 -0
  65. package/claude/commands/how-to/setup-database.md +274 -0
  66. package/claude/commands/how-to/setup-email-providers.md +598 -0
  67. package/claude/commands/how-to/setup-mobile-dev.md +627 -0
  68. package/claude/commands/how-to/start.md +500 -0
  69. package/claude/commands/how-to/use-devtools.md +639 -0
  70. package/claude/commands/how-to/use-superadmin.md +622 -0
  71. package/claude/commands/session/README.md +193 -0
  72. package/claude/commands/session/block-create.md +190 -0
  73. package/claude/commands/session/block-list.md +203 -0
  74. package/claude/commands/session/block-update.md +192 -0
  75. package/claude/commands/session/block-validate.md +218 -0
  76. package/claude/commands/session/changelog.md +115 -0
  77. package/claude/commands/session/close.md +225 -0
  78. package/claude/commands/session/commit.md +174 -0
  79. package/claude/commands/session/db-entity.md +206 -0
  80. package/claude/commands/session/db-fix.md +212 -0
  81. package/claude/commands/session/db-sample.md +206 -0
  82. package/claude/commands/session/demo.md +178 -0
  83. package/claude/commands/session/doc-bdd.md +207 -0
  84. package/claude/commands/session/doc-feature.md +218 -0
  85. package/claude/commands/session/doc-read.md +225 -0
  86. package/claude/commands/session/execute.md +204 -0
  87. package/claude/commands/session/explain.md +202 -0
  88. package/claude/commands/session/fix-bug.md +210 -0
  89. package/claude/commands/session/fix-build.md +182 -0
  90. package/claude/commands/session/fix-test.md +189 -0
  91. package/claude/commands/session/pending.md +232 -0
  92. package/claude/commands/session/refine.md +188 -0
  93. package/claude/commands/session/resume.md +192 -0
  94. package/claude/commands/session/review.md +192 -0
  95. package/claude/commands/session/scope-change.md +181 -0
  96. package/claude/commands/session/start-blocks.md +347 -0
  97. package/claude/commands/session/start.md +604 -0
  98. package/claude/commands/session/status.md +169 -0
  99. package/claude/commands/session/test-fix.md +221 -0
  100. package/claude/commands/session/test-run.md +203 -0
  101. package/claude/commands/session/test-write.md +242 -0
  102. package/claude/commands/session/validate.md +162 -0
  103. package/claude/config/context.json +40 -0
  104. package/claude/config/github.json +69 -0
  105. package/claude/config/github.schema.json +106 -0
  106. package/claude/config/team.json +46 -0
  107. package/claude/config/team.schema.json +106 -0
  108. package/claude/config/workspace.json +43 -0
  109. package/claude/config/workspace.schema.json +75 -0
  110. package/claude/skills/README.md +228 -0
  111. package/claude/skills/accessibility/SKILL.md +573 -0
  112. package/claude/skills/api-bypass-layers/SKILL.md +550 -0
  113. package/claude/skills/asana-integration/SKILL.md +499 -0
  114. package/claude/skills/better-auth/SKILL.md +666 -0
  115. package/claude/skills/billing-subscriptions/SKILL.md +660 -0
  116. package/claude/skills/block-decision-matrix/SKILL.md +359 -0
  117. package/claude/skills/clickup-integration/SKILL.md +434 -0
  118. package/claude/skills/core-theme-responsibilities/SKILL.md +485 -0
  119. package/claude/skills/create-plugin/SKILL.md +425 -0
  120. package/claude/skills/create-theme/SKILL.md +331 -0
  121. package/claude/skills/cypress-api/SKILL.md +511 -0
  122. package/claude/skills/cypress-api/scripts/generate-api-controller.py +329 -0
  123. package/claude/skills/cypress-api/scripts/generate-api-test.py +930 -0
  124. package/claude/skills/cypress-e2e/SKILL.md +526 -0
  125. package/claude/skills/cypress-e2e/scripts/extract-selectors.py +383 -0
  126. package/claude/skills/cypress-e2e/scripts/generate-uat-test.py +788 -0
  127. package/claude/skills/cypress-selectors/SKILL.md +309 -0
  128. package/claude/skills/cypress-selectors/scripts/extract-missing.py +243 -0
  129. package/claude/skills/cypress-selectors/scripts/generate-block-selectors.py +283 -0
  130. package/claude/skills/cypress-selectors/scripts/validate-selectors.py +145 -0
  131. package/claude/skills/database-migrations/SKILL.md +335 -0
  132. package/claude/skills/database-migrations/scripts/generate-sample-data.py +284 -0
  133. package/claude/skills/database-migrations/scripts/validate-migration.py +323 -0
  134. package/claude/skills/design-system/SKILL.md +682 -0
  135. package/claude/skills/documentation/SKILL.md +540 -0
  136. package/claude/skills/entity-api/SKILL.md +482 -0
  137. package/claude/skills/entity-system/SKILL.md +635 -0
  138. package/claude/skills/entity-system/scripts/generate-child-migration.py +298 -0
  139. package/claude/skills/entity-system/scripts/generate-metas-migration.py +233 -0
  140. package/claude/skills/entity-system/scripts/generate-migration.py +382 -0
  141. package/claude/skills/entity-system/scripts/generate-sample-data.py +418 -0
  142. package/claude/skills/entity-system/scripts/scaffold-entity.py +661 -0
  143. package/claude/skills/github/SKILL.md +467 -0
  144. package/claude/skills/i18n-nextintl/SKILL.md +302 -0
  145. package/claude/skills/i18n-nextintl/scripts/add-translation.py +243 -0
  146. package/claude/skills/i18n-nextintl/scripts/extract-hardcoded.py +246 -0
  147. package/claude/skills/i18n-nextintl/scripts/validate-translations.py +260 -0
  148. package/claude/skills/impact-analysis/SKILL.md +203 -0
  149. package/claude/skills/jest-unit/SKILL.md +306 -0
  150. package/claude/skills/jest-unit/references/component-testing.md +371 -0
  151. package/claude/skills/jest-unit/references/mocking-patterns.md +380 -0
  152. package/claude/skills/jest-unit/references/service-hook-testing.md +454 -0
  153. package/claude/skills/jira-integration/SKILL.md +539 -0
  154. package/claude/skills/media-library/SKILL.md +743 -0
  155. package/claude/skills/mock-analysis/SKILL.md +276 -0
  156. package/claude/skills/monorepo-architecture/SKILL.md +162 -0
  157. package/claude/skills/nextjs-api-development/SKILL.md +364 -0
  158. package/claude/skills/nextjs-api-development/scripts/generate-crud-tests.py +456 -0
  159. package/claude/skills/nextjs-api-development/scripts/scaffold-endpoint.py +481 -0
  160. package/claude/skills/nextjs-api-development/scripts/validate-api.py +283 -0
  161. package/claude/skills/notion-integration/SKILL.md +641 -0
  162. package/claude/skills/npm-development-workflow/SKILL.md +480 -0
  163. package/claude/skills/page-builder-blocks/SKILL.md +530 -0
  164. package/claude/skills/page-builder-blocks/scripts/scaffold-block.py +444 -0
  165. package/claude/skills/permissions-system/SKILL.md +619 -0
  166. package/claude/skills/plugins/SKILL.md +340 -0
  167. package/claude/skills/plugins/references/plugin-templates.md +414 -0
  168. package/claude/skills/plugins/references/plugin-testing.md +353 -0
  169. package/claude/skills/plugins/references/plugin-types.md +198 -0
  170. package/claude/skills/plugins/scripts/scaffold-plugin.py +443 -0
  171. package/claude/skills/pom-patterns/SKILL.md +452 -0
  172. package/claude/skills/pom-patterns/scripts/generate-pom.py +392 -0
  173. package/claude/skills/rate-limiting/SKILL.md +342 -0
  174. package/claude/skills/react-best-practices/AGENTS.md +2410 -0
  175. package/claude/skills/react-best-practices/README.md +123 -0
  176. package/claude/skills/react-best-practices/SKILL.md +125 -0
  177. package/claude/skills/react-best-practices/metadata.json +15 -0
  178. package/claude/skills/react-best-practices/rules/_sections.md +46 -0
  179. package/claude/skills/react-best-practices/rules/_template.md +28 -0
  180. package/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  181. package/claude/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
  182. package/claude/skills/react-best-practices/rules/async-api-routes.md +38 -0
  183. package/claude/skills/react-best-practices/rules/async-defer-await.md +80 -0
  184. package/claude/skills/react-best-practices/rules/async-dependencies.md +36 -0
  185. package/claude/skills/react-best-practices/rules/async-parallel.md +28 -0
  186. package/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  187. package/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  188. package/claude/skills/react-best-practices/rules/bundle-conditional.md +31 -0
  189. package/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
  190. package/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  191. package/claude/skills/react-best-practices/rules/bundle-preload.md +50 -0
  192. package/claude/skills/react-best-practices/rules/client-event-listeners.md +74 -0
  193. package/claude/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
  194. package/claude/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  195. package/claude/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  196. package/claude/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
  197. package/claude/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  198. package/claude/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  199. package/claude/skills/react-best-practices/rules/js-cache-storage.md +70 -0
  200. package/claude/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  201. package/claude/skills/react-best-practices/rules/js-early-exit.md +50 -0
  202. package/claude/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  203. package/claude/skills/react-best-practices/rules/js-index-maps.md +37 -0
  204. package/claude/skills/react-best-practices/rules/js-length-check-first.md +49 -0
  205. package/claude/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  206. package/claude/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  207. package/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  208. package/claude/skills/react-best-practices/rules/rendering-activity.md +26 -0
  209. package/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  210. package/claude/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
  211. package/claude/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  212. package/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  213. package/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  214. package/claude/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  215. package/claude/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  216. package/claude/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  217. package/claude/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  218. package/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  219. package/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  220. package/claude/skills/react-best-practices/rules/rerender-memo.md +44 -0
  221. package/claude/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  222. package/claude/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  223. package/claude/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  224. package/claude/skills/react-best-practices/rules/server-cache-react.md +76 -0
  225. package/claude/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
  226. package/claude/skills/react-best-practices/rules/server-serialization.md +38 -0
  227. package/claude/skills/react-patterns/SKILL.md +688 -0
  228. package/claude/skills/registry-system/SKILL.md +331 -0
  229. package/claude/skills/scheduled-actions/SKILL.md +671 -0
  230. package/claude/skills/scope-enforcement/SKILL.md +542 -0
  231. package/claude/skills/scope-enforcement/scripts/validate-scope.py +357 -0
  232. package/claude/skills/server-actions/SKILL.md +493 -0
  233. package/claude/skills/service-layer/SKILL.md +587 -0
  234. package/claude/skills/session-management/SKILL.md +266 -0
  235. package/claude/skills/session-management/scripts/create-session.py +166 -0
  236. package/claude/skills/session-management/scripts/iteration-close.sh +105 -0
  237. package/claude/skills/session-management/scripts/iteration-init.sh +180 -0
  238. package/claude/skills/session-management/scripts/session-archive.sh +87 -0
  239. package/claude/skills/session-management/scripts/session-close.sh +133 -0
  240. package/claude/skills/session-management/scripts/session-init.sh +225 -0
  241. package/claude/skills/session-management/scripts/session-list.sh +163 -0
  242. package/claude/skills/session-management/scripts/split-plan.sh +116 -0
  243. package/claude/skills/shadcn-components/SKILL.md +586 -0
  244. package/claude/skills/shadcn-theming/SKILL.md +446 -0
  245. package/claude/skills/suspense-loading/SKILL.md +280 -0
  246. package/claude/skills/tailwind-theming/SKILL.md +507 -0
  247. package/claude/skills/tanstack-query/SKILL.md +608 -0
  248. package/claude/skills/test-coverage/SKILL.md +239 -0
  249. package/claude/skills/web-design-guidelines/SKILL.md +39 -0
  250. package/claude/skills/zod-validation/SKILL.md +537 -0
  251. package/claude/templates/blocks/progress.md +86 -0
  252. package/claude/templates/iteration/changes.md +61 -0
  253. package/claude/templates/iteration/progress.md +55 -0
  254. package/claude/templates/log.md +31 -0
  255. package/claude/templates/story/context.md +77 -0
  256. package/claude/templates/story/pendings.md +37 -0
  257. package/claude/templates/story/plan.md +299 -0
  258. package/claude/templates/story/requirements.md +109 -0
  259. package/claude/templates/story/scope.json +10 -0
  260. package/claude/templates/story/tests.md +91 -0
  261. package/claude/templates/task/progress.md +58 -0
  262. package/claude/templates/task/requirements.md +54 -0
  263. package/claude/workflows/README.md +154 -0
  264. package/claude/workflows/blocks.md +614 -0
  265. package/claude/workflows/story.md +1207 -0
  266. package/claude/workflows/task.md +927 -0
  267. package/claude/workflows/tweak.md +527 -0
  268. package/cursor/.gitkeep +0 -0
  269. package/package.json +35 -0
  270. package/scripts/postinstall.mjs +198 -0
  271. package/scripts/setup.mjs +282 -0
  272. package/scripts/sync.mjs +209 -0
@@ -0,0 +1,335 @@
1
+ ---
2
+ name: database-migrations
3
+ description: |
4
+ PostgreSQL migration patterns with RLS, Better Auth integration, and TIMESTAMPTZ.
5
+ Covers main tables, meta tables, child entities, and sample data.
6
+ Use this skill when creating migrations, validating SQL, or generating sample data.
7
+ allowed-tools: Read, Glob, Grep, Bash(python:*)
8
+ version: 1.0.0
9
+ ---
10
+
11
+ # Database Migrations Skill
12
+
13
+ Patterns and tools for PostgreSQL database migrations with RLS, Better Auth, and strict conventions.
14
+
15
+ ## Architecture Overview
16
+
17
+ ```
18
+ core/migrations/
19
+ ├── 001_better_auth_and_functions.sql # Base auth (DO NOT MODIFY)
20
+ ├── 002_auth_tables.sql # Auth tables (DO NOT MODIFY)
21
+ ├── XXX_[entity]_table.sql # Main entity table
22
+ ├── XXX_[entity]_metas.sql # Meta table (optional)
23
+ ├── XXX_[entity]_sample_data.sql # Sample data (optional)
24
+ └── XXX_[parent]_[child]_table.sql # Child entities
25
+ ```
26
+
27
+ > **📍 Context-Aware Paths:** Paths shown assume monorepo development. In consumer projects,
28
+ > create migrations in `contents/themes/{theme}/migrations/` instead (use sequence 1001+). Core is read-only.
29
+ > See `core-theme-responsibilities` skill for complete rules.
30
+
31
+ ## When to Use This Skill
32
+
33
+ - Creating new entity migrations
34
+ - Adding meta tables for entities
35
+ - Creating child entity relationships
36
+ - Validating migration conventions
37
+ - Generating sample data
38
+
39
+ ## Core Principles
40
+
41
+ ### 1. Better Auth Integration
42
+
43
+ **Better Auth uses TEXT for IDs, not UUID type:**
44
+
45
+ ```sql
46
+ -- ✅ CORRECT
47
+ id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
48
+ "userId" TEXT NOT NULL REFERENCES public."users"(id) ON DELETE CASCADE,
49
+
50
+ -- ❌ WRONG
51
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
52
+ ```
53
+
54
+ **Use existing functions (NEVER redefine):**
55
+ - `get_auth_user_id()` - Get current authenticated user ID
56
+ - `set_updated_at()` - Auto-update timestamp trigger
57
+
58
+ ### 2. Field Ordering (MANDATORY)
59
+
60
+ Fields MUST follow this exact order:
61
+
62
+ ```sql
63
+ CREATE TABLE IF NOT EXISTS public."EntityName" (
64
+ -- 1. Primary Key (always first)
65
+ id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
66
+
67
+ -- 2. Relational Fields (foreign keys)
68
+ "userId" TEXT NOT NULL REFERENCES public."users"(id) ON DELETE CASCADE,
69
+ "teamId" TEXT REFERENCES public."teams"(id) ON DELETE CASCADE,
70
+
71
+ -- 3. Entity-specific Fields (business logic)
72
+ title TEXT NOT NULL,
73
+ description TEXT,
74
+ content JSONB,
75
+ priority INTEGER DEFAULT 0,
76
+
77
+ -- 4. System Fields (always last)
78
+ status TEXT DEFAULT 'draft',
79
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
80
+ "updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now()
81
+ );
82
+ ```
83
+
84
+ ### 3. TIMESTAMPTZ Requirement (CRITICAL)
85
+
86
+ **ALL timestamps MUST use `TIMESTAMPTZ`, never plain `TIMESTAMP`:**
87
+
88
+ ```sql
89
+ -- ✅ CORRECT
90
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
91
+ "updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
92
+ "expiresAt" TIMESTAMPTZ,
93
+
94
+ -- ❌ FORBIDDEN
95
+ "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
96
+ ```
97
+
98
+ ### 4. CASCADE Rules
99
+
100
+ ```sql
101
+ -- ✅ Main entity tables - ALWAYS use CASCADE
102
+ DROP TABLE IF EXISTS public."EntityName" CASCADE;
103
+
104
+ -- ✅ Meta tables - NO DROP (removed by parent CASCADE)
105
+ CREATE TABLE IF NOT EXISTS public."EntityName_metas" (...);
106
+
107
+ -- ✅ Foreign Keys - Use CASCADE for parent-child
108
+ REFERENCES public."Parent"(id) ON DELETE CASCADE
109
+ ```
110
+
111
+ ## RLS Patterns (4 Cases)
112
+
113
+ ### Case 1: Private to Owner
114
+ ```sql
115
+ CREATE POLICY "Entity owner can do all"
116
+ ON public."Entity"
117
+ FOR ALL TO authenticated
118
+ USING ("userId" = public.get_auth_user_id())
119
+ WITH CHECK ("userId" = public.get_auth_user_id());
120
+ ```
121
+
122
+ ### Case 2: Team-Based Access
123
+ ```sql
124
+ CREATE POLICY "Entity team can do all"
125
+ ON public."Entity"
126
+ FOR ALL TO authenticated
127
+ USING (
128
+ "teamId" IN (
129
+ SELECT "teamId" FROM public."members"
130
+ WHERE "userId" = public.get_auth_user_id()
131
+ )
132
+ )
133
+ WITH CHECK (...);
134
+ ```
135
+
136
+ ### Case 3: Shared Among Authenticated
137
+ ```sql
138
+ CREATE POLICY "Entity any auth can do all"
139
+ ON public."Entity"
140
+ FOR ALL TO authenticated
141
+ USING (true)
142
+ WITH CHECK (true);
143
+ ```
144
+
145
+ ### Case 4: Public Read with Auth Write
146
+ ```sql
147
+ -- Anonymous can read published
148
+ CREATE POLICY "Entity public can select"
149
+ ON public."Entity"
150
+ FOR SELECT TO anon
151
+ USING (published = TRUE);
152
+
153
+ -- Authenticated can manage all
154
+ CREATE POLICY "Entity auth can do all"
155
+ ON public."Entity"
156
+ FOR ALL TO authenticated
157
+ USING (true)
158
+ WITH CHECK (true);
159
+ ```
160
+
161
+ ## Meta Tables Pattern
162
+
163
+ **CRITICAL: Always use `"entityId"` for foreign key (never `"postId"`, `"userId"`, etc.)**
164
+
165
+ ```sql
166
+ CREATE TABLE IF NOT EXISTS public."EntityName_metas" (
167
+ id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
168
+ "entityId" TEXT NOT NULL REFERENCES public."EntityName"(id) ON DELETE CASCADE,
169
+ "metaKey" TEXT NOT NULL,
170
+ "metaValue" JSONB NOT NULL DEFAULT '{}'::jsonb,
171
+ "dataType" TEXT,
172
+ "isPublic" BOOLEAN NOT NULL DEFAULT FALSE,
173
+ "isSearchable" BOOLEAN NOT NULL DEFAULT FALSE,
174
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
175
+ "updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
176
+ CONSTRAINT entity_metas_unique_key UNIQUE ("entityId", "metaKey")
177
+ );
178
+ ```
179
+
180
+ ## Child Entities Pattern
181
+
182
+ **CRITICAL: Always use `"parentId"` for foreign key (never `"clientId"`, `"orderId"`, etc.)**
183
+
184
+ ```sql
185
+ CREATE TABLE IF NOT EXISTS public."parent_children" (
186
+ id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
187
+ "parentId" TEXT NOT NULL REFERENCES public."parent"(id) ON DELETE CASCADE,
188
+
189
+ -- Child-specific fields (NO userId - inherited via parent)
190
+ name TEXT NOT NULL,
191
+ description TEXT,
192
+
193
+ -- System fields
194
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
195
+ "updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now()
196
+ );
197
+
198
+ -- RLS inherits parent access
199
+ CREATE POLICY "Child inherit parent access"
200
+ ON public."parent_children"
201
+ FOR ALL TO authenticated
202
+ USING (
203
+ EXISTS (
204
+ SELECT 1 FROM public."parent" p
205
+ WHERE p.id = "parentId"
206
+ AND p."userId" = public.get_auth_user_id()
207
+ )
208
+ )
209
+ WITH CHECK (...);
210
+ ```
211
+
212
+ ## Scripts
213
+
214
+ ### Validate Migration Conventions
215
+ ```bash
216
+ # Validate a specific migration file
217
+ python3 .claude/skills/database-migrations/scripts/validate-migration.py \
218
+ --file core/migrations/017_scheduled_actions_table.sql
219
+
220
+ # Validate all migrations
221
+ python3 .claude/skills/database-migrations/scripts/validate-migration.py \
222
+ --path core/migrations/
223
+
224
+ # Strict mode (exit with error if issues found)
225
+ python3 .claude/skills/database-migrations/scripts/validate-migration.py \
226
+ --path core/migrations/ \
227
+ --strict
228
+ ```
229
+
230
+ ### Generate Sample Data
231
+ ```bash
232
+ # Generate sample data for an entity
233
+ python3 .claude/skills/database-migrations/scripts/generate-sample-data.py \
234
+ --entity posts \
235
+ --count 20
236
+
237
+ # With custom team and user IDs
238
+ python3 .claude/skills/database-migrations/scripts/generate-sample-data.py \
239
+ --entity tasks \
240
+ --count 10 \
241
+ --user-id "user-sample-1" \
242
+ --team-id "team-tmt-001"
243
+
244
+ # Preview without writing
245
+ python3 .claude/skills/database-migrations/scripts/generate-sample-data.py \
246
+ --entity products \
247
+ --dry-run
248
+ ```
249
+
250
+ ## Required Indexes
251
+
252
+ ```sql
253
+ -- ============================================
254
+ -- INDEXES
255
+ -- ============================================
256
+ -- Primary relationships
257
+ CREATE INDEX IF NOT EXISTS idx_entity_user_id ON public."entity"("userId");
258
+ CREATE INDEX IF NOT EXISTS idx_entity_team_id ON public."entity"("teamId");
259
+
260
+ -- Common query patterns
261
+ CREATE INDEX IF NOT EXISTS idx_entity_status ON public."entity"(status);
262
+ CREATE INDEX IF NOT EXISTS idx_entity_created_at ON public."entity"("createdAt" DESC);
263
+
264
+ -- Conditional indexes
265
+ CREATE INDEX IF NOT EXISTS idx_entity_published ON public."entity"(published) WHERE published = TRUE;
266
+
267
+ -- JSONB indexes
268
+ CREATE INDEX IF NOT EXISTS idx_entity_payload_gin ON public."entity" USING GIN (payload);
269
+ ```
270
+
271
+ ## Trigger Pattern
272
+
273
+ **Always use existing Better Auth function:**
274
+
275
+ ```sql
276
+ -- ============================================
277
+ -- TRIGGER updatedAt (uses Better Auth function)
278
+ -- ============================================
279
+ DROP TRIGGER IF EXISTS entity_set_updated_at ON public."entity";
280
+ CREATE TRIGGER entity_set_updated_at
281
+ BEFORE UPDATE ON public."entity"
282
+ FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
283
+ ```
284
+
285
+ ## Naming Conventions
286
+
287
+ | Convention | Example |
288
+ |------------|---------|
289
+ | Table names | camelCase: `"scheduledActions"` |
290
+ | Column names | camelCase: `"createdAt"`, `"userId"` |
291
+ | Index names | snake_case: `idx_entity_user_id` |
292
+ | Policy names | "Entity action description" |
293
+ | Constraint names | snake_case: `entity_metas_unique_key` |
294
+
295
+ ## Anti-Patterns
296
+
297
+ ```sql
298
+ -- ❌ NEVER: Plain TIMESTAMP
299
+ "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
300
+
301
+ -- ❌ NEVER: UUID type (Better Auth uses TEXT)
302
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid()
303
+
304
+ -- ❌ NEVER: Redefine auth functions
305
+ CREATE OR REPLACE FUNCTION public.get_auth_user_id()...
306
+
307
+ -- ❌ NEVER: Wrong meta FK naming
308
+ "postId" TEXT NOT NULL REFERENCES public."posts"(id)
309
+ -- ✅ CORRECT: "entityId"
310
+
311
+ -- ❌ NEVER: Wrong child FK naming
312
+ "clientId" TEXT NOT NULL REFERENCES public."clients"(id)
313
+ -- ✅ CORRECT: "parentId"
314
+
315
+ -- ❌ NEVER: Business logic in DB triggers
316
+ CREATE FUNCTION calculate_order_totals()...
317
+ ```
318
+
319
+ ## Checklist
320
+
321
+ Before finalizing a migration:
322
+
323
+ - [ ] Uses TEXT for all ID fields (not UUID type)
324
+ - [ ] References `public."users"` for user relationships
325
+ - [ ] Uses `get_auth_user_id()` in RLS (not redefined)
326
+ - [ ] Uses `set_updated_at()` in triggers (not redefined)
327
+ - [ ] ALL timestamps use `TIMESTAMPTZ` (not `TIMESTAMP`)
328
+ - [ ] Uses `now()` (not `CURRENT_TIMESTAMP`)
329
+ - [ ] Fields follow strict ordering (id → FK → business → system)
330
+ - [ ] Main tables use `DROP ... CASCADE`
331
+ - [ ] Meta tables use `"entityId"` (not entity-specific name)
332
+ - [ ] Child tables use `"parentId"` (not parent-specific name)
333
+ - [ ] Appropriate RLS policies for access pattern
334
+ - [ ] Required indexes created
335
+ - [ ] Sample data uses `ON CONFLICT` clause
@@ -0,0 +1,284 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Generate Sample Data Script
4
+
5
+ Generates SQL INSERT statements for sample/test data.
6
+
7
+ Usage:
8
+ python generate-sample-data.py --entity ENTITY [--count COUNT]
9
+
10
+ Options:
11
+ --entity ENTITY Entity name (e.g., posts, tasks, products)
12
+ --count COUNT Number of records to generate (default: 20)
13
+ --user-id ID User ID for ownership (default: user-sample-1)
14
+ --team-id ID Team ID for team context (default: team-tmt-001)
15
+ --dry-run Preview without writing to file
16
+ --output FILE Output file path (default: core/migrations/XXX_entity_sample_data.sql)
17
+ """
18
+
19
+ import os
20
+ import sys
21
+ import re
22
+ import random
23
+ import argparse
24
+ from datetime import datetime, timedelta
25
+ from pathlib import Path
26
+ from typing import List, Dict
27
+
28
+
29
+ def to_pascal_case(name: str) -> str:
30
+ """Convert kebab-case/snake_case to PascalCase."""
31
+ return ''.join(x.title() for x in re.split(r'[-_]', name))
32
+
33
+
34
+ def to_camel_case(name: str) -> str:
35
+ """Convert kebab-case/snake_case to camelCase."""
36
+ parts = re.split(r'[-_]', name)
37
+ return parts[0].lower() + ''.join(x.title() for x in parts[1:])
38
+
39
+
40
+ def get_next_migration_number(migrations_path: Path) -> str:
41
+ """Get the next available migration number."""
42
+ if not migrations_path.exists():
43
+ return "020"
44
+
45
+ existing = list(migrations_path.glob("*.sql"))
46
+ if not existing:
47
+ return "020"
48
+
49
+ numbers = []
50
+ for f in existing:
51
+ match = re.match(r'^(\d+)_', f.name)
52
+ if match:
53
+ numbers.append(int(match.group(1)))
54
+
55
+ if numbers:
56
+ return str(max(numbers) + 1).zfill(3)
57
+ return "020"
58
+
59
+
60
+ def generate_sample_titles(entity: str, count: int) -> List[str]:
61
+ """Generate sample titles based on entity type."""
62
+ templates = {
63
+ 'posts': [
64
+ "Introduction to {topic}",
65
+ "Understanding {topic}",
66
+ "A Guide to {topic}",
67
+ "Best Practices for {topic}",
68
+ "Deep Dive into {topic}",
69
+ "Mastering {topic}",
70
+ "The Complete {topic} Guide",
71
+ "Getting Started with {topic}",
72
+ "{topic} Explained",
73
+ "Why {topic} Matters",
74
+ ],
75
+ 'tasks': [
76
+ "Review {topic} implementation",
77
+ "Fix {topic} issue",
78
+ "Update {topic} documentation",
79
+ "Test {topic} feature",
80
+ "Refactor {topic} code",
81
+ "Deploy {topic} to production",
82
+ "Configure {topic} settings",
83
+ "Analyze {topic} metrics",
84
+ "Optimize {topic} performance",
85
+ "Design {topic} system",
86
+ ],
87
+ 'products': [
88
+ "Premium {topic} Package",
89
+ "Professional {topic} Suite",
90
+ "Enterprise {topic} Solution",
91
+ "Basic {topic} Plan",
92
+ "Advanced {topic} Tools",
93
+ "Essential {topic} Kit",
94
+ "Ultimate {topic} Bundle",
95
+ "Starter {topic} Pack",
96
+ "{topic} Pro Edition",
97
+ "{topic} Deluxe Version",
98
+ ],
99
+ 'default': [
100
+ "Sample {topic} Item",
101
+ "Test {topic} Record",
102
+ "{topic} Example",
103
+ "Demo {topic} Entry",
104
+ "New {topic} Data",
105
+ ]
106
+ }
107
+
108
+ topics = [
109
+ "React", "TypeScript", "Next.js", "PostgreSQL", "Authentication",
110
+ "API Design", "Testing", "CI/CD", "Docker", "Kubernetes",
111
+ "Performance", "Security", "Caching", "Database", "Frontend",
112
+ "Backend", "DevOps", "Monitoring", "Logging", "Analytics"
113
+ ]
114
+
115
+ template_list = templates.get(entity, templates['default'])
116
+ titles = []
117
+
118
+ for i in range(count):
119
+ template = template_list[i % len(template_list)]
120
+ topic = topics[i % len(topics)]
121
+ titles.append(template.format(topic=topic))
122
+
123
+ return titles
124
+
125
+
126
+ def generate_slugs(titles: List[str]) -> List[str]:
127
+ """Generate URL slugs from titles."""
128
+ slugs = []
129
+ for title in titles:
130
+ slug = title.lower()
131
+ slug = re.sub(r'[^a-z0-9\s-]', '', slug)
132
+ slug = re.sub(r'\s+', '-', slug)
133
+ slug = re.sub(r'-+', '-', slug)
134
+ slugs.append(slug.strip('-'))
135
+ return slugs
136
+
137
+
138
+ def generate_sample_data(
139
+ entity: str,
140
+ count: int,
141
+ user_id: str,
142
+ team_id: str
143
+ ) -> str:
144
+ """Generate SQL INSERT statements for sample data."""
145
+
146
+ table_name = to_camel_case(entity)
147
+ titles = generate_sample_titles(entity, count)
148
+ slugs = generate_slugs(titles)
149
+
150
+ # Status options
151
+ statuses = ['draft', 'active', 'published', 'archived']
152
+
153
+ # Build SQL
154
+ lines = [
155
+ f"-- Migration: XXX_{entity}_sample_data.sql",
156
+ f"-- Description: Sample data for {entity}",
157
+ f"-- Date: {datetime.now().strftime('%Y-%m-%d')}",
158
+ "",
159
+ "-- ============================================",
160
+ f"-- SAMPLE {entity.upper()}",
161
+ "-- ============================================",
162
+ f'INSERT INTO public."{table_name}" (',
163
+ " id,",
164
+ ' "userId",',
165
+ ]
166
+
167
+ # Add teamId if provided
168
+ if team_id:
169
+ lines.append(' "teamId",')
170
+
171
+ lines.extend([
172
+ " title,",
173
+ " slug,",
174
+ " description,",
175
+ " status,",
176
+ ' "createdAt",',
177
+ ' "updatedAt"',
178
+ ") VALUES",
179
+ ])
180
+
181
+ # Generate records
182
+ values = []
183
+ base_date = datetime.now() - timedelta(days=30)
184
+
185
+ for i in range(count):
186
+ record_id = f'{entity[:4]}-sample-{i + 1}'
187
+ created_at = base_date + timedelta(days=i, hours=random.randint(0, 23))
188
+ updated_at = created_at + timedelta(days=random.randint(0, 5))
189
+ status = statuses[i % len(statuses)]
190
+ description = f"Sample description for {entity} #{i + 1}. This is test data for development."
191
+
192
+ value_parts = [
193
+ f" '{record_id}'",
194
+ f" '{user_id}'",
195
+ ]
196
+
197
+ if team_id:
198
+ value_parts.append(f" '{team_id}'")
199
+
200
+ value_parts.extend([
201
+ f" '{titles[i]}'",
202
+ f" '{slugs[i]}'",
203
+ f" '{description}'",
204
+ f" '{status}'",
205
+ f" '{created_at.strftime('%Y-%m-%d %H:%M:%S')}'::timestamptz",
206
+ f" '{updated_at.strftime('%Y-%m-%d %H:%M:%S')}'::timestamptz",
207
+ ])
208
+
209
+ values.append(" (\n" + ",\n".join(value_parts) + "\n )")
210
+
211
+ lines.append(",\n".join(values))
212
+ lines.append("ON CONFLICT (id) DO NOTHING;")
213
+
214
+ return "\n".join(lines)
215
+
216
+
217
+ def main():
218
+ parser = argparse.ArgumentParser(description='Generate sample data')
219
+ parser.add_argument('--entity', required=True, help='Entity name')
220
+ parser.add_argument('--count', type=int, default=20, help='Number of records')
221
+ parser.add_argument('--user-id', default='user-sample-1', help='User ID')
222
+ parser.add_argument('--team-id', default='team-tmt-001', help='Team ID')
223
+ parser.add_argument('--dry-run', action='store_true', help='Preview without writing')
224
+ parser.add_argument('--output', help='Output file path')
225
+
226
+ args = parser.parse_args()
227
+
228
+ entity = args.entity.lower()
229
+
230
+ print(f"\n{'=' * 60}")
231
+ print("GENERATING SAMPLE DATA")
232
+ print(f"{'=' * 60}")
233
+ print(f"Entity: {entity}")
234
+ print(f"Count: {args.count}")
235
+ print(f"User ID: {args.user_id}")
236
+ print(f"Team ID: {args.team_id}")
237
+ print(f"{'=' * 60}\n")
238
+
239
+ # Generate SQL
240
+ sql_content = generate_sample_data(
241
+ entity,
242
+ args.count,
243
+ args.user_id,
244
+ args.team_id
245
+ )
246
+
247
+ if args.dry_run:
248
+ print("DRY RUN - Generated SQL:\n")
249
+ print("-" * 60)
250
+ print(sql_content)
251
+ print("-" * 60)
252
+ print("\nRun without --dry-run to write to file.")
253
+ return 0
254
+
255
+ # Determine output path
256
+ if args.output:
257
+ output_path = Path(args.output)
258
+ else:
259
+ migrations_path = Path('core/migrations')
260
+ next_num = get_next_migration_number(migrations_path)
261
+ output_path = migrations_path / f"{next_num}_{entity}_sample_data.sql"
262
+
263
+ # Write file
264
+ output_path.parent.mkdir(parents=True, exist_ok=True)
265
+
266
+ with open(output_path, 'w', encoding='utf-8') as f:
267
+ f.write(sql_content)
268
+ f.write('\n')
269
+
270
+ print(f"Sample data written to: {output_path}")
271
+ print(f"Records generated: {args.count}")
272
+ print(f"\n{'=' * 60}")
273
+ print("NEXT STEPS:")
274
+ print("=" * 60)
275
+ print(f"1. Review generated file: {output_path}")
276
+ print("2. Adjust fields as needed for your entity schema")
277
+ print("3. Run migration: pnpm db:migrate")
278
+ print("=" * 60 + "\n")
279
+
280
+ return 0
281
+
282
+
283
+ if __name__ == '__main__':
284
+ sys.exit(main())