@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,587 @@
1
+ ---
2
+ name: service-layer
3
+ description: |
4
+ Service layer patterns for this Next.js application.
5
+ Covers static class pattern, RLS integration, standard method signatures, and BaseEntityService.
6
+ Use this skill when implementing business logic or data access services.
7
+ allowed-tools: Read, Glob, Grep
8
+ version: 1.0.0
9
+ ---
10
+
11
+ # Service Layer Skill
12
+
13
+ Patterns for implementing business logic and data access services with RLS integration.
14
+
15
+ ## Architecture Overview
16
+
17
+ ```
18
+ core/lib/services/
19
+ ├── base-entity.service.ts # Generic CRUD service base class
20
+ ├── user.service.ts # User management
21
+ ├── team.service.ts # Team CRUD and membership
22
+ ├── team-member.service.ts # Team membership management
23
+ ├── permission.service.ts # Permission checks (O(1))
24
+ ├── membership.service.ts # Complete membership context
25
+ ├── subscription.service.ts # Subscription lifecycle
26
+ ├── plan.service.ts # Plan queries
27
+ ├── usage.service.ts # Usage tracking and quotas
28
+ ├── meta.service.ts # Flexible entity metadata
29
+ ├── invoice.service.ts # Invoice management
30
+ ├── theme.service.ts # Theme registry queries
31
+ ├── entity-type.service.ts # Entity registry queries
32
+ └── ...
33
+
34
+ core/lib/db.ts # RLS query functions
35
+ ```
36
+
37
+ > **📍 Context-Aware Paths:** Paths shown assume monorepo development. In consumer projects,
38
+ > create in `contents/themes/{theme}/services/` instead. Core is read-only.
39
+ > See `core-theme-responsibilities` skill for complete rules.
40
+
41
+ ## When to Use This Skill
42
+
43
+ - Implementing business logic services
44
+ - Creating data access layer for entities
45
+ - Working with RLS (Row Level Security)
46
+ - Implementing transactions
47
+ - Querying registries
48
+
49
+ ## Static Class Pattern
50
+
51
+ **All services use static methods exclusively:**
52
+
53
+ ```typescript
54
+ // core/lib/services/customer.service.ts
55
+
56
+ export class CustomerService {
57
+ // No constructor - all methods are static
58
+ // No instance state
59
+
60
+ static async getById(id: string, userId: string): Promise<Customer | null> {
61
+ // Implementation
62
+ }
63
+
64
+ static async list(userId: string, options?: ListOptions): Promise<ListResult<Customer>> {
65
+ // Implementation
66
+ }
67
+
68
+ static async create(userId: string, teamId: string, data: CreateCustomer): Promise<Customer> {
69
+ // Implementation
70
+ }
71
+
72
+ static async update(id: string, userId: string, data: UpdateCustomer): Promise<Customer> {
73
+ // Implementation
74
+ }
75
+
76
+ static async delete(id: string, userId: string): Promise<boolean> {
77
+ // Implementation
78
+ }
79
+ }
80
+ ```
81
+
82
+ **Usage (no instantiation):**
83
+ ```typescript
84
+ import { CustomerService } from '@/core/lib/services/customer.service'
85
+
86
+ // Direct static method calls
87
+ const customer = await CustomerService.getById('cust-123', userId)
88
+ const customers = await CustomerService.list(userId, { limit: 10 })
89
+ const created = await CustomerService.create(userId, teamId, { name: 'Acme' })
90
+ ```
91
+
92
+ ## Standard Method Signatures
93
+
94
+ ### Query Methods (Read Operations)
95
+
96
+ ```typescript
97
+ // Get single entity by ID
98
+ static async getById(
99
+ id: string,
100
+ userId: string
101
+ ): Promise<Entity | null>
102
+
103
+ // List with pagination, filtering, ordering
104
+ static async list(
105
+ userId: string,
106
+ options?: ListOptions
107
+ ): Promise<ListResult<Entity>>
108
+
109
+ // Simple query (wrapper over list)
110
+ static async query(
111
+ userId: string,
112
+ options?: QueryOptions
113
+ ): Promise<Entity[]>
114
+
115
+ // Check existence
116
+ static async exists(
117
+ id: string,
118
+ userId: string
119
+ ): Promise<boolean>
120
+
121
+ // Count with optional filtering
122
+ static async count(
123
+ userId: string,
124
+ where?: Record<string, unknown>
125
+ ): Promise<number>
126
+ ```
127
+
128
+ ### Mutation Methods (Write Operations)
129
+
130
+ ```typescript
131
+ // Create new entity
132
+ static async create(
133
+ userId: string,
134
+ teamId: string,
135
+ data: CreateEntity
136
+ ): Promise<Entity>
137
+
138
+ // Update existing entity
139
+ static async update(
140
+ id: string,
141
+ userId: string,
142
+ data: UpdateEntity
143
+ ): Promise<Entity>
144
+
145
+ // Delete entity
146
+ static async delete(
147
+ id: string,
148
+ userId: string
149
+ ): Promise<boolean>
150
+ ```
151
+
152
+ ### ListOptions Interface
153
+
154
+ ```typescript
155
+ interface ListOptions {
156
+ limit?: number // Pagination limit (default: 20)
157
+ offset?: number // Pagination offset
158
+ orderBy?: string // Sort field (default: 'createdAt')
159
+ orderDir?: 'asc' | 'desc' // Sort direction (default: 'desc')
160
+ where?: Record<string, unknown> // Filters
161
+ search?: string // Text search
162
+ }
163
+
164
+ interface ListResult<T> {
165
+ data: T[]
166
+ total: number
167
+ limit: number
168
+ offset: number
169
+ }
170
+ ```
171
+
172
+ ## RLS Integration
173
+
174
+ ### Core RLS Functions
175
+
176
+ ```typescript
177
+ // core/lib/db.ts
178
+
179
+ // Query with RLS context (SELECT)
180
+ export async function queryWithRLS<T>(
181
+ query: string,
182
+ params: unknown[] = [],
183
+ userId?: string | null
184
+ ): Promise<T[]>
185
+
186
+ // Query single result with RLS
187
+ export async function queryOneWithRLS<T>(
188
+ query: string,
189
+ params: unknown[] = [],
190
+ userId?: string | null
191
+ ): Promise<T | null>
192
+
193
+ // Mutation with RLS (INSERT, UPDATE, DELETE)
194
+ export async function mutateWithRLS<T>(
195
+ query: string,
196
+ params: unknown[] = [],
197
+ userId?: string | null
198
+ ): Promise<{ rows: T[], rowCount: number }>
199
+ ```
200
+
201
+ **RLS Context:**
202
+ - Functions set PostgreSQL `app.user_id` session variable
203
+ - RLS policies use this to filter/restrict data access
204
+ - Always pass `userId` parameter for proper isolation
205
+
206
+ ### Service Implementation with RLS
207
+
208
+ ```typescript
209
+ import { queryOneWithRLS, queryWithRLS, mutateWithRLS } from '@/core/lib/db'
210
+
211
+ export class CustomerService {
212
+ static async getById(id: string, userId: string): Promise<Customer | null> {
213
+ // Input validation
214
+ if (!id?.trim()) throw new Error('Customer ID is required')
215
+ if (!userId?.trim()) throw new Error('User ID is required')
216
+
217
+ return queryOneWithRLS<Customer>(
218
+ 'SELECT * FROM "customers" WHERE id = $1',
219
+ [id],
220
+ userId // Sets app.user_id for RLS
221
+ )
222
+ }
223
+
224
+ static async list(userId: string, options: ListOptions = {}): Promise<ListResult<Customer>> {
225
+ const { limit = 20, offset = 0, orderBy = 'createdAt', orderDir = 'desc' } = options
226
+
227
+ const data = await queryWithRLS<Customer>(
228
+ `SELECT * FROM "customers"
229
+ ORDER BY "${orderBy}" ${orderDir.toUpperCase()}
230
+ LIMIT $1 OFFSET $2`,
231
+ [limit, offset],
232
+ userId
233
+ )
234
+
235
+ const countResult = await queryOneWithRLS<{ count: number }>(
236
+ 'SELECT COUNT(*) as count FROM "customers"',
237
+ [],
238
+ userId
239
+ )
240
+
241
+ return {
242
+ data,
243
+ total: countResult?.count ?? 0,
244
+ limit,
245
+ offset
246
+ }
247
+ }
248
+
249
+ static async create(userId: string, teamId: string, data: CreateCustomer): Promise<Customer> {
250
+ const id = generateId()
251
+ const now = new Date().toISOString()
252
+
253
+ const result = await mutateWithRLS<Customer>(
254
+ `INSERT INTO "customers" (id, "userId", "teamId", name, email, "createdAt", "updatedAt")
255
+ VALUES ($1, $2, $3, $4, $5, $6, $7)
256
+ RETURNING *`,
257
+ [id, userId, teamId, data.name, data.email, now, now],
258
+ userId
259
+ )
260
+
261
+ return result.rows[0]
262
+ }
263
+
264
+ static async update(id: string, userId: string, data: UpdateCustomer): Promise<Customer> {
265
+ const setClauses: string[] = []
266
+ const params: unknown[] = []
267
+ let paramIndex = 1
268
+
269
+ if (data.name !== undefined) {
270
+ setClauses.push(`name = $${paramIndex++}`)
271
+ params.push(data.name)
272
+ }
273
+ if (data.email !== undefined) {
274
+ setClauses.push(`email = $${paramIndex++}`)
275
+ params.push(data.email)
276
+ }
277
+
278
+ setClauses.push(`"updatedAt" = $${paramIndex++}`)
279
+ params.push(new Date().toISOString())
280
+
281
+ params.push(id) // WHERE id = $N
282
+
283
+ const result = await mutateWithRLS<Customer>(
284
+ `UPDATE "customers"
285
+ SET ${setClauses.join(', ')}
286
+ WHERE id = $${paramIndex}
287
+ RETURNING *`,
288
+ params,
289
+ userId
290
+ )
291
+
292
+ if (result.rowCount === 0) {
293
+ throw new Error('Customer not found')
294
+ }
295
+
296
+ return result.rows[0]
297
+ }
298
+
299
+ static async delete(id: string, userId: string): Promise<boolean> {
300
+ const result = await mutateWithRLS(
301
+ 'DELETE FROM "customers" WHERE id = $1',
302
+ [id],
303
+ userId
304
+ )
305
+ return result.rowCount > 0
306
+ }
307
+ }
308
+ ```
309
+
310
+ ## Transaction Pattern
311
+
312
+ ```typescript
313
+ import { getTransactionClient } from '@/core/lib/db'
314
+
315
+ export class TeamService {
316
+ static async createWithOwner(
317
+ userId: string,
318
+ teamData: CreateTeam
319
+ ): Promise<{ team: Team; membership: TeamMember }> {
320
+ const tx = await getTransactionClient(userId)
321
+
322
+ try {
323
+ // Create team
324
+ const team = await tx.queryOne<Team>(
325
+ `INSERT INTO "teams" (id, name, slug, "createdAt")
326
+ VALUES ($1, $2, $3, $4)
327
+ RETURNING *`,
328
+ [generateId(), teamData.name, teamData.slug, new Date().toISOString()]
329
+ )
330
+
331
+ // Add owner membership
332
+ const membership = await tx.queryOne<TeamMember>(
333
+ `INSERT INTO "teamMembers" (id, "userId", "teamId", role, "createdAt")
334
+ VALUES ($1, $2, $3, $4, $5)
335
+ RETURNING *`,
336
+ [generateId(), userId, team.id, 'owner', new Date().toISOString()]
337
+ )
338
+
339
+ // Commit transaction
340
+ await tx.commit()
341
+
342
+ return { team, membership }
343
+ } catch (error) {
344
+ // Rollback on error
345
+ await tx.rollback()
346
+ throw error
347
+ }
348
+ }
349
+ }
350
+ ```
351
+
352
+ ## BaseEntityService
353
+
354
+ Generic base class for entity CRUD operations:
355
+
356
+ ```typescript
357
+ // core/lib/services/base-entity.service.ts
358
+
359
+ export interface EntityServiceConfig {
360
+ tableName: string // e.g., 'customers'
361
+ fields: string[] // Custom fields (excluding system fields)
362
+ searchableFields?: string[] // Fields for text search
363
+ defaultOrderBy?: string // Default: 'createdAt'
364
+ defaultOrderDir?: 'asc' | 'desc' // Default: 'desc'
365
+ defaultLimit?: number // Default: 20
366
+ }
367
+
368
+ export class BaseEntityService<TEntity, TCreate, TUpdate> {
369
+ protected config: EntityServiceConfig
370
+
371
+ constructor(config: EntityServiceConfig) {
372
+ this.config = {
373
+ defaultOrderBy: 'createdAt',
374
+ defaultOrderDir: 'desc',
375
+ defaultLimit: 20,
376
+ ...config
377
+ }
378
+ }
379
+
380
+ async getById(id: string, userId: string): Promise<TEntity | null> { ... }
381
+ async list(userId: string, options?: ListOptions): Promise<ListResult<TEntity>> { ... }
382
+ async create(userId: string, teamId: string, data: TCreate): Promise<TEntity> { ... }
383
+ async update(id: string, userId: string, data: TUpdate): Promise<TEntity> { ... }
384
+ async delete(id: string, userId: string): Promise<boolean> { ... }
385
+ }
386
+ ```
387
+
388
+ **Extending BaseEntityService:**
389
+ ```typescript
390
+ class ProductsService extends BaseEntityService<Product, CreateProduct, UpdateProduct> {
391
+ constructor() {
392
+ super({
393
+ tableName: 'products',
394
+ fields: ['title', 'description', 'status', 'price'],
395
+ searchableFields: ['title', 'description'],
396
+ })
397
+ }
398
+
399
+ // Custom methods
400
+ async getByStatus(userId: string, status: string): Promise<Product[]> {
401
+ return this.query(userId, {
402
+ where: { status },
403
+ orderBy: 'createdAt'
404
+ })
405
+ }
406
+ }
407
+
408
+ // Usage
409
+ const service = new ProductsService()
410
+ const products = await service.list(userId, { search: 'laptop' })
411
+ ```
412
+
413
+ ## Service Categories
414
+
415
+ ### Data Access Services
416
+ Use `queryWithRLS` and `mutateWithRLS` for database operations:
417
+ - UserService, TeamService, CustomerService
418
+ - SubscriptionService, InvoiceService
419
+ - Always accept `userId` parameter
420
+
421
+ ### Registry Services
422
+ Query pre-generated registries (O(1) lookups):
423
+ - ThemeService, EntityTypeService
424
+ - NamespaceService, ScopeService
425
+ - Synchronous operations, no RLS needed
426
+
427
+ ```typescript
428
+ // Registry service example
429
+ export class ThemeService {
430
+ static getAll(): ThemeConfig[] {
431
+ return Object.values(THEME_REGISTRY)
432
+ }
433
+
434
+ static getByName(name: string): ThemeConfig | undefined {
435
+ return THEME_REGISTRY[name]
436
+ }
437
+ }
438
+ ```
439
+
440
+ ### Composite Services
441
+ Combine multiple services for complex operations:
442
+ - MembershipService (TeamMember + Subscription + Permissions)
443
+ - Returns rich objects with helper methods
444
+
445
+ ## Existing Services (24)
446
+
447
+ | Service | Category | Purpose |
448
+ |---------|----------|---------|
449
+ | `UserService` | Data | User management, profile |
450
+ | `TeamService` | Data | Team CRUD, slug management |
451
+ | `TeamMemberService` | Data | Membership, role management |
452
+ | `MetaService` | Data | Flexible entity metadata |
453
+ | `PermissionService` | Registry | O(1) permission checks |
454
+ | `MembershipService` | Composite | Complete membership context |
455
+ | `SubscriptionService` | Data | Subscription lifecycle |
456
+ | `PlanService` | Registry | Plan queries |
457
+ | `UsageService` | Data | Usage tracking, quotas |
458
+ | `InvoiceService` | Data | Invoice management |
459
+ | `ThemeService` | Registry | Theme configuration |
460
+ | `EntityTypeService` | Registry | Entity registry queries |
461
+ | `NamespaceService` | Registry | Route namespaces |
462
+ | `ScopeService` | Registry | API scopes |
463
+ | `MiddlewareService` | Registry | Middleware execution |
464
+ | `RouteHandlerService` | Registry | Route handlers |
465
+ | `PluginService` | Registry | Plugin configuration |
466
+ | `ApiRoutesService` | Registry | API route discovery |
467
+ | `BlockService` | Registry | Page builder blocks |
468
+ | `TemplateService` | Registry | Template management |
469
+ | `TranslationService` | Registry | I18n translations |
470
+ | `UserFlagsService` | Data | Feature flags |
471
+
472
+ ## Error Handling
473
+
474
+ ```typescript
475
+ static async getById(id: string, userId: string): Promise<Entity | null> {
476
+ // Input validation
477
+ if (!id || id.trim() === '') {
478
+ throw new Error('Entity ID is required')
479
+ }
480
+ if (!userId || userId.trim() === '') {
481
+ throw new Error('User ID is required for authentication')
482
+ }
483
+
484
+ try {
485
+ return await queryOneWithRLS<Entity>(
486
+ 'SELECT * FROM "entities" WHERE id = $1',
487
+ [id],
488
+ userId
489
+ )
490
+ } catch (error) {
491
+ console.error('EntityService.getById error:', error)
492
+ throw new Error(
493
+ error instanceof Error ? error.message : 'Failed to fetch entity'
494
+ )
495
+ }
496
+ }
497
+ ```
498
+
499
+ ## JSDoc Documentation
500
+
501
+ ```typescript
502
+ /**
503
+ * Get entity by ID
504
+ *
505
+ * @param id - Entity UUID
506
+ * @param userId - Current user ID for RLS context
507
+ * @returns Entity object or null if not found
508
+ * @throws Error if ID or userId is missing
509
+ *
510
+ * @example
511
+ * const customer = await CustomerService.getById('cust-123', userId)
512
+ * if (customer) {
513
+ * console.log(customer.name)
514
+ * }
515
+ */
516
+ static async getById(id: string, userId: string): Promise<Customer | null> {
517
+ // Implementation
518
+ }
519
+ ```
520
+
521
+ ## Anti-Patterns
522
+
523
+ ```typescript
524
+ // NEVER: Instance methods
525
+ class BadService {
526
+ async getById(id: string, userId: string) {} // Not static!
527
+ }
528
+ const service = new BadService() // Requires instantiation
529
+
530
+ // CORRECT: Static methods
531
+ class GoodService {
532
+ static async getById(id: string, userId: string) {}
533
+ }
534
+ GoodService.getById('id', userId) // No instantiation
535
+
536
+ // NEVER: Skip RLS
537
+ const customers = await query('SELECT * FROM customers') // No RLS!
538
+
539
+ // CORRECT: Use RLS functions
540
+ const customers = await queryWithRLS('SELECT * FROM customers', [], userId)
541
+
542
+ // NEVER: Build SQL with string interpolation
543
+ const query = `SELECT * FROM customers WHERE name = '${name}'` // SQL injection!
544
+
545
+ // CORRECT: Use parameterized queries
546
+ const query = 'SELECT * FROM customers WHERE name = $1'
547
+ await queryWithRLS(query, [name], userId)
548
+
549
+ // NEVER: Skip input validation
550
+ static async delete(id: string, userId: string) {
551
+ await mutateWithRLS('DELETE FROM customers WHERE id = $1', [id], userId)
552
+ }
553
+
554
+ // CORRECT: Validate inputs
555
+ static async delete(id: string, userId: string) {
556
+ if (!id?.trim()) throw new Error('ID is required')
557
+ if (!userId?.trim()) throw new Error('User ID is required')
558
+ await mutateWithRLS('DELETE FROM customers WHERE id = $1', [id], userId)
559
+ }
560
+
561
+ // NEVER: Forget to pass userId for RLS
562
+ await queryWithRLS(query, params) // Missing userId!
563
+
564
+ // CORRECT: Always pass userId
565
+ await queryWithRLS(query, params, userId)
566
+ ```
567
+
568
+ ## Checklist
569
+
570
+ Before finalizing service implementation:
571
+
572
+ - [ ] All methods are static
573
+ - [ ] Uses RLS functions (queryWithRLS, mutateWithRLS)
574
+ - [ ] userId parameter on all database operations
575
+ - [ ] Input validation at method start
576
+ - [ ] Parameterized queries (no string interpolation)
577
+ - [ ] Proper error handling with descriptive messages
578
+ - [ ] JSDoc documentation with @param, @returns, @example
579
+ - [ ] Transactions for multi-step operations
580
+ - [ ] Consistent method signatures
581
+
582
+ ## Related Skills
583
+
584
+ - `entity-system` - Entity definition patterns
585
+ - `entity-api` - API endpoint patterns
586
+ - `permissions-system` - Permission checking
587
+ - `database-migrations` - Migration patterns