@tailor-platform/erp-kit 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +196 -28
  4. package/dist/cli.js +914 -0
  5. package/package.json +67 -8
  6. package/schemas/app-compose/actors.yml +34 -0
  7. package/schemas/app-compose/business-flow.yml +50 -0
  8. package/schemas/app-compose/requirements.yml +33 -0
  9. package/schemas/app-compose/resolver.yml +47 -0
  10. package/schemas/app-compose/screen.yml +81 -0
  11. package/schemas/app-compose/story.yml +67 -0
  12. package/schemas/module/command.yml +52 -0
  13. package/schemas/module/feature.yml +58 -0
  14. package/schemas/module/model.yml +70 -0
  15. package/schemas/module/module.yml +50 -0
  16. package/skills/1-module-docs/SKILL.md +111 -0
  17. package/skills/1-module-docs/references/structure.md +22 -0
  18. package/skills/2-module-feature-breakdown/SKILL.md +72 -0
  19. package/skills/2-module-feature-breakdown/references/commands.md +48 -0
  20. package/skills/2-module-feature-breakdown/references/models.md +29 -0
  21. package/skills/2-module-feature-breakdown/references/structure.md +22 -0
  22. package/skills/3-module-doc-review/SKILL.md +236 -0
  23. package/skills/3-module-doc-review/references/commands.md +54 -0
  24. package/skills/3-module-doc-review/references/models.md +29 -0
  25. package/skills/3-module-doc-review/references/testing.md +37 -0
  26. package/skills/4-module-tdd-implementation/SKILL.md +74 -0
  27. package/skills/4-module-tdd-implementation/references/commands.md +45 -0
  28. package/skills/4-module-tdd-implementation/references/db-relations.md +69 -0
  29. package/skills/4-module-tdd-implementation/references/errors.md +7 -0
  30. package/skills/4-module-tdd-implementation/references/exports.md +8 -0
  31. package/skills/4-module-tdd-implementation/references/models.md +30 -0
  32. package/skills/4-module-tdd-implementation/references/structure.md +22 -0
  33. package/skills/4-module-tdd-implementation/references/testing.md +37 -0
  34. package/skills/5-module-implementation-review/SKILL.md +408 -0
  35. package/skills/5-module-implementation-review/references/commands.md +45 -0
  36. package/skills/5-module-implementation-review/references/errors.md +7 -0
  37. package/skills/5-module-implementation-review/references/exports.md +8 -0
  38. package/skills/5-module-implementation-review/references/models.md +30 -0
  39. package/skills/5-module-implementation-review/references/testing.md +29 -0
  40. package/skills/app-compose-1-requirement-analysis/SKILL.md +89 -0
  41. package/skills/app-compose-1-requirement-analysis/references/structure.md +27 -0
  42. package/skills/app-compose-2-requirements-breakdown/SKILL.md +95 -0
  43. package/skills/app-compose-2-requirements-breakdown/references/screen-detailview.md +106 -0
  44. package/skills/app-compose-2-requirements-breakdown/references/screen-form.md +139 -0
  45. package/skills/app-compose-2-requirements-breakdown/references/screen-listview.md +153 -0
  46. package/skills/app-compose-2-requirements-breakdown/references/structure.md +27 -0
  47. package/skills/app-compose-3-doc-review/SKILL.md +116 -0
  48. package/skills/app-compose-3-doc-review/references/structure.md +27 -0
  49. package/skills/app-compose-4-design-mock/SKILL.md +256 -0
  50. package/skills/app-compose-4-design-mock/references/component.md +50 -0
  51. package/skills/app-compose-4-design-mock/references/screen-detailview.md +106 -0
  52. package/skills/app-compose-4-design-mock/references/screen-form.md +139 -0
  53. package/skills/app-compose-4-design-mock/references/screen-listview.md +153 -0
  54. package/skills/app-compose-4-design-mock/references/structure.md +27 -0
  55. package/skills/app-compose-5-design-mock-review/SKILL.md +290 -0
  56. package/skills/app-compose-5-design-mock-review/references/component.md +50 -0
  57. package/skills/app-compose-5-design-mock-review/references/screen-detailview.md +106 -0
  58. package/skills/app-compose-5-design-mock-review/references/screen-form.md +139 -0
  59. package/skills/app-compose-5-design-mock-review/references/screen-listview.md +153 -0
  60. package/skills/app-compose-6-implementation-spec/SKILL.md +127 -0
  61. package/skills/app-compose-6-implementation-spec/references/auth.md +72 -0
  62. package/skills/app-compose-6-implementation-spec/references/structure.md +27 -0
  63. package/skills/mock-scenario/SKILL.md +118 -0
  64. package/src/app.ts +1 -0
  65. package/src/cli.ts +120 -0
  66. package/src/commands/check.test.ts +30 -0
  67. package/src/commands/check.ts +66 -0
  68. package/src/commands/init.test.ts +88 -0
  69. package/src/commands/init.ts +120 -0
  70. package/src/commands/mock/index.ts +53 -0
  71. package/src/commands/mock/start.ts +179 -0
  72. package/src/commands/mock/validate.test.ts +185 -0
  73. package/src/commands/mock/validate.ts +198 -0
  74. package/src/commands/scaffold.test.ts +76 -0
  75. package/src/commands/scaffold.ts +119 -0
  76. package/src/commands/sync-check.test.ts +125 -0
  77. package/src/commands/sync-check.ts +182 -0
  78. package/src/integration.test.ts +63 -0
  79. package/src/mdschema.ts +48 -0
  80. package/src/mockServer.ts +55 -0
  81. package/src/module.ts +86 -0
  82. package/src/modules/accounting/.gitkeep +0 -0
  83. package/src/modules/coa-management/.gitkeep +0 -0
  84. package/src/modules/inventory/.gitkeep +0 -0
  85. package/src/modules/manufacturing/.gitkeep +0 -0
  86. package/src/modules/primitives/README.md +39 -0
  87. package/src/modules/primitives/command/activateCategory.test.ts +75 -0
  88. package/src/modules/primitives/command/activateCategory.ts +50 -0
  89. package/src/modules/primitives/command/activateCurrency.test.ts +70 -0
  90. package/src/modules/primitives/command/activateCurrency.ts +50 -0
  91. package/src/modules/primitives/command/activateUnit.test.ts +53 -0
  92. package/src/modules/primitives/command/activateUnit.ts +50 -0
  93. package/src/modules/primitives/command/convertAmount.test.ts +275 -0
  94. package/src/modules/primitives/command/convertAmount.ts +126 -0
  95. package/src/modules/primitives/command/convertQuantity.test.ts +219 -0
  96. package/src/modules/primitives/command/convertQuantity.ts +73 -0
  97. package/src/modules/primitives/command/createCategory.test.ts +126 -0
  98. package/src/modules/primitives/command/createCategory.ts +89 -0
  99. package/src/modules/primitives/command/createCurrency.test.ts +191 -0
  100. package/src/modules/primitives/command/createCurrency.ts +77 -0
  101. package/src/modules/primitives/command/createExchangeRate.test.ts +216 -0
  102. package/src/modules/primitives/command/createExchangeRate.ts +91 -0
  103. package/src/modules/primitives/command/createUnit.test.ts +214 -0
  104. package/src/modules/primitives/command/createUnit.ts +88 -0
  105. package/src/modules/primitives/command/deactivateCategory.test.ts +97 -0
  106. package/src/modules/primitives/command/deactivateCategory.ts +62 -0
  107. package/src/modules/primitives/command/deactivateCurrency.test.ts +85 -0
  108. package/src/modules/primitives/command/deactivateCurrency.ts +55 -0
  109. package/src/modules/primitives/command/deactivateUnit.test.ts +78 -0
  110. package/src/modules/primitives/command/deactivateUnit.ts +62 -0
  111. package/src/modules/primitives/command/setBaseCurrency.test.ts +98 -0
  112. package/src/modules/primitives/command/setBaseCurrency.ts +74 -0
  113. package/src/modules/primitives/command/setReferenceUnit.test.ts +108 -0
  114. package/src/modules/primitives/command/setReferenceUnit.ts +84 -0
  115. package/src/modules/primitives/db/currency.ts +30 -0
  116. package/src/modules/primitives/db/exchangeRate.ts +28 -0
  117. package/src/modules/primitives/db/unit.ts +32 -0
  118. package/src/modules/primitives/db/uomCategory.ts +32 -0
  119. package/src/modules/primitives/docs/commands/ActivateCategory.md +34 -0
  120. package/src/modules/primitives/docs/commands/ActivateCurrency.md +33 -0
  121. package/src/modules/primitives/docs/commands/ActivateUnit.md +34 -0
  122. package/src/modules/primitives/docs/commands/ConvertAmount.md +50 -0
  123. package/src/modules/primitives/docs/commands/ConvertQuantity.md +43 -0
  124. package/src/modules/primitives/docs/commands/CreateCategory.md +44 -0
  125. package/src/modules/primitives/docs/commands/CreateCurrency.md +47 -0
  126. package/src/modules/primitives/docs/commands/CreateExchangeRate.md +48 -0
  127. package/src/modules/primitives/docs/commands/CreateUnit.md +48 -0
  128. package/src/modules/primitives/docs/commands/DeactivateCategory.md +38 -0
  129. package/src/modules/primitives/docs/commands/DeactivateCurrency.md +38 -0
  130. package/src/modules/primitives/docs/commands/DeactivateUnit.md +38 -0
  131. package/src/modules/primitives/docs/commands/SetBaseCurrency.md +39 -0
  132. package/src/modules/primitives/docs/commands/SetReferenceUnit.md +43 -0
  133. package/src/modules/primitives/docs/features/currency-definitions.md +55 -0
  134. package/src/modules/primitives/docs/features/exchange-rates.md +61 -0
  135. package/src/modules/primitives/docs/features/unit-conversion.md +66 -0
  136. package/src/modules/primitives/docs/features/uom-categories.md +52 -0
  137. package/src/modules/primitives/docs/models/Currency.md +45 -0
  138. package/src/modules/primitives/docs/models/ExchangeRate.md +33 -0
  139. package/src/modules/primitives/docs/models/Unit.md +46 -0
  140. package/src/modules/primitives/docs/models/UoMCategory.md +44 -0
  141. package/src/modules/primitives/generated/kysely-tailordb.ts +95 -0
  142. package/src/modules/primitives/index.ts +40 -0
  143. package/src/modules/primitives/lib/errors.ts +138 -0
  144. package/src/modules/primitives/lib/types.ts +20 -0
  145. package/src/modules/primitives/module.ts +66 -0
  146. package/src/modules/primitives/permissions.ts +18 -0
  147. package/src/modules/primitives/tailor.config.ts +11 -0
  148. package/src/modules/primitives/testing/fixtures.ts +161 -0
  149. package/src/modules/product-management/.gitkeep +0 -0
  150. package/src/modules/purchase/.gitkeep +0 -0
  151. package/src/modules/sales/.gitkeep +0 -0
  152. package/src/modules/shared/createContext.test.ts +39 -0
  153. package/src/modules/shared/createContext.ts +15 -0
  154. package/src/modules/shared/defineCommand.test.ts +42 -0
  155. package/src/modules/shared/defineCommand.ts +19 -0
  156. package/src/modules/shared/definePermissions.test.ts +146 -0
  157. package/src/modules/shared/definePermissions.ts +94 -0
  158. package/src/modules/shared/entityTypes.ts +15 -0
  159. package/src/modules/shared/errors.ts +22 -0
  160. package/src/modules/shared/index.ts +1 -0
  161. package/src/modules/shared/internal.ts +13 -0
  162. package/src/modules/shared/requirePermission.test.ts +47 -0
  163. package/src/modules/shared/requirePermission.ts +8 -0
  164. package/src/modules/shared/types.ts +4 -0
  165. package/src/modules/supplier-management/.gitkeep +0 -0
  166. package/src/modules/supplier-portal/.gitkeep +0 -0
  167. package/src/modules/testing/index.ts +120 -0
  168. package/src/modules/user-management/README.md +38 -0
  169. package/src/modules/user-management/command/activateUser.test.ts +112 -0
  170. package/src/modules/user-management/command/activateUser.ts +67 -0
  171. package/src/modules/user-management/command/assignPermissionToRole.test.ts +119 -0
  172. package/src/modules/user-management/command/assignPermissionToRole.ts +87 -0
  173. package/src/modules/user-management/command/assignRoleToUser.test.ts +162 -0
  174. package/src/modules/user-management/command/assignRoleToUser.ts +93 -0
  175. package/src/modules/user-management/command/createPermission.test.ts +143 -0
  176. package/src/modules/user-management/command/createPermission.ts +66 -0
  177. package/src/modules/user-management/command/createRole.test.ts +115 -0
  178. package/src/modules/user-management/command/createRole.ts +52 -0
  179. package/src/modules/user-management/command/createUser.test.ts +198 -0
  180. package/src/modules/user-management/command/createUser.ts +85 -0
  181. package/src/modules/user-management/command/deactivateUser.test.ts +112 -0
  182. package/src/modules/user-management/command/deactivateUser.ts +67 -0
  183. package/src/modules/user-management/command/logAuditEvent.test.ts +179 -0
  184. package/src/modules/user-management/command/logAuditEvent.ts +59 -0
  185. package/src/modules/user-management/command/reactivateUser.test.ts +115 -0
  186. package/src/modules/user-management/command/reactivateUser.ts +67 -0
  187. package/src/modules/user-management/command/revokePermissionFromRole.test.ts +112 -0
  188. package/src/modules/user-management/command/revokePermissionFromRole.ts +81 -0
  189. package/src/modules/user-management/command/revokeRoleFromUser.test.ts +112 -0
  190. package/src/modules/user-management/command/revokeRoleFromUser.ts +81 -0
  191. package/src/modules/user-management/db/auditEvent.ts +47 -0
  192. package/src/modules/user-management/db/permission.ts +31 -0
  193. package/src/modules/user-management/db/role.ts +28 -0
  194. package/src/modules/user-management/db/rolePermission.ts +44 -0
  195. package/src/modules/user-management/db/user.ts +38 -0
  196. package/src/modules/user-management/db/userRole.ts +44 -0
  197. package/src/modules/user-management/docs/commands/ActivateUser.md +36 -0
  198. package/src/modules/user-management/docs/commands/AssignPermissionToRole.md +39 -0
  199. package/src/modules/user-management/docs/commands/AssignRoleToUser.md +43 -0
  200. package/src/modules/user-management/docs/commands/CreatePermission.md +35 -0
  201. package/src/modules/user-management/docs/commands/CreateRole.md +35 -0
  202. package/src/modules/user-management/docs/commands/CreateUser.md +41 -0
  203. package/src/modules/user-management/docs/commands/DeactivateUser.md +38 -0
  204. package/src/modules/user-management/docs/commands/LogAuditEvent.md +37 -0
  205. package/src/modules/user-management/docs/commands/ReactivateUser.md +37 -0
  206. package/src/modules/user-management/docs/commands/RevokePermissionFromRole.md +40 -0
  207. package/src/modules/user-management/docs/commands/RevokeRoleFromUser.md +40 -0
  208. package/src/modules/user-management/docs/features/audit-trail.md +80 -0
  209. package/src/modules/user-management/docs/features/role-based-access-control.md +76 -0
  210. package/src/modules/user-management/docs/features/user-account-management.md +64 -0
  211. package/src/modules/user-management/docs/models/AuditEvent.md +34 -0
  212. package/src/modules/user-management/docs/models/Permission.md +31 -0
  213. package/src/modules/user-management/docs/models/Role.md +31 -0
  214. package/src/modules/user-management/docs/models/RolePermission.md +33 -0
  215. package/src/modules/user-management/docs/models/User.md +47 -0
  216. package/src/modules/user-management/docs/models/UserRole.md +34 -0
  217. package/src/modules/user-management/docs/plans/2026-01-30-flattened-permissions-design.md +52 -0
  218. package/src/modules/user-management/executor/recomputeOnRolePermissionChange.ts +61 -0
  219. package/src/modules/user-management/generated/enums.ts +24 -0
  220. package/src/modules/user-management/generated/kysely-tailordb.ts +112 -0
  221. package/src/modules/user-management/index.ts +32 -0
  222. package/src/modules/user-management/lib/errors.ts +81 -0
  223. package/src/modules/user-management/lib/recomputeUserPermissions.ts +53 -0
  224. package/src/modules/user-management/lib/types.ts +31 -0
  225. package/src/modules/user-management/module.ts +77 -0
  226. package/src/modules/user-management/permissions.ts +15 -0
  227. package/src/modules/user-management/tailor.config.ts +11 -0
  228. package/src/modules/user-management/testing/fixtures.ts +98 -0
  229. package/src/schemas.ts +25 -0
  230. package/src/testing.ts +10 -0
  231. package/src/util.ts +3 -0
@@ -0,0 +1,153 @@
1
+ # ListView Screen Implementation
2
+
3
+ Implementation pattern for screens with `Screen Type: ListView`.
4
+ Assumes `page.md` and `component.md` rules.
5
+
6
+ ## File Structure
7
+
8
+ ```
9
+ {screen-path}/
10
+ ├── components/
11
+ │ └── {screen-name}-table.tsx # Table component with fragments
12
+ └── page.tsx
13
+ ```
14
+
15
+ ## Page Component (page.tsx)
16
+
17
+ Data fetching and `Layout` must be co-located in the same page component.
18
+ Do NOT split into an inner Content component — `Layout` requires `Layout.Column` as direct children.
19
+
20
+ ```tsx
21
+ const ResourcesQuery = graphql(
22
+ `
23
+ query Resources {
24
+ resources {
25
+ ...ResourceTable
26
+ }
27
+ }
28
+ `,
29
+ [ResourceTableFragment],
30
+ );
31
+
32
+ const ResourcesPage = () => {
33
+ const [{ data, error, fetching }, reexecuteQuery] = useQuery({
34
+ query: ResourcesQuery,
35
+ });
36
+
37
+ if (fetching) return <Loading />;
38
+
39
+ if (error || !data) {
40
+ return (
41
+ <ErrorFallback
42
+ title="Failed to load resources"
43
+ message="An error occurred while fetching the list."
44
+ onReset={() => reexecuteQuery({ requestPolicy: "network-only" })}
45
+ />
46
+ );
47
+ }
48
+
49
+ return (
50
+ <Layout
51
+ columns={1}
52
+ title="Resources"
53
+ actions={[
54
+ <Button key="create" asChild>
55
+ <Link to="create">Create</Link>
56
+ </Button>,
57
+ ]}
58
+ >
59
+ <Layout.Column>
60
+ <ResourceTable data={data.resources} />
61
+ </Layout.Column>
62
+ </Layout>
63
+ );
64
+ };
65
+ ```
66
+
67
+ ## Table Component (components/{screen-name}-table.tsx)
68
+
69
+ ### Fragment Collocation
70
+
71
+ Define a row fragment and a table fragment wrapping the Connection type.
72
+
73
+ ```tsx
74
+ const ResourceRowFragment = graphql(`
75
+ fragment ResourceRow on Resource {
76
+ id
77
+ title
78
+ status
79
+ createdAt
80
+ }
81
+ `);
82
+
83
+ export const ResourceTableFragment = graphql(
84
+ `
85
+ fragment ResourceTable on ResourceConnection {
86
+ edges {
87
+ node {
88
+ ...ResourceRow
89
+ }
90
+ }
91
+ }
92
+ `,
93
+ [ResourceRowFragment],
94
+ );
95
+ ```
96
+
97
+ ### Row Component
98
+
99
+ ```tsx
100
+ const ResourceRow = ({ resource: resourceFragment }: ResourceRowProps) => {
101
+ const resource = readFragment(ResourceRowFragment, resourceFragment);
102
+ return (
103
+ <TableRow>
104
+ <TableCell>{resource.title}</TableCell>
105
+ <TableCell>
106
+ <Badge variant={resource.status === "ACTIVE" ? "default" : "secondary"}>
107
+ {resource.status}
108
+ </Badge>
109
+ </TableCell>
110
+ <TableCell>
111
+ <Button variant="ghost" size="sm" asChild>
112
+ <Link to={resource.id}>View</Link>
113
+ </Button>
114
+ </TableCell>
115
+ </TableRow>
116
+ );
117
+ };
118
+ ```
119
+
120
+ ### Empty State
121
+
122
+ ```tsx
123
+ if (connection.edges.length === 0) {
124
+ return (
125
+ <EmptyState
126
+ title="No resources"
127
+ message="Get started by creating a new resource."
128
+ action={
129
+ <Button asChild>
130
+ <Link to="create">Create</Link>
131
+ </Button>
132
+ }
133
+ />
134
+ );
135
+ }
136
+ ```
137
+
138
+ ## Column Property Mapping
139
+
140
+ | Property | Implementation |
141
+ | --------------- | ----------------------------------------------------------- |
142
+ | Hideable: Yes | Column visibility state to toggle show/hide |
143
+ | Sortable: Yes | Sort icon on `<TableHead>` + onClick to toggle query vars |
144
+ | Filterable: Yes | Filter UI above table (`<Select />`) |
145
+ | Searchable: Yes | Search input above table (`<Input placeholder="Search" />`) |
146
+
147
+ ## Key Points
148
+
149
+ - Use `<Badge />` for status columns
150
+ - Format dates with `toLocaleDateString()`
151
+ - Use `<EmptyState />` with Create action for empty lists
152
+ - Add a View button per row to navigate to the detail page
153
+ - Iterate data using Connection type `edges.node` pattern
@@ -0,0 +1,127 @@
1
+ ---
2
+ name: app-compose-6-implementation-spec
3
+ description: Create Tier 4 documentation (resolvers) for GraphQL operations. Use after completing design review with app-compose-5-design-mock-review.
4
+ ---
5
+
6
+ # Implementation Spec Workflow
7
+
8
+ Create Tier 4 documentation: GraphQL Resolvers (mutations and queries).
9
+
10
+ ## Prerequisites
11
+
12
+ Tier 1-3 documentation and design mockups must exist:
13
+
14
+ - `README.md` (requirements)
15
+ - `docs/actors/*.md` (actors)
16
+ - `docs/business-flow/*/README.md` (flows)
17
+ - `docs/business-flow/*/story/*.md` (stories)
18
+ - `docs/screen/*.md` (screens)
19
+ - `docs/design.pen` (UI mockups)
20
+
21
+ ## Workflow Phases
22
+
23
+ ```
24
+ ANALYZE → IDENTIFY → CHECK MODULES → CREATE → VALIDATE
25
+ ```
26
+
27
+ ### Phase 1: Analyze
28
+
29
+ Read all story files and identify:
30
+
31
+ 1. **Operations** that modify data → mutations
32
+ 2. **Operations** that retrieve data → queries
33
+ 3. **Error scenarios** for each operation
34
+
35
+ ### Phase 2: Identify
36
+
37
+ Map stories to resolvers:
38
+
39
+ | Story Element | Resolver Type |
40
+ | -------------------- | ------------- |
41
+ | Create/Update/Delete | Mutation |
42
+ | View/List/Search | Query |
43
+ | Real-time updates | Subscription |
44
+
45
+ **Naming:** Use action-verb names: `create-`, `update-`, `delete-`, `submit-`, `approve-`
46
+
47
+ ### Phase 3: Check Module Dependencies
48
+
49
+ Resolvers reference module commands. Before creating resolver docs, verify required modules exist.
50
+
51
+ **Check existing modules:**
52
+
53
+ ```bash
54
+ ls modules/
55
+ ```
56
+
57
+ **Check module commands:**
58
+
59
+ ```bash
60
+ ls modules/<module-name>/docs/commands/
61
+ ```
62
+
63
+ **Map resolvers to modules:**
64
+
65
+ | Resolver Operation | Typical Module |
66
+ | ------------------ | --------------------- |
67
+ | User invite/roles | `user-management` |
68
+ | Supplier CRUD | `supplier-management` |
69
+ | Document handling | `document-management` |
70
+ | Task workflows | `task-management` |
71
+
72
+ **If modules don't exist:**
73
+
74
+ 1. **Identify needed modules** - Group resolver operations by domain
75
+ 2. **Create module docs first** - Use `1-module-docs` skill
76
+ 3. **Return to Tier 4** - After modules have documented commands
77
+
78
+ ```
79
+ Tier 4 blocked → Create modules → Return to Tier 4
80
+ ```
81
+
82
+ **Only reference existing module commands** in resolver documentation. Never reference modules or commands that don't exist.
83
+
84
+ ### Phase 4: Create
85
+
86
+ Generate documentation using `erp-kit` CLI:
87
+
88
+ ```bash
89
+ erp-kit scaffold --app-root examples resolver <app> <resolver-name>
90
+ ```
91
+
92
+ **Naming conventions:**
93
+
94
+ - Filename must match H1 heading exactly (kebab-case)
95
+ - Action-focused names: `create-supplier-invitation.md`
96
+
97
+ ### Phase 5: Validate
98
+
99
+ ```bash
100
+ pnpm run app:doc:check
101
+ ```
102
+
103
+ ## Schema Reference
104
+
105
+ | Schema | Tier | Output Path |
106
+ | -------------- | ---- | ------------------------- |
107
+ | `resolver.yml` | 4 | `docs/resolver/<name>.md` |
108
+
109
+ ## Tips
110
+
111
+ - One story may require 1-3 resolvers
112
+ - Group related operations logically
113
+ - Document all error scenarios
114
+
115
+ ## Completion
116
+
117
+ After Tier 4, the application specification is complete:
118
+
119
+ - **Tier 1**: Application overview
120
+ - **Tier 2**: Actors and business workflows
121
+ - **Tier 3**: User stories and screens
122
+ - **Tier 4**: Implementation specifications
123
+
124
+ ## References
125
+
126
+ - [Application structure](references/structure.md)
127
+ - [Backend auth](references/auth.md)
@@ -0,0 +1,72 @@
1
+ # Backend Auth Configuration
2
+
3
+ Use Tailor SDK auth resources as the default pattern for backend authentication setup.
4
+
5
+ ## Standard Auth Shape
6
+
7
+ In `tailor.config.ts`:
8
+
9
+ - Define IdP with `defineIdp(...)`
10
+ - Define Auth with `defineAuth(...)`
11
+ - Define static website with `defineStaticWebSite(...)` when frontend is deployed as static hosting
12
+ - Wire `idProvider` via `idp.provider(...)`
13
+ - Set exactly one OAuth2 client for frontend login (default client name: `default`)
14
+ - Export config with `auth: auth` and `idp: [idp]`
15
+ - Include static website URL in CORS when using deployed frontend (for example, `cors: ["http://localhost:5173", website.url]`)
16
+
17
+ Prefer this stable naming unless there is a clear reason to change:
18
+
19
+ - Auth name: `default`
20
+ - IdP name: `default`
21
+ - OAuth2 client name: `default`
22
+
23
+ ## User Mapping
24
+
25
+ Use `userProfile` to map authenticated identities to the application user type.
26
+
27
+ - `type`: module-provided user type
28
+ - `usernameField`: stable unique field (for example, `email`)
29
+ - `attributes`: explicitly list required attributes
30
+
31
+ Avoid implicit attribute assumptions.
32
+
33
+ ## CORS for Static Website Login
34
+
35
+ When frontend is deployed via `staticWebsites`, OAuth metadata and query calls are cross-origin from `https://<name>-<workspace>.web.erp.dev` to app backend.
36
+
37
+ - Always include the deployed static website origin via `website.url` in backend `cors`
38
+ - Keep local development origin in `cors` as well (for example, `http://localhost:5173`)
39
+ - If your template uses IP allow lists, set `allowedIpAddresses` appropriately for Tailor internal access
40
+
41
+ If `website.url` is missing from `cors`, login may fail with browser CORS errors before authentication starts.
42
+
43
+ ## Seed Permission Alignment
44
+
45
+ Seeded login users in `seed/data/User.jsonl` must receive module permissions required by guarded commands/resolvers.
46
+
47
+ - Do not assume `ADMIN` is automatically privileged unless your permission evaluator explicitly supports it
48
+ - Grant concrete permission keys defined by the module (for example, `user-management:createUser`)
49
+ - Keep `User.jsonl` permissions aligned with the module currently wired in `src/modules.ts`
50
+
51
+ ## Workspace and CLI Inputs
52
+
53
+ Use `TAILOR_PLATFORM_WORKSPACE_ID` in backend `.env` for CLI operations.
54
+
55
+ Required for non-interactive resource lookup and automation:
56
+
57
+ - `tailor-sdk oauth2client list`
58
+ - `tailor-sdk oauth2client get <name>`
59
+
60
+ Use `--env-file <backend/.env>` for deterministic command execution in local/dev scripts.
61
+
62
+ ## OAuth Client ID Source of Truth
63
+
64
+ Frontend `VITE_TAILOR_CLIENT_ID` must come from backend-managed OAuth2 client data.
65
+
66
+ Canonical retrieval flow:
67
+
68
+ 1. `tailor-sdk oauth2client get default --json`
69
+ 2. Copy `clientId` from command output
70
+ 3. Set it in frontend env
71
+
72
+ Do not hardcode OAuth client IDs in source code.
@@ -0,0 +1,27 @@
1
+ # Application Directory Structure
2
+
3
+ ```
4
+ {app_name}/
5
+ ├── backend/
6
+ │ ├── src/
7
+ │ │ ├── modules.ts # Declaring module usage
8
+ │ │ ├── modules/
9
+ │ │ │ └── {module-name}/ # Module-specific directory
10
+ │ │ │ ├── resolvers/ # API Definition to expose graphql apis
11
+ │ │ │ └── executors/ # PubSub Automation (one file per declaration)
12
+ │ │ └── generated/ # Auto-generated code (do not edit)
13
+ │ └── tailor.config.ts # tailor application config
14
+
15
+ └── frontend/
16
+ └── src/
17
+ ├── pages/ # File-based routing (auto-discovered by Vite plugin)
18
+ │ └── {page-path}/
19
+ │ ├── page.tsx
20
+ │ └── {page-path}/
21
+ │ ├── components/
22
+ │ └── page.tsx
23
+ ├── components/
24
+ │ └── ui/ # Generic UI components
25
+ ├── graphql/ # gql.tada settings
26
+ └── providers/ # react providers
27
+ ```
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: mock-scenario
3
+ description: Scaffold a new Mockoon mock scenario with CRUD routes, error scenarios, and registry updates
4
+ ---
5
+
6
+ # Mock Scenario Scaffolder
7
+
8
+ Generate a complete Mockoon mock API config for a new provider scenario and wire it into the registry.
9
+
10
+ ## Workflow
11
+
12
+ ### Step 1: Identify target API
13
+
14
+ Ask the user for:
15
+
16
+ - **Provider name** (e.g. `stripe`, `github`, `twilio`)
17
+ - **Scenario name** (e.g. `admin-api`, `payments-api`, `product-sync`)
18
+ - **Key resources to mock** (e.g. customers, invoices, messages)
19
+ - **Scenario to test** (e.g. initial full sync, incremental sync, webhook-triggered update, error recovery)
20
+
21
+ ### Step 2: Research real API
22
+
23
+ Use web search to find:
24
+
25
+ - Base URL and API version
26
+ - Authentication scheme (API key, OAuth, bearer token)
27
+ - Endpoint patterns and HTTP methods
28
+ - Response shapes for the key resources
29
+ - Error response format (status codes, error body structure)
30
+ - Rate limit headers
31
+
32
+ ### Step 3: Generate Mockoon JSON
33
+
34
+ Create `mocks/{provider}/{scenario}/mock.json` following the Shopify admin-api mock as the canonical reference (`mocks/shopify/admin-api/mock.json`).
35
+
36
+ The config must include:
37
+
38
+ - **uuid**: a valid UUID v4
39
+ - **name**: Human-readable API name
40
+ - **endpointPrefix**: Match the real API's base path
41
+ - **port**: `3000` (overridden at runtime by the reverse proxy launcher)
42
+ - **hostname**: `0.0.0.0`
43
+ - **latency**: `0`
44
+ - **folders**: `[]`
45
+ - **rootChildren**: `[]`
46
+ - **proxyMode**: `false`
47
+ - **proxyHost**: `""`
48
+ - **proxyRemovePrefix**: `false`
49
+ - **tlsOptions**: `{ "enabled": false, "type": "CERT", "pfxPath": "", "certPath": "", "keyPath": "", "caPath": "", "passphrase": "" }`
50
+ - **cors**: `true`
51
+ - **headers**: `[{ "key": "Content-Type", "value": "application/json" }]`
52
+ - **proxyReqHeaders**: `[]`
53
+ - **proxyResHeaders**: `[]`
54
+ - **callbacks**: `[]`
55
+
56
+ All UUIDs (environment, routes, responses, data buckets) must be valid UUID v4 values.
57
+
58
+ **Data buckets** — for each stateful/CRUD resource:
59
+
60
+ - 2–3 seed records with realistic field values
61
+ - Use the `id` field matching Mockoon's `"id"` property for CRUD lookup
62
+
63
+ **Routes:**
64
+
65
+ 1. **CRUD routes** — for mutable resources:
66
+
67
+ ```json
68
+ {
69
+ "type": "crud",
70
+ "endpoint": "{resource}",
71
+ "responses": [
72
+ {
73
+ "label": "CRUD {Resource}",
74
+ "statusCode": 200,
75
+ "headers": [{ "key": "Content-Type", "value": "application/json" }],
76
+ "bodyType": "DATABUCKET",
77
+ "databucketID": "{resource-bucket-id}"
78
+ }
79
+ ]
80
+ }
81
+ ```
82
+
83
+ 2. **Static routes** — for read-only endpoints:
84
+ - List endpoints returning JSON arrays
85
+ - Single-item endpoints using `{{urlParam 'id'}}` interpolation
86
+
87
+ 3. **Error scenarios** — triggered via `X-Test-Scenario` header:
88
+ - `unauthorized` → 401
89
+ - `not-found` → 404
90
+ - `rate-limit` → 429 with `Retry-After` header
91
+ - `server-error` → 500
92
+
93
+ 4. **Catch-all** — `*` endpoint returning 500 when `X-Test-Scenario: server-error`
94
+
95
+ **Every route must have:** `type`, `documentation`, `responseMode: null`, `streamingMode: null`, `streamingInterval: 0`
96
+
97
+ **Every response must have:** `latency: 0`, `bodyType`, `databucketID`, `filePath: ""`, `sendFileAsBody: false`, `rules`, `rulesOperator: "OR"`, `disableTemplating: false`, `fallbackTo404: false`, `default`, `crudKey: "id"`, `callbacks: []`, a `Content-Type` header, and a non-empty `label`
98
+
99
+ **Every rule must have:** `target`, `modifier`, `value`, `operator`, `invert: false`
100
+
101
+ ### Step 4: Generate scenario README
102
+
103
+ Create `mocks/{provider}/{scenario}/README.md` with:
104
+
105
+ - Title and one-line description
106
+ - Quick start with both methods: `erp-kit mock start` (proxy) and direct `npx @mockoon/cli start`
107
+ - Endpoints table (method, path, scenarios)
108
+ - CRUD workflow example with curl commands using proxy URL (`http://localhost:3000/{provider}/{scenario}/...`)
109
+ - Error scenario examples
110
+ - Test data description
111
+
112
+ ### Step 5: Validate
113
+
114
+ ```bash
115
+ erp-kit mock validate
116
+ ```
117
+
118
+ Fix any failures before finishing.
package/src/app.ts ADDED
@@ -0,0 +1 @@
1
+ export { createContext } from "./modules/shared/createContext";
package/src/cli.ts ADDED
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { z } from "zod";
4
+ import { defineCommand, runMain, arg } from "politty";
5
+ import { runCheck } from "./commands/check.js";
6
+ import { runSyncCheck, formatSyncCheckReport } from "./commands/sync-check.js";
7
+ import { runScaffold, ALL_TYPES, isModuleType, type ScaffoldType } from "./commands/scaffold.js";
8
+ import { runInit } from "./commands/init.js";
9
+ import { mockCommand } from "./commands/mock/index.js";
10
+
11
+ const cwd = process.cwd();
12
+
13
+ const rootArgs = z.object({
14
+ modulesRoot: arg(z.string().optional(), {
15
+ alias: "m",
16
+ description: "Path to modules directory",
17
+ }),
18
+ appRoot: arg(z.string().optional(), {
19
+ alias: "a",
20
+ description: "Path to app-compose directory (apps/ or examples/)",
21
+ }),
22
+ });
23
+
24
+ function requireRoot(args: { modulesRoot?: string; appRoot?: string }) {
25
+ const paths = { modulesRoot: args.modulesRoot, appRoot: args.appRoot };
26
+ if (!paths.modulesRoot && !paths.appRoot) {
27
+ console.error("At least one of --modules-root or --app-root is required.");
28
+ process.exit(2);
29
+ }
30
+ return paths;
31
+ }
32
+
33
+ const checkCommand = defineCommand({
34
+ name: "check",
35
+ description: "Validate docs against schemas",
36
+ args: rootArgs,
37
+ run: async (args) => {
38
+ const paths = requireRoot(args);
39
+ const exitCode = await runCheck(paths, cwd);
40
+ process.exit(exitCode);
41
+ },
42
+ });
43
+
44
+ const syncCheckCommand = defineCommand({
45
+ name: "sync-check",
46
+ description: "Validate source <-> doc correspondence",
47
+ args: rootArgs,
48
+ run: async (args) => {
49
+ const paths = requireRoot(args);
50
+ const result = await runSyncCheck(paths, cwd);
51
+ console.log(formatSyncCheckReport(result));
52
+ process.exit(result.exitCode);
53
+ },
54
+ });
55
+
56
+ const scaffoldCommand = defineCommand({
57
+ name: "scaffold",
58
+ description: "Generate doc file from schema template",
59
+ args: rootArgs.extend({
60
+ type: arg(z.enum(ALL_TYPES as unknown as [string, ...string[]]), {
61
+ positional: true,
62
+ description: `Scaffold type (${ALL_TYPES.join(", ")})`,
63
+ }),
64
+ parent: arg(z.string(), {
65
+ positional: true,
66
+ description: "Parent name (module or app name)",
67
+ }),
68
+ name: arg(z.string().optional(), {
69
+ positional: true,
70
+ description: "Item name (required for most types)",
71
+ }),
72
+ }),
73
+ run: async (args) => {
74
+ const paths = requireRoot(args);
75
+ const root = isModuleType(args.type) ? paths.modulesRoot : paths.appRoot;
76
+ if (!root) {
77
+ console.error(
78
+ `--${isModuleType(args.type) ? "modules-root" : "app-root"} is required for scaffold type "${args.type}".`,
79
+ );
80
+ process.exit(2);
81
+ }
82
+ const exitCode = await runScaffold(
83
+ args.type as ScaffoldType,
84
+ args.parent,
85
+ args.name,
86
+ root,
87
+ cwd,
88
+ );
89
+ process.exit(exitCode);
90
+ },
91
+ });
92
+
93
+ const initCommand = defineCommand({
94
+ name: "init",
95
+ description: "Set up consumer repo with framework skills",
96
+ args: z.object({
97
+ force: arg(z.boolean().default(false), {
98
+ alias: "f",
99
+ description: "Overwrite existing skills",
100
+ }),
101
+ }),
102
+ run: (args) => {
103
+ const exitCode = runInit(cwd, args.force);
104
+ process.exit(exitCode);
105
+ },
106
+ });
107
+
108
+ const main = defineCommand({
109
+ name: "erp-kit",
110
+ description: "Documentation validation and scaffolding tool",
111
+ subCommands: {
112
+ check: checkCommand,
113
+ "sync-check": syncCheckCommand,
114
+ scaffold: scaffoldCommand,
115
+ init: initCommand,
116
+ mock: mockCommand,
117
+ },
118
+ });
119
+
120
+ void runMain(main);
@@ -0,0 +1,30 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { buildCheckTargets } from "./check.js";
3
+
4
+ describe("buildCheckTargets", () => {
5
+ it("generates module targets when modulesRoot is set", () => {
6
+ const targets = buildCheckTargets({ modulesRoot: "modules", appRoot: undefined });
7
+ expect(targets).toEqual([
8
+ { glob: "modules/[a-zA-Z]*/docs/features/*.md", schemaKey: "feature" },
9
+ { glob: "modules/[a-zA-Z]*/docs/commands/*.md", schemaKey: "command" },
10
+ { glob: "modules/[a-zA-Z]*/docs/models/*.md", schemaKey: "model" },
11
+ { glob: "modules/[a-zA-Z]*/README.md", schemaKey: "module" },
12
+ ]);
13
+ });
14
+
15
+ it("generates app-compose targets when appRoot is set", () => {
16
+ const targets = buildCheckTargets({ modulesRoot: undefined, appRoot: "apps" });
17
+ expect(targets[0].glob).toBe("apps/[a-zA-Z]*/README.md");
18
+ expect(targets).toHaveLength(6);
19
+ });
20
+
21
+ it("generates both when both roots are set", () => {
22
+ const targets = buildCheckTargets({ modulesRoot: "modules", appRoot: "examples" });
23
+ expect(targets).toHaveLength(10);
24
+ });
25
+
26
+ it("returns empty when neither root is set", () => {
27
+ const targets = buildCheckTargets({ modulesRoot: undefined, appRoot: undefined });
28
+ expect(targets).toHaveLength(0);
29
+ });
30
+ });