create-mercato-app 0.6.5-develop.4534.1.b459babe6d → 0.6.5-develop.4559.1.839e136509
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.
|
@@ -126,7 +126,7 @@ export class <Entity> {
|
|
|
126
126
|
- Table name: **plural, snake_case** — matches module ID
|
|
127
127
|
- PK: always `uuid` with `v4()` default
|
|
128
128
|
- MUST include `organization_id` + `tenant_id` with `@Index()`
|
|
129
|
-
- MUST include `created_at`, `updated_at`, `deleted_at`, `is_active`
|
|
129
|
+
- MUST include `created_at`, `updated_at`, `deleted_at`, `is_active`. The `updated_at` column is what OSS **optimistic locking** (default ON) compares — keep it on every user-editable entity, and make your CRUD GET/list responses return `updatedAt` so the UI can send the expected version.
|
|
130
130
|
- Entity decorators MUST come from `@mikro-orm/decorators/legacy`
|
|
131
131
|
- Cross-module references: store FK as `uuid` field (e.g., `customer_id`) — never use ORM `@ManyToOne`
|
|
132
132
|
- Use `@Property({ type: 'jsonb' })` for flexible/nested data
|
|
@@ -234,6 +234,8 @@ export const openApi = {
|
|
|
234
234
|
|
|
235
235
|
Use `CrudForm` and `DataTable` from `@open-mercato/ui`. See the `backend-ui-design` skill for full component reference.
|
|
236
236
|
|
|
237
|
+
> **Optimistic locking (default ON).** `CrudForm` in edit mode auto-derives the expected-version header from `initialValues.updatedAt` and applies it to **both** save and delete — so pass the loaded record's `updatedAt` into `initialValues`. For custom (non-`CrudForm`) list-row deletes or dialog mutations, wrap the call with `withScopedApiRequestHeaders(buildOptimisticLockHeader(record.updatedAt), () => deleteCrud(...))` and surface the 409 with `surfaceRecordConflict(err, t)` from `@open-mercato/ui/backend/conflicts`. Never leave a mutating edit/delete UI without a version header — concurrent edits would silently overwrite.
|
|
238
|
+
|
|
237
239
|
### Page Metadata & Sidebar Navigation
|
|
238
240
|
|
|
239
241
|
**File**: `src/modules/<module_id>/backend/page.meta.ts`
|
|
@@ -126,7 +126,7 @@ export class <Entity> {
|
|
|
126
126
|
- Table name: **plural, snake_case** — matches module ID
|
|
127
127
|
- PK: always `uuid` with `v4()` default
|
|
128
128
|
- MUST include `organization_id` + `tenant_id` with `@Index()`
|
|
129
|
-
- MUST include `created_at`, `updated_at`, `deleted_at`, `is_active`
|
|
129
|
+
- MUST include `created_at`, `updated_at`, `deleted_at`, `is_active`. The `updated_at` column is what OSS **optimistic locking** (default ON) compares — keep it on every user-editable entity, and make your CRUD GET/list responses return `updatedAt` so the UI can send the expected version.
|
|
130
130
|
- Entity decorators MUST come from `@mikro-orm/decorators/legacy`
|
|
131
131
|
- Cross-module references: store FK as `uuid` field (e.g., `customer_id`) — never use ORM `@ManyToOne`
|
|
132
132
|
- Use `@Property({ type: 'jsonb' })` for flexible/nested data
|
|
@@ -234,6 +234,8 @@ export const openApi = {
|
|
|
234
234
|
|
|
235
235
|
Use `CrudForm` and `DataTable` from `@open-mercato/ui`. See the `backend-ui-design` skill for full component reference.
|
|
236
236
|
|
|
237
|
+
> **Optimistic locking (default ON).** `CrudForm` in edit mode auto-derives the expected-version header from `initialValues.updatedAt` and applies it to **both** save and delete — so pass the loaded record's `updatedAt` into `initialValues`. For custom (non-`CrudForm`) list-row deletes or dialog mutations, wrap the call with `withScopedApiRequestHeaders(buildOptimisticLockHeader(record.updatedAt), () => deleteCrud(...))` and surface the 409 with `surfaceRecordConflict(err, t)` from `@open-mercato/ui/backend/conflicts`. Never leave a mutating edit/delete UI without a version header — concurrent edits would silently overwrite.
|
|
238
|
+
|
|
237
239
|
### Page Metadata & Sidebar Navigation
|
|
238
240
|
|
|
239
241
|
**File**: `src/modules/<module_id>/backend/page.meta.ts`
|
package/package.json
CHANGED
package/template/AGENTS.md
CHANGED
|
@@ -214,6 +214,7 @@ Install official package-backed modules with `yarn mercato module add @open-merc
|
|
|
214
214
|
|
|
215
215
|
- Define module entities in `src/modules/<module>/data/entities.ts`.
|
|
216
216
|
- Import entity decorators from `@mikro-orm/decorators/legacy`, not `@mikro-orm/core`.
|
|
217
|
+
- User-editable entities MUST carry an `updated_at` column (onCreate+onUpdate) — it backs OSS **optimistic locking** (default ON). Return `updatedAt` from CRUD list/detail responses, and on edit/delete UI let `CrudForm` auto-derive the version header from `initialValues.updatedAt`, or for custom handlers wrap with `withScopedApiRequestHeaders(buildOptimisticLockHeader(record.updatedAt), …)` + `surfaceRecordConflict(err, t)`. Without it, concurrent edits silently overwrite.
|
|
217
218
|
- Treat `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 the module you are changing and update `src/modules/<module>/migrations/.snapshot-open-mercato.json` in the same change.
|
|
218
219
|
|
|
219
220
|
### API Route Files MUST Export `metadata`
|