@donotdev/cli 0.0.9 → 0.0.11

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 (32) hide show
  1. package/dependencies-matrix.json +24 -7
  2. package/dist/bin/commands/build.js +2 -2
  3. package/dist/bin/commands/bump.js +578 -94
  4. package/dist/bin/commands/cacheout.js +2 -2
  5. package/dist/bin/commands/create-app.js +3 -3
  6. package/dist/bin/commands/create-project.js +3 -3
  7. package/dist/bin/commands/deploy.js +3 -3
  8. package/dist/bin/commands/dev.js +2 -2
  9. package/dist/bin/commands/emu.js +2 -2
  10. package/dist/bin/commands/format.js +2 -2
  11. package/dist/bin/commands/lint.js +2 -2
  12. package/dist/bin/commands/preview.js +2 -2
  13. package/dist/bin/commands/sync-secrets.js +2 -2
  14. package/dist/index.js +3 -3
  15. package/package.json +2 -2
  16. package/templates/root-consumer/.claude/agents/architect.md.example +313 -0
  17. package/templates/root-consumer/.claude/agents/builder.md.example +329 -0
  18. package/templates/root-consumer/.claude/agents/coder.md.example +87 -0
  19. package/templates/root-consumer/.claude/agents/extractor.md.example +235 -0
  20. package/templates/root-consumer/.claude/agents/polisher.md.example +359 -0
  21. package/templates/root-consumer/.claude/agents/prompt-engineer.md.example +85 -0
  22. package/templates/root-consumer/.claude/commands/brainstorm.md.example +133 -0
  23. package/templates/root-consumer/.claude/commands/build.md.example +109 -0
  24. package/templates/root-consumer/.claude/commands/design.md.example +136 -0
  25. package/templates/root-consumer/.claude/commands/polish.md.example +145 -0
  26. package/templates/root-consumer/.cursor/mcp.json.example +8 -0
  27. package/templates/root-consumer/.mcp.json.example +8 -0
  28. package/templates/root-consumer/CLAUDE.md.example +146 -0
  29. package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +15 -12
  30. package/templates/root-consumer/guides/dndev/COMPONENT_API.md.example +195 -0
  31. package/templates/root-consumer/guides/dndev/INDEX.md.example +3 -1
  32. package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +157 -1
@@ -1,6 +1,8 @@
1
1
  # DoNotDev Framework Guides
2
2
 
3
- **For AI Agents:** See [AGENT_START_HERE.md](./AGENT_START_HERE.md)
3
+ **For AI Agents:** See [AGENT_START_HERE.md](./AGENT_START_HERE.md) ← **START HERE**
4
+
5
+ **AI System:** Commands in `.claude/commands/`, agents in `.claude/agents/` (synced via `dndev bump`)
4
6
 
5
7
  ---
6
8
 
@@ -12,7 +12,7 @@
12
12
  | **Display Utilities** (`formatValue`, `DisplayFieldRenderer`, `EntityFilters`, `translateFieldLabel`) | `@donotdev/crud` |
13
13
  | **Form Components** (`FormFieldRenderer`, `Controlled*Field`, `UploadProvider`) | `@donotdev/crud` |
14
14
  | **Routing-Aware Components** (`EntityFormRenderer`, `EntityList`, `EntityCardList`, `EntityDisplayRenderer`) | `@donotdev/ui` |
15
- | **Specialized Templates** (`ProductCardListTemplate`, `CarCardListTemplate`) | `@donotdev/templates` |
15
+ | **Specialized Templates** (`ProductCardListTemplate`, `CarCardListTemplate`, `InquiryFormTemplate`, `InquiryAdminTemplate`) | `@donotdev/templates` |
16
16
  | **Routing** (`useNavigate`, `Link`, `useParams`) | `@donotdev/ui` |
17
17
  | **Entity Definition** (`defineEntity`) | `@donotdev/core` |
18
18
 
@@ -147,8 +147,49 @@ registerScopeProvider('tenant', () => tenantStore.getState().currentTenantId);
147
147
  | `'user'` | Authenticated |
148
148
  | `'admin'` | Admins |
149
149
  | `'super'` | Super admins |
150
+ | `'technical'` | Admins only (read-only in forms; e.g. scope field) |
151
+ | `'owner'` | Only when the current user is a stakeholder (see **Stakeholder Access** below) |
150
152
  | `'hidden'` | Never |
151
153
 
154
+ ### Stakeholder Access (ownership)
155
+
156
+ For marketplace-style entities: documents **public when available**, **private to stakeholders** (e.g. partner, customer) when booked.
157
+
158
+ **1. Add `ownership` to the entity:**
159
+
160
+ ```typescript
161
+ ownership: {
162
+ ownerFields: ['providerId', 'customerId'], // Document fields whose value is a user id
163
+ publicCondition: [ // When can anyone read? (AND together)
164
+ { field: 'status', op: '==', value: 'available' },
165
+ ],
166
+ },
167
+ ```
168
+
169
+ **2. Use `visibility: 'owner'`** for fields only stakeholders should see (e.g. internal notes, customer contact after booking):
170
+
171
+ ```typescript
172
+ internalNotes: {
173
+ name: 'internalNotes',
174
+ label: 'Internal notes',
175
+ type: 'textarea',
176
+ visibility: 'owner', // Returned only when request.auth.uid matches one of ownerFields
177
+ editable: true,
178
+ validation: { required: false },
179
+ },
180
+ ```
181
+
182
+ **3. Firestore rules (read and update):** Use the framework helper, then paste the condition into your hand-written `firestore.rules`:
183
+
184
+ ```typescript
185
+ import { generateFirestoreRuleCondition } from '@donotdev/core';
186
+
187
+ const condition = generateFirestoreRuleCondition(scheduleEntity.ownership);
188
+ // Paste into firestore.rules: allow read, update: if <condition>;
189
+ ```
190
+
191
+ **Behavior:** `listCard_` returns only documents matching `publicCondition` (e.g. public slots). `list_` returns only documents where the current user is in one of `ownerFields` ("mine"). Same condition is used for **allow read** and **allow update** so owners can update (e.g. status to cancelled, notes). For multiple owner fields, prefer an `ownerIds` array and `array-contains` in rules and queries.
192
+
152
193
  ### Entity Access (who CAN DO)
153
194
  ```typescript
154
195
  access: {
@@ -365,6 +406,85 @@ export default function ShopPage() {
365
406
  }
366
407
  ```
367
408
 
409
+ #### Contact/Inquiry Form (Specialized Template)
410
+
411
+ For contact forms that create both a Customer and an Inquiry record:
412
+
413
+ ```tsx
414
+ import { InquiryFormTemplate } from '@donotdev/templates';
415
+ import { customerEntity, inquiryEntity } from 'entities';
416
+
417
+ export default function ContactPage() {
418
+ return (
419
+ <PageContainer>
420
+ <InquiryFormTemplate
421
+ customerEntity={customerEntity}
422
+ inquiryEntity={inquiryEntity}
423
+ // Optional: contextId="car123" - links inquiry to a car/product
424
+ // Optional: contextName="BMW X5 2024" - shown in message placeholder
425
+ // Optional: contextDetails="BMW X5 2024 • 50,000 km • €45,000" - detailed placeholder
426
+ // Optional: messageField="message" - defaults to 'message'
427
+ // Optional: contextField="carId" - defaults to 'carId'
428
+ // Optional: customerFields={['firstName', 'lastName', 'email', 'phone']} - fields to show
429
+ // Optional: onSuccess={() => navigate('/thank-you')}
430
+ />
431
+ </PageContainer>
432
+ );
433
+ }
434
+ ```
435
+
436
+ **What it does:**
437
+ - Creates a Customer record (with `findOrCreate` logic via `uniqueKeys` - prevents duplicates by email/phone)
438
+ - Creates an Inquiry record linked to the customer
439
+ - Handles GDPR consent tracking
440
+ - Auto-fills message with context details if provided
441
+ - Shows success state after submission
442
+
443
+ **Requirements:**
444
+ - Customer entity must have `uniqueKeys` configured (e.g., `{ fields: ['email'], findOrCreate: true }`)
445
+ - Inquiry entity should have `customerId` field (type: `reference`)
446
+ - Both entities should have `status` field (defaults to `'draft'`)
447
+
448
+ #### Inquiry Admin Dashboard (Specialized Template)
449
+
450
+ For admin pages to review and respond to inquiries with one-click actions:
451
+
452
+ ```tsx
453
+ import { InquiryAdminTemplate } from '@donotdev/templates';
454
+ import { customerEntity, inquiryEntity } from 'entities';
455
+
456
+ export default function InquiriesAdminPage() {
457
+ return (
458
+ <PageContainer>
459
+ <InquiryAdminTemplate
460
+ customerEntity={customerEntity}
461
+ inquiryEntity={inquiryEntity}
462
+ // Optional: customerBasePath="/customers" - defaults to '/customers'
463
+ />
464
+ </PageContainer>
465
+ );
466
+ }
467
+ ```
468
+
469
+ **What it does:**
470
+ - Shows all inquiries in a responsive card grid (1 column mobile, 2 columns desktop)
471
+ - Displays inquiry message preview (first 150 chars)
472
+ - Shows customer info inline (name, email, phone)
473
+ - One-click actions:
474
+ - **Email** - Opens `mailto:` link (includes subject if `carId` present)
475
+ - **Call** - Opens `tel:` link
476
+ - **View Customer** - Navigates to customer detail page
477
+ - **Mark Responded** - Updates inquiry status to `'responded'` (only shown if not already responded)
478
+ - Status badges with icons (✓ for responded, ⏰ for pending)
479
+ - Auto-sorted by priority: available → draft → responded → deleted (then by date, newest first)
480
+
481
+ **Features:**
482
+ - Fetches all inquiries and customers in parallel
483
+ - Efficient customer lookup via Map (no N+1 queries)
484
+ - Loading state with spinner
485
+ - Empty state message
486
+ - Responsive grid layout
487
+
368
488
  ---
369
489
 
370
490
  ## 5. Component Props
@@ -765,6 +885,42 @@ export const productEntity = defineEntity({
765
885
 
766
886
  Field `label` → translation key in `fields.*`
767
887
 
888
+ ### Status Field Translations
889
+
890
+ The `status` field uses CRUD namespace translations with entity-specific overrides:
891
+
892
+ **Translation Fallback Order:**
893
+ 1. **Entity namespace** (`entity-{name}`) - User overrides take priority
894
+ 2. **CRUD namespace** (`crud`) - Framework defaults
895
+
896
+ **Framework Defaults** (in `crud` namespace):
897
+ - `crud:status.draft` → "Draft"
898
+ - `crud:status.available` → "Available"
899
+ - `crud:status.deleted` → "Deleted"
900
+
901
+ **Override in Entity Translation File:**
902
+
903
+ ```json
904
+ // locales/entity-inquiry_en.json
905
+ {
906
+ "status": {
907
+ "draft": "New",
908
+ "available": "Read",
909
+ "deleted": "Closed"
910
+ }
911
+ }
912
+ ```
913
+
914
+ **How it works:**
915
+ - Framework components (`EntityList`, `EntityFormRenderer`, etc.) automatically use `[entity.namespace, 'crud']` translation namespaces
916
+ - Status labels are translated via `translateLabel()` which tries entity namespace first, then falls back to `crud`
917
+ - No `dndev` namespace fallback - CRUD is optional and doesn't pollute core framework translations
918
+
919
+ **Example:** For an `inquiry` entity:
920
+ - If `entity-inquiry_en.json` has `"status.draft": "New"` → displays "New"
921
+ - If not found → falls back to `crud:status.draft` → displays "Draft"
922
+ - Never falls back to `dndev` namespace
923
+
768
924
  ---
769
925
 
770
926
  ## 11. Display Utilities