@donotdev/cli 0.0.5 → 0.0.7

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 (102) hide show
  1. package/dependencies-matrix.json +76 -34
  2. package/dist/bin/commands/build.js +165 -161
  3. package/dist/bin/commands/bump.js +172 -160
  4. package/dist/bin/commands/cacheout.js +163 -157
  5. package/dist/bin/commands/create-app.js +205 -163
  6. package/dist/bin/commands/create-project.js +176 -161
  7. package/dist/bin/commands/deploy.js +480 -472
  8. package/dist/bin/commands/dev.js +164 -158
  9. package/dist/bin/commands/emu.js +164 -158
  10. package/dist/bin/commands/format.js +163 -157
  11. package/dist/bin/commands/lint.js +166 -157
  12. package/dist/bin/commands/make-admin.d.ts +11 -0
  13. package/dist/bin/commands/make-admin.d.ts.map +1 -0
  14. package/dist/bin/commands/make-admin.js +12 -0
  15. package/dist/bin/commands/make-admin.js.map +1 -0
  16. package/dist/bin/commands/preview.js +164 -158
  17. package/dist/bin/commands/sync-secrets.js +164 -158
  18. package/dist/bin/commands/wai.d.ts +11 -0
  19. package/dist/bin/commands/wai.d.ts.map +1 -0
  20. package/dist/bin/commands/wai.js +12 -0
  21. package/dist/bin/commands/wai.js.map +1 -0
  22. package/dist/bin/dndev.js +24 -8
  23. package/dist/bin/donotdev.js +24 -8
  24. package/dist/index.js +557 -514
  25. package/package.json +1 -1
  26. package/templates/app-demo/index.html.example +4 -0
  27. package/templates/app-demo/src/App.tsx.example +28 -10
  28. package/templates/app-demo/src/config/app.ts.example +68 -0
  29. package/templates/app-next/src/app/ClientLayout.tsx.example +4 -3
  30. package/templates/app-next/src/app/layout.tsx.example +17 -25
  31. package/templates/app-next/src/config/app.ts.example +75 -48
  32. package/templates/app-next/src/globals.css.example +10 -7
  33. package/templates/app-next/src/locales/dndev_en.json.example +68 -0
  34. package/templates/app-next/src/pages/locales/example_en.json.example +5 -0
  35. package/templates/app-vite/index.html.example +71 -34
  36. package/templates/app-vite/src/config/app.ts.example +75 -47
  37. package/templates/app-vite/src/globals.css.example +14 -6
  38. package/templates/app-vite/src/locales/dndev_en.json.example +68 -0
  39. package/templates/app-vite/src/pages/FormPageExample.tsx.example +152 -0
  40. package/templates/app-vite/src/pages/HomePage.tsx.example +81 -134
  41. package/templates/app-vite/src/pages/ListPageExample.tsx.example +88 -0
  42. package/templates/functions-firebase/README.md.example +25 -0
  43. package/templates/functions-firebase/build.mjs.example +8 -1
  44. package/templates/functions-firebase/functions-firebase/build.mjs.example +8 -1
  45. package/templates/functions-firebase/functions-firebase/src/index.ts.example +19 -25
  46. package/templates/functions-firebase/functions.config.js.example +35 -0
  47. package/templates/functions-firebase/tsconfig.json.example +3 -13
  48. package/templates/functions-vercel/tsconfig.json.example +1 -13
  49. package/templates/root-consumer/entities/ExampleEntity.ts.example +223 -0
  50. package/templates/root-consumer/entities/demo.ts.example +562 -0
  51. package/templates/root-consumer/entities/index.ts.example +15 -0
  52. package/templates/root-consumer/firebase.json.example +1 -1
  53. package/templates/root-consumer/guides/{AGENT_START_HERE.md.example → dndev/AGENT_START_HERE.md.example} +22 -0
  54. package/templates/root-consumer/guides/{COMPONENTS_ADV.md.example → dndev/COMPONENTS_ADV.md.example} +456 -360
  55. package/templates/root-consumer/guides/{COMPONENTS_ATOMIC.md.example → dndev/COMPONENTS_ATOMIC.md.example} +42 -0
  56. package/templates/root-consumer/guides/dndev/COMPONENTS_CRUD.md.example +231 -0
  57. package/templates/root-consumer/guides/{INDEX.md.example → dndev/INDEX.md.example} +3 -0
  58. package/templates/root-consumer/guides/{SETUP_APP_CONFIG.md.example → dndev/SETUP_APP_CONFIG.md.example} +5 -2
  59. package/templates/root-consumer/guides/{SETUP_AUTH.md.example → dndev/SETUP_AUTH.md.example} +30 -0
  60. package/templates/root-consumer/guides/{SETUP_BILLING.md.example → dndev/SETUP_BILLING.md.example} +44 -4
  61. package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +473 -0
  62. package/templates/root-consumer/guides/dndev/SETUP_FUNCTIONS.md.example +116 -0
  63. package/templates/root-consumer/guides/{SETUP_PAGES.md.example → dndev/SETUP_PAGES.md.example} +17 -0
  64. package/templates/root-consumer/guides/dndev/SETUP_PWA.md.example +213 -0
  65. package/templates/root-consumer/guides/dndev/USE_ROUTING.md.example +503 -0
  66. package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +404 -0
  67. package/templates/root-consumer/guides/wai-way/agents/architect.md.example +78 -0
  68. package/templates/root-consumer/guides/wai-way/agents/builder.md.example +87 -0
  69. package/templates/root-consumer/guides/wai-way/agents/extractor.md.example +325 -0
  70. package/templates/root-consumer/guides/wai-way/agents/polisher.md.example +100 -0
  71. package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +281 -0
  72. package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +77 -0
  73. package/templates/root-consumer/guides/wai-way/blueprints/2_entities.md.example +104 -0
  74. package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +124 -0
  75. package/templates/root-consumer/guides/wai-way/blueprints/4_configure.md.example +165 -0
  76. package/templates/root-consumer/guides/wai-way/context_map.json.example +95 -0
  77. package/templates/root-consumer/guides/wai-way/entity_patterns.md.example +840 -0
  78. package/templates/root-consumer/guides/wai-way/page_patterns.md.example +686 -0
  79. package/templates/root-consumer/guides/wai-way/presets_guide.md.example +217 -0
  80. package/templates/root-consumer/guides/wai-way/spec_template.md.example +312 -0
  81. package/templates/root-consumer/vercel.json.example +315 -20
  82. package/templates/app-demo/src/Routes.tsx.example +0 -20
  83. package/templates/app-vite/src/Routes.tsx.example +0 -16
  84. package/templates/app-vite/src/pages/locales/README.md.example +0 -1
  85. package/templates/functions-firebase/functions-firebase/src/crud/createEntity.ts.example +0 -19
  86. package/templates/functions-firebase/functions-firebase/src/crud/deleteEntity.ts.example +0 -14
  87. package/templates/functions-firebase/functions-firebase/src/crud/getEntity.ts.example +0 -14
  88. package/templates/functions-firebase/functions-firebase/src/crud/index.ts.example +0 -12
  89. package/templates/functions-firebase/functions-firebase/src/crud/listEntities.ts.example +0 -14
  90. package/templates/functions-firebase/functions-firebase/src/crud/updateEntity.ts.example +0 -14
  91. package/templates/root-consumer/guides/COMPONENTS_CRUD.md.example +0 -70
  92. package/templates/root-consumer/guides/SETUP_FUNCTIONS.md.example +0 -62
  93. /package/templates/root-consumer/guides/{COMPONENTS_UI.md.example → dndev/COMPONENTS_UI.md.example} +0 -0
  94. /package/templates/root-consumer/guides/{ENV_SETUP.md.example → dndev/ENV_SETUP.md.example} +0 -0
  95. /package/templates/root-consumer/guides/{SETUP_I18N.md.example → dndev/SETUP_I18N.md.example} +0 -0
  96. /package/templates/root-consumer/guides/{SETUP_LAYOUTS.md.example → dndev/SETUP_LAYOUTS.md.example} +0 -0
  97. /package/templates/root-consumer/guides/{SETUP_OAUTH.md.example → dndev/SETUP_OAUTH.md.example} +0 -0
  98. /package/templates/root-consumer/guides/{SETUP_THEMES.md.example → dndev/SETUP_THEMES.md.example} +0 -0
  99. /package/templates/root-consumer/guides/{advanced → dndev/advanced}/APP_CHECK.md.example +0 -0
  100. /package/templates/root-consumer/guides/{advanced → dndev/advanced}/COOKIE_REFERENCE.md.example +0 -0
  101. /package/templates/root-consumer/guides/{advanced → dndev/advanced}/EMULATORS.md.example +0 -0
  102. /package/templates/root-consumer/guides/{advanced → dndev/advanced}/VERSION_CONTROL.md.example +0 -0
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @fileoverview Example CRUD List Page
3
+ *
4
+ * COPY THIS FILE and rename (e.g., ProductsListPage.tsx, CustomersListPage.tsx)
5
+ *
6
+ * HOW IT WORKS:
7
+ * 1. Import your entity definition
8
+ * 2. Use EntityList component - it handles everything:
9
+ * - Fetching data (optimized via listFields)
10
+ * - Table columns (respects field visibility by role)
11
+ * - Search, sort, pagination
12
+ * - Create/Edit/Delete actions
13
+ */
14
+
15
+ import { Package } from 'lucide-react';
16
+
17
+ import { EntityList } from '@donotdev/crud';
18
+ import { useAuth } from '@donotdev/auth';
19
+ import type { PageMeta } from '@donotdev/core';
20
+ import { PageContainer } from '@donotdev/ui';
21
+
22
+ // Import your entity from root-level entities folder
23
+ // import { productEntity } from 'entities/Product';
24
+
25
+ // Placeholder - replace with your entity import
26
+ const productEntity = null as any;
27
+
28
+ // ============================================================================
29
+ // PAGE METADATA
30
+ // ============================================================================
31
+
32
+ export const NAMESPACE = 'products';
33
+
34
+ export const meta: PageMeta = {
35
+ namespace: NAMESPACE,
36
+ icon: <Package />,
37
+ route: '/products',
38
+ auth: { required: true, role: 'admin' }, // Admin-only page
39
+ };
40
+
41
+ // ============================================================================
42
+ // PAGE COMPONENT
43
+ // ============================================================================
44
+
45
+ export default function ProductsListPage() {
46
+ const user = useAuth('user');
47
+
48
+ // Zero-Config: EntityList handles everything automatically:
49
+ // - Fetches data using entity's listFields (optimized query)
50
+ // - Renders columns based on field definitions
51
+ // - Applies visibility rules based on user role
52
+ // - Includes search, sort, pagination
53
+ // - Add/Edit/Delete buttons with proper permissions
54
+
55
+ return (
56
+ <PageContainer>
57
+ <EntityList
58
+ entity={productEntity}
59
+ userRole={user?.role}
60
+ // Optional overrides:
61
+ // onRowClick={(item) => navigate(`/products/${item.id}`)}
62
+ // createPath="/products/new"
63
+ // hideActions={false}
64
+ // pageSize={25}
65
+ />
66
+ </PageContainer>
67
+ );
68
+ }
69
+
70
+ // ============================================================================
71
+ // ALTERNATIVE: Card Grid Layout
72
+ // ============================================================================
73
+ //
74
+ // For a card-based grid instead of table:
75
+ //
76
+ // import { EntityCardList } from '@donotdev/crud';
77
+ //
78
+ // export default function ProductsGridPage() {
79
+ // return (
80
+ // <PageContainer>
81
+ // <EntityCardList
82
+ // entity={productEntity}
83
+ // // Optional: custom card rendering
84
+ // // renderCard={(item) => <CustomProductCard product={item} />}
85
+ // />
86
+ // </PageContainer>
87
+ // );
88
+ // }
@@ -2,6 +2,31 @@
2
2
 
3
3
  This directory contains the Firebase Functions for the {{APP_NAME}} app, generated using the DoNotDev framework's scaffolding system.
4
4
 
5
+ ## ⚠️ CRITICAL: Import Rules
6
+
7
+ **Functions run on Node.js - you MUST use `/server` imports or your function will crash on deploy.**
8
+
9
+ ```typescript
10
+ // ✅ CORRECT - Functions MUST use /server imports
11
+ import { getFirebaseAdminAuth } from '@donotdev/firebase/server';
12
+ import { getFirebaseAdminFirestore } from '@donotdev/firebase/server';
13
+ import { handleError } from '@donotdev/core/server';
14
+
15
+ // ❌ WRONG - This will crash on deploy (pulls in React/client code)
16
+ import { getAuth } from '@donotdev/firebase';
17
+ import { getFirestore } from '@donotdev/firebase';
18
+ import { handleError } from '@donotdev/core';
19
+ ```
20
+
21
+ **Why?** Functions run in Node.js, not the browser. Client imports (`@donotdev/firebase`) include React and browser-only code that will crash your function.
22
+
23
+ **Rule:** Always use `/server` suffix for:
24
+ - `@donotdev/firebase/server` (not `@donotdev/firebase`)
25
+ - `@donotdev/core/server` (not `@donotdev/core`)
26
+ - `@donotdev/utils/server` (not `@donotdev/utils`)
27
+
28
+ ---
29
+
5
30
  ## Structure
6
31
 
7
32
  ```
@@ -5,7 +5,9 @@
5
5
  */
6
6
 
7
7
  import { build } from 'esbuild';
8
- import { createAppFunctionsConfig } from '@donotdev/core/functions';
8
+ import { writeFileSync } from 'fs';
9
+ import { createAppFunctionsConfig, generateFunctionsYamlWithInfo } from '@donotdev/core/functions';
10
+ import { functionsConfig } from './functions.config.js';
9
11
 
10
12
  async function buildFunctions() {
11
13
  console.log('🔨 Building {{APP_NAME}} functions...');
@@ -33,6 +35,11 @@ async function buildFunctions() {
33
35
 
34
36
  console.log('✅ {{APP_NAME}} functions built successfully!');
35
37
  console.log('📁 Output directory: lib/');
38
+
39
+ // Generate functions.yaml from config
40
+ const { yaml, staticFunctions, crudFunctions } = generateFunctionsYamlWithInfo(functionsConfig);
41
+ writeFileSync('functions.yaml', yaml);
42
+ console.log(`📄 Generated functions.yaml: ${staticFunctions.length} static + ${crudFunctions.length} CRUD functions`);
36
43
 
37
44
  // Log bundle info if metafile is available
38
45
  if (result.metafile) {
@@ -5,7 +5,9 @@
5
5
  */
6
6
 
7
7
  import { build } from 'esbuild';
8
- import { createAppFunctionsConfig } from '@donotdev/core/functions';
8
+ import { writeFileSync } from 'fs';
9
+ import { createAppFunctionsConfig, generateFunctionsYamlWithInfo } from '@donotdev/core/functions';
10
+ import { functionsConfig } from './functions.config.js';
9
11
 
10
12
  async function buildFunctions() {
11
13
  console.log('🔨 Building {{APP_NAME}} functions...');
@@ -33,6 +35,11 @@ async function buildFunctions() {
33
35
 
34
36
  console.log('✅ {{APP_NAME}} functions built successfully!');
35
37
  console.log('📁 Output directory: lib/');
38
+
39
+ // Generate functions.yaml from config
40
+ const { yaml, staticFunctions, crudFunctions } = generateFunctionsYamlWithInfo(functionsConfig);
41
+ writeFileSync('functions.yaml', yaml);
42
+ console.log(`📄 Generated functions.yaml: ${staticFunctions.length} static + ${crudFunctions.length} CRUD functions`);
36
43
 
37
44
  // Log bundle info if metafile is available
38
45
  if (result.metafile) {
@@ -2,18 +2,29 @@
2
2
 
3
3
  /**
4
4
  * @fileoverview {{APP_NAME}} Firebase Functions
5
- * @description {{APP_NAME}} functions that wrap framework functions with {{APP_NAME}}-specific configuration
5
+ * @description Auto-registered CRUD + custom functions for {{APP_NAME}}
6
6
  */
7
7
 
8
8
  import { initializeApp } from 'firebase-admin/app';
9
+ import { registerCrudFunctions } from '@donotdev/functions/firebase';
10
+ import * as entities from 'entities';
9
11
 
10
- // Initialize Firebase Admin if not already initialized
12
+ // Initialize Firebase Admin
11
13
  if (!(globalThis as any).__FIREBASE_ADMIN_INITIALIZED__) {
12
14
  initializeApp();
13
15
  (globalThis as any).__FIREBASE_ADMIN_INITIALIZED__ = true;
14
16
  }
15
17
 
16
- // Export auth functions
18
+ // ============================================================================
19
+ // CRUD Functions (auto-registered from entities)
20
+ // ============================================================================
21
+ // Registers: create_cars, get_cars, list_cars, update_cars, delete_cars
22
+ // create_customers, get_customers, ... for each entity
23
+ registerCrudFunctions(entities);
24
+
25
+ // ============================================================================
26
+ // Auth Functions
27
+ // ============================================================================
17
28
  export {
18
29
  setCustomClaims,
19
30
  getCustomClaims,
@@ -21,25 +32,8 @@ export {
21
32
  getUserAuthStatus,
22
33
  } from './auth';
23
34
 
24
- // Export OAuth functions
25
- export {
26
- grantGitHubAccess,
27
- revokeGitHubAccess,
28
- checkGitHubAccess,
29
- } from './oauth';
30
-
31
- // Export CRUD functions
32
- export {
33
- createEntity,
34
- updateEntity,
35
- deleteEntity,
36
- getEntity,
37
- listEntities,
38
- } from './crud';
39
-
40
- // Export billing functions
41
- export {
42
- processPaymentSuccess,
43
- refreshSubscriptionStatus,
44
- stripeWebhook,
45
- } from './billing';
35
+ // ============================================================================
36
+ // Custom Functions (analytics, webhooks, etc.)
37
+ // ============================================================================
38
+ // export { getDashboardMetrics } from './analytics';
39
+ // export { stripeWebhook } from './billing';
@@ -0,0 +1,35 @@
1
+ // functions/functions.config.js
2
+
3
+ /**
4
+ * @fileoverview {{APP_NAME}} Functions Configuration
5
+ * @description Configuration for Firebase Functions deployment
6
+ * @type {import('@donotdev/types').FunctionsConfig}
7
+ *
8
+ * This config file is used to auto-generate functions.yaml during build.
9
+ *
10
+ * - Static functions: List your custom functions here
11
+ * - CRUD functions: List entity names to auto-generate CRUD endpoints
12
+ * (e.g., ['car', 'customer'] generates: create_car, get_car, list_car, update_car, delete_car, etc.)
13
+ */
14
+
15
+ export const functionsConfig = {
16
+ defaults: {
17
+ region: ['us-central1'],
18
+ platform: 'gcfv2',
19
+ labels: { app: '{{APP_NAME}}' },
20
+ },
21
+ functions: {
22
+ // Add your static (non-CRUD) functions here
23
+ // Example:
24
+ // getCustomClaims: { category: 'auth' },
25
+ // setCustomClaims: { category: 'auth' },
26
+ // stripeWebhook: { category: 'billing', trigger: 'http' },
27
+ },
28
+ crud: {
29
+ // List entity names to auto-generate CRUD functions
30
+ // Each entity will generate: create_*, get_*, list_*, update_*, delete_*
31
+ // Example:
32
+ // entities: ['car', 'customer', 'inquiry'],
33
+ entities: [],
34
+ },
35
+ };
@@ -1,18 +1,8 @@
1
1
  {
2
+ "extends": "../../../tsconfig.functions.json",
2
3
  "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "lib": ["ES2022"],
7
- "strict": true,
8
- "skipLibCheck": true,
9
- "esModuleInterop": true,
10
- "resolveJsonModule": true,
11
- "isolatedModules": true,
12
- "forceConsistentCasingInFileNames": true,
13
- "allowSyntheticDefaultImports": true,
14
- "noUncheckedIndexedAccess": true,
15
- "types": ["node"],
4
+ "module": "preserve",
5
+ "moduleResolution": "bundler",
16
6
  "outDir": "./lib",
17
7
  "rootDir": "./src",
18
8
  "declaration": true,
@@ -1,18 +1,6 @@
1
1
  {
2
+ "extends": "../../../tsconfig.functions.json",
2
3
  "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "lib": ["ES2022"],
7
- "strict": true,
8
- "skipLibCheck": true,
9
- "esModuleInterop": true,
10
- "resolveJsonModule": true,
11
- "isolatedModules": true,
12
- "forceConsistentCasingInFileNames": true,
13
- "allowSyntheticDefaultImports": true,
14
- "noUncheckedIndexedAccess": true,
15
- "types": ["node"],
16
4
  "outDir": "./lib",
17
5
  "rootDir": "./src",
18
6
  "declaration": true,
@@ -0,0 +1,223 @@
1
+ /**
2
+ * @fileoverview Example Entity Definition
3
+ *
4
+ * COPY THIS FILE and rename to your entity (e.g., Product.ts, Task.ts, Customer.ts)
5
+ *
6
+ * HOW ENTITIES WORK:
7
+ * 1. Define fields with types, visibility, validation
8
+ * 2. Set access rules (who can create/read/update/delete)
9
+ * 3. Choose which fields show in list vs card vs form views
10
+ * 4. Framework generates: Firestore queries, forms, lists, cards automatically
11
+ *
12
+ * FIRESTORE PATH: `products/{productId}` (collection name from 'collection' prop)
13
+ */
14
+
15
+ import { defineEntity } from '@donotdev/core';
16
+
17
+ // ============================================================================
18
+ // ENTITY DEFINITION
19
+ // ============================================================================
20
+
21
+ export const productEntity = defineEntity({
22
+ // Entity name - used for i18n keys, display labels
23
+ name: 'Product',
24
+
25
+ // Firestore collection path
26
+ collection: 'products',
27
+
28
+ // Fields shown in EntityList table (column order matters)
29
+ listFields: ['name', 'category', 'price', 'status'],
30
+
31
+ // Fields shown in EntityCardList (card layout)
32
+ listCardFields: ['images', 'name', 'price', 'category'],
33
+
34
+ // ==========================================================================
35
+ // ACCESS RULES - Who can do what
36
+ // ==========================================================================
37
+ //
38
+ // 'guest' → Anyone (including not logged in)
39
+ // 'user' → Any logged-in user
40
+ // 'owner' → Only the document owner (createdById matches)
41
+ // 'admin' → Only admin role
42
+ //
43
+ access: {
44
+ create: 'admin', // Only admins can create products
45
+ read: 'guest', // Anyone can view products (public catalog)
46
+ update: 'admin', // Only admins can edit
47
+ delete: 'admin', // Only admins can delete
48
+ },
49
+
50
+ // ==========================================================================
51
+ // FIELD DEFINITIONS
52
+ // ==========================================================================
53
+ //
54
+ // FIELD TYPES:
55
+ // 'text' → Single-line text input
56
+ // 'textarea' → Multi-line text
57
+ // 'number' → Numeric input
58
+ // 'email' → Email with validation
59
+ // 'tel' → Phone number with country picker
60
+ // 'select' → Dropdown with options
61
+ // 'combobox' → Searchable dropdown
62
+ // 'switch' → Toggle on/off
63
+ // 'checkbox' → Multiple selections
64
+ // 'date' → Date picker
65
+ // 'timestamp' → Date + time
66
+ // 'images' → Image upload (multiple)
67
+ // 'reference' → Link to another entity
68
+ //
69
+ // VISIBILITY:
70
+ // 'guest' → Everyone can see this field
71
+ // 'user' → Only logged-in users
72
+ // 'owner' → Only document owner
73
+ // 'admin' → Only admins
74
+ //
75
+ // EDITABLE:
76
+ // 'admin' → Only admins can edit
77
+ // 'owner' → Only owner can edit
78
+ // 'create-only' → Set on creation, read-only after
79
+ //
80
+ fields: {
81
+ // ==========================================================================
82
+ // PUBLIC FIELDS - Visible to all, editable by admin
83
+ // ==========================================================================
84
+
85
+ name: {
86
+ name: 'name',
87
+ label: 'name', // i18n key: products.fields.name
88
+ type: 'text',
89
+ visibility: 'guest',
90
+ editable: 'admin',
91
+ validation: { required: true },
92
+ },
93
+
94
+ description: {
95
+ name: 'description',
96
+ label: 'description',
97
+ type: 'textarea',
98
+ visibility: 'guest',
99
+ editable: 'admin',
100
+ validation: { required: false },
101
+ },
102
+
103
+ category: {
104
+ name: 'category',
105
+ label: 'category',
106
+ type: 'select',
107
+ visibility: 'guest',
108
+ editable: 'admin',
109
+ validation: {
110
+ required: true,
111
+ options: [
112
+ { value: 'electronics', label: 'category.electronics' },
113
+ { value: 'clothing', label: 'category.clothing' },
114
+ { value: 'home', label: 'category.home' },
115
+ { value: 'other', label: 'category.other' },
116
+ ],
117
+ },
118
+ },
119
+
120
+ price: {
121
+ name: 'price',
122
+ label: 'price',
123
+ type: 'number',
124
+ visibility: 'guest',
125
+ editable: 'admin',
126
+ validation: { required: true },
127
+ },
128
+
129
+ images: {
130
+ name: 'images',
131
+ label: 'images',
132
+ type: 'images',
133
+ visibility: 'guest',
134
+ editable: 'admin',
135
+ validation: { required: false },
136
+ },
137
+
138
+ // ==========================================================================
139
+ // ADMIN-ONLY FIELDS - Hidden from public, visible to admins
140
+ // ==========================================================================
141
+
142
+ cost: {
143
+ name: 'cost',
144
+ label: 'cost',
145
+ type: 'number',
146
+ visibility: 'admin', // Only admins see this
147
+ editable: 'admin',
148
+ validation: { required: false },
149
+ },
150
+
151
+ supplier: {
152
+ name: 'supplier',
153
+ label: 'supplier',
154
+ type: 'text',
155
+ visibility: 'admin',
156
+ editable: 'admin',
157
+ validation: { required: false },
158
+ },
159
+
160
+ // ==========================================================================
161
+ // STATUS FIELD - Framework provides draft/available/deleted by default
162
+ // ==========================================================================
163
+ // Add custom status options that extend framework defaults:
164
+
165
+ status: {
166
+ name: 'status',
167
+ label: 'status',
168
+ type: 'select',
169
+ visibility: 'admin',
170
+ validation: {
171
+ options: [
172
+ // Framework adds: draft, available, deleted
173
+ // Add your custom statuses:
174
+ { value: 'featured', label: 'status.featured' },
175
+ { value: 'clearance', label: 'status.clearance' },
176
+ ],
177
+ },
178
+ },
179
+ },
180
+ });
181
+
182
+ // ============================================================================
183
+ // USAGE EXAMPLES
184
+ // ============================================================================
185
+ //
186
+ // In a List Page:
187
+ // ```tsx
188
+ // import { EntityList } from '@donotdev/crud';
189
+ // import { productEntity } from '../entities/ExampleEntity';
190
+ //
191
+ // export default function ProductsListPage() {
192
+ // return (
193
+ // <PageContainer>
194
+ // <EntityList entity={productEntity} />
195
+ // </PageContainer>
196
+ // );
197
+ // }
198
+ // ```
199
+ //
200
+ // In a Form Page:
201
+ // ```tsx
202
+ // import { EntityFormRenderer, useCrud } from '@donotdev/crud';
203
+ // import { productEntity } from '../entities/ExampleEntity';
204
+ //
205
+ // export default function ProductPage() {
206
+ // const { get, add, update } = useCrud(productEntity);
207
+ // // ... see ExampleFormPage.tsx for full pattern
208
+ // }
209
+ // ```
210
+ //
211
+ // In a Card Grid:
212
+ // ```tsx
213
+ // import { EntityCardList } from '@donotdev/crud';
214
+ // import { productEntity } from '../entities/ExampleEntity';
215
+ //
216
+ // export default function ProductsGridPage() {
217
+ // return (
218
+ // <PageContainer>
219
+ // <EntityCardList entity={productEntity} />
220
+ // </PageContainer>
221
+ // );
222
+ // }
223
+ // ```