@open-mercato/cli 0.5.1-develop.2972.6c5cd4a1c3 → 0.5.1-develop.2975.ccbadc8198
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/AGENTS.md +5 -1
- package/dist/agentic/shared/AGENTS.md.template +14 -12
- package/dist/agentic/shared/ai/skills/auto-continue-pr/STANDALONE.md +1 -1
- package/dist/agentic/shared/ai/skills/auto-create-pr/STANDALONE.md +1 -1
- package/dist/agentic/shared/ai/skills/auto-fix-github/STANDALONE.md +1 -1
- package/dist/agentic/shared/ai/skills/auto-review-pr/SKILL.md +2 -2
- package/dist/agentic/shared/ai/skills/auto-review-pr/STANDALONE.md +1 -1
- package/dist/agentic/shared/ai/skills/backend-ui-design/SKILL.md +25 -2
- package/dist/agentic/shared/ai/skills/backend-ui-design/references/ui-components.md +12 -7
- package/dist/agentic/shared/ai/skills/code-review/SKILL.md +3 -3
- package/dist/agentic/shared/ai/skills/code-review/references/review-checklist.md +1 -1
- package/dist/agentic/shared/ai/skills/data-model-design/SKILL.md +21 -12
- package/dist/agentic/shared/ai/skills/implement-spec/SKILL.md +2 -2
- package/dist/agentic/shared/ai/skills/module-scaffold/SKILL.md +16 -12
- package/dist/agentic/shared/ai/skills/troubleshooter/SKILL.md +17 -8
- package/package.json +5 -5
package/AGENTS.md
CHANGED
|
@@ -49,7 +49,11 @@ yarn db:generate # Generate migrations for all modules (writes to src/modules/
|
|
|
49
49
|
yarn db:migrate # Apply all pending migrations (ordered, directory first)
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
Default workflow: update ORM entities in `data/entities.ts`, then run `yarn db:generate` to emit SQL and keep `.snapshot-open-mercato.json` in sync.
|
|
53
|
+
|
|
54
|
+
Coding-agent exception: if `yarn db:generate` emits unrelated migrations because another module's snapshot is stale, do not commit the noise. Delete unrelated generated files, keep or write only the SQL for the intended entity change, and update the affected module's `migrations/.snapshot-open-mercato.json` to the post-change schema. The snapshot update is mandatory; without it, standalone apps will regenerate already-committed migrations.
|
|
55
|
+
|
|
56
|
+
Do not run `yarn db:migrate` as part of generation unless the user explicitly asks to apply migrations. A PR should normally include the migration file plus snapshot, not depend on local DB state.
|
|
53
57
|
|
|
54
58
|
## Standalone App Considerations
|
|
55
59
|
|
|
@@ -41,7 +41,7 @@ step, you WILL produce incorrect imports and miss required patterns.
|
|
|
41
41
|
|
|
42
42
|
| Task | Load |
|
|
43
43
|
|---|---|
|
|
44
|
-
| Add/modify an entity, create migration | `.ai/guides/core.md` → Module Files, then `yarn
|
|
44
|
+
| Add/modify an entity, create migration | `.ai/skills/data-model-design/SKILL.md`, `.ai/guides/core.md` → Module Files, then `yarn db:generate` |
|
|
45
45
|
| Add a REST API endpoint | `.ai/guides/core.md` → API Routes |
|
|
46
46
|
| Add a backend page | `.ai/guides/ui.md` → CrudForm / DataTable |
|
|
47
47
|
| Configure sidebar navigation, page groups, settings pages | `.ai/skills/module-scaffold/references/navigation-patterns.md` |
|
|
@@ -135,11 +135,12 @@ Register in `src/modules.ts`: `{ id: '<id>', from: '@app' }`
|
|
|
135
135
|
|
|
136
136
|
## CRITICAL rules — always follow without exception
|
|
137
137
|
|
|
138
|
-
1. **
|
|
138
|
+
1. **Entity classes live in `src/modules/<module>/data/entities.ts` and MUST import decorators from `@mikro-orm/decorators/legacy`.** Start there for every schema change.
|
|
139
139
|
2. **After editing `src/modules.ts`** or any structural module file: run `yarn generate`
|
|
140
140
|
3. **Never edit `.mercato/generated/*`** — auto-generated. Never edit `node_modules/@open-mercato/*` — eject instead.
|
|
141
|
-
4. **
|
|
142
|
-
5. **
|
|
141
|
+
4. **After editing `src/modules/<module>/data/entities.ts`**: run `yarn db:generate` as a schema-diff probe. Default to the generated SQL, but if it emits unrelated churn, keep or write only the scoped SQL for your module and update `src/modules/<module>/migrations/.snapshot-open-mercato.json` in the same change.
|
|
142
|
+
5. **Confirm migrations with user** before running `yarn db:migrate`
|
|
143
|
+
6. **API route files MUST export `metadata`.** Every `src/modules/<module>/api/**/route.ts` that exports an HTTP handler (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`) MUST also export a `metadata` object describing per-method auth, otherwise the generator emits the warning `[generate] ⚠ Route file exports handlers but no metadata — auth will default to required` and every method silently falls back to "authentication required". Use the per-method shape:
|
|
143
144
|
```ts
|
|
144
145
|
export const metadata = {
|
|
145
146
|
GET: { requireAuth: true, requireFeatures: ['mymodule.view'] },
|
|
@@ -147,13 +148,13 @@ Register in `src/modules.ts`: `{ id: '<id>', from: '@app' }`
|
|
|
147
148
|
}
|
|
148
149
|
```
|
|
149
150
|
For public endpoints, opt out explicitly with `{ requireAuth: false }`. Do not use the legacy top-level `export const requireAuth` / `export const requireFeatures` — they are no longer recognised.
|
|
150
|
-
|
|
151
|
-
|
|
151
|
+
7. **Write migrations in one shot.** `yarn dev` auto-applies pending migrations at startup by default (`OM_DEV_AUTO_MIGRATE=1`). Once a migration has been applied, editing the same file usually has no effect — the next migrate pass skips it as already-applied. If `yarn db:generate` shows unrelated churn, manual SQL for the intended module is allowed, but you MUST also update that module's `.snapshot-open-mercato.json`. Never hand-edit a historical migration that has already shipped; add a **new** migration instead.
|
|
152
|
+
8. **After the user adds a new module, offer to trim classic mode.** A fresh `create-mercato-app` scaffold enables every built-in module (classic mode). Once the user has added their own custom module, the defaults are usually dead weight. **Ask the user** (via a short `AskUserQuestion`) whether they want to disable built-in modules that are not needed for their project. If they say yes, invoke the `trim-unused-modules` skill — do NOT hand-craft the slimdown inside the AGENTS.md reading flow. If they say no, preserve classic mode silently.
|
|
152
153
|
|
|
153
154
|
**Dashboards fallback rule.** When the user (or the `trim-unused-modules` skill) disables the `dashboards` module, you MUST update `src/app/(backend)/backend/page.tsx` so it no longer renders `<DashboardScreen />`. Replace the dashboard render with a `redirect(...)` to the first enabled backend page for the current user — preferring pages already registered in the main sidebar group and respecting the admin/superadmin role of the caller. Otherwise `/backend` will crash at build or request time because the removed module no longer ships `DashboardScreen`. Always fall back to `/backend/profile` only if no other backend page is available.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
9. **New features MUST be visible to admin/superadmin immediately.** Every time you add a new feature ID (e.g. `my_module.view`, `my_module.manage`) to `src/modules/<module>/acl.ts`, you MUST also (a) add that feature to `defaultRoleFeatures` in the same module's `setup.ts` so the admin and superadmin roles get it on every tenant setup; and (b) run `yarn mercato auth sync-role-acls --all-tenants` so existing tenants pick up the new feature without a reinstall. Do this automatically unless the user has explicitly said otherwise — the user should see the features you are building, not stare at a blank admin because their role is missing a grant. Feature IDs are FROZEN once shipped; if a rename is required, add the new ID alongside, grant it, and keep the old one as a deprecated alias.
|
|
156
|
+
10. **Strict Design System alignment for every UI change.** Any UI you add or edit MUST use the Open Mercato design system components and tokens. No hardcoded Tailwind status colors (`text-red-500`, `bg-green-100`, etc.) — use semantic tokens (`text-status-error-text`, `bg-status-success-bg`, …). No arbitrary text sizes (`text-[11px]`, `text-[13px]`) — use the Tailwind scale (`text-xs`, `text-sm`, `text-base`, `text-lg`, `text-xl`, `text-2xl`) or the `text-overline` token for 11px uppercase labels. In PAGE BODY UI, use `lucide-react` icons (never inline `<svg>`). Use `StatusBadge` for entity status, `Alert` for inline feedback, `FormField` for standalone form inputs, `SectionHeader` for detail-page section headings, `CollapsibleSection` for collapsible regions, `LoadingMessage`/`Spinner`/`DataLoader` for async states, and `EmptyState` (or DataTable's `emptyState` prop) for empty lists. For list pages, follow `.ai/skills/backend-ui-design/SKILL.md` and prefer the `DataTable` host pattern shown there (`entityId`, `apiPath`, stable `extensionTableId`, and explicit pagination props when you own the data source). Every dialog MUST support `Cmd/Ctrl+Enter` to submit and `Escape` to cancel. Every icon-only button MUST have an `aria-label`. These rules apply to `src/modules/<module>/backend/**` and `src/modules/<module>/frontend/**` alike.
|
|
157
|
+
11. **BEFORE writing ANY code**, you MUST:
|
|
157
158
|
- Match your task against the **Task → Context Map** above
|
|
158
159
|
- `Read` every file listed in the "Load" column for your task type
|
|
159
160
|
- Only then proceed to implementation
|
|
@@ -163,6 +164,7 @@ Register in `src/modules.ts`: `{ id: '<id>', from: '@app' }`
|
|
|
163
164
|
## Additional Conventions
|
|
164
165
|
|
|
165
166
|
- Custom modules use `from: '@app'` in `src/modules.ts`
|
|
167
|
+
- Entity classes belong in `src/modules/<module>/data/entities.ts` and use decorators from `@mikro-orm/decorators/legacy`
|
|
166
168
|
- Standalone apps expose `yarn mercato configs cache ...` because the template enables the `configs` module from `@open-mercato/core`
|
|
167
169
|
- `yarn generate` automatically runs a best-effort structural cache purge (`yarn mercato configs cache structural --all-tenants`) after successful generation; if the cache command is unavailable, generation still succeeds
|
|
168
170
|
- Detail/read-model APIs that expose `customFields` MUST return bare field keys via `normalizeCustomFieldResponse()` (for example `{ priority: 3 }`). Keep `cf_` / `cf:` prefixes for request payloads, filters, and form field IDs only.
|
|
@@ -170,7 +172,7 @@ Register in `src/modules.ts`: `{ id: '<id>', from: '@app' }`
|
|
|
170
172
|
- `page.meta.ts` MUST include `pageGroup`, `pageGroupKey`, and `pageOrder` for sidebar grouping
|
|
171
173
|
- Settings pages MUST use `pageContext: 'settings' as const` with `navHidden: true`
|
|
172
174
|
- All related pages within a module MUST share the same `pageGroupKey`
|
|
173
|
-
- DataTable MUST
|
|
175
|
+
- DataTable hosts MUST keep `extensionTableId` stable; when you own pagination state, wire `page`, `pageSize`, `totalCount`, and `onPageChange`
|
|
174
176
|
|
|
175
177
|
## Naming Conventions
|
|
176
178
|
|
|
@@ -227,8 +229,8 @@ import type { ApiInterceptor } from '@open-mercato/shared/lib/crud/api-intercept
|
|
|
227
229
|
| `yarn generate` | Regenerate `.mercato/generated/` |
|
|
228
230
|
| `yarn mercato configs cache structural --all-tenants` | Manually purge structural navigation/sidebar cache entries |
|
|
229
231
|
| `yarn mercato module add <package>` | Install and enable an official module package |
|
|
230
|
-
| `yarn
|
|
231
|
-
| `yarn
|
|
232
|
+
| `yarn db:generate` | Probe/create migration SQL for entity changes |
|
|
233
|
+
| `yarn db:migrate` | Apply pending migrations after user confirmation |
|
|
232
234
|
| `yarn initialize` | Bootstrap DB + first admin account |
|
|
233
235
|
| `yarn build` | Build for production |
|
|
234
236
|
| `yarn mercato eject <module>` | Copy a core module into `src/modules/` |
|
|
@@ -53,7 +53,7 @@ gh label create in-progress --color c5def5 --description "Auto-skill is wo
|
|
|
53
53
|
|
|
54
54
|
## 3. Validation gate probes `package.json` scripts
|
|
55
55
|
|
|
56
|
-
SKILL.md lists commands like `yarn typecheck`, `yarn test`, `yarn generate`, `yarn build:packages`, `yarn build:app`, `yarn i18n:check-sync`, `yarn i18n:check-usage`.
|
|
56
|
+
SKILL.md lists commands like `yarn typecheck`, `yarn test`, `yarn generate`, `yarn build:packages`, `yarn build:app`, `yarn i18n:check-sync`, `yarn i18n:check-usage`. The current standalone template ships `yarn build`, `yarn typecheck`, `yarn test`, `yarn generate`, `yarn db:generate`, and `yarn db:migrate`; monorepo-specific `build:packages`, `build:app`, and `i18n:*` scripts usually do not exist.
|
|
57
57
|
|
|
58
58
|
Before running each step, probe:
|
|
59
59
|
|
|
@@ -53,7 +53,7 @@ gh label create in-progress --color c5def5 --description "Auto-skill is wo
|
|
|
53
53
|
|
|
54
54
|
## 3. Validation gate probes `package.json` scripts
|
|
55
55
|
|
|
56
|
-
SKILL.md lists commands like `yarn typecheck`, `yarn test`, `yarn generate`, `yarn build:packages`, `yarn build:app`, `yarn i18n:check-sync`, `yarn i18n:check-usage`.
|
|
56
|
+
SKILL.md lists commands like `yarn typecheck`, `yarn test`, `yarn generate`, `yarn build:packages`, `yarn build:app`, `yarn i18n:check-sync`, `yarn i18n:check-usage`. The current standalone template ships `yarn build`, `yarn typecheck`, `yarn test`, `yarn generate`, `yarn db:generate`, and `yarn db:migrate`; monorepo-specific `build:packages`, `build:app`, and `i18n:*` scripts usually do not exist.
|
|
57
57
|
|
|
58
58
|
Before running each step, probe:
|
|
59
59
|
|
|
@@ -53,7 +53,7 @@ gh label create in-progress --color c5def5 --description "Auto-skill is wo
|
|
|
53
53
|
|
|
54
54
|
## 3. Validation gate probes `package.json` scripts
|
|
55
55
|
|
|
56
|
-
SKILL.md lists commands like `yarn typecheck`, `yarn test`, `yarn generate`, `yarn build:packages`, `yarn build:app`, `yarn i18n:check-sync`, `yarn i18n:check-usage`.
|
|
56
|
+
SKILL.md lists commands like `yarn typecheck`, `yarn test`, `yarn generate`, `yarn build:packages`, `yarn build:app`, `yarn i18n:check-sync`, `yarn i18n:check-usage`. The current standalone template ships `yarn build`, `yarn typecheck`, `yarn test`, `yarn generate`, `yarn db:generate`, and `yarn db:migrate`; monorepo-specific `build:packages`, `build:app`, and `i18n:*` scripts usually do not exist.
|
|
57
57
|
|
|
58
58
|
Before running each step, probe:
|
|
59
59
|
|
|
@@ -282,8 +282,8 @@ Record findings from the patterns below. These are mandatory findings, not optio
|
|
|
282
282
|
| Hardcoded user-facing string in API errors or UI labels | Medium: must use i18n |
|
|
283
283
|
| New `any` type annotation outside tests | Medium: use zod plus `z.infer` |
|
|
284
284
|
| `alert(` or custom toast instead of `flash()` | Medium: use `flash()` |
|
|
285
|
-
| Hand-written migration SQL file | Medium:
|
|
286
|
-
| Entity schema changed but no migration file in the diff | Medium:
|
|
285
|
+
| Hand-written migration SQL file without snapshot update or scope rationale | Medium: prefer generated migrations; manual SQL must be scoped and update `.snapshot-open-mercato.json` |
|
|
286
|
+
| Entity schema changed but no migration file or no-op rationale in the diff | Medium: create a scoped migration and update the snapshot |
|
|
287
287
|
| Missing explicit tenant scoping in sub-entity queries | Medium: defense in depth |
|
|
288
288
|
| New or modified i18n locale JSON keys not in alphabetical order | Medium: CI i18n-check-sync requires sorted keys — run `yarn i18n:check-sync --fix` or sort manually |
|
|
289
289
|
|
|
@@ -53,7 +53,7 @@ gh label create in-progress --color c5def5 --description "Auto-skill is wo
|
|
|
53
53
|
|
|
54
54
|
## 3. Validation gate probes `package.json` scripts
|
|
55
55
|
|
|
56
|
-
SKILL.md lists commands like `yarn typecheck`, `yarn test`, `yarn generate`, `yarn build:packages`, `yarn build:app`, `yarn i18n:check-sync`, `yarn i18n:check-usage`.
|
|
56
|
+
SKILL.md lists commands like `yarn typecheck`, `yarn test`, `yarn generate`, `yarn build:packages`, `yarn build:app`, `yarn i18n:check-sync`, `yarn i18n:check-usage`. The current standalone template ships `yarn build`, `yarn typecheck`, `yarn test`, `yarn generate`, `yarn db:generate`, and `yarn db:migrate`; monorepo-specific `build:packages`, `build:app`, and `i18n:*` scripts usually do not exist.
|
|
57
57
|
|
|
58
58
|
Before running each step, probe:
|
|
59
59
|
|
|
@@ -7,7 +7,7 @@ description: Design and implement consistent backend/backoffice interfaces using
|
|
|
7
7
|
|
|
8
8
|
Guide for creating consistent, production-grade backend interfaces using the `@open-mercato/ui` component library. All implementations must use existing components for visual and behavioral consistency.
|
|
9
9
|
|
|
10
|
-
For complete component API reference, see `references/ui-components.md`.
|
|
10
|
+
For complete component API reference, see `references/ui-components.md`. Pair this skill with `.ai/guides/ui.md` when present and with the standalone `AGENTS.md` rules for DataTable hosts, design-system primitives, and backend page conventions.
|
|
11
11
|
|
|
12
12
|
## Design Principles
|
|
13
13
|
|
|
@@ -16,6 +16,7 @@ For complete component API reference, see `references/ui-components.md`.
|
|
|
16
16
|
3. **Data Density**: Admin users need information-rich interfaces. Optimize for scanning.
|
|
17
17
|
4. **Keyboard Navigation**: `Cmd/Ctrl+Enter` for primary actions, `Escape` to cancel.
|
|
18
18
|
5. **Clear Hierarchy**: Page → Section → Content. Use `PageHeader`, `PageBody`, consistent spacing.
|
|
19
|
+
6. **Design System Discipline**: Use semantic status tokens plus shared primitives like `StatusBadge`, `Alert`, `FormField`, `SectionHeader`, `CollapsibleSection`, and `EmptyState`. No hardcoded status colors or arbitrary text sizes.
|
|
19
20
|
|
|
20
21
|
## Required Component Library
|
|
21
22
|
|
|
@@ -50,6 +51,26 @@ Column patterns:
|
|
|
50
51
|
- Status/enum: `EnumBadge` with severity presets
|
|
51
52
|
- Actions: `RowActions` for context menus
|
|
52
53
|
|
|
54
|
+
### Preferred DataTable Host Pattern
|
|
55
|
+
|
|
56
|
+
For standard CRUD lists, prefer the built-in host pattern instead of manually fetching and shaping rows:
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
<DataTable
|
|
60
|
+
entityId="tickets.ticket"
|
|
61
|
+
apiPath="tickets/tickets"
|
|
62
|
+
extensionTableId="tickets.ticket"
|
|
63
|
+
columns={columns}
|
|
64
|
+
createHref="/backend/tickets/tickets/new"
|
|
65
|
+
emptyState={{
|
|
66
|
+
title: t('tickets.list.empty.title'),
|
|
67
|
+
description: t('tickets.list.empty.description'),
|
|
68
|
+
}}
|
|
69
|
+
/>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Keep `extensionTableId` stable so DataTable injections remain backward-compatible.
|
|
73
|
+
|
|
53
74
|
### DataTable Pagination
|
|
54
75
|
|
|
55
76
|
DataTable MUST be configured with pagination props to display all data correctly. Without these, the table only shows the first page with no way to navigate:
|
|
@@ -182,6 +203,8 @@ import { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customF
|
|
|
182
203
|
- [ ] Loading states use `LoadingMessage` or `DataLoader`
|
|
183
204
|
- [ ] Error states use `ErrorMessage`, `ErrorNotice`, or `Notice variant="error"`
|
|
184
205
|
- [ ] Empty states use `EmptyState`
|
|
206
|
+
- [ ] Status displays use `StatusBadge` or `EnumBadge`, not hardcoded colors
|
|
207
|
+
- [ ] Standalone inputs use `FormField`; detail sections use `SectionHeader` / `CollapsibleSection` when applicable
|
|
185
208
|
- [ ] Column truncation uses `meta.truncate` and `meta.maxWidth`
|
|
186
209
|
- [ ] Boolean values use `BooleanIcon`
|
|
187
210
|
- [ ] Status/enum values use `EnumBadge`
|
|
@@ -194,7 +217,7 @@ import { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customF
|
|
|
194
217
|
2. Manual table markup — use `DataTable`
|
|
195
218
|
3. Custom toast/notification — use `flash()`
|
|
196
219
|
4. Inline styles — use Tailwind classes
|
|
197
|
-
5. Hardcoded colors — use theme variables
|
|
220
|
+
5. Hardcoded colors or status classes — use theme variables and semantic status tokens
|
|
198
221
|
6. Missing loading states — every async operation needs feedback
|
|
199
222
|
7. Missing error handling — every failure needs messaging
|
|
200
223
|
8. Missing keyboard shortcuts — all dialogs need `Cmd+Enter` and `Escape`
|
|
@@ -47,7 +47,7 @@ Complete reference of all available UI components in `@open-mercato/ui`.
|
|
|
47
47
|
|
|
48
48
|
| Component | Import Path | Purpose | Key Props |
|
|
49
49
|
|-----------|-------------|---------|-----------|
|
|
50
|
-
| **DataTable** | `@open-mercato/ui/backend/DataTable` | Feature-rich table with sorting, filtering, pagination, export, perspectives | `columns`, `data`, `
|
|
50
|
+
| **DataTable** | `@open-mercato/ui/backend/DataTable` | Feature-rich table with sorting, filtering, pagination, export, perspectives | `entityId`, `apiPath`, `extensionTableId`, `columns`, `data`, `page`, `pageSize`, `totalCount`, `onPageChange`, `onRowClick` |
|
|
51
51
|
| **TruncatedCell** | `@open-mercato/ui/backend/TruncatedCell` | Table cell with text truncation and tooltip | `value`, `maxWidth` |
|
|
52
52
|
| **EmptyState** | `@open-mercato/ui/backend/EmptyState` | Empty state placeholder | `title`, `description`, `action`, `icon` |
|
|
53
53
|
| **RowActions** | `@open-mercato/ui/backend/RowActions` | Context menu for row actions | `items: {label, href?, onSelect?, destructive?}[]` |
|
|
@@ -127,14 +127,18 @@ const filters: FilterDef[] = [
|
|
|
127
127
|
]
|
|
128
128
|
|
|
129
129
|
<DataTable
|
|
130
|
-
|
|
130
|
+
entityId="inventory.item"
|
|
131
|
+
apiPath="inventory/items"
|
|
132
|
+
extensionTableId="inventory.item"
|
|
131
133
|
columns={columns}
|
|
132
|
-
data={data}
|
|
133
134
|
filters={filters}
|
|
134
135
|
filterValues={filterValues}
|
|
135
136
|
onFiltersApply={handleFiltersApply}
|
|
136
137
|
onFiltersClear={handleFiltersClear}
|
|
137
|
-
|
|
138
|
+
page={page}
|
|
139
|
+
pageSize={pageSize}
|
|
140
|
+
totalCount={totalCount}
|
|
141
|
+
onPageChange={setPage}
|
|
138
142
|
onRowClick={(row) => router.push(`/items/${row.id}`)}
|
|
139
143
|
/>
|
|
140
144
|
```
|
|
@@ -228,6 +232,7 @@ const deleted = await deleteCrud('module/items', id)
|
|
|
228
232
|
1. **Always use `flash()` for notifications** - Don't use `alert()` or custom toast implementations
|
|
229
233
|
2. **Use `CrudForm` for forms** - Provides consistent validation, field rendering, and keyboard shortcuts
|
|
230
234
|
3. **Use `DataTable` for lists** - Includes filtering, sorting, pagination, export, and perspectives
|
|
231
|
-
4. **
|
|
232
|
-
5. **
|
|
233
|
-
6. **
|
|
235
|
+
4. **Keep `extensionTableId` stable** - Injection spots must remain backward-compatible
|
|
236
|
+
5. **Use `JsonBuilder` for JSON editing** - Provides both raw JSON and visual builder modes
|
|
237
|
+
6. **Dialog forms need `embedded={true}`** - And add `[&_.grid]:!grid-cols-1` to DialogContent for single-column layout
|
|
238
|
+
7. **Support Cmd/Ctrl+Enter and Escape** - All dialogs should support these keyboard shortcuts
|
|
@@ -98,7 +98,7 @@ Omit empty severity sections.
|
|
|
98
98
|
|
|
99
99
|
### Data Integrity
|
|
100
100
|
|
|
101
|
-
- **
|
|
101
|
+
- **Migration files and snapshots must match entity intent** — prefer `yarn db:generate`; scoped manual SQL is allowed only to avoid unrelated generated churn and must include `.snapshot-open-mercato.json`
|
|
102
102
|
- **Validate migration scope** — autogenerated doesn't mean correct
|
|
103
103
|
- **Workers/subscribers MUST be idempotent**
|
|
104
104
|
- **Commands MUST be undoable** — include before/after snapshots
|
|
@@ -130,8 +130,8 @@ Omit empty severity sections.
|
|
|
130
130
|
## Review Heuristics
|
|
131
131
|
|
|
132
132
|
1. **New files**: Check if `yarn generate` is needed. Verify auto-discovery paths.
|
|
133
|
-
2. **Entity changes**: Check if
|
|
134
|
-
3. **Migration sanity**: Inspect SQL content. Reject unrelated schema churn.
|
|
133
|
+
2. **Entity changes**: Check if migration and snapshot updates are needed. Look for missing tenant columns.
|
|
134
|
+
3. **Migration sanity**: Inspect SQL content and `.snapshot-open-mercato.json`. Reject unrelated schema churn.
|
|
135
135
|
4. **New API routes**: Verify `openApi` export, auth guards, zod validation, tenant filtering.
|
|
136
136
|
5. **Event emitters**: Verify event is declared in `events.ts` with `as const`.
|
|
137
137
|
6. **Commands**: Verify undoable, before/after snapshots.
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
## 3. Data Integrity & ORM
|
|
22
22
|
|
|
23
|
-
- [ ]
|
|
23
|
+
- [ ] Migration workflow is coherent — `yarn db:generate` was used as the default probe, or scoped manual SQL is justified and paired with a matching `.snapshot-open-mercato.json` update
|
|
24
24
|
- [ ] Migration scope matches PR intent (no unrelated schema churn)
|
|
25
25
|
- [ ] UUID primary keys with standard columns (`id`, `created_at`, `updated_at`)
|
|
26
26
|
- [ ] Soft delete via `deleted_at` where applicable
|
|
@@ -37,8 +37,10 @@ When the developer describes data requirements:
|
|
|
37
37
|
|
|
38
38
|
### Standard Entity Template
|
|
39
39
|
|
|
40
|
+
Define entities in `src/modules/<module_id>/data/entities.ts`. Standalone apps keep the module's entity classes together there unless the file becomes large enough that a split is justified.
|
|
41
|
+
|
|
40
42
|
```typescript
|
|
41
|
-
import { Entity,
|
|
43
|
+
import { Entity, Enum, Index, PrimaryKey, Property } from '@mikro-orm/decorators/legacy'
|
|
42
44
|
import { v4 } from 'uuid'
|
|
43
45
|
|
|
44
46
|
@Entity({ tableName: '<entities>' })
|
|
@@ -322,14 +324,15 @@ const enricher: ResponseEnricher = {
|
|
|
322
324
|
### Creating a Migration
|
|
323
325
|
|
|
324
326
|
```bash
|
|
325
|
-
# 1. Modify
|
|
326
|
-
# 2.
|
|
327
|
+
# 1. Modify src/modules/<module_id>/data/entities.ts
|
|
328
|
+
# 2. Probe/generate migration
|
|
327
329
|
yarn db:generate
|
|
328
330
|
|
|
329
|
-
# 3. Review the generated migration
|
|
331
|
+
# 3. Review the generated migration or use it as the baseline for scoped manual SQL
|
|
330
332
|
# Check src/modules/<module_id>/migrations/Migration_YYYYMMDD_HHMMSS.ts
|
|
331
333
|
|
|
332
|
-
# 4.
|
|
334
|
+
# 4. Update src/modules/<module_id>/migrations/.snapshot-open-mercato.json
|
|
335
|
+
# 5. Apply migration only after explicit user confirmation
|
|
333
336
|
yarn db:migrate
|
|
334
337
|
```
|
|
335
338
|
|
|
@@ -337,9 +340,12 @@ yarn db:migrate
|
|
|
337
340
|
|
|
338
341
|
1. **Review every migration** — auto-generated doesn't mean correct
|
|
339
342
|
2. **Check for unintended changes** — sometimes generators pick up unrelated diffs
|
|
340
|
-
3. **
|
|
341
|
-
4. **
|
|
342
|
-
5. **
|
|
343
|
+
3. **Do not commit unrelated generated migrations** — delete them from the diff
|
|
344
|
+
4. **Scoped manual SQL is allowed** when generator churn is unrelated, but the migration and `.snapshot-open-mercato.json` must still describe the same post-change schema
|
|
345
|
+
5. **Update `.snapshot-open-mercato.json`** — it is the baseline that prevents duplicate future migrations
|
|
346
|
+
6. **New columns should have defaults** — prevents breaking existing rows
|
|
347
|
+
7. **Never rename columns** — add new column, migrate data, remove old column (across releases)
|
|
348
|
+
8. **Never drop tables** — soft delete or archive first
|
|
343
349
|
|
|
344
350
|
### Adding a Column to Existing Entity
|
|
345
351
|
|
|
@@ -355,8 +361,8 @@ new_field: string | null = null
|
|
|
355
361
|
|
|
356
362
|
Then:
|
|
357
363
|
```bash
|
|
358
|
-
yarn db:generate #
|
|
359
|
-
yarn db:migrate # Applies it
|
|
364
|
+
yarn db:generate # Probes/creates ALTER TABLE ADD COLUMN migration
|
|
365
|
+
yarn db:migrate # Applies it only after explicit user confirmation
|
|
360
366
|
```
|
|
361
367
|
|
|
362
368
|
### Removing a Column
|
|
@@ -484,7 +490,8 @@ export class TicketHistory {
|
|
|
484
490
|
| `@ManyToOne` across modules | Tight coupling, breaks module isolation | Store FK as `uuid` column, use enrichers |
|
|
485
491
|
| Storing computed values | Stale data, maintenance burden | Compute on read via enrichers or queries |
|
|
486
492
|
| Using `any` for JSONB fields | No type safety | Define a Zod schema, use `z.infer` |
|
|
487
|
-
|
|
|
493
|
+
| Blindly committing all generated migrations | Captures unrelated snapshot drift | Keep only scoped SQL and update the matching snapshot |
|
|
494
|
+
| Manual migration SQL without snapshot update | Future `yarn db:generate` recreates the same migration | Update `.snapshot-open-mercato.json` in the same change |
|
|
488
495
|
| Renaming columns | Breaks existing data/queries | Add new column, migrate data, drop old |
|
|
489
496
|
| Missing `organization_id` | Cross-tenant data leaks | Always include and index |
|
|
490
497
|
| Using `varchar` without `length` | Defaults vary by DB | Always specify `length` |
|
|
@@ -500,8 +507,10 @@ export class TicketHistory {
|
|
|
500
507
|
- **MUST** include standard columns (`id`, `created_at`, `updated_at`, `deleted_at`, `is_active`)
|
|
501
508
|
- **MUST** use UUID v4 for primary keys
|
|
502
509
|
- **MUST** index all FK columns and `organization_id` / `tenant_id`
|
|
503
|
-
- **MUST**
|
|
510
|
+
- **MUST** create or keep a scoped migration after entity changes and update `.snapshot-open-mercato.json`
|
|
504
511
|
- **MUST** review generated migration before applying
|
|
512
|
+
- **MUST NOT** commit unrelated migrations emitted by `yarn db:generate`
|
|
513
|
+
- **MUST NOT** run `yarn db:migrate` without explicit user confirmation
|
|
505
514
|
- **MUST** use `nullable: true` with `= null` default for optional fields
|
|
506
515
|
- **MUST** specify `length` on all `varchar` columns
|
|
507
516
|
- **MUST NOT** use ORM relationship decorators across module boundaries
|
|
@@ -129,7 +129,7 @@ After all targeted phases are complete:
|
|
|
129
129
|
3. **Build check**: `yarn build` — must pass
|
|
130
130
|
4. **Unit test check**: `yarn test` — must pass
|
|
131
131
|
5. **Integration test check**: run any new integration tests — must pass
|
|
132
|
-
6. **Migration check**: `yarn
|
|
132
|
+
6. **Migration check**: `yarn db:generate` — if any entities changed (verify the resulting SQL is scoped correctly; manual SQL is acceptable only when avoiding unrelated churn, and the touched `.snapshot-open-mercato.json` must match)
|
|
133
133
|
|
|
134
134
|
Report results to the user. If any check fails, fix and re-verify.
|
|
135
135
|
|
|
@@ -159,4 +159,4 @@ Report results to the user. If any check fails, fix and re-verify.
|
|
|
159
159
|
- MUST keep subagents focused — one task per subagent, clear boundaries
|
|
160
160
|
- MUST report blockers to the user immediately rather than working around them silently
|
|
161
161
|
- MUST run `yarn generate` after creating or modifying module convention files
|
|
162
|
-
- MUST run `yarn
|
|
162
|
+
- MUST run `yarn db:generate` after creating or modifying entities (and confirm migration with user before applying)
|
|
@@ -57,9 +57,8 @@ src/modules/<module_id>/
|
|
|
57
57
|
├── setup.ts # Tenant init, role features
|
|
58
58
|
├── di.ts # Awilix DI registrations
|
|
59
59
|
├── events.ts # Typed event declarations (if needed)
|
|
60
|
-
├── entities/
|
|
61
|
-
│ └── <Entity>.ts # MikroORM entity class
|
|
62
60
|
├── data/
|
|
61
|
+
│ ├── entities.ts # MikroORM entity classes
|
|
63
62
|
│ └── validators.ts # Zod validation schemas
|
|
64
63
|
├── api/
|
|
65
64
|
│ ├── get/
|
|
@@ -81,12 +80,12 @@ src/modules/<module_id>/
|
|
|
81
80
|
|
|
82
81
|
## 3. Create Entity
|
|
83
82
|
|
|
84
|
-
**File**: `src/modules/<module_id>/entities
|
|
83
|
+
**File**: `src/modules/<module_id>/data/entities.ts`
|
|
85
84
|
|
|
86
85
|
### Template
|
|
87
86
|
|
|
88
87
|
```typescript
|
|
89
|
-
import { Entity,
|
|
88
|
+
import { Entity, Index, PrimaryKey, Property } from '@mikro-orm/decorators/legacy'
|
|
90
89
|
import { v4 } from 'uuid'
|
|
91
90
|
|
|
92
91
|
@Entity({ tableName: '<entities>' }) // plural, snake_case
|
|
@@ -132,6 +131,7 @@ export class <Entity> {
|
|
|
132
131
|
- PK: always `uuid` with `v4()` default
|
|
133
132
|
- MUST include `organization_id` + `tenant_id` with `@Index()`
|
|
134
133
|
- MUST include `created_at`, `updated_at`, `deleted_at`, `is_active`
|
|
134
|
+
- Entity decorators MUST come from `@mikro-orm/decorators/legacy`
|
|
135
135
|
- Cross-module references: store FK as `uuid` field (e.g., `customer_id`) — never use ORM `@ManyToOne`
|
|
136
136
|
- Use `@Property({ type: 'jsonb' })` for flexible/nested data
|
|
137
137
|
- Use `@Property({ type: 'varchar', length: N })` for bounded strings
|
|
@@ -179,7 +179,7 @@ Use `makeCrudRoute` for standard CRUD. Each HTTP method lives in its own file.
|
|
|
179
179
|
|
|
180
180
|
```typescript
|
|
181
181
|
import { makeCrudRoute } from '@open-mercato/shared/lib/crud/make-crud-route'
|
|
182
|
-
import { <Entity> } from '../../entities
|
|
182
|
+
import { <Entity> } from '../../data/entities'
|
|
183
183
|
|
|
184
184
|
const handler = makeCrudRoute({
|
|
185
185
|
entity: <Entity>,
|
|
@@ -202,7 +202,7 @@ export const openApi = {
|
|
|
202
202
|
|
|
203
203
|
```typescript
|
|
204
204
|
import { makeCrudRoute } from '@open-mercato/shared/lib/crud/make-crud-route'
|
|
205
|
-
import { <Entity> } from '../../entities
|
|
205
|
+
import { <Entity> } from '../../data/entities'
|
|
206
206
|
import { create<Entity>Schema } from '../../data/validators'
|
|
207
207
|
|
|
208
208
|
const handler = makeCrudRoute({
|
|
@@ -226,7 +226,7 @@ export const openApi = {
|
|
|
226
226
|
|
|
227
227
|
```typescript
|
|
228
228
|
import { makeCrudRoute } from '@open-mercato/shared/lib/crud/make-crud-route'
|
|
229
|
-
import { <Entity> } from '../../entities
|
|
229
|
+
import { <Entity> } from '../../data/entities'
|
|
230
230
|
import { update<Entity>Schema } from '../../data/validators'
|
|
231
231
|
|
|
232
232
|
const handler = makeCrudRoute({
|
|
@@ -250,7 +250,7 @@ export const openApi = {
|
|
|
250
250
|
|
|
251
251
|
```typescript
|
|
252
252
|
import { makeCrudRoute } from '@open-mercato/shared/lib/crud/make-crud-route'
|
|
253
|
-
import { <Entity> } from '../../entities
|
|
253
|
+
import { <Entity> } from '../../data/entities'
|
|
254
254
|
|
|
255
255
|
const handler = makeCrudRoute({
|
|
256
256
|
entity: <Entity>,
|
|
@@ -589,7 +589,7 @@ Add to `src/modules.ts`:
|
|
|
589
589
|
|
|
590
590
|
```bash
|
|
591
591
|
yarn generate # Discover module files, update .mercato/generated/
|
|
592
|
-
yarn db:generate #
|
|
592
|
+
yarn db:generate # Probe/create migration for the new entity
|
|
593
593
|
```
|
|
594
594
|
|
|
595
595
|
### Step 3: Review Migration
|
|
@@ -599,11 +599,13 @@ Check the generated migration file in `src/modules/<module_id>/migrations/`. Ver
|
|
|
599
599
|
- All columns present with correct types
|
|
600
600
|
- Indexes on `organization_id`, `tenant_id`
|
|
601
601
|
- No unexpected changes
|
|
602
|
+
- `migrations/.snapshot-open-mercato.json` was updated to the post-change schema
|
|
603
|
+
- Unrelated generated migrations were deleted from the diff
|
|
602
604
|
|
|
603
605
|
### Step 4: Apply & Test
|
|
604
606
|
|
|
605
607
|
```bash
|
|
606
|
-
yarn db:migrate # Apply migration
|
|
608
|
+
yarn db:migrate # Apply migration only after explicit user confirmation
|
|
607
609
|
yarn dev # Start dev server
|
|
608
610
|
```
|
|
609
611
|
|
|
@@ -631,7 +633,7 @@ yarn dev # Start dev server
|
|
|
631
633
|
- [ ] ACL features declared and wired in `setup.ts`
|
|
632
634
|
- [ ] Module registered in `src/modules.ts` with `from: '@app'`
|
|
633
635
|
- [ ] `yarn generate` run after creating files
|
|
634
|
-
- [ ]
|
|
636
|
+
- [ ] Migration SQL is scoped to this entity and `.snapshot-open-mercato.json` is updated
|
|
635
637
|
- [ ] No `any` types
|
|
636
638
|
- [ ] No hardcoded user-facing strings
|
|
637
639
|
- [ ] No direct ORM relationships to other modules
|
|
@@ -651,6 +653,8 @@ yarn dev # Start dev server
|
|
|
651
653
|
- **MUST** declare ACL features and wire them in `setup.ts` `defaultRoleFeatures`
|
|
652
654
|
- **MUST** register module in `src/modules.ts` with `from: '@app'`
|
|
653
655
|
- **MUST** run `yarn generate` after creating module files
|
|
654
|
-
- **MUST**
|
|
656
|
+
- **MUST** create or keep a scoped migration after creating/modifying entities and update `.snapshot-open-mercato.json`
|
|
657
|
+
- **MUST NOT** commit unrelated migrations emitted by `yarn db:generate`
|
|
658
|
+
- **MUST NOT** run `yarn db:migrate` without explicit user confirmation
|
|
655
659
|
- **MUST NOT** create ORM relationships (`@ManyToOne`, `@OneToMany`) to entities in other modules
|
|
656
660
|
- **MUST NOT** edit `.mercato/generated/*` files manually
|
|
@@ -128,17 +128,21 @@ yarn typecheck
|
|
|
128
128
|
|
|
129
129
|
1. **Did you create a migration after adding/changing the entity?**
|
|
130
130
|
```bash
|
|
131
|
-
yarn db:generate #
|
|
131
|
+
yarn db:generate # Probes/creates migration file
|
|
132
132
|
```
|
|
133
|
-
Fix: Run `yarn db:generate` to
|
|
133
|
+
Fix: Run `yarn db:generate` to inspect the required migration, then keep only the scoped SQL for your module and update `src/modules/<module_id>/migrations/.snapshot-open-mercato.json`.
|
|
134
134
|
|
|
135
|
-
2. **
|
|
135
|
+
2. **Is the entity declared in the right file with the right imports?**
|
|
136
|
+
Entity classes belong in `src/modules/<module_id>/data/entities.ts` and decorators must come from `@mikro-orm/decorators/legacy`.
|
|
137
|
+
Fix: move stale `entities/<Entity>.ts` patterns into `data/entities.ts` and fix the imports before regenerating the migration.
|
|
138
|
+
|
|
139
|
+
3. **Did you apply the migration?**
|
|
136
140
|
```bash
|
|
137
141
|
yarn db:migrate # Applies pending migrations
|
|
138
142
|
```
|
|
139
143
|
Fix: Run `yarn db:migrate`.
|
|
140
144
|
|
|
141
|
-
|
|
145
|
+
4. **Is the migration file correct?**
|
|
142
146
|
Check `src/modules/<module_id>/migrations/` for the latest migration.
|
|
143
147
|
Verify it has the expected columns and types.
|
|
144
148
|
Fix: If wrong, delete the migration file, fix the entity, and regenerate.
|
|
@@ -158,16 +162,21 @@ yarn typecheck
|
|
|
158
162
|
Never edit `node_modules/@open-mercato/*`.
|
|
159
163
|
Fix: Revert changes to node_modules. Use UMES extensions instead, or eject the module.
|
|
160
164
|
|
|
165
|
+
3. **Is a module snapshot stale?**
|
|
166
|
+
Check whether the generated SQL recreates a table or column that already has a committed migration.
|
|
167
|
+
Fix: update that module's `migrations/.snapshot-open-mercato.json` to include the already-migrated schema, then re-run `yarn db:generate` and expect `no changes`.
|
|
168
|
+
|
|
161
169
|
### Entity changes not reflected
|
|
162
170
|
|
|
163
171
|
**Symptoms**: Changed entity file but API still returns old schema
|
|
164
172
|
|
|
165
173
|
**Checklist**:
|
|
166
174
|
|
|
167
|
-
1.
|
|
168
|
-
2. Run `yarn
|
|
169
|
-
3. Run `yarn db:
|
|
170
|
-
4.
|
|
175
|
+
1. Verify the entity lives in `src/modules/<module_id>/data/entities.ts` and imports decorators from `@mikro-orm/decorators/legacy`
|
|
176
|
+
2. Run `yarn generate` — entity discovery is cached
|
|
177
|
+
3. Run `yarn db:generate` — schema needs a migration
|
|
178
|
+
4. Run `yarn db:migrate` — migration needs to be applied
|
|
179
|
+
5. Restart `yarn dev` — server caches entity metadata
|
|
171
180
|
|
|
172
181
|
---
|
|
173
182
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/cli",
|
|
3
|
-
"version": "0.5.1-develop.
|
|
3
|
+
"version": "0.5.1-develop.2975.ccbadc8198",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"@mikro-orm/decorators": "^7.0.10",
|
|
60
60
|
"@mikro-orm/migrations": "^7.0.10",
|
|
61
61
|
"@mikro-orm/postgresql": "^7.0.10",
|
|
62
|
-
"@open-mercato/queue": "0.5.1-develop.
|
|
63
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
62
|
+
"@open-mercato/queue": "0.5.1-develop.2975.ccbadc8198",
|
|
63
|
+
"@open-mercato/shared": "0.5.1-develop.2975.ccbadc8198",
|
|
64
64
|
"cross-spawn": "^7.0.6",
|
|
65
65
|
"pg": "8.20.0",
|
|
66
66
|
"semver": "^7.7.4",
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
"typescript": "^5.9.3"
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|
|
73
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
73
|
+
"@open-mercato/shared": "0.5.1-develop.2975.ccbadc8198"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
76
|
+
"@open-mercato/shared": "0.5.1-develop.2975.ccbadc8198",
|
|
77
77
|
"@types/jest": "^30.0.0",
|
|
78
78
|
"jest": "^30.3.0",
|
|
79
79
|
"ts-jest": "^29.4.9"
|