@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,635 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: entity-system
|
|
3
|
+
description: |
|
|
4
|
+
Config-driven entity system for creating automatic CRUDs.
|
|
5
|
+
Includes: config, fields, types, service, messages (i18n), migrations.
|
|
6
|
+
Use this skill to create, modify, or understand system entities.
|
|
7
|
+
allowed-tools: Read, Glob, Grep, Bash(python:*)
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Entity System Skill
|
|
12
|
+
|
|
13
|
+
Config-driven system for defining entities with automatic CRUDs, similar to WordPress Custom Post Types.
|
|
14
|
+
|
|
15
|
+
## Architecture Overview
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
┌──────────────────────────────────────────────────────────────────────────┐
|
|
19
|
+
│ ENTITY CONFIGURATION │
|
|
20
|
+
│ │
|
|
21
|
+
│ contents/themes/{theme}/entities/{entity}/ │
|
|
22
|
+
│ ├── {entity}.config.ts ← Main configuration │
|
|
23
|
+
│ ├── {entity}.fields.ts ← Field definitions │
|
|
24
|
+
│ ├── {entity}.types.ts ← TypeScript types │
|
|
25
|
+
│ ├── {entity}.service.ts ← Optional but recommended │
|
|
26
|
+
│ ├── messages/ │
|
|
27
|
+
│ │ ├── en.json ← English translations │
|
|
28
|
+
│ │ ├── es.json ← Spanish translations │
|
|
29
|
+
│ │ └── {locale}.json ← Additional locales if project requires │
|
|
30
|
+
│ └── migrations/ │
|
|
31
|
+
│ ├── 001_{entity}_table.sql │
|
|
32
|
+
│ ├── 002_{entity}_metas.sql (if metadata enabled) │
|
|
33
|
+
│ └── sample_data.json ← Sample data for seeding │
|
|
34
|
+
└──────────────────────────────────────────────────────────────────────────┘
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
> **📍 Context-Aware Paths:** Entity configs go in `contents/themes/{theme}/entities/` in both contexts.
|
|
38
|
+
> Core entities are read-only in consumer projects.
|
|
39
|
+
> See `core-theme-responsibilities` skill for complete rules.
|
|
40
|
+
|
|
41
|
+
## When to Use This Skill
|
|
42
|
+
|
|
43
|
+
- Creating a new entity (CRUD resource)
|
|
44
|
+
- Adding/modifying fields on an entity
|
|
45
|
+
- Understanding entity configuration structure
|
|
46
|
+
- Generating migrations for entity tables
|
|
47
|
+
- Creating sample data for development
|
|
48
|
+
|
|
49
|
+
## Entity Configuration Structure
|
|
50
|
+
|
|
51
|
+
### EntityConfig (4 Sections)
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
interface EntityConfig {
|
|
55
|
+
// 1. BASIC IDENTIFICATION
|
|
56
|
+
slug: string // URL/table name (single source of truth)
|
|
57
|
+
enabled: boolean
|
|
58
|
+
names: { singular: string, plural: string }
|
|
59
|
+
icon: LucideIcon
|
|
60
|
+
|
|
61
|
+
// 2. ACCESS AND SCOPE
|
|
62
|
+
access: {
|
|
63
|
+
public: boolean // Accessible without auth
|
|
64
|
+
api: boolean // Has external API endpoints
|
|
65
|
+
metadata: boolean // Supports key-value metadata
|
|
66
|
+
shared: boolean // Shared among team members (no userId filter)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 3. UI/UX FEATURES
|
|
70
|
+
ui: {
|
|
71
|
+
dashboard: {
|
|
72
|
+
showInMenu: boolean
|
|
73
|
+
showInTopbar: boolean
|
|
74
|
+
filters?: EntityFilterConfig[]
|
|
75
|
+
}
|
|
76
|
+
public: {
|
|
77
|
+
hasArchivePage: boolean
|
|
78
|
+
hasSinglePage: boolean
|
|
79
|
+
}
|
|
80
|
+
features: {
|
|
81
|
+
searchable: boolean
|
|
82
|
+
sortable: boolean
|
|
83
|
+
filterable: boolean
|
|
84
|
+
bulkOperations: boolean
|
|
85
|
+
importExport: boolean
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 4. INTERNATIONALIZATION
|
|
90
|
+
i18n: {
|
|
91
|
+
fallbackLocale: 'en' | 'es'
|
|
92
|
+
loaders: Record<'en' | 'es', () => Promise<object>>
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// FIELDS (imported separately)
|
|
96
|
+
fields: EntityField[]
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
> **Note:** Permissions are defined centrally in `config/permissions.config.ts`, not in entity config.
|
|
101
|
+
|
|
102
|
+
### Field Types
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
type EntityFieldType =
|
|
106
|
+
// Basic
|
|
107
|
+
| 'text' | 'textarea' | 'number' | 'boolean' | 'date' | 'datetime'
|
|
108
|
+
| 'email' | 'url' | 'json'
|
|
109
|
+
|
|
110
|
+
// Selection
|
|
111
|
+
| 'select' | 'multiselect' | 'radio' | 'buttongroup' | 'tags' | 'combobox'
|
|
112
|
+
|
|
113
|
+
// Media
|
|
114
|
+
| 'file' | 'image' | 'video' | 'audio'
|
|
115
|
+
|
|
116
|
+
// Specialized
|
|
117
|
+
| 'phone' | 'rating' | 'range' | 'doublerange'
|
|
118
|
+
| 'markdown' | 'richtext' | 'code'
|
|
119
|
+
| 'timezone' | 'currency' | 'country' | 'address'
|
|
120
|
+
|
|
121
|
+
// Relations
|
|
122
|
+
| 'relation' | 'relation-multi' | 'relation-prop' | 'relation-prop-multi'
|
|
123
|
+
| 'reference' | 'user'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Field Definition
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
interface EntityField {
|
|
130
|
+
name: string
|
|
131
|
+
type: EntityFieldType
|
|
132
|
+
required: boolean
|
|
133
|
+
defaultValue?: unknown
|
|
134
|
+
validation?: ZodSchema
|
|
135
|
+
|
|
136
|
+
display: {
|
|
137
|
+
label: string
|
|
138
|
+
description?: string
|
|
139
|
+
placeholder?: string
|
|
140
|
+
showInList: boolean
|
|
141
|
+
showInDetail: boolean
|
|
142
|
+
showInForm: boolean
|
|
143
|
+
order: number
|
|
144
|
+
columnWidth?: number // 1-12 grid
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
api: {
|
|
148
|
+
searchable: boolean
|
|
149
|
+
sortable: boolean
|
|
150
|
+
filterable?: boolean
|
|
151
|
+
readOnly: boolean
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// For select/multiselect
|
|
155
|
+
options?: { value: string, label: string }[]
|
|
156
|
+
|
|
157
|
+
// For relations
|
|
158
|
+
relation?: {
|
|
159
|
+
entity: string
|
|
160
|
+
titleField?: string
|
|
161
|
+
parentId?: string
|
|
162
|
+
userFiltered?: boolean
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Auto-Generated Features
|
|
168
|
+
|
|
169
|
+
From an EntityConfig, the system automatically provides:
|
|
170
|
+
|
|
171
|
+
1. **Database Table** - Via migrations
|
|
172
|
+
2. **API Endpoints** - `/api/v1/{slug}` with CRUD operations
|
|
173
|
+
3. **Dashboard UI** - List, create, edit, delete views
|
|
174
|
+
4. **Form Components** - Auto-generated from fields
|
|
175
|
+
5. **Validation** - Server and client-side from field config
|
|
176
|
+
6. **i18n Support** - Labels, placeholders, messages
|
|
177
|
+
7. **Search & Filtering** - Based on field API config
|
|
178
|
+
8. **Metadata System** - Key-value pairs (if enabled)
|
|
179
|
+
9. **Server Actions** - Direct CRUD from Client Components
|
|
180
|
+
|
|
181
|
+
## Server Actions (Client Component CRUD)
|
|
182
|
+
|
|
183
|
+
Server Actions permiten ejecutar operaciones CRUD desde Client Components sin pasar por HTTP.
|
|
184
|
+
|
|
185
|
+
### Server Actions Architecture
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
189
|
+
│ SERVER ACTIONS FLOW │
|
|
190
|
+
│ │
|
|
191
|
+
│ Client Component Server Action GenericEntityService
|
|
192
|
+
│ ───────────────── ───────────── ────────────────────
|
|
193
|
+
│ │ │ │
|
|
194
|
+
│ │ createEntity(slug,data) │ │
|
|
195
|
+
│ │ ─────────────────────► │ │
|
|
196
|
+
│ │ │ │
|
|
197
|
+
│ │ ┌─────┴─────┐ │
|
|
198
|
+
│ │ │ 1. Auth │ │
|
|
199
|
+
│ │ │ (session) │ │
|
|
200
|
+
│ │ ├───────────┤ │
|
|
201
|
+
│ │ │ 2. Perms │ │
|
|
202
|
+
│ │ │ (registry)│ │
|
|
203
|
+
│ │ └─────┬─────┘ │
|
|
204
|
+
│ │ │ │
|
|
205
|
+
│ │ │ create(slug,uid,tid,data)
|
|
206
|
+
│ │ │ ─────────────────────► │
|
|
207
|
+
│ │ │ ┌────┴────┐
|
|
208
|
+
│ │ │ │ Validate│
|
|
209
|
+
│ │ │ │ Hooks │
|
|
210
|
+
│ │ │ │ SQL+RLS │
|
|
211
|
+
│ │ │ └────┬────┘
|
|
212
|
+
│ │ │ ◄───────────────────── │
|
|
213
|
+
│ │ ◄───────────────────── │ │
|
|
214
|
+
│ │ EntityActionResult │ │
|
|
215
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Server Actions vs API HTTP
|
|
219
|
+
|
|
220
|
+
| Escenario | Server Actions | API HTTP |
|
|
221
|
+
|-----------|----------------|----------|
|
|
222
|
+
| Client Component mutations | Recommended | No |
|
|
223
|
+
| Server Component data fetching | No | Yes |
|
|
224
|
+
| External integrations | No | Yes |
|
|
225
|
+
| Webhooks | No | Yes |
|
|
226
|
+
| Cache revalidation automática | Yes | Manual |
|
|
227
|
+
|
|
228
|
+
### Available Functions
|
|
229
|
+
|
|
230
|
+
| Function | Required Permission | Description |
|
|
231
|
+
|----------|---------------------|-------------|
|
|
232
|
+
| `createEntity(slug, data, config?)` | `{slug}.create` | Create entity |
|
|
233
|
+
| `updateEntity(slug, id, data, config?)` | `{slug}.update` | Update entity |
|
|
234
|
+
| `deleteEntity(slug, id, config?)` | `{slug}.delete` | Delete one |
|
|
235
|
+
| `deleteEntities(slug, ids, config?)` | `{slug}.delete` | Delete many |
|
|
236
|
+
| `getEntity(slug, id)` | `{slug}.read` | Get by ID |
|
|
237
|
+
| `listEntities(slug, options?)` | `{slug}.list` | List with filters |
|
|
238
|
+
| `entityExists(slug, id)` | `{slug}.read` | Check existence |
|
|
239
|
+
| `countEntities(slug, where?)` | `{slug}.list` | Count records |
|
|
240
|
+
|
|
241
|
+
### Usage Example
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
'use client'
|
|
245
|
+
|
|
246
|
+
import { createEntity, updateEntity, deleteEntity } from '@nextsparkjs/core/actions'
|
|
247
|
+
|
|
248
|
+
// CREATE - Auth and permissions verified automatically
|
|
249
|
+
async function handleCreate(data: FormData) {
|
|
250
|
+
const result = await createEntity('schools', {
|
|
251
|
+
name: data.get('name'),
|
|
252
|
+
status: 'active'
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
if (result.success) {
|
|
256
|
+
console.log('Created:', result.data)
|
|
257
|
+
} else {
|
|
258
|
+
console.error('Error:', result.error)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// UPDATE with custom revalidation
|
|
263
|
+
async function handleUpdate(id: string, data: Partial<School>) {
|
|
264
|
+
const result = await updateEntity('schools', id, data, {
|
|
265
|
+
revalidatePaths: ['/dashboard/overview'],
|
|
266
|
+
revalidateTags: ['school-stats'],
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// DELETE with redirect
|
|
271
|
+
async function handleDelete(id: string) {
|
|
272
|
+
await deleteEntity('schools', id, {
|
|
273
|
+
redirectTo: '/dashboard/schools'
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Return Types
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
// For operations that return data
|
|
282
|
+
type EntityActionResult<T> =
|
|
283
|
+
| { success: true; data: T }
|
|
284
|
+
| { success: false; error: string }
|
|
285
|
+
|
|
286
|
+
// For void operations (delete)
|
|
287
|
+
type EntityActionVoidResult =
|
|
288
|
+
| { success: true }
|
|
289
|
+
| { success: false; error: string }
|
|
290
|
+
|
|
291
|
+
// List result
|
|
292
|
+
interface ListEntityResult<T> {
|
|
293
|
+
data: T[]
|
|
294
|
+
total: number
|
|
295
|
+
limit: number
|
|
296
|
+
offset: number
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Action Configuration
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
interface ActionConfig {
|
|
304
|
+
revalidatePaths?: string[] // Paths to revalidate
|
|
305
|
+
revalidateTags?: string[] // Cache tags
|
|
306
|
+
redirectTo?: string // Redirect after action
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Automatic Security
|
|
311
|
+
|
|
312
|
+
1. **Auth**: userId from `getTypedSession()` (server-side)
|
|
313
|
+
2. **Team**: teamId from httpOnly cookie `activeTeamId`
|
|
314
|
+
3. **Permissions**: Verified against `permissions.config.ts`
|
|
315
|
+
4. **Validation**: Fields validated against entity schema
|
|
316
|
+
5. **RLS**: Queries executed with Row-Level Security
|
|
317
|
+
6. **Team Isolation**: All operations filter by active teamId (prevents cross-team access for multi-team users)
|
|
318
|
+
|
|
319
|
+
### Team Isolation (Multi-Team Users)
|
|
320
|
+
|
|
321
|
+
Users can belong to multiple teams. Server Actions automatically filter by the active team cookie to prevent accidental cross-team data access:
|
|
322
|
+
|
|
323
|
+
```
|
|
324
|
+
User belongs to: TeamA, TeamB
|
|
325
|
+
Active team cookie: TeamA
|
|
326
|
+
|
|
327
|
+
getEntity('campaigns', 'id-from-teamB') → Returns null (filtered out)
|
|
328
|
+
updateEntity('campaigns', 'id-from-teamB', data) → Error: not found
|
|
329
|
+
deleteEntity('campaigns', 'id-from-teamB') → Error: not found
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
This isolation is automatic and cannot be bypassed from client code.
|
|
333
|
+
|
|
334
|
+
### Server Actions Anti-Patterns
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
// NEVER: Ignore the result
|
|
338
|
+
await createEntity('schools', data) // Without checking success
|
|
339
|
+
|
|
340
|
+
// CORRECT: Always check result
|
|
341
|
+
const result = await createEntity('schools', data)
|
|
342
|
+
if (!result.success) {
|
|
343
|
+
toast.error(result.error)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// NEVER: Use for Server Components (no 'use client')
|
|
347
|
+
// Server Actions are for CLIENT Components only
|
|
348
|
+
|
|
349
|
+
// CORRECT: In Server Components use service directly
|
|
350
|
+
import { GenericEntityService } from '@nextsparkjs/core/services'
|
|
351
|
+
const data = await GenericEntityService.list('schools', userId, { teamId })
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### List Entities Example
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
'use client'
|
|
358
|
+
|
|
359
|
+
import { listEntities } from '@nextsparkjs/core/actions'
|
|
360
|
+
|
|
361
|
+
async function loadCampaigns() {
|
|
362
|
+
const result = await listEntities<Campaign>('campaigns', {
|
|
363
|
+
where: { status: 'active' },
|
|
364
|
+
orderBy: 'createdAt',
|
|
365
|
+
orderDir: 'desc',
|
|
366
|
+
limit: 20,
|
|
367
|
+
offset: 0,
|
|
368
|
+
search: 'marketing', // Full-text search on searchable fields
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
if (result.success) {
|
|
372
|
+
const { data, total, limit, offset } = result.data
|
|
373
|
+
console.log(`Showing ${data.length} of ${total} campaigns`)
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Server Actions Files
|
|
379
|
+
|
|
380
|
+
| File | Purpose |
|
|
381
|
+
|------|---------|
|
|
382
|
+
| `core/lib/actions/entity.actions.ts` | Server Actions (entry points) |
|
|
383
|
+
| `core/lib/actions/types.ts` | TypeScript types |
|
|
384
|
+
| `core/lib/services/generic-entity.service.ts` | Business logic |
|
|
385
|
+
| `core/lib/permissions/check.ts` | Permission verification |
|
|
386
|
+
|
|
387
|
+
## Metadata System
|
|
388
|
+
|
|
389
|
+
When `access.metadata: true` is set in the entity config, the entity supports dynamic key-value metadata.
|
|
390
|
+
|
|
391
|
+
### Migration Required
|
|
392
|
+
|
|
393
|
+
A separate migration creates the `{entity}_metas` table:
|
|
394
|
+
|
|
395
|
+
```sql
|
|
396
|
+
-- migrations/002_{entity}_metas.sql
|
|
397
|
+
CREATE TABLE IF NOT EXISTS "{entity}_metas" (
|
|
398
|
+
"id" TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
399
|
+
"{entity}Id" TEXT NOT NULL REFERENCES "{entity}"(id) ON DELETE CASCADE,
|
|
400
|
+
"metaKey" TEXT NOT NULL,
|
|
401
|
+
"metaValue" JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
402
|
+
"dataType" TEXT, -- Optional: string, number, boolean, json
|
|
403
|
+
"isPublic" BOOLEAN NOT NULL DEFAULT FALSE, -- Visible without auth
|
|
404
|
+
"isSearchable" BOOLEAN NOT NULL DEFAULT FALSE, -- Indexed for search
|
|
405
|
+
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
406
|
+
"updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
407
|
+
CONSTRAINT {entity}_metas_unique_key UNIQUE ("{entity}Id", "metaKey")
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
-- Indexes
|
|
411
|
+
CREATE INDEX "idx_{entity}_metas_entity_id" ON "{entity}_metas"("{entity}Id");
|
|
412
|
+
CREATE INDEX "idx_{entity}_metas_key" ON "{entity}_metas"("metaKey");
|
|
413
|
+
CREATE INDEX "idx_{entity}_metas_value_gin" ON "{entity}_metas" USING GIN ("metaValue");
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### When to Use Metas vs Fields
|
|
417
|
+
|
|
418
|
+
| Use Case | Fields | Metas |
|
|
419
|
+
|----------|--------|-------|
|
|
420
|
+
| Structured, validated data | ✅ | ❌ |
|
|
421
|
+
| Shown in forms/lists | ✅ | ❌ |
|
|
422
|
+
| Searchable/sortable | ✅ | ❌ |
|
|
423
|
+
| Dynamic/extensible data | ❌ | ✅ |
|
|
424
|
+
| Plugin-specific data | ❌ | ✅ |
|
|
425
|
+
| User preferences/settings | ❌ | ✅ |
|
|
426
|
+
| Third-party integrations | ❌ | ✅ |
|
|
427
|
+
|
|
428
|
+
### API Access
|
|
429
|
+
|
|
430
|
+
Metas are accessed via query parameter (covered in `entity-api` skill):
|
|
431
|
+
```
|
|
432
|
+
GET /api/v1/products/123?metas=all
|
|
433
|
+
GET /api/v1/products/123?metas=category,tags
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
## Child Entities
|
|
437
|
+
|
|
438
|
+
Child entities are 1:N relationships where the child only exists in the context of its parent (e.g., order items, post comments).
|
|
439
|
+
|
|
440
|
+
### Configuration in EntityConfig
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
export const orderEntityConfig: EntityConfig = {
|
|
444
|
+
slug: 'orders',
|
|
445
|
+
// ... other config
|
|
446
|
+
|
|
447
|
+
childEntities: {
|
|
448
|
+
'items': {
|
|
449
|
+
table: 'order_items', // Convention: {parent}_{child}
|
|
450
|
+
showInParentView: true, // Show in parent detail view
|
|
451
|
+
hasOwnRoutes: false, // Only via /orders/{id}/child/items
|
|
452
|
+
|
|
453
|
+
fields: [
|
|
454
|
+
{
|
|
455
|
+
name: 'productName',
|
|
456
|
+
type: 'text',
|
|
457
|
+
required: true,
|
|
458
|
+
display: { label: 'Product' }
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
name: 'quantity',
|
|
462
|
+
type: 'number',
|
|
463
|
+
required: true,
|
|
464
|
+
display: { label: 'Qty' }
|
|
465
|
+
}
|
|
466
|
+
],
|
|
467
|
+
|
|
468
|
+
display: {
|
|
469
|
+
title: 'Order Items',
|
|
470
|
+
description: 'Products in this order',
|
|
471
|
+
mode: 'table' // 'table' | 'cards' | 'list'
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### ChildEntityDefinition Interface
|
|
479
|
+
|
|
480
|
+
```typescript
|
|
481
|
+
interface ChildEntityDefinition {
|
|
482
|
+
table: string // Database table name
|
|
483
|
+
fields: ChildEntityField[] // Child entity fields
|
|
484
|
+
showInParentView: boolean // Show in parent view
|
|
485
|
+
hasOwnRoutes: boolean // Has independent routes?
|
|
486
|
+
// Note: Permissions are defined centrally in permissions.config.ts
|
|
487
|
+
display: {
|
|
488
|
+
title: string
|
|
489
|
+
description?: string
|
|
490
|
+
mode: 'table' | 'cards' | 'list'
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### Migration Required
|
|
496
|
+
|
|
497
|
+
```sql
|
|
498
|
+
-- migrations/002_{parent}_{child}.sql
|
|
499
|
+
CREATE TABLE "order_items" (
|
|
500
|
+
"id" TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
501
|
+
"parentId" TEXT NOT NULL REFERENCES "orders"(id) ON DELETE CASCADE,
|
|
502
|
+
"productName" VARCHAR(255) NOT NULL,
|
|
503
|
+
"quantity" INTEGER NOT NULL,
|
|
504
|
+
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
505
|
+
"updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
506
|
+
);
|
|
507
|
+
|
|
508
|
+
CREATE INDEX "idx_order_items_parentId" ON "order_items"("parentId");
|
|
509
|
+
|
|
510
|
+
-- RLS: Access via parent ownership
|
|
511
|
+
ALTER TABLE "order_items" ENABLE ROW LEVEL SECURITY;
|
|
512
|
+
|
|
513
|
+
CREATE POLICY "order_items_via_parent" ON "order_items"
|
|
514
|
+
FOR ALL TO authenticated
|
|
515
|
+
USING (
|
|
516
|
+
EXISTS (
|
|
517
|
+
SELECT 1 FROM "orders"
|
|
518
|
+
WHERE "orders".id = "parentId"
|
|
519
|
+
AND "orders"."userId" = public.get_auth_user_id()
|
|
520
|
+
)
|
|
521
|
+
);
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
### Key Properties
|
|
525
|
+
|
|
526
|
+
| Property | Required | Description |
|
|
527
|
+
|----------|----------|-------------|
|
|
528
|
+
| `table` | Yes | Table name. Convention: `{parent}_{child}` |
|
|
529
|
+
| `fields` | Yes | Child entity fields (same structure as entity fields) |
|
|
530
|
+
| `showInParentView` | Yes | Display in parent detail view |
|
|
531
|
+
| `hasOwnRoutes` | Yes | If `true`: also `/api/v1/{child}`. If `false`: only via parent |
|
|
532
|
+
| `display.mode` | Yes | `table` (rows), `cards` (cards), `list` (simple) |
|
|
533
|
+
|
|
534
|
+
### Limitations
|
|
535
|
+
|
|
536
|
+
- **One level deep**: Child entities cannot have their own children
|
|
537
|
+
- **Cascade deletion**: Deleting parent deletes all children
|
|
538
|
+
- **No public routes**: Children don't have public pages
|
|
539
|
+
|
|
540
|
+
### API Access
|
|
541
|
+
|
|
542
|
+
Child entity endpoints (covered in `entity-api` skill):
|
|
543
|
+
```
|
|
544
|
+
GET /api/v1/orders/{id}/child/items
|
|
545
|
+
POST /api/v1/orders/{id}/child/items
|
|
546
|
+
GET /api/v1/orders/{id}/child/items/{itemId}
|
|
547
|
+
PATCH /api/v1/orders/{id}/child/items/{itemId}
|
|
548
|
+
DELETE /api/v1/orders/{id}/child/items/{itemId}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
## Scripts
|
|
552
|
+
|
|
553
|
+
### Scaffold New Entity
|
|
554
|
+
```bash
|
|
555
|
+
python .claude/skills/entity-system/scripts/scaffold-entity.py --entity products --theme default
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### Generate Migration
|
|
559
|
+
```bash
|
|
560
|
+
python .claude/skills/entity-system/scripts/generate-migration.py --entity products --theme default
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### Generate Metas Migration
|
|
564
|
+
```bash
|
|
565
|
+
python .claude/skills/entity-system/scripts/generate-metas-migration.py --entity products --theme default
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Generate Child Entity Migration
|
|
569
|
+
```bash
|
|
570
|
+
python .claude/skills/entity-system/scripts/generate-child-migration.py --parent orders --child items --theme default
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
### Generate Sample Data
|
|
574
|
+
```bash
|
|
575
|
+
python .claude/skills/entity-system/scripts/generate-sample-data.py --entity products --count 10
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
## Key Files Reference
|
|
579
|
+
|
|
580
|
+
| File | Purpose |
|
|
581
|
+
|------|---------|
|
|
582
|
+
| `core/lib/entities/types.ts` | All entity type definitions |
|
|
583
|
+
| `core/lib/entities/migration-helper.ts` | Migration SQL generation |
|
|
584
|
+
| `core/lib/entities/registry.ts` | Entity registry (auto-generated) |
|
|
585
|
+
| `core/lib/entities/queries.ts` | Database query helpers |
|
|
586
|
+
| `core/lib/entities/helpers.ts` | Utility functions |
|
|
587
|
+
|
|
588
|
+
## Naming Conventions
|
|
589
|
+
|
|
590
|
+
- **Slug**: kebab-case, plural (`tasks`, `blog-posts`)
|
|
591
|
+
- **Table**: Same as slug (`tasks`, `blog_posts`)
|
|
592
|
+
- **API Path**: `/api/v1/{slug}`
|
|
593
|
+
- **Config file**: `{singular}.config.ts` (`task.config.ts`)
|
|
594
|
+
- **Fields file**: `{slug}.fields.ts` (`tasks.fields.ts`)
|
|
595
|
+
|
|
596
|
+
## Anti-Patterns
|
|
597
|
+
|
|
598
|
+
```typescript
|
|
599
|
+
// ❌ NEVER: Add system fields manually
|
|
600
|
+
fields: [
|
|
601
|
+
{ name: 'id', type: 'text', ... }, // Auto-included
|
|
602
|
+
{ name: 'teamId', type: 'text', ... }, // Auto-included (team-mode entities)
|
|
603
|
+
{ name: 'createdAt', type: 'datetime' }, // Auto-included
|
|
604
|
+
{ name: 'updatedAt', type: 'datetime' }, // Auto-included
|
|
605
|
+
]
|
|
606
|
+
|
|
607
|
+
// ❌ NEVER: Use dynamic imports for entity configs
|
|
608
|
+
const config = await import(`@/contents/entities/${slug}`)
|
|
609
|
+
|
|
610
|
+
// ❌ NEVER: Define tableName explicitly (derived from slug)
|
|
611
|
+
tableName: 'my_custom_table'
|
|
612
|
+
|
|
613
|
+
// ✅ CORRECT: Only declare business fields
|
|
614
|
+
fields: [
|
|
615
|
+
{ name: 'title', type: 'text', ... },
|
|
616
|
+
{ name: 'status', type: 'select', ... },
|
|
617
|
+
]
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
## Checklist for New Entity
|
|
621
|
+
|
|
622
|
+
- [ ] Created `{entity}.config.ts` with all 5 sections
|
|
623
|
+
- [ ] Created `{entity}.fields.ts` with field definitions
|
|
624
|
+
- [ ] Created `{entity}.types.ts` with TypeScript interfaces
|
|
625
|
+
- [ ] Created `messages/` with required locales (en.json, es.json, + others if project defines)
|
|
626
|
+
- [ ] Created migration in `migrations/001_{entity}_table.sql`
|
|
627
|
+
- [ ] Created `_metas` migration if `access.metadata: true`
|
|
628
|
+
- [ ] Added entity to theme's entity registry
|
|
629
|
+
- [ ] Ran `node core/scripts/build/registry.mjs`
|
|
630
|
+
|
|
631
|
+
## References
|
|
632
|
+
|
|
633
|
+
- Load `references/entity-types.md` for complete type definitions
|
|
634
|
+
- Load `references/field-examples.md` for field configuration examples
|
|
635
|
+
- Load `references/migration-patterns.md` for SQL patterns
|