@nebulit/embuilder 0.1.39
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/README.md +254 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +138 -0
- package/package.json +49 -0
- package/templates/.claude/hooks/QUICKSTART.md +256 -0
- package/templates/.claude/hooks/README.md +533 -0
- package/templates/.claude/hooks/analyze-commit.sh +22 -0
- package/templates/.claude/hooks/analyze-commit.ts +518 -0
- package/templates/.claude/hooks/analyzers/README.md +198 -0
- package/templates/.claude/hooks/analyzers/code-quality-checker.ts +154 -0
- package/templates/.claude/hooks/analyzers/code-quality.md +54 -0
- package/templates/.claude/hooks/analyzers/commit-blocker-example.ts.disabled +110 -0
- package/templates/.claude/hooks/analyzers/commit-policy.md +49 -0
- package/templates/.claude/hooks/analyzers/event-model-validator.md +49 -0
- package/templates/.claude/hooks/analyzers/event-model-validator.ts +169 -0
- package/templates/.claude/hooks/analyzers/example-logger.ts +70 -0
- package/templates/.claude/hooks/analyzers/slice-scope-validator.md +81 -0
- package/templates/.claude/hooks/check-review-result.sh +47 -0
- package/templates/.claude/hooks/prepare-review.sh +34 -0
- package/templates/.claude/hooks/review-agent-prompt.md +42 -0
- package/templates/.claude/hooks/run-review-agent.sh +124 -0
- package/templates/.claude/settings.local.json +37 -0
- package/templates/.claude/skills/help/README.md +84 -0
- package/templates/.claude/skills/help/SKILL.md +393 -0
- package/templates/.claude/skills/help/templates/demo-config.json +6753 -0
- package/templates/.claude/skills/sample-slices/SKILL.md +8 -0
- package/templates/.claude/skills/sample-slices/templates/.slices/Library/addbook/code-slice.json +124 -0
- package/templates/.claude/skills/sample-slices/templates/.slices/Library/addbook/slice.json +255 -0
- package/templates/.claude/skills/sample-slices/templates/.slices/Library/availablebooks/slice.json +107 -0
- package/templates/.claude/skills/sample-slices/templates/.slices/index.json +20 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/additem/slice.json +979 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/archiveitem/slice.json +529 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/cartitems/slice.json +1072 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/cartwithproducts/slice.json +394 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/changedprices/slice.json +88 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/changeinventory/slice.json +264 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/changeprice/slice.json +308 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/clearcart/slice.json +358 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/inventories/slice.json +203 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/publishcart/slice.json +876 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/removeitem/slice.json +560 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/submitcart/slice.json +708 -0
- package/templates/.claude/skills/sample-slices/templates/Cart/submittedcartdata/slice.json +399 -0
- package/templates/.claude/skills/sample-slices/templates/index.json +108 -0
- package/templates/.claude/skills/slice-automation/SKILL.md +49 -0
- package/templates/.claude/skills/slice-state-change/SKILL.md +369 -0
- package/templates/.claude/skills/slice-state-change/templates/AddLocation/AddLocation.test.ts.sample +76 -0
- package/templates/.claude/skills/slice-state-change/templates/AddLocation/AddLocationCommand.ts.sample +84 -0
- package/templates/.claude/skills/slice-state-change/templates/AddLocation/routes.ts.sample +73 -0
- package/templates/.claude/skills/slice-state-change/templates/README.md +46 -0
- package/templates/.claude/skills/slice-state-view/SKILL.md +336 -0
- package/templates/.claude/skills/slice-state-view/templates/Locations/Locations.test.ts.sample +84 -0
- package/templates/.claude/skills/slice-state-view/templates/Locations/LocationsProjection.ts.sample +50 -0
- package/templates/.claude/skills/slice-state-view/templates/Locations/routes.ts.sample +46 -0
- package/templates/.claude/skills/slice-state-view/templates/README.md +109 -0
- package/templates/.claude/skills/slice-state-view/templates/Tables/Tables.test.ts.sample +104 -0
- package/templates/.claude/skills/slice-state-view/templates/Tables/TablesProjection.ts.sample +59 -0
- package/templates/.claude/skills/slice-state-view/templates/Tables/routes.ts.sample +46 -0
- package/templates/.claude/skills/slice-state-view/templates/V2__tables.sql +7 -0
- package/templates/.claude/skills/slice-state-view/templates/V8__locations.sql +7 -0
- package/templates/.claude/skills/test-analyzer/SKILL.md +373 -0
- package/templates/.claude/skills/test-analyzer/examples/specification-format.md +143 -0
- package/templates/.claude/skills/test-analyzer/examples/state-change-example.md +111 -0
- package/templates/.claude/skills/test-analyzer/examples/state-view-example.md +122 -0
- package/templates/AGENTS.md +110 -0
- package/templates/Claude.md +58 -0
- package/templates/README.md +178 -0
- package/templates/backend/.env +9 -0
- package/templates/backend/BACKEND_AUTH_SETUP.md +183 -0
- package/templates/backend/SWAGGER.md +213 -0
- package/templates/backend/eslint.config.mjs +31 -0
- package/templates/backend/flyway.conf +17 -0
- package/templates/backend/package.json +44 -0
- package/templates/backend/prd.json.example +64 -0
- package/templates/backend/public/assets/images/banner.png +0 -0
- package/templates/backend/public/assets/logo.png +0 -0
- package/templates/backend/public/file.svg +4 -0
- package/templates/backend/public/globe.svg +12 -0
- package/templates/backend/public/next.svg +6 -0
- package/templates/backend/public/vercel.svg +3 -0
- package/templates/backend/public/window.svg +5 -0
- package/templates/backend/server.ts +129 -0
- package/templates/backend/setup-env.sh +50 -0
- package/templates/backend/src/common/assertions.ts +6 -0
- package/templates/backend/src/common/db.ts +1 -0
- package/templates/backend/src/common/loadPostgresEventstore.ts +16 -0
- package/templates/backend/src/common/parseEndpoint.ts +51 -0
- package/templates/backend/src/common/replay.ts +9 -0
- package/templates/backend/src/common/routes.ts +19 -0
- package/templates/backend/src/common/testHelpers.ts +53 -0
- package/templates/backend/src/core/readmodel.ts +28 -0
- package/templates/backend/src/core/types.ts +26 -0
- package/templates/backend/src/process/process.ts +53 -0
- package/templates/backend/src/supabase/LoginHandler.ts +36 -0
- package/templates/backend/src/supabase/ProtectedPageProps.ts +21 -0
- package/templates/backend/src/supabase/README.md +171 -0
- package/templates/backend/src/supabase/api.ts +63 -0
- package/templates/backend/src/supabase/authMiddleware.ts +53 -0
- package/templates/backend/src/supabase/component.ts +12 -0
- package/templates/backend/src/supabase/requireUser.ts +72 -0
- package/templates/backend/src/supabase/serverProps.ts +25 -0
- package/templates/backend/src/supabase/staticProps.ts +10 -0
- package/templates/backend/src/swagger.ts +34 -0
- package/templates/backend/src/util/assertions.ts +6 -0
- package/templates/backend/supabase/config.toml +295 -0
- package/templates/backend/supabase/migrations/20260121155918593_catalogentries.sql.sample +23 -0
- package/templates/backend/supabase/seed.sql +1 -0
- package/templates/backend/tsconfig.json +31 -0
- package/templates/frontend/.env.development +3 -0
- package/templates/frontend/AGENTS.md +7 -0
- package/templates/frontend/README.md +73 -0
- package/templates/frontend/components.json +20 -0
- package/templates/frontend/eslint.config.js +26 -0
- package/templates/frontend/index.html +18 -0
- package/templates/frontend/package-lock.json +8347 -0
- package/templates/frontend/package.json +94 -0
- package/templates/frontend/postcss.config.js +6 -0
- package/templates/frontend/public/favicon.ico +0 -0
- package/templates/frontend/public/logo.png +0 -0
- package/templates/frontend/public/placeholder.svg +1 -0
- package/templates/frontend/public/robots.txt +14 -0
- package/templates/frontend/src/App.css +42 -0
- package/templates/frontend/src/App.tsx +47 -0
- package/templates/frontend/src/components/NavLink.tsx +28 -0
- package/templates/frontend/src/components/ProtectedRoute.tsx +24 -0
- package/templates/frontend/src/components/calendar/Calendar.tsx +302 -0
- package/templates/frontend/src/components/layout/DashboardLayout.tsx +21 -0
- package/templates/frontend/src/components/layout/Header.tsx +45 -0
- package/templates/frontend/src/components/layout/Sidebar.tsx +82 -0
- package/templates/frontend/src/components/tables/ReservationTemplates.tsx +189 -0
- package/templates/frontend/src/components/ui/accordion.tsx +52 -0
- package/templates/frontend/src/components/ui/alert-dialog.tsx +104 -0
- package/templates/frontend/src/components/ui/alert.tsx +43 -0
- package/templates/frontend/src/components/ui/aspect-ratio.tsx +5 -0
- package/templates/frontend/src/components/ui/avatar.tsx +38 -0
- package/templates/frontend/src/components/ui/badge.tsx +29 -0
- package/templates/frontend/src/components/ui/breadcrumb.tsx +90 -0
- package/templates/frontend/src/components/ui/button.tsx +47 -0
- package/templates/frontend/src/components/ui/calendar.tsx +54 -0
- package/templates/frontend/src/components/ui/card.tsx +43 -0
- package/templates/frontend/src/components/ui/carousel.tsx +224 -0
- package/templates/frontend/src/components/ui/chart.tsx +303 -0
- package/templates/frontend/src/components/ui/checkbox.tsx +26 -0
- package/templates/frontend/src/components/ui/collapsible.tsx +9 -0
- package/templates/frontend/src/components/ui/command.tsx +132 -0
- package/templates/frontend/src/components/ui/context-menu.tsx +178 -0
- package/templates/frontend/src/components/ui/dialog.tsx +95 -0
- package/templates/frontend/src/components/ui/drawer.tsx +87 -0
- package/templates/frontend/src/components/ui/dropdown-menu.tsx +179 -0
- package/templates/frontend/src/components/ui/form.tsx +129 -0
- package/templates/frontend/src/components/ui/hover-card.tsx +27 -0
- package/templates/frontend/src/components/ui/input-otp.tsx +61 -0
- package/templates/frontend/src/components/ui/input.tsx +22 -0
- package/templates/frontend/src/components/ui/label.tsx +17 -0
- package/templates/frontend/src/components/ui/menubar.tsx +207 -0
- package/templates/frontend/src/components/ui/navigation-menu.tsx +120 -0
- package/templates/frontend/src/components/ui/pagination.tsx +81 -0
- package/templates/frontend/src/components/ui/popover.tsx +29 -0
- package/templates/frontend/src/components/ui/progress.tsx +23 -0
- package/templates/frontend/src/components/ui/radio-group.tsx +36 -0
- package/templates/frontend/src/components/ui/resizable.tsx +37 -0
- package/templates/frontend/src/components/ui/scroll-area.tsx +38 -0
- package/templates/frontend/src/components/ui/select.tsx +143 -0
- package/templates/frontend/src/components/ui/separator.tsx +20 -0
- package/templates/frontend/src/components/ui/sheet.tsx +107 -0
- package/templates/frontend/src/components/ui/sidebar.tsx +637 -0
- package/templates/frontend/src/components/ui/skeleton.tsx +7 -0
- package/templates/frontend/src/components/ui/slider.tsx +23 -0
- package/templates/frontend/src/components/ui/sonner.tsx +27 -0
- package/templates/frontend/src/components/ui/stat-card.tsx +44 -0
- package/templates/frontend/src/components/ui/switch.tsx +27 -0
- package/templates/frontend/src/components/ui/table.tsx +72 -0
- package/templates/frontend/src/components/ui/tabs.tsx +53 -0
- package/templates/frontend/src/components/ui/textarea.tsx +21 -0
- package/templates/frontend/src/components/ui/toast.tsx +111 -0
- package/templates/frontend/src/components/ui/toaster.tsx +24 -0
- package/templates/frontend/src/components/ui/toggle-group.tsx +49 -0
- package/templates/frontend/src/components/ui/toggle.tsx +37 -0
- package/templates/frontend/src/components/ui/tooltip.tsx +28 -0
- package/templates/frontend/src/components/ui/use-toast.ts +3 -0
- package/templates/frontend/src/contexts/AuthContext.tsx +94 -0
- package/templates/frontend/src/contexts/RefreshContext.tsx +236 -0
- package/templates/frontend/src/hooks/api/index.ts +2 -0
- package/templates/frontend/src/hooks/api/useLocations.ts +15 -0
- package/templates/frontend/src/hooks/use-mobile.tsx +19 -0
- package/templates/frontend/src/hooks/use-toast.ts +186 -0
- package/templates/frontend/src/hooks/useApiContext.ts +11 -0
- package/templates/frontend/src/index.css +118 -0
- package/templates/frontend/src/integrations/supabase/client.ts +9 -0
- package/templates/frontend/src/lib/api-client.ts +136 -0
- package/templates/frontend/src/lib/api.ts +1028 -0
- package/templates/frontend/src/lib/utils.ts +6 -0
- package/templates/frontend/src/main.tsx +5 -0
- package/templates/frontend/src/pages/Auth.tsx +408 -0
- package/templates/frontend/src/pages/Dashboard.tsx +168 -0
- package/templates/frontend/src/pages/Menus.tsx +224 -0
- package/templates/frontend/src/pages/NotFound.tsx +24 -0
- package/templates/frontend/src/pages/Register.tsx +285 -0
- package/templates/frontend/src/test/example.test.ts +0 -0
- package/templates/frontend/src/test/setup.ts +15 -0
- package/templates/frontend/src/types/index.ts +8 -0
- package/templates/frontend/src/vite-env.d.ts +1 -0
- package/templates/frontend/tailwind.config.ts +101 -0
- package/templates/frontend/tsconfig.app.json +31 -0
- package/templates/frontend/tsconfig.json +16 -0
- package/templates/frontend/tsconfig.node.json +22 -0
- package/templates/frontend/vite.config.ts +21 -0
- package/templates/frontend/vitest.config.ts +16 -0
- package/templates/init.sh +1 -0
- package/templates/prompt.md +139 -0
- package/templates/ralph.sh +120 -0
- package/templates/server.mjs +505 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Specification Format Template
|
|
2
|
+
|
|
3
|
+
## Output File Structure
|
|
4
|
+
|
|
5
|
+
The `code-slice.json` file contains:
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"id": "<slice-id-from-slice.json>",
|
|
10
|
+
"title": "<slice-title-from-slice.json>",
|
|
11
|
+
"specifications": [...]
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**CRITICAL:**
|
|
16
|
+
- MUST include `id` and `title` fields copied from the corresponding `slice.json` file
|
|
17
|
+
- NO commands, events, readmodels, or other slice metadata (only id, title, and specifications)
|
|
18
|
+
- Each specification must have complete nested objects with fields, NOT simple strings
|
|
19
|
+
- Given/when/then must be arrays of objects with full field definitions
|
|
20
|
+
|
|
21
|
+
## Specification Object Template
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"vertical": false,
|
|
26
|
+
"id": "<generated-id>",
|
|
27
|
+
"sliceName": "slice: <SliceName>",
|
|
28
|
+
"title": "spec: <test description>",
|
|
29
|
+
"given": [
|
|
30
|
+
{
|
|
31
|
+
"title": "<Event Title>",
|
|
32
|
+
"tags": [],
|
|
33
|
+
"id": "<generated-id>",
|
|
34
|
+
"index": 0,
|
|
35
|
+
"specRow": -1,
|
|
36
|
+
"type": "SPEC_EVENT",
|
|
37
|
+
"fields": [
|
|
38
|
+
{
|
|
39
|
+
"name": "fieldName",
|
|
40
|
+
"type": "String|Date|UUID|Integer|Boolean|Decimal",
|
|
41
|
+
"subfields": [],
|
|
42
|
+
"cardinality": "Single",
|
|
43
|
+
"example": ""
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"linkedId": "<linked-event-id-from-elements>"
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"when": [
|
|
50
|
+
{
|
|
51
|
+
"title": "<Command Title>",
|
|
52
|
+
"tags": [],
|
|
53
|
+
"id": "<generated-id>",
|
|
54
|
+
"index": 0,
|
|
55
|
+
"specRow": -1,
|
|
56
|
+
"type": "SPEC_COMMAND",
|
|
57
|
+
"fields": [
|
|
58
|
+
{
|
|
59
|
+
"name": "fieldName",
|
|
60
|
+
"type": "String|Date|UUID|Integer|Boolean|Decimal",
|
|
61
|
+
"subfields": [],
|
|
62
|
+
"cardinality": "Single",
|
|
63
|
+
"example": ""
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"linkedId": "<linked-command-id-from-elements>"
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"then": [
|
|
70
|
+
{
|
|
71
|
+
"title": "<Event or Error Title>",
|
|
72
|
+
"tags": [],
|
|
73
|
+
"id": "<generated-id>",
|
|
74
|
+
"index": 0,
|
|
75
|
+
"specRow": -1,
|
|
76
|
+
"type": "SPEC_EVENT|SPEC_ERROR|SPEC_READMODEL",
|
|
77
|
+
"fields": [
|
|
78
|
+
{
|
|
79
|
+
"name": "fieldName",
|
|
80
|
+
"type": "String|Date|UUID|Integer|Boolean|Decimal",
|
|
81
|
+
"subfields": [],
|
|
82
|
+
"cardinality": "Single",
|
|
83
|
+
"example": ""
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"linkedId": "<linked-event-id-from-elements>"
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
"comments": [],
|
|
90
|
+
"linkedId": "<same-as-specification-id-above>"
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Given/When/Then Structure
|
|
95
|
+
|
|
96
|
+
### For STATE_CHANGE Slices
|
|
97
|
+
|
|
98
|
+
- **given**: Array of event objects (preconditions - events that happened before)
|
|
99
|
+
- **when**: Array with single command object (the action being tested)
|
|
100
|
+
- **then**: Array of event/error objects (what happened as a result)
|
|
101
|
+
|
|
102
|
+
### For STATE_VIEW Slices
|
|
103
|
+
|
|
104
|
+
- **given**: Array of event objects (events to be projected)
|
|
105
|
+
- **when**: Empty array `[]` (no command in projections)
|
|
106
|
+
- **then**: Array with readmodel assertion objects (SPEC_READMODEL type)
|
|
107
|
+
|
|
108
|
+
## Field Object Structure
|
|
109
|
+
|
|
110
|
+
Each field in the `fields` array must have:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"name": "fieldName",
|
|
115
|
+
"type": "String|Date|UUID|Integer|Boolean|Decimal|Integer|List",
|
|
116
|
+
"subfields": [],
|
|
117
|
+
"cardinality": "Single|Multiple",
|
|
118
|
+
"example": "actual value from test"
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Field Type Mapping
|
|
123
|
+
|
|
124
|
+
Infer types from test data:
|
|
125
|
+
- String values → `"String"`
|
|
126
|
+
- UUID format → `"UUID"`
|
|
127
|
+
- Date strings (ISO format) → `"Date"` or `"DateTime"`
|
|
128
|
+
- Numbers with decimals → `"Decimal"`
|
|
129
|
+
- Whole numbers → `"Integer"`
|
|
130
|
+
- Boolean values → `"Boolean"`
|
|
131
|
+
- Arrays → `"List"` with element type
|
|
132
|
+
|
|
133
|
+
### Cardinality
|
|
134
|
+
|
|
135
|
+
- `"Single"` - for single values
|
|
136
|
+
- `"Multiple"` - for arrays
|
|
137
|
+
|
|
138
|
+
## Element Types
|
|
139
|
+
|
|
140
|
+
- `SPEC_COMMAND` - Command in `when` array (STATE_CHANGE only)
|
|
141
|
+
- `SPEC_EVENT` - Event in `given` or `then` arrays
|
|
142
|
+
- `SPEC_ERROR` - Error in `then` array (when test uses `thenThrows()`)
|
|
143
|
+
- `SPEC_READMODEL` - Readmodel assertion in `then` array (STATE_VIEW only)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# STATE_CHANGE Slice Example
|
|
2
|
+
|
|
3
|
+
## Input Test File
|
|
4
|
+
|
|
5
|
+
**File:** `src/slices/ActivateShift/ActivateShift.test.ts`
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
describe('Activate Shift Specification', () => {
|
|
9
|
+
it('spec: Activate Shift - scenario', () => {
|
|
10
|
+
given([{
|
|
11
|
+
type: 'ShiftCreated',
|
|
12
|
+
data: { shiftId: '123', restaurantId: 'r1', startDate: '2026-01-15' }
|
|
13
|
+
}])
|
|
14
|
+
.when({ type: 'ActivateShift', data: { shiftId: '123', restaurantId: 'r1' }})
|
|
15
|
+
.then([{
|
|
16
|
+
type: 'ShiftActivated',
|
|
17
|
+
data: { shiftId: '123', restaurantId: 'r1' }
|
|
18
|
+
}])
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('spec: Activate Shift - shift not found', () => {
|
|
22
|
+
given([])
|
|
23
|
+
.when({ type: 'ActivateShift', data: { shiftId: '999', restaurantId: 'r1' }})
|
|
24
|
+
.thenThrows()
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Processing Steps
|
|
30
|
+
|
|
31
|
+
1. Slice name detected: "ActivateShift" (from file path)
|
|
32
|
+
2. Looks up in `.slices/index.json` → finds entry with `"slice": "slice: Activate Shift"`
|
|
33
|
+
3. Gets folder: "activateshift" and context: "Restaurant Management"
|
|
34
|
+
4. Reads: `.slices/Restaurant Management/activateshift/slice.json`
|
|
35
|
+
5. Checks specifications array in slice.json for existing test specs
|
|
36
|
+
6. First test found in slice.json specifications array → not included in code-slice.json
|
|
37
|
+
7. Second test (error case) NOT in slice.json specifications array → included in code-slice.json
|
|
38
|
+
8. **CRITICAL: Looks up real IDs from slice.json:**
|
|
39
|
+
- Command "Activate Shift" → finds `"id": "3458764657124632223"` in slice.json commands array
|
|
40
|
+
- Uses this real ID as `linkedId` for the command in the specification
|
|
41
|
+
|
|
42
|
+
## Output
|
|
43
|
+
|
|
44
|
+
**File:** `src/slices/ActivateShift/code-slice.json`
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"id": "3458764657124632353",
|
|
49
|
+
"title": "slice: Activate Shift",
|
|
50
|
+
"specifications": [
|
|
51
|
+
{
|
|
52
|
+
"vertical": false,
|
|
53
|
+
"id": "3458764660410459999",
|
|
54
|
+
"sliceName": "slice: Activate Shift",
|
|
55
|
+
"title": "spec: Activate Shift - shift not found",
|
|
56
|
+
"given": [],
|
|
57
|
+
"when": [
|
|
58
|
+
{
|
|
59
|
+
"title": "Activate Shift",
|
|
60
|
+
"tags": [],
|
|
61
|
+
"id": "3458764660410459998",
|
|
62
|
+
"index": 0,
|
|
63
|
+
"specRow": -1,
|
|
64
|
+
"type": "SPEC_COMMAND",
|
|
65
|
+
"fields": [
|
|
66
|
+
{
|
|
67
|
+
"name": "shiftId",
|
|
68
|
+
"type": "String",
|
|
69
|
+
"subfields": [],
|
|
70
|
+
"cardinality": "Single",
|
|
71
|
+
"example": "999"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "restaurantId",
|
|
75
|
+
"type": "String",
|
|
76
|
+
"subfields": [],
|
|
77
|
+
"cardinality": "Single",
|
|
78
|
+
"example": "r1"
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"linkedId": "3458764657124632223"
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
"then": [
|
|
85
|
+
{
|
|
86
|
+
"title": "Shift not found error",
|
|
87
|
+
"tags": [],
|
|
88
|
+
"id": "3458764660410459997",
|
|
89
|
+
"index": 0,
|
|
90
|
+
"specRow": -1,
|
|
91
|
+
"type": "SPEC_ERROR",
|
|
92
|
+
"fields": []
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
"comments": [],
|
|
96
|
+
"linkedId": "3458764660410459999"
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Key Points
|
|
103
|
+
|
|
104
|
+
- **Top-level fields**: `id` and `title` are copied from `.slices/Restaurant Management/activateshift/slice.json`
|
|
105
|
+
- **Given**: Empty array (no preconditions for error case)
|
|
106
|
+
- **When**: Single command object with full field definitions
|
|
107
|
+
- **CRITICAL**: `linkedId` is `"3458764657124632223"` - the REAL ID from slice.json commands array for "Activate Shift" command
|
|
108
|
+
- **Then**: Error object (SPEC_ERROR type) with empty fields
|
|
109
|
+
- Errors have no `linkedId` field (they don't represent elements in slice.json)
|
|
110
|
+
- Only the error case is included because the happy path specification already exists in slice.json specifications array
|
|
111
|
+
- If slice.json specifications array is empty, ALL test specifications would be included in code-slice.json
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# STATE_VIEW Slice Example
|
|
2
|
+
|
|
3
|
+
## Input Test File
|
|
4
|
+
|
|
5
|
+
**File:** `src/slices/ActivatedOnlineReservations/OnlineReservationStatus.test.ts`
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
describe('OnlineReservationStatus Specification', () => {
|
|
9
|
+
it('spec: Online reservation activated - sets active to true', async () => {
|
|
10
|
+
await given([{type: 'OnlineReservationActivated', data: {restaurantId: 'r1'}}])
|
|
11
|
+
.when([]) // empty for projections
|
|
12
|
+
.then(assertReadModel);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('spec: Toggle online reservation - activates then deactivates', async () => {
|
|
16
|
+
await given([
|
|
17
|
+
{type: 'OnlineReservationActivated', data: {restaurantId: 'r1'}},
|
|
18
|
+
{type: 'OnlineReservationDeactivated', data: {restaurantId: 'r1'}}
|
|
19
|
+
])
|
|
20
|
+
.when([]) // empty for projections
|
|
21
|
+
.then(assertReadModel);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Processing Steps
|
|
27
|
+
|
|
28
|
+
1. Slice name detected: "OnlineReservationStatus" (from file path or describe block)
|
|
29
|
+
2. Looks up in `.slices/index.json` → searches for matching slice title
|
|
30
|
+
3. Gets folder and context from index
|
|
31
|
+
4. Reads corresponding `.slices/<context>/<folder>/slice.json`
|
|
32
|
+
5. Compares test events with slice.json
|
|
33
|
+
6. If "toggle" scenario not in slice.json → include in specifications
|
|
34
|
+
7. **CRITICAL: Looks up real event IDs:**
|
|
35
|
+
- Events may be defined in other slices, but referenced in readmodel dependencies
|
|
36
|
+
- Search for event IDs in the readmodel's `dependencies` array with `type: "INBOUND"`
|
|
37
|
+
- "Online Reservation Activated" → ID `"3458764659470382480"` (from dependencies)
|
|
38
|
+
- "Online Reservation Deactivated" → ID `"3458764659470541221"` (from dependencies)
|
|
39
|
+
|
|
40
|
+
## Output
|
|
41
|
+
|
|
42
|
+
**File:** `src/slices/ActivatedOnlineReservations/code-slice.json`
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"id": "3458764659470991969",
|
|
47
|
+
"title": "slice: Activated Online reservations",
|
|
48
|
+
"specifications": [
|
|
49
|
+
{
|
|
50
|
+
"vertical": false,
|
|
51
|
+
"id": "3458764660410460001",
|
|
52
|
+
"sliceName": "slice: Online Reservation Status",
|
|
53
|
+
"title": "spec: Toggle online reservation - activates then deactivates",
|
|
54
|
+
"given": [
|
|
55
|
+
{
|
|
56
|
+
"title": "Online Reservation Activated",
|
|
57
|
+
"tags": [],
|
|
58
|
+
"id": "3458764660410460002",
|
|
59
|
+
"index": 0,
|
|
60
|
+
"specRow": -1,
|
|
61
|
+
"type": "SPEC_EVENT",
|
|
62
|
+
"fields": [
|
|
63
|
+
{
|
|
64
|
+
"name": "restaurantId",
|
|
65
|
+
"type": "String",
|
|
66
|
+
"subfields": [],
|
|
67
|
+
"cardinality": "Single",
|
|
68
|
+
"example": "r1"
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
"linkedId": "3458764659470382480"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"title": "Online Reservation Deactivated",
|
|
75
|
+
"tags": [],
|
|
76
|
+
"id": "3458764660410460003",
|
|
77
|
+
"index": 1,
|
|
78
|
+
"specRow": -1,
|
|
79
|
+
"type": "SPEC_EVENT",
|
|
80
|
+
"fields": [
|
|
81
|
+
{
|
|
82
|
+
"name": "restaurantId",
|
|
83
|
+
"type": "String",
|
|
84
|
+
"subfields": [],
|
|
85
|
+
"cardinality": "Single",
|
|
86
|
+
"example": "r1"
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
"linkedId": "3458764659470541221"
|
|
90
|
+
}
|
|
91
|
+
],
|
|
92
|
+
"when": [],
|
|
93
|
+
"then": [
|
|
94
|
+
{
|
|
95
|
+
"title": "active = false in read model",
|
|
96
|
+
"tags": [],
|
|
97
|
+
"id": "3458764660410460004",
|
|
98
|
+
"index": 0,
|
|
99
|
+
"specRow": -1,
|
|
100
|
+
"type": "SPEC_READMODEL",
|
|
101
|
+
"fields": []
|
|
102
|
+
}
|
|
103
|
+
],
|
|
104
|
+
"comments": [],
|
|
105
|
+
"linkedId": "3458764660410460001"
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Key Points
|
|
112
|
+
|
|
113
|
+
- **Top-level fields**: `id` and `title` are copied from the corresponding `slice.json` in `.slices/Restaurant Management/activatedonlinereservations/slice.json`
|
|
114
|
+
- **Specification linkedId**: `"3458764660410460001"` matches the specification's `id` field (self-reference)
|
|
115
|
+
- **Given**: Array of events to be projected (this is where events go for STATE_VIEW)
|
|
116
|
+
- **CRITICAL**: Each event's `linkedId` uses the REAL event ID from slice.json
|
|
117
|
+
- "Online Reservation Activated" → `linkedId: "3458764659470382480"`
|
|
118
|
+
- "Online Reservation Deactivated" → `linkedId: "3458764659470541221"`
|
|
119
|
+
- For STATE_VIEW slices, look for event IDs in the readmodel's `dependencies` array
|
|
120
|
+
- **When**: Empty array (no command in projections)
|
|
121
|
+
- **Then**: Readmodel assertion (SPEC_READMODEL type)
|
|
122
|
+
- Only the "toggle" scenario is included because it represents additional behavior beyond basic projection
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Agent Learnings
|
|
2
|
+
|
|
3
|
+
This file captures patterns, gotchas, and best practices discovered during development.
|
|
4
|
+
Update this file as you learn new patterns that future iterations should know.
|
|
5
|
+
|
|
6
|
+
## Core Principles
|
|
7
|
+
|
|
8
|
+
### Event Model as Source of Truth
|
|
9
|
+
- Event model JSON files define the desired state
|
|
10
|
+
- Code must match the event model specification
|
|
11
|
+
- When in doubt, check the event model
|
|
12
|
+
|
|
13
|
+
### File Organization
|
|
14
|
+
- Each slice lives in `src/slices/{SliceName}/`
|
|
15
|
+
- Keep slices self-contained and focused
|
|
16
|
+
- Follow consistent naming conventions
|
|
17
|
+
|
|
18
|
+
## Event-Driven Architecture Patterns
|
|
19
|
+
|
|
20
|
+
### State-Change Slices (Commands)
|
|
21
|
+
- Use `decide()` for business logic validation
|
|
22
|
+
- Use `evolve()` for state reconstruction from events
|
|
23
|
+
- State should only track what's needed for validation
|
|
24
|
+
- Simple commands can have empty state `{}`
|
|
25
|
+
|
|
26
|
+
### State-View Slices (Queries)
|
|
27
|
+
- Projections build read models from events
|
|
28
|
+
- Read models are optimized for querying
|
|
29
|
+
- One read model per use case/view
|
|
30
|
+
|
|
31
|
+
### Automation Slices
|
|
32
|
+
- Automations = State-Change + CRON processor
|
|
33
|
+
- Read from TODO list (work queue) read models
|
|
34
|
+
- Process one item at a time with `.limit(1)`
|
|
35
|
+
- Always wrap command execution in try-catch
|
|
36
|
+
|
|
37
|
+
## Common Patterns
|
|
38
|
+
|
|
39
|
+
### Stream IDs
|
|
40
|
+
- Use consistent stream ID patterns per aggregate
|
|
41
|
+
- Format: `{aggregate}-{id}` or `{context}-{aggregate}-{id}`
|
|
42
|
+
- Document stream ID patterns in each slice
|
|
43
|
+
|
|
44
|
+
### Metadata
|
|
45
|
+
- Always include `correlation_id` and `causation_id`
|
|
46
|
+
- Use optional chaining: `metadata?.field`
|
|
47
|
+
- Include tenant/user IDs for multi-tenancy
|
|
48
|
+
|
|
49
|
+
### Testing
|
|
50
|
+
- Use `DeciderSpecification.for()` for state-change tests
|
|
51
|
+
- Use `PostgreSQLProjectionSpec.for()` for state-view tests
|
|
52
|
+
- Test format: given/when/then
|
|
53
|
+
- Include both happy path and error scenarios
|
|
54
|
+
|
|
55
|
+
## Database Patterns
|
|
56
|
+
|
|
57
|
+
### Migrations
|
|
58
|
+
- Never modify existing migrations
|
|
59
|
+
- Always create new migrations for changes
|
|
60
|
+
- Use sequential version numbers (V1, V2, V3...)
|
|
61
|
+
- Check latest migration before creating new one
|
|
62
|
+
|
|
63
|
+
### Tables
|
|
64
|
+
- Use snake_case for table and column names
|
|
65
|
+
- Include proper indexes for query performance
|
|
66
|
+
- Add tenant ID columns for multi-tenancy
|
|
67
|
+
|
|
68
|
+
## TypeScript Best Practices
|
|
69
|
+
|
|
70
|
+
### Types
|
|
71
|
+
- Use strict TypeScript mode
|
|
72
|
+
- Define explicit types for commands, events, and state
|
|
73
|
+
- Avoid `any` - use `unknown` if needed
|
|
74
|
+
|
|
75
|
+
### Imports
|
|
76
|
+
- Use ES modules (import/export)
|
|
77
|
+
- Organize imports: external, internal, types
|
|
78
|
+
- Keep imports minimal and specific
|
|
79
|
+
|
|
80
|
+
## Error Handling
|
|
81
|
+
|
|
82
|
+
### Validation Errors
|
|
83
|
+
- Throw descriptive error messages
|
|
84
|
+
- Use error codes for common failures
|
|
85
|
+
- Map errors to user-friendly messages in routes
|
|
86
|
+
|
|
87
|
+
### HTTP Status Codes
|
|
88
|
+
- 200: Success
|
|
89
|
+
- 400: Bad request (validation error)
|
|
90
|
+
- 401: Unauthorized
|
|
91
|
+
- 409: Conflict (business rule violation)
|
|
92
|
+
- 500: Server error
|
|
93
|
+
|
|
94
|
+
## Code Quality
|
|
95
|
+
|
|
96
|
+
### Before Committing
|
|
97
|
+
- Run `npm run build` - ensure TypeScript compiles
|
|
98
|
+
- Run `npm run test` - ensure all tests pass
|
|
99
|
+
- Update this file with new learnings
|
|
100
|
+
- Update progress.txt with iteration summary
|
|
101
|
+
|
|
102
|
+
### Clean Code
|
|
103
|
+
- Follow existing patterns in codebase
|
|
104
|
+
- Keep functions focused and small
|
|
105
|
+
- Use descriptive names for variables and functions
|
|
106
|
+
- Comment complex business logic
|
|
107
|
+
|
|
108
|
+
## Future Development Notes
|
|
109
|
+
|
|
110
|
+
Add your learnings here as you discover patterns specific to your domain and architecture.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Project Configuration
|
|
2
|
+
|
|
3
|
+
Read Events in src/events to understand the global structure.
|
|
4
|
+
|
|
5
|
+
## Framework & Styling
|
|
6
|
+
|
|
7
|
+
- **CSS Framework**: Use Bulma CSS exclusively for all styling
|
|
8
|
+
- **Assumption**: Bulma CSS is already available and imported in the project
|
|
9
|
+
- **Styling Guidelines**:
|
|
10
|
+
- Use Bulma's utility classes and components
|
|
11
|
+
- Follow Bulma's naming conventions and class structure
|
|
12
|
+
- Leverage Bulma's responsive design features
|
|
13
|
+
- Prefer Bulma components over custom CSS
|
|
14
|
+
|
|
15
|
+
## File Structure Constraints
|
|
16
|
+
|
|
17
|
+
- **Strict Path Limitation**: if not instructed otherwise, only check `src/slices/{slicename}/*.ts`
|
|
18
|
+
- **Slice Organization**: Each feature/domain should be organized as a separate slice
|
|
19
|
+
|
|
20
|
+
## Code Standards
|
|
21
|
+
|
|
22
|
+
- **Language**: TypeScript only
|
|
23
|
+
- **Module System**: Use ES modules (import/export)
|
|
24
|
+
- **Type Safety**: Ensure all code is properly typed
|
|
25
|
+
|
|
26
|
+
## Development Guidelines
|
|
27
|
+
|
|
28
|
+
1. Each slice should be self-contained and focused on a specific domain
|
|
29
|
+
2. Use Bulma's grid system, components, and utilities for all UI-related code
|
|
30
|
+
3. Maintain clear separation of concerns within each slice
|
|
31
|
+
4. Follow TypeScript best practices for type definitions and interfaces
|
|
32
|
+
|
|
33
|
+
Only check src/slices/{slice}/*.ts, do not check subfolders, if not explicitely tasked to build the UI.
|
|
34
|
+
If not tasked explicitely to change routes, ignore routes*.ts
|
|
35
|
+
|
|
36
|
+
Ignore case for files and slices in prompts. "CartItems" slice is the same as "cartitemsrun t"
|
|
37
|
+
|
|
38
|
+
Do not change files with tests unless explicitely instructed: *.test.ts
|
|
39
|
+
|
|
40
|
+
After you are done, automatically run the tests for the slice that was edited.
|
|
41
|
+
|
|
42
|
+
## Example Slice Structure
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
src/slices/
|
|
46
|
+
├── {slice-name}/
|
|
47
|
+
│ ├── CommandHandler.ts
|
|
48
|
+
│ ├── ui/
|
|
49
|
+
│ └── routes.ts
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Bulma Integration Notes
|
|
53
|
+
|
|
54
|
+
- Utilize Bulma's component library: navbar, cards, buttons, forms, modals, etc.
|
|
55
|
+
- Apply Bulma's spacing utilities: `m-*`, `p-*`, `has-text-*`, `has-background-*`
|
|
56
|
+
- Use Bulma's flexbox utilities for layouts
|
|
57
|
+
- Implement responsive design with Bulma's breakpoint classes
|
|
58
|
+
- Leverage Bulma's color palette and typography classes
|