@nebulit/embuilder 0.1.39 → 0.1.40
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/package.json +1 -1
- package/templates/.claude/skills/sample-slices/SKILL.md +3 -1
- package/templates/.slices/Context/event/slice.json +117 -0
- package/templates/.slices/index.json +12 -0
- package/templates/backend/prompt.md +140 -0
- package/templates/config.json +133 -0
- package/templates/frontend/prompt.md +324 -0
- package/templates/prompt.md +4 -132
- package/templates/server.mjs +24 -2
package/package.json
CHANGED
|
@@ -5,4 +5,6 @@ description: Generate a sample configuration for slices
|
|
|
5
5
|
|
|
6
6
|
# Copy the configuration
|
|
7
7
|
|
|
8
|
-
Copy the .slices folder from templates to the project root
|
|
8
|
+
Copy the .slices folder from skills templates to the project root
|
|
9
|
+
|
|
10
|
+
You don´t need to understand the structure, nor do you need to verify after copying.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "3458764661682330686",
|
|
3
|
+
"status": "Created",
|
|
4
|
+
"title": "slice: Event",
|
|
5
|
+
"context": "Context",
|
|
6
|
+
"sliceType": "STATE_CHANGE",
|
|
7
|
+
"commands": [
|
|
8
|
+
{
|
|
9
|
+
"id": "3458764661682330640",
|
|
10
|
+
"tags": [],
|
|
11
|
+
"modelContext": "Context",
|
|
12
|
+
"slice": "slice: Event",
|
|
13
|
+
"title": " Event",
|
|
14
|
+
"fields": [],
|
|
15
|
+
"type": "COMMAND",
|
|
16
|
+
"description": "",
|
|
17
|
+
"aggregate": "default",
|
|
18
|
+
"aggregateDependencies": [],
|
|
19
|
+
"dependencies": [
|
|
20
|
+
{
|
|
21
|
+
"id": "3458764661682330558",
|
|
22
|
+
"type": "OUTBOUND",
|
|
23
|
+
"title": "event",
|
|
24
|
+
"elementType": "EVENT"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "3458764661682330666",
|
|
28
|
+
"type": "INBOUND",
|
|
29
|
+
"title": "screen",
|
|
30
|
+
"elementType": "SCREEN"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"createsAggregate": false,
|
|
34
|
+
"triggers": [],
|
|
35
|
+
"sketched": false,
|
|
36
|
+
"prototype": {
|
|
37
|
+
"activeByDefault": false
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"events": [
|
|
42
|
+
{
|
|
43
|
+
"id": "3458764661682330558",
|
|
44
|
+
"tags": [],
|
|
45
|
+
"elementContext": "INTERNAL",
|
|
46
|
+
"modelContext": "Context",
|
|
47
|
+
"context": "INTERNAL",
|
|
48
|
+
"slice": "slice: Event",
|
|
49
|
+
"title": "event",
|
|
50
|
+
"fields": [],
|
|
51
|
+
"type": "EVENT",
|
|
52
|
+
"description": "",
|
|
53
|
+
"aggregate": "default",
|
|
54
|
+
"aggregateDependencies": [],
|
|
55
|
+
"dependencies": [
|
|
56
|
+
{
|
|
57
|
+
"id": "3458764661682330640",
|
|
58
|
+
"type": "INBOUND",
|
|
59
|
+
"title": " Event",
|
|
60
|
+
"elementType": "COMMAND"
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"createsAggregate": false,
|
|
64
|
+
"triggers": [],
|
|
65
|
+
"sketched": false,
|
|
66
|
+
"prototype": {
|
|
67
|
+
"activeByDefault": false
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
"readmodels": [],
|
|
72
|
+
"screens": [
|
|
73
|
+
{
|
|
74
|
+
"id": "3458764661682330666",
|
|
75
|
+
"tags": [],
|
|
76
|
+
"groupId": "3458764661682330671",
|
|
77
|
+
"modelContext": "Context",
|
|
78
|
+
"slice": "slice: Event",
|
|
79
|
+
"title": "screen",
|
|
80
|
+
"fields": [],
|
|
81
|
+
"type": "SCREEN",
|
|
82
|
+
"description": "",
|
|
83
|
+
"aggregate": "default",
|
|
84
|
+
"aggregateDependencies": [],
|
|
85
|
+
"dependencies": [
|
|
86
|
+
{
|
|
87
|
+
"id": "3458764661682330640",
|
|
88
|
+
"type": "OUTBOUND",
|
|
89
|
+
"title": " Event",
|
|
90
|
+
"elementType": "COMMAND"
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
"createsAggregate": false,
|
|
94
|
+
"triggers": [],
|
|
95
|
+
"sketched": false,
|
|
96
|
+
"prototype": {
|
|
97
|
+
"activeByDefault": false
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
"screenImages": [],
|
|
102
|
+
"screenLayouts": [],
|
|
103
|
+
"processors": [],
|
|
104
|
+
"tables": [],
|
|
105
|
+
"specifications": [],
|
|
106
|
+
"actors": [],
|
|
107
|
+
"codeGen": {
|
|
108
|
+
"backendPrompts": [
|
|
109
|
+
"slice be prompt",
|
|
110
|
+
"group be prompt"
|
|
111
|
+
],
|
|
112
|
+
"uiPrompts": [
|
|
113
|
+
"group fe prompt"
|
|
114
|
+
]
|
|
115
|
+
},
|
|
116
|
+
"aggregates": []
|
|
117
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Ralph Agent Instructions
|
|
2
|
+
|
|
3
|
+
You are an autonomous coding agent working on the backend of a software project. You apply your skills to build software slices. You only work on one slice at a time.
|
|
4
|
+
|
|
5
|
+
The structure defined in the Project-Skills is relevant.
|
|
6
|
+
|
|
7
|
+
## Your Task
|
|
8
|
+
|
|
9
|
+
0. Do not read the entire code base. Focus on the tasks in this description.
|
|
10
|
+
1. Read the description at `.slices/index.json` (in the same directory as this file). Every item in status "planned" is a task.
|
|
11
|
+
2. Read the progress log at `progress.txt` (check Codebase Patterns section first)
|
|
12
|
+
3. Make sure you are on the right branch "feature/<slicename>", if unsure, start from main.
|
|
13
|
+
5. Pick the **highest priority** slice where status is "planned" ( case insensitive ) and is not assigned to 'ui_worker'. This becomes your PRD. Set the status "InProgress", add a started_date ( including date and time ) and add an "assignee=backend_worker" in the index.json. If no slice has status planned, reply with:
|
|
14
|
+
<promise>NO_TASKS</promise> and stop. Do not work on other slices.
|
|
15
|
+
6. Pick the slice definition from the project root /.slices in <folder> defined in the prd. Never work on more than one slice per iteration.
|
|
16
|
+
7. A slice can define additional prompts as codegen/backendPrompt. any additional prompts defined in backend are hints for the implementation of the slice and have to be taken into account. If you use the additional prompt, add a line in progress.txt
|
|
17
|
+
7. Define the slice type. If the processors-array is not empty, it´s an automation slice. Load the matching skill (automation-slice, state-change-slice, state-view-slice)
|
|
18
|
+
8. Write a short progress one liner after each step to progress.txt
|
|
19
|
+
9. Analyze and Implement that single slice, make use of the skills in the skills directory, but also your previsously collected
|
|
20
|
+
knowledge. Make a list TODO list for what needs to be done. Also make sure to adjust the implementation according to the json definition. Carefully inspect events, fields and compare against the implemented slice. JSON is the desired state. ATTENTION: A "planned" task can also be just added specifications. So always look at the slice itself, but also the specifications. If specifications were added in json, which are not on code, you need to add them in code.
|
|
21
|
+
10. The slice in the json is always true, the code follows what is defined in the json
|
|
22
|
+
11. the backend of a slice is only 'Done' if business logic is implemented as defined in the JSON, APIs are implemented, all scenarios in JSON are implemented in code and it
|
|
23
|
+
fulfills the slice.json. There must be no specification in json, that has no equivalent in code.
|
|
24
|
+
12. make sure to write the ui-prompt.md as defined if defined in the skill
|
|
25
|
+
13. Run quality checks ( npm run build, npm run test ) - Attention - it´s enough to run the tests for the slice. Do not run all tests.
|
|
26
|
+
14. even if the slice is fully implemented, run your test-analyzer skill and provide the code-slice.json file as defined in the skill
|
|
27
|
+
15. Update the Slice in the index.json back to status 'Planned' and assign the 'ui-worker'
|
|
28
|
+
16. If checks pass, commit ALL changes with message: `feat: [Slice Name]` and merge back to main as FF merge ( update
|
|
29
|
+
first )
|
|
30
|
+
17. Append your progress to `progress.txt` after each step in the iteration.
|
|
31
|
+
18. append your new learnings to AGENTS.md in a compressed form, reusable for future iterations. Only add learnings if they are not already there.
|
|
32
|
+
19. change the assignee to ui_worker and set it back to planned.
|
|
33
|
+
20. Finish the iteration.
|
|
34
|
+
|
|
35
|
+
## Progress Report Format
|
|
36
|
+
|
|
37
|
+
APPEND to progress.txt (never replace, always append):
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
## [Date/Time] - [Slice]
|
|
41
|
+
|
|
42
|
+
- What was implemented
|
|
43
|
+
- Files changed
|
|
44
|
+
- **Learnings for future iterations:**
|
|
45
|
+
- Patterns discovered (e.g., "this codebase uses X for Y")
|
|
46
|
+
- Gotchas encountered (e.g., "don't forget to update Z when changing W")
|
|
47
|
+
- Useful context (e.g., "the evaluation panel is in component X")
|
|
48
|
+
---
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The learnings section is critical - it helps future iterations avoid repeating mistakes and understand the codebase
|
|
52
|
+
better.
|
|
53
|
+
|
|
54
|
+
## Consolidate Patterns
|
|
55
|
+
|
|
56
|
+
If you discover a **reusable pattern** that future iterations should know, add it to the `## Codebase Patterns` section
|
|
57
|
+
at the TOP of progress.txt (create it if it doesn't exist). This section should consolidate the most important
|
|
58
|
+
learnings:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
## Codebase Patterns
|
|
62
|
+
- Example: Use `sql<number>` template for aggregations
|
|
63
|
+
- Example: Always use `IF NOT EXISTS` for migrations
|
|
64
|
+
- Example: Export types from actions.ts for UI components
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Only add patterns that are **general and reusable**, not story-specific details.
|
|
68
|
+
|
|
69
|
+
## Update AGENTS.md Files
|
|
70
|
+
|
|
71
|
+
Before committing, check if any edited files have learnings worth preserving in nearby AGENTS.md files:
|
|
72
|
+
|
|
73
|
+
1. **Identify directories with edited files** - Look at which directories you modified
|
|
74
|
+
3. **Add valuable learnings that apply to all tasks** to the Agents.md - If you discovered something future developers/agents should know:
|
|
75
|
+
- API patterns or conventions specific to that module
|
|
76
|
+
- Gotchas or non-obvious requirements
|
|
77
|
+
- Dependencies between files
|
|
78
|
+
- Testing approaches for that area
|
|
79
|
+
- Configuration or environment requirements
|
|
80
|
+
|
|
81
|
+
**Examples of good AGENTS.md additions:**
|
|
82
|
+
|
|
83
|
+
- "When modifying X, also update Y to keep them in sync"
|
|
84
|
+
- "This module uses pattern Z for all API calls"
|
|
85
|
+
- "Tests require the dev server running on PORT 3000"
|
|
86
|
+
- "Field names must match the template exactly"
|
|
87
|
+
|
|
88
|
+
**Do NOT add:**
|
|
89
|
+
|
|
90
|
+
- Slice specific implementation details
|
|
91
|
+
- Story-specific implementation details
|
|
92
|
+
- Temporary debugging notes
|
|
93
|
+
- Information already in progress.txt
|
|
94
|
+
- Task speecific learnings like "- Timesheet approval requires: submitted=true, reverted=false, approved=false, declined=false"
|
|
95
|
+
|
|
96
|
+
Only update AGENTS.md if you have **genuinely reusable knowledge** that would help future work
|
|
97
|
+
|
|
98
|
+
## Quality Requirements
|
|
99
|
+
|
|
100
|
+
- ALL commits must pass your project's quality checks (typecheck, lint, test)
|
|
101
|
+
- run 'npm run build'
|
|
102
|
+
- run 'npm run test'
|
|
103
|
+
- Do NOT commit broken code
|
|
104
|
+
- Keep changes focused and minimal
|
|
105
|
+
- Follow existing code patterns
|
|
106
|
+
|
|
107
|
+
## Skills
|
|
108
|
+
|
|
109
|
+
Use the provided skills in the skills folder as guidance.
|
|
110
|
+
Update skill definitions if you find an improvement you can make.
|
|
111
|
+
|
|
112
|
+
## Specifications
|
|
113
|
+
|
|
114
|
+
For every specification added to the Slice, you need to implement one use executable Specification in Code.
|
|
115
|
+
|
|
116
|
+
A Slice is not complete if specifications are missing or can´t be executed.
|
|
117
|
+
|
|
118
|
+
## Stop Condition
|
|
119
|
+
|
|
120
|
+
After completing a user story, check if ALL slices have `status: Done`.
|
|
121
|
+
|
|
122
|
+
If ALL stories are complete and passing, reply with:
|
|
123
|
+
<promise>COMPLETE</promise>
|
|
124
|
+
|
|
125
|
+
If there are no stories with `status: Planned` (but not all are Done), reply with:
|
|
126
|
+
<promise>NO_TASKS</promise>
|
|
127
|
+
|
|
128
|
+
If there are still stories with `status: Planned`, end your response normally (another iteration will pick up the next
|
|
129
|
+
story).
|
|
130
|
+
|
|
131
|
+
## Important
|
|
132
|
+
|
|
133
|
+
- Work on ONE slice per iteration
|
|
134
|
+
- Commit frequently
|
|
135
|
+
- update progress.txt frequently
|
|
136
|
+
- Read the Codebase Patterns section in progress.txt before starting
|
|
137
|
+
|
|
138
|
+
## When an iteration completes
|
|
139
|
+
|
|
140
|
+
Use all the key learnings from the project.txt and update the Agends.md file with those learning.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slices": [
|
|
3
|
+
{
|
|
4
|
+
"id": "3458764661682330686",
|
|
5
|
+
"status": "Created",
|
|
6
|
+
"index": 1,
|
|
7
|
+
"title": "slice: Event",
|
|
8
|
+
"context": "Context",
|
|
9
|
+
"sliceType": "STATE_CHANGE",
|
|
10
|
+
"commands": [
|
|
11
|
+
{
|
|
12
|
+
"id": "3458764661682330640",
|
|
13
|
+
"tags": [],
|
|
14
|
+
"modelContext": "Context",
|
|
15
|
+
"slice": "slice: Event",
|
|
16
|
+
"title": " Event",
|
|
17
|
+
"fields": [],
|
|
18
|
+
"type": "COMMAND",
|
|
19
|
+
"description": "",
|
|
20
|
+
"aggregate": "default",
|
|
21
|
+
"aggregateDependencies": [],
|
|
22
|
+
"dependencies": [
|
|
23
|
+
{
|
|
24
|
+
"id": "3458764661682330558",
|
|
25
|
+
"type": "OUTBOUND",
|
|
26
|
+
"title": "event",
|
|
27
|
+
"elementType": "EVENT"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "3458764661682330666",
|
|
31
|
+
"type": "INBOUND",
|
|
32
|
+
"title": "screen",
|
|
33
|
+
"elementType": "SCREEN"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"createsAggregate": false,
|
|
37
|
+
"triggers": [],
|
|
38
|
+
"sketched": false,
|
|
39
|
+
"prototype": {
|
|
40
|
+
"activeByDefault": false
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"events": [
|
|
45
|
+
{
|
|
46
|
+
"id": "3458764661682330558",
|
|
47
|
+
"tags": [],
|
|
48
|
+
"elementContext": "INTERNAL",
|
|
49
|
+
"modelContext": "Context",
|
|
50
|
+
"context": "INTERNAL",
|
|
51
|
+
"slice": "slice: Event",
|
|
52
|
+
"title": "event",
|
|
53
|
+
"fields": [],
|
|
54
|
+
"type": "EVENT",
|
|
55
|
+
"description": "",
|
|
56
|
+
"aggregate": "default",
|
|
57
|
+
"aggregateDependencies": [],
|
|
58
|
+
"dependencies": [
|
|
59
|
+
{
|
|
60
|
+
"id": "3458764661682330640",
|
|
61
|
+
"type": "INBOUND",
|
|
62
|
+
"title": " Event",
|
|
63
|
+
"elementType": "COMMAND"
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"createsAggregate": false,
|
|
67
|
+
"triggers": [],
|
|
68
|
+
"sketched": false,
|
|
69
|
+
"prototype": {
|
|
70
|
+
"activeByDefault": false
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"readmodels": [],
|
|
75
|
+
"screens": [
|
|
76
|
+
{
|
|
77
|
+
"id": "3458764661682330666",
|
|
78
|
+
"tags": [],
|
|
79
|
+
"groupId": "3458764661682330671",
|
|
80
|
+
"modelContext": "Context",
|
|
81
|
+
"slice": "slice: Event",
|
|
82
|
+
"title": "screen",
|
|
83
|
+
"fields": [],
|
|
84
|
+
"type": "SCREEN",
|
|
85
|
+
"description": "",
|
|
86
|
+
"aggregate": "default",
|
|
87
|
+
"aggregateDependencies": [],
|
|
88
|
+
"dependencies": [
|
|
89
|
+
{
|
|
90
|
+
"id": "3458764661682330640",
|
|
91
|
+
"type": "OUTBOUND",
|
|
92
|
+
"title": " Event",
|
|
93
|
+
"elementType": "COMMAND"
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
"createsAggregate": false,
|
|
97
|
+
"triggers": [],
|
|
98
|
+
"sketched": false,
|
|
99
|
+
"prototype": {
|
|
100
|
+
"activeByDefault": false
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
],
|
|
104
|
+
"screenImages": [],
|
|
105
|
+
"screenLayouts": [],
|
|
106
|
+
"processors": [],
|
|
107
|
+
"tables": [],
|
|
108
|
+
"specifications": [],
|
|
109
|
+
"actors": [],
|
|
110
|
+
"codeGen": {
|
|
111
|
+
"backendPrompts": [
|
|
112
|
+
"slice be prompt",
|
|
113
|
+
"group be prompt"
|
|
114
|
+
],
|
|
115
|
+
"uiPrompts": [
|
|
116
|
+
"group fe prompt"
|
|
117
|
+
]
|
|
118
|
+
},
|
|
119
|
+
"aggregates": []
|
|
120
|
+
}
|
|
121
|
+
],
|
|
122
|
+
"flows": [],
|
|
123
|
+
"aggregates": [],
|
|
124
|
+
"actors": [],
|
|
125
|
+
"context": "Context",
|
|
126
|
+
"codeGen": {
|
|
127
|
+
"application": "Context"
|
|
128
|
+
},
|
|
129
|
+
"boardId": "uXjVJ13p-9M=",
|
|
130
|
+
"sliceGroups": [],
|
|
131
|
+
"sliceImages": [],
|
|
132
|
+
"sliceLayouts": []
|
|
133
|
+
}
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
# Frontend Agent Prompt - UI Component Generation
|
|
2
|
+
|
|
3
|
+
Build React + TypeScript UI components from slice JSON definitions using established patterns.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Slice Composition (CRITICAL)
|
|
8
|
+
|
|
9
|
+
### Slice Types
|
|
10
|
+
|
|
11
|
+
- **STATE_VIEW**: One read model table → Query hook → List component
|
|
12
|
+
- **STATE_CHANGE**: One command/POST endpoint → Mutation hook → Form/Dialog
|
|
13
|
+
|
|
14
|
+
### Grouping Rule
|
|
15
|
+
|
|
16
|
+
**Slices with same `groupId` → Implement together as one component**
|
|
17
|
+
|
|
18
|
+
```javascript
|
|
19
|
+
// Multiple slices, same groupId → One component
|
|
20
|
+
Slice A: { groupId: "123", sliceType: "STATE_VIEW", title: "Events View" }
|
|
21
|
+
Slice B: { groupId: "123", sliceType: "STATE_CHANGE", title: "Create Event" }
|
|
22
|
+
Slice C: { groupId: "123", sliceType: "STATE_CHANGE", title: "Cancel Event" }
|
|
23
|
+
// → Combine into EventsPage component
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### UI Prompts Priority
|
|
27
|
+
|
|
28
|
+
1. Check `ui-prompt.md` (detailed specs)
|
|
29
|
+
2. Check `codeGen.uiPrompts` array (high-level guidance)
|
|
30
|
+
3. Follow this prompt (standard patterns)
|
|
31
|
+
4. Keep it simple if no guidance
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 2. Authentication & API Context
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// AuthContext: user, session, restaurantId
|
|
39
|
+
import { useAuth } from "@/contexts/AuthContext";
|
|
40
|
+
const { user, session, restaurantId } = useAuth();
|
|
41
|
+
|
|
42
|
+
// ApiContext: token, restaurantId, userId (auto-injected into headers)
|
|
43
|
+
import { useApiContext } from "@/hooks/useApiContext";
|
|
44
|
+
const ctx = useApiContext();
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 3. Hooks Pattern
|
|
50
|
+
|
|
51
|
+
### Query Hook (STATE_VIEW)
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// src/hooks/api/useEvents.ts
|
|
55
|
+
import { useQuery } from "@tanstack/react-query";
|
|
56
|
+
import * as api from "@/lib/api";
|
|
57
|
+
|
|
58
|
+
export function useEvents() {
|
|
59
|
+
return useQuery({
|
|
60
|
+
queryKey: ["events"],
|
|
61
|
+
queryFn: () => api.fetchEvents(),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Mutation Hook (STATE_CHANGE)
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
export function useCreateEvent() {
|
|
70
|
+
const ctx = useApiContext();
|
|
71
|
+
const queryClient = useQueryClient();
|
|
72
|
+
|
|
73
|
+
return useMutation({
|
|
74
|
+
mutationFn: (params: api.CreateEventParams) => api.createEvent(params, ctx),
|
|
75
|
+
onSuccess: () => {
|
|
76
|
+
queryClient.invalidateQueries({ queryKey: ["events"] });
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 4. API Layer (CQRS)
|
|
85
|
+
|
|
86
|
+
### Query (Read from Supabase)
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// src/lib/api.ts
|
|
90
|
+
export async function fetchEvents(): Promise<Event[]> {
|
|
91
|
+
const { data, error } = await supabase
|
|
92
|
+
.from("events_for_planning") // Read model table
|
|
93
|
+
.select("*");
|
|
94
|
+
if (error) throw new Error(error.message);
|
|
95
|
+
return data || [];
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Command (POST to Backend)
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
export async function createEvent(params: CreateEventParams, ctx: ApiContext) {
|
|
103
|
+
const response = await apiRequest(
|
|
104
|
+
commandEndpoints.createEvent, // /api/createevent
|
|
105
|
+
ctx,
|
|
106
|
+
{ method: "POST", body: { ...params } }
|
|
107
|
+
);
|
|
108
|
+
if (!response.ok) throw new Error(response.error);
|
|
109
|
+
return response.data;
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Add endpoint in `src/lib/api-client.ts`**:
|
|
114
|
+
```typescript
|
|
115
|
+
export const commandEndpoints = {
|
|
116
|
+
createEvent: "/api/createevent",
|
|
117
|
+
// ...
|
|
118
|
+
};
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 5. Component Patterns
|
|
124
|
+
|
|
125
|
+
### List Component (STATE_VIEW)
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
129
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
130
|
+
import { useEvents } from "@/hooks/api/useEvents";
|
|
131
|
+
|
|
132
|
+
export function EventList() {
|
|
133
|
+
const { data: events = [], isLoading } = useEvents();
|
|
134
|
+
|
|
135
|
+
if (isLoading) {
|
|
136
|
+
return <Skeleton className="h-20 w-full" />;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<div className="grid gap-4 md:grid-cols-2">
|
|
141
|
+
{events.map(event => (
|
|
142
|
+
<Card key={event.id}>
|
|
143
|
+
<CardHeader><CardTitle>{event.name}</CardTitle></CardHeader>
|
|
144
|
+
<CardContent>{event.date}</CardContent>
|
|
145
|
+
</Card>
|
|
146
|
+
))}
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Dialog Component (STATE_CHANGE)
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { useState } from "react";
|
|
156
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
|
157
|
+
import { Button } from "@/components/ui/button";
|
|
158
|
+
import { Input } from "@/components/ui/input";
|
|
159
|
+
import { Label } from "@/components/ui/label";
|
|
160
|
+
import { useCreateEvent } from "@/hooks/api/useEvents";
|
|
161
|
+
import { toast } from "sonner";
|
|
162
|
+
|
|
163
|
+
export function CreateEventDialog({ open, onOpenChange }) {
|
|
164
|
+
const createEvent = useCreateEvent();
|
|
165
|
+
const [form, setForm] = useState({ name: "", date: "" });
|
|
166
|
+
|
|
167
|
+
const handleSubmit = async () => {
|
|
168
|
+
if (!form.name) return toast.error("Name required");
|
|
169
|
+
try {
|
|
170
|
+
await createEvent.mutateAsync(form);
|
|
171
|
+
toast.success("Created");
|
|
172
|
+
onOpenChange(false);
|
|
173
|
+
} catch (err) {
|
|
174
|
+
toast.error(`Error: ${err.message}`);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
180
|
+
<DialogContent>
|
|
181
|
+
<DialogHeader><DialogTitle>Create Event</DialogTitle></DialogHeader>
|
|
182
|
+
<div className="space-y-4">
|
|
183
|
+
<div>
|
|
184
|
+
<Label>Name</Label>
|
|
185
|
+
<Input value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} />
|
|
186
|
+
</div>
|
|
187
|
+
<Button onClick={handleSubmit} disabled={createEvent.isPending}>
|
|
188
|
+
Create
|
|
189
|
+
</Button>
|
|
190
|
+
</div>
|
|
191
|
+
</DialogContent>
|
|
192
|
+
</Dialog>
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Page Composition (Combine Slices)
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
export function EventsPage() {
|
|
201
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
|
202
|
+
|
|
203
|
+
return (
|
|
204
|
+
<div className="p-6">
|
|
205
|
+
<div className="flex justify-between mb-6">
|
|
206
|
+
<h1 className="text-2xl font-bold">Events</h1>
|
|
207
|
+
<Button onClick={() => setDialogOpen(true)}>Create Event</Button>
|
|
208
|
+
</div>
|
|
209
|
+
|
|
210
|
+
<EventList />
|
|
211
|
+
<CreateEventDialog open={dialogOpen} onOpenChange={setDialogOpen} />
|
|
212
|
+
</div>
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## 6. Implementation Workflow
|
|
220
|
+
|
|
221
|
+
### Step 0: Analyze Grouping
|
|
222
|
+
- Find all slices with same `groupId`
|
|
223
|
+
- Check `codeGen.uiPrompts` and `ui-prompt.md`
|
|
224
|
+
- Plan to implement together
|
|
225
|
+
|
|
226
|
+
### Step 1: Types
|
|
227
|
+
```typescript
|
|
228
|
+
// src/types/index.ts
|
|
229
|
+
export interface Event {
|
|
230
|
+
event_id: string;
|
|
231
|
+
name: string;
|
|
232
|
+
date: string;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export interface CreateEventParams {
|
|
236
|
+
name: string;
|
|
237
|
+
date: string;
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Step 2: API Functions
|
|
242
|
+
- Add endpoints to `src/lib/api-client.ts`
|
|
243
|
+
- Implement queries (Supabase) in `src/lib/api.ts`
|
|
244
|
+
- Implement commands (POST) in `src/lib/api.ts`
|
|
245
|
+
|
|
246
|
+
### Step 3: Hooks
|
|
247
|
+
- Create query/mutation hooks in `src/hooks/api/use<Entity>.ts`
|
|
248
|
+
- Export in `src/hooks/api/index.ts`
|
|
249
|
+
|
|
250
|
+
### Step 4: Components
|
|
251
|
+
- Build list component (STATE_VIEW)
|
|
252
|
+
- Build dialog/form components (STATE_CHANGE)
|
|
253
|
+
- Compose into page component
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## 7. Field Type Mapping
|
|
258
|
+
|
|
259
|
+
| JSON Type | TypeScript | UI Component |
|
|
260
|
+
|-----------|-----------|--------------|
|
|
261
|
+
| `string` | `string` | `<Input type="text">` |
|
|
262
|
+
| `number` | `number` | `<Input type="number">` |
|
|
263
|
+
| `date` | `string` | `<Input type="date">` |
|
|
264
|
+
| `time` | `string` | `<Input type="time">` |
|
|
265
|
+
| `boolean` | `boolean` | `<Switch>` or `<Checkbox>` |
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## 8. Common Patterns
|
|
270
|
+
|
|
271
|
+
**Loading**: `if (isLoading) return <Skeleton />;`
|
|
272
|
+
|
|
273
|
+
**Error Handling**:
|
|
274
|
+
```typescript
|
|
275
|
+
try {
|
|
276
|
+
await mutation.mutateAsync(params);
|
|
277
|
+
toast.success("Success");
|
|
278
|
+
} catch (err) {
|
|
279
|
+
toast.error(`Error: ${err.message}`);
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**Form State**: `const [form, setForm] = useState({ field: "" });`
|
|
284
|
+
|
|
285
|
+
**Invalidation**: `queryClient.invalidateQueries({ queryKey: ["entity"] });`
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## 9. UI Components (shadcn/ui)
|
|
290
|
+
|
|
291
|
+
Import from `@/components/ui/*`:
|
|
292
|
+
- `Button`, `Input`, `Label`, `Textarea`, `Select`
|
|
293
|
+
- `Card`, `CardHeader`, `CardTitle`, `CardContent`
|
|
294
|
+
- `Dialog`, `DialogContent`, `DialogHeader`, `DialogTitle`
|
|
295
|
+
- `Table`, `Tabs`, `Skeleton`
|
|
296
|
+
- `toast` from `sonner`
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Checklist
|
|
301
|
+
|
|
302
|
+
**Pre-Implementation**:
|
|
303
|
+
- [ ] Check `groupId` - find all related slices
|
|
304
|
+
- [ ] Read `ui-prompt.md` and `codeGen.uiPrompts`
|
|
305
|
+
- [ ] Identify STATE_VIEW vs STATE_CHANGE slices
|
|
306
|
+
|
|
307
|
+
**Implementation**:
|
|
308
|
+
- [ ] Define types in `src/types/index.ts`
|
|
309
|
+
- [ ] Add endpoints to `src/lib/api-client.ts`
|
|
310
|
+
- [ ] Implement API functions in `src/lib/api.ts`
|
|
311
|
+
- [ ] Create hooks in `src/hooks/api/use<Entity>.ts`
|
|
312
|
+
- [ ] Build components in `src/components/<domain>/`
|
|
313
|
+
- [ ] Compose page combining all grouped slices
|
|
314
|
+
- [ ] Test loading, error handling, success flows
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Quick Reference
|
|
319
|
+
|
|
320
|
+
✅ **Same `groupId`** = Implement together
|
|
321
|
+
✅ **STATE_VIEW** = Read table → Query hook → List
|
|
322
|
+
✅ **STATE_CHANGE** = Command → Mutation hook → Form/Dialog
|
|
323
|
+
✅ **Keep modular** = Sub-components for each slice capability
|
|
324
|
+
✅ **Keep simple** = Follow existing patterns, don't over-engineer
|
package/templates/prompt.md
CHANGED
|
@@ -1,139 +1,11 @@
|
|
|
1
1
|
# Ralph Agent Instructions
|
|
2
2
|
|
|
3
|
-
You are an autonomous
|
|
3
|
+
You are an autonomous software architect, oversseing the sliced architecture. working on the backend of a software project. You apply your skills to build software slices. You only work on one slice at a time.
|
|
4
4
|
|
|
5
5
|
The structure defined in the Project-Skills is relevant.
|
|
6
6
|
|
|
7
7
|
## Your Task
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
3. Make sure you are on the right branch "feature/<slicename>", if unsure, start from main.
|
|
13
|
-
5. Pick the **highest priority** slice where status is "planned" ( case insensitive ). This becomes your PRD. Set the status "InProgress" in the index.json. If no slice has status planned, reply with:
|
|
14
|
-
<promise>NO_TASKS</promise> and stop. Do not work on other slices.
|
|
15
|
-
6. Pick the slice definition from the project root /.slices in <folder> defined in the prd. Never work on more than one slice per iteration.
|
|
16
|
-
7. A slice can define additional prompts as codegen/backendPrompt. any additional prompts defined in backend are hints for the implementation of the slice and have to be taken into account. If you use the additional prompt, add a line in progress.txt
|
|
17
|
-
7. Define the slice type and load the matching skill. If the processors-array is not empty, it´s an automation slice.
|
|
18
|
-
8. Write a short progress one liner after each step to progress.txt
|
|
19
|
-
9. Analyze and Implement that single slice, make use of the skills in the skills directory, but also your previsously collected
|
|
20
|
-
knowledge. Make a list TODO list for what needs to be done. Also make sure to adjust the implementation according to the json definition. Carefully inspect events, fields and compare against the implemented slice. JSON is the desired state. ATTENTION: A "planned" task can also be just added specifications. So always look at the slice itself, but also the specifications. If specifications were added in json, which are not on code, you need to add them in code.
|
|
21
|
-
10. The slice in the json is always true, the code follows what is defined in the json
|
|
22
|
-
11. slice is only 'Done' if business logic is implemented as defined in the JSON, APIs are implemented, all scenarios in JSON are implemented in code and it
|
|
23
|
-
fulfills the slice.json. There must be no specification in json, that has no equivalent in code.
|
|
24
|
-
12. make sure to write the ui-prompt.md as defined if defined in the skill
|
|
25
|
-
13. Run quality checks ( npm run build, npm run test ) - Attention - it´s enough to run the tests for the slice. Do not run all tests.
|
|
26
|
-
14. even if the slice is fully implemented, run your test-analyzer skill and provide the code-slice.json file as defined in the skill
|
|
27
|
-
15. Update the Slice in the index.json to either `status: Done` for the completed, 'status: Planned' if rework is necessary.
|
|
28
|
-
16. If checks pass, commit ALL changes with message: `feat: [Slice Name]` and merge back to main as FF merge ( update
|
|
29
|
-
first )
|
|
30
|
-
17. Append your progress to `progress.txt` after each step in the iteration.
|
|
31
|
-
18. append your new learnings to AGENTS.md in a compressed form, reusable for future iterations. Only add learnings if they are not already there.
|
|
32
|
-
19. Finish the iteration.
|
|
33
|
-
|
|
34
|
-
## Progress Report Format
|
|
35
|
-
|
|
36
|
-
APPEND to progress.txt (never replace, always append):
|
|
37
|
-
|
|
38
|
-
```
|
|
39
|
-
## [Date/Time] - [Slice]
|
|
40
|
-
|
|
41
|
-
- What was implemented
|
|
42
|
-
- Files changed
|
|
43
|
-
- **Learnings for future iterations:**
|
|
44
|
-
- Patterns discovered (e.g., "this codebase uses X for Y")
|
|
45
|
-
- Gotchas encountered (e.g., "don't forget to update Z when changing W")
|
|
46
|
-
- Useful context (e.g., "the evaluation panel is in component X")
|
|
47
|
-
---
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
The learnings section is critical - it helps future iterations avoid repeating mistakes and understand the codebase
|
|
51
|
-
better.
|
|
52
|
-
|
|
53
|
-
## Consolidate Patterns
|
|
54
|
-
|
|
55
|
-
If you discover a **reusable pattern** that future iterations should know, add it to the `## Codebase Patterns` section
|
|
56
|
-
at the TOP of progress.txt (create it if it doesn't exist). This section should consolidate the most important
|
|
57
|
-
learnings:
|
|
58
|
-
|
|
59
|
-
```
|
|
60
|
-
## Codebase Patterns
|
|
61
|
-
- Example: Use `sql<number>` template for aggregations
|
|
62
|
-
- Example: Always use `IF NOT EXISTS` for migrations
|
|
63
|
-
- Example: Export types from actions.ts for UI components
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
Only add patterns that are **general and reusable**, not story-specific details.
|
|
67
|
-
|
|
68
|
-
## Update AGENTS.md Files
|
|
69
|
-
|
|
70
|
-
Before committing, check if any edited files have learnings worth preserving in nearby AGENTS.md files:
|
|
71
|
-
|
|
72
|
-
1. **Identify directories with edited files** - Look at which directories you modified
|
|
73
|
-
3. **Add valuable learnings that apply to all tasks** to the Agents.md - If you discovered something future developers/agents should know:
|
|
74
|
-
- API patterns or conventions specific to that module
|
|
75
|
-
- Gotchas or non-obvious requirements
|
|
76
|
-
- Dependencies between files
|
|
77
|
-
- Testing approaches for that area
|
|
78
|
-
- Configuration or environment requirements
|
|
79
|
-
|
|
80
|
-
**Examples of good AGENTS.md additions:**
|
|
81
|
-
|
|
82
|
-
- "When modifying X, also update Y to keep them in sync"
|
|
83
|
-
- "This module uses pattern Z for all API calls"
|
|
84
|
-
- "Tests require the dev server running on PORT 3000"
|
|
85
|
-
- "Field names must match the template exactly"
|
|
86
|
-
|
|
87
|
-
**Do NOT add:**
|
|
88
|
-
|
|
89
|
-
- Slice specific implementation details
|
|
90
|
-
- Story-specific implementation details
|
|
91
|
-
- Temporary debugging notes
|
|
92
|
-
- Information already in progress.txt
|
|
93
|
-
- Task speecific learnings like "- Timesheet approval requires: submitted=true, reverted=false, approved=false, declined=false"
|
|
94
|
-
|
|
95
|
-
Only update AGENTS.md if you have **genuinely reusable knowledge** that would help future work
|
|
96
|
-
|
|
97
|
-
## Quality Requirements
|
|
98
|
-
|
|
99
|
-
- ALL commits must pass your project's quality checks (typecheck, lint, test)
|
|
100
|
-
- run 'npm run build'
|
|
101
|
-
- run 'npm run test'
|
|
102
|
-
- Do NOT commit broken code
|
|
103
|
-
- Keep changes focused and minimal
|
|
104
|
-
- Follow existing code patterns
|
|
105
|
-
|
|
106
|
-
## Skills
|
|
107
|
-
|
|
108
|
-
Use the provided skills in the skills folder as guidance.
|
|
109
|
-
Update skill definitions if you find an improvement you can make.
|
|
110
|
-
|
|
111
|
-
## Specifications
|
|
112
|
-
|
|
113
|
-
For every specification added to the Slice, you need to implement one use executable Specification in Code.
|
|
114
|
-
|
|
115
|
-
A Slice is not complete if specifications are missing or can´t be executed.
|
|
116
|
-
|
|
117
|
-
## Stop Condition
|
|
118
|
-
|
|
119
|
-
After completing a user story, check if ALL slices have `status: Done`.
|
|
120
|
-
|
|
121
|
-
If ALL stories are complete and passing, reply with:
|
|
122
|
-
<promise>COMPLETE</promise>
|
|
123
|
-
|
|
124
|
-
If there are no stories with `status: Planned` (but not all are Done), reply with:
|
|
125
|
-
<promise>NO_TASKS</promise>
|
|
126
|
-
|
|
127
|
-
If there are still stories with `status: Planned`, end your response normally (another iteration will pick up the next
|
|
128
|
-
story).
|
|
129
|
-
|
|
130
|
-
## Important
|
|
131
|
-
|
|
132
|
-
- Work on ONE slice per iteration
|
|
133
|
-
- Commit frequently
|
|
134
|
-
- update progress.txt frequently
|
|
135
|
-
- Read the Codebase Patterns section in progress.txt before starting
|
|
136
|
-
|
|
137
|
-
## When an iteration completes
|
|
138
|
-
|
|
139
|
-
Use all the key learnings from the project.txt and update the Agends.md file with those learning.
|
|
9
|
+
1. find the most important next slice
|
|
10
|
+
2. if the slice is in status planned and not assigned, assign it to backend_worker (property assigned in ) and continue with backend/prompt.md. Ignore the rest of this file.
|
|
11
|
+
3. if the slice is in status planned and assigned to ui_worker, continue with frontend/prompt.md. Ignore the rest of this file.
|
package/templates/server.mjs
CHANGED
|
@@ -172,6 +172,18 @@ const server = createServer(async (req, res) => {
|
|
|
172
172
|
|
|
173
173
|
// Write all slices
|
|
174
174
|
if (config.slices) {
|
|
175
|
+
// Build a map of slice ID to group ID from sliceGroups
|
|
176
|
+
const sliceToGroupMap = new Map();
|
|
177
|
+
if (config.sliceGroups) {
|
|
178
|
+
config.sliceGroups.forEach((group) => {
|
|
179
|
+
if (group.sliceIds) {
|
|
180
|
+
group.sliceIds.forEach((sliceId) => {
|
|
181
|
+
sliceToGroupMap.set(sliceId, group.id);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
175
187
|
config.slices.forEach((slice) => {
|
|
176
188
|
const baseFolder = join(SLICES_DIR, slice.context ?? "default");
|
|
177
189
|
const sliceFolder = slice.title?.replaceAll(" ", "")?.replaceAll("slice:", "")?.toLowerCase();
|
|
@@ -184,6 +196,13 @@ const server = createServer(async (req, res) => {
|
|
|
184
196
|
const filePath = join(folder, 'slice.json');
|
|
185
197
|
const sliceData = { ...slice };
|
|
186
198
|
delete sliceData.index;
|
|
199
|
+
|
|
200
|
+
// Add group ID to slice data if it belongs to a group
|
|
201
|
+
const groupId = sliceToGroupMap.get(slice.id);
|
|
202
|
+
if (groupId) {
|
|
203
|
+
sliceData.group = groupId;
|
|
204
|
+
}
|
|
205
|
+
|
|
187
206
|
writeFileSync(filePath, JSON.stringify(sliceData, null, 2));
|
|
188
207
|
|
|
189
208
|
const sliceIndex = {
|
|
@@ -195,6 +214,11 @@ const server = createServer(async (req, res) => {
|
|
|
195
214
|
status: slice.status
|
|
196
215
|
};
|
|
197
216
|
|
|
217
|
+
// Add group ID to index entry if it belongs to a group
|
|
218
|
+
if (groupId) {
|
|
219
|
+
sliceIndex.group = groupId;
|
|
220
|
+
}
|
|
221
|
+
|
|
198
222
|
const index = sliceIndices.slices.findIndex(it => it.id == slice.id);
|
|
199
223
|
if (index == -1) {
|
|
200
224
|
sliceIndices.slices.push(sliceIndex);
|
|
@@ -223,8 +247,6 @@ const server = createServer(async (req, res) => {
|
|
|
223
247
|
}
|
|
224
248
|
|
|
225
249
|
sendJSON(res, { success: true, path: join(ROOT, fileName) });
|
|
226
|
-
console.log('🛑 Shutting down server...');
|
|
227
|
-
server.close(() => process.exit(0));
|
|
228
250
|
} catch (err) {
|
|
229
251
|
sendJSON(res, { success: false, error: err.message }, 400);
|
|
230
252
|
}
|