@objectql/create 4.0.1 → 4.0.3

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 (41) hide show
  1. package/package.json +1 -1
  2. package/templates/enterprise/CHANGELOG.md +20 -0
  3. package/templates/enterprise/README.md +2 -2
  4. package/templates/enterprise/jest.config.js +9 -1
  5. package/templates/enterprise/package.json +4 -5
  6. package/templates/enterprise/src/core/attachment.object.yml +10 -1
  7. package/templates/enterprise/src/core/organization.object.yml +41 -6
  8. package/templates/enterprise/src/core/user.object.yml +37 -12
  9. package/templates/enterprise/src/extensions/README.md +4 -4
  10. package/templates/enterprise/src/extensions/user_extension.object.yml +65 -0
  11. package/templates/enterprise/src/modules/crm/crm_account.object.yml +57 -13
  12. package/templates/enterprise/src/modules/crm/crm_contact.object.yml +42 -8
  13. package/templates/enterprise/src/modules/crm/crm_lead.object.yml +82 -21
  14. package/templates/enterprise/src/modules/crm/crm_opportunity.object.yml +65 -15
  15. package/templates/enterprise/src/modules/finance/finance_budget.object.yml +67 -16
  16. package/templates/enterprise/src/modules/finance/finance_expense.object.yml +75 -19
  17. package/templates/enterprise/src/modules/finance/finance_invoice.object.yml +61 -16
  18. package/templates/enterprise/src/modules/finance/finance_payment.object.yml +65 -16
  19. package/templates/enterprise/src/modules/hr/hr_department.object.yml +29 -2
  20. package/templates/enterprise/src/modules/hr/hr_employee.object.yml +50 -8
  21. package/templates/enterprise/src/modules/hr/hr_position.object.yml +46 -10
  22. package/templates/enterprise/src/modules/hr/hr_timesheet.object.yml +44 -8
  23. package/templates/enterprise/src/modules/project/project_milestone.object.yml +36 -4
  24. package/templates/enterprise/src/modules/project/project_project.object.yml +64 -13
  25. package/templates/enterprise/src/modules/project/project_task.object.yml +70 -9
  26. package/templates/enterprise/src/modules/project/project_timesheet_entry.object.yml +39 -4
  27. package/templates/enterprise/src/plugins/audit/audit.plugin.ts +8 -24
  28. package/templates/enterprise/src/plugins/audit/note.object.yml +17 -0
  29. package/templates/hello-world/CHANGELOG.md +16 -0
  30. package/templates/hello-world/README.md +73 -10
  31. package/templates/hello-world/package.json +1 -1
  32. package/templates/hello-world/src/index.ts +17 -5
  33. package/templates/starter/CHANGELOG.md +20 -0
  34. package/templates/starter/jest.config.js +9 -1
  35. package/templates/starter/package.json +1 -1
  36. package/templates/starter/src/modules/projects/projects.object.yml +65 -6
  37. package/templates/starter/src/modules/projects/projects.validation.yml +13 -4
  38. package/templates/starter/src/seed.ts +1 -1
  39. package/templates/enterprise/src/extensions/user.extension.object.yml +0 -42
  40. package/templates/enterprise/tsconfig.tsbuildinfo +0 -1
  41. package/templates/starter/tsconfig.tsbuildinfo +0 -1
@@ -1,13 +1,26 @@
1
+ # File: project_task.object.yml
2
+ # Object name is inferred from filename as 'project_task'
1
3
  label: Task
2
4
  description: Project task or work item
3
5
  icon: task-line
4
6
 
7
+ ai_context:
8
+ intent: "Track individual work items and tasks within projects"
9
+ domain: project_management
10
+ aliases: [task, work item, issue]
11
+ common_queries:
12
+ - "Show my assigned tasks"
13
+ - "Find overdue tasks"
14
+ - "List tasks by project"
15
+
5
16
  fields:
6
17
  name:
7
18
  type: text
8
19
  required: true
9
20
  label: Task Name
10
21
  index: true
22
+ ai_context:
23
+ intent: "Brief description of the task"
11
24
 
12
25
  project:
13
26
  type: lookup
@@ -15,73 +28,121 @@ fields:
15
28
  label: Project
16
29
  required: true
17
30
  index: true
31
+ ai_context:
32
+ intent: "Parent project containing this task"
33
+ semantic_type: hierarchy
18
34
 
19
35
  parent_task:
20
36
  type: lookup
21
37
  reference_to: project_task
22
38
  label: Parent Task
23
39
  index: true
40
+ ai_context:
41
+ intent: "Parent task for hierarchical task structure"
42
+ semantic_type: hierarchy
24
43
 
25
44
  description:
26
45
  type: textarea
27
46
  label: Description
47
+ ai_context:
48
+ intent: "Detailed task requirements and acceptance criteria"
28
49
 
29
50
  status:
30
51
  type: select
52
+ label: Task Status
31
53
  options:
32
- - todo
33
- - in_progress
34
- - in_review
35
- - blocked
36
- - completed
54
+ - label: To Do
55
+ value: todo
56
+ - label: In Progress
57
+ value: in_progress
58
+ - label: In Review
59
+ value: in_review
60
+ - label: Blocked
61
+ value: blocked
62
+ - label: Completed
63
+ value: completed
37
64
  defaultValue: todo
38
65
  required: true
39
66
  index: true
67
+ ai_context:
68
+ intent: "Current state of task execution"
69
+ is_state_machine: true
70
+ transitions:
71
+ todo: [in_progress]
72
+ in_progress: [in_review, blocked, completed]
73
+ in_review: [in_progress, completed]
74
+ blocked: [in_progress, todo]
75
+ completed: []
40
76
 
41
77
  priority:
42
78
  type: select
79
+ label: Priority
43
80
  options:
44
- - low
45
- - medium
46
- - high
47
- - critical
81
+ - label: Low
82
+ value: low
83
+ - label: Medium
84
+ value: medium
85
+ - label: High
86
+ value: high
87
+ - label: Critical
88
+ value: critical
48
89
  defaultValue: medium
49
90
  index: true
91
+ ai_context:
92
+ intent: "Task urgency and importance level"
93
+ selection_guidance: "Critical for blockers; High for urgent items"
50
94
 
51
95
  assigned_to:
52
96
  type: lookup
53
97
  reference_to: user
54
98
  label: Assigned To
55
99
  index: true
100
+ ai_context:
101
+ intent: "User responsible for completing this task"
102
+ semantic_type: ownership
103
+ selection_guidance: "Active team members with relevant skills"
56
104
 
57
105
  due_date:
58
106
  type: date
59
107
  label: Due Date
60
108
  index: true
109
+ ai_context:
110
+ intent: "Target completion deadline"
61
111
 
62
112
  completed_date:
63
113
  type: datetime
64
114
  label: Completion Date
115
+ ai_context:
116
+ intent: "Actual completion timestamp for reporting"
65
117
 
66
118
  estimated_hours:
67
119
  type: number
68
120
  label: Estimated Hours
69
121
  scale: 2
122
+ ai_context:
123
+ intent: "Planned effort for capacity planning"
70
124
 
71
125
  actual_hours:
72
126
  type: number
73
127
  label: Actual Hours
74
128
  scale: 2
129
+ ai_context:
130
+ intent: "Actual time spent for productivity tracking"
75
131
 
76
132
  milestone:
77
133
  type: lookup
78
134
  reference_to: project_milestone
79
135
  label: Milestone
80
136
  index: true
137
+ ai_context:
138
+ intent: "Associated milestone for tracking progress"
139
+ semantic_type: association
81
140
 
82
141
  tags:
83
142
  type: text
84
143
  label: Tags
144
+ ai_context:
145
+ intent: "Categorization labels for filtering and organization"
85
146
 
86
147
  indexes:
87
148
  # For project task list
@@ -1,7 +1,18 @@
1
+ # File: project_timesheet_entry.object.yml
2
+ # Object name is inferred from filename as 'project_timesheet_entry'
1
3
  label: Timesheet Entry
2
4
  description: Time entry for project tasks
3
5
  icon: time-line
4
6
 
7
+ ai_context:
8
+ intent: "Track time spent on project tasks for billing and productivity"
9
+ domain: project_management
10
+ aliases: [time entry, timesheet, time log]
11
+ common_queries:
12
+ - "Show time entries by project"
13
+ - "Find billable hours by employee"
14
+ - "List time entries for approval"
15
+
5
16
  fields:
6
17
  employee:
7
18
  type: lookup
@@ -9,6 +20,9 @@ fields:
9
20
  label: Employee
10
21
  required: true
11
22
  index: true
23
+ ai_context:
24
+ intent: "Employee who performed the work"
25
+ semantic_type: association
12
26
 
13
27
  project:
14
28
  type: lookup
@@ -16,12 +30,18 @@ fields:
16
30
  label: Project
17
31
  required: true
18
32
  index: true
33
+ ai_context:
34
+ intent: "Project this time is charged to"
35
+ semantic_type: hierarchy
19
36
 
20
37
  task:
21
38
  type: lookup
22
39
  reference_to: project_task
23
40
  label: Task
24
41
  index: true
42
+ ai_context:
43
+ intent: "Specific task this time is charged to"
44
+ semantic_type: association
25
45
 
26
46
  work_date:
27
47
  type: date
@@ -50,17 +70,32 @@ fields:
50
70
  status:
51
71
  type: select
52
72
  options:
53
- - draft
54
- - submitted
55
- - approved
56
- - rejected
73
+ - label: Draft
74
+ value: draft
75
+ - label: Submitted
76
+ value: submitted
77
+ - label: Approved
78
+ value: approved
79
+ - label: Rejected
80
+ value: rejected
57
81
  defaultValue: draft
58
82
  index: true
83
+ ai_context:
84
+ intent: "Approval workflow state"
85
+ is_state_machine: true
86
+ transitions:
87
+ draft: [submitted]
88
+ submitted: [approved, rejected]
89
+ approved: []
90
+ rejected: [draft]
59
91
 
60
92
  approved_by:
61
93
  type: lookup
62
94
  reference_to: user
63
95
  label: Approved By
96
+ ai_context:
97
+ intent: "Manager who approved this time entry"
98
+ semantic_type: association
64
99
 
65
100
  approved_at:
66
101
  type: datetime
@@ -6,38 +6,22 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
 
9
- // Import RuntimePlugin types from @objectql/core instead of @objectql/runtime
9
+ // Import ObjectQLPlugin types from @objectql/core instead of @objectstack/runtime
10
10
  // to avoid ESM/CJS compatibility issues
11
- interface RuntimeContext {
12
- engine: any; // ObjectStackKernel
13
- }
11
+ type RuntimeContext = any;
14
12
 
15
- interface RuntimePlugin {
13
+ interface ObjectQLPlugin {
16
14
  name: string;
17
- install?: (ctx: RuntimeContext) => void | Promise<void>;
18
- onStart?: (ctx: RuntimeContext) => void | Promise<void>;
15
+ init: (ctx: any) => void | Promise<void>;
19
16
  }
20
17
 
21
- const AuditLogPlugin: RuntimePlugin = {
18
+ const AuditLogPlugin: ObjectQLPlugin = {
22
19
  name: 'audit-log',
23
20
 
24
- async install(ctx: RuntimeContext) {
25
- console.log('[AuditLogPlugin] Installing...');
21
+ async init(ctx: any) {
22
+ console.log('[AuditLogPlugin] Init...');
26
23
  // Plugin installation logic here
27
- },
28
-
29
- async onStart(ctx: RuntimeContext) {
30
- console.log('[AuditLogPlugin] Starting...');
31
-
32
- // TODO: Register event handlers using the runtime context
33
- // The RuntimeContext provides:
34
- // - ctx.engine for accessing the kernel
35
-
36
- // For now, we'll just log that the plugin is started
37
- console.log('[AuditLogPlugin] Plugin started');
38
-
39
- // Note: The new plugin system uses RuntimeContext instead of PluginContextData
40
- // This will need to be enhanced when the full events API is available
24
+ console.log('[AuditLogPlugin] Plugin initialized');
41
25
  }
42
26
  };
43
27
 
@@ -1,3 +1,20 @@
1
+ # File: note.object.yml
2
+ # Object name is inferred from filename as 'note'
3
+ label: Note
4
+ description: Audit note or comment
5
+ icon: file-text-line
6
+
7
+ ai_context:
8
+ intent: "Track audit notes and comments on records"
9
+ domain: audit
10
+ aliases: [note, comment, audit log]
11
+ common_queries:
12
+ - "Show recent notes"
13
+ - "Find notes by user"
14
+ - "List notes on a record"
15
+
1
16
  fields:
2
17
  content:
3
18
  type: text
19
+ ai_context:
20
+ intent: "Note content or comment text"
@@ -1,5 +1,21 @@
1
1
  # @example/hello-world
2
2
 
3
+ ## 4.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @objectql/core@4.0.3
9
+ - @objectql/driver-sql@4.0.3
10
+
11
+ ## 4.0.2
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies
16
+ - @objectql/core@4.0.2
17
+ - @objectql/driver-sql@4.0.2
18
+
3
19
  ## 4.0.1
4
20
 
5
21
  ### Patch Changes
@@ -1,11 +1,51 @@
1
1
  # Hello ObjectQL
2
2
 
3
- This is the simplest possible example of **ObjectQL**.
3
+ This is the simplest possible example of **ObjectQL** following the **latest ObjectStack specification** (v4.0+).
4
4
 
5
- It demonstrates:
6
- 1. **Zero Config:** No YAML files or server setup required.
7
- 2. **In-Memory SQL:** Uses SQLite in memory, so no database installation is needed.
8
- 3. **Inline Schema:** Defines the data model directly in code.
5
+ ## What it demonstrates
6
+
7
+ 1. **Zero Config:** No YAML files or server setup required
8
+ 2. **In-Memory SQL:** Uses SQLite in memory, so no database installation is needed
9
+ 3. **Inline Schema:** Defines the data model directly in code using programmatic API
10
+ 4. **Latest Spec Compliance:**
11
+ - Label/value format for select options
12
+ - Explicit field labels for AI-friendly metadata
13
+ - Proper field type declarations
14
+
15
+ ## Key Concepts
16
+
17
+ ### Metadata Definition Approaches
18
+
19
+ **Programmatic (This Example):**
20
+ ```typescript
21
+ app.registerObject({
22
+ name: 'deal', // Required when using code
23
+ fields: {
24
+ stage: {
25
+ type: 'select',
26
+ options: [
27
+ { label: 'New', value: 'new' }, // ✅ Latest spec format
28
+ { label: 'Negotiation', value: 'negotiation' }
29
+ ]
30
+ }
31
+ }
32
+ });
33
+ ```
34
+
35
+ **YAML-based (Recommended for Production):**
36
+ ```yaml
37
+ # File: deal.object.yml
38
+ # NO 'name:' field needed - inferred from filename! ✅
39
+ label: Deal
40
+ fields:
41
+ stage:
42
+ type: select
43
+ options:
44
+ - label: New
45
+ value: new
46
+ - label: Negotiation
47
+ value: negotiation
48
+ ```
9
49
 
10
50
  ## How to Run
11
51
 
@@ -16,14 +56,37 @@ Since you are in the monorepo, simply run:
16
56
  pnpm install
17
57
 
18
58
  # Run the script
19
- cd examples/starters/hello-world
59
+ cd examples/quickstart/hello-world
20
60
  pnpm start
21
61
  ```
22
62
 
23
63
  ## What you see
24
64
 
25
65
  The script will:
26
- 1. Initialize the ObjectQL engine.
27
- 2. Create a `deal` object definition on the fly.
28
- 3. Insert a record into the in-memory SQLite database.
29
- 4. Query it back and print the result.
66
+ 1. Initialize the ObjectQL engine with an in-memory SQLite driver
67
+ 2. Create a `deal` object definition programmatically
68
+ 3. Insert a record into the database
69
+ 4. Query it back and print the result
70
+
71
+ ## Expected Output
72
+
73
+ ```
74
+ 🚀 Starting ObjectQL Hello World...
75
+ Creating a new Deal...
76
+ ✅ Deals found in database: [
77
+ {
78
+ _id: '...',
79
+ title: 'Enterprise Contract',
80
+ amount: 50000,
81
+ stage: 'new',
82
+ created_at: '...',
83
+ updated_at: '...'
84
+ }
85
+ ]
86
+ ```
87
+
88
+ ## Next Steps
89
+
90
+ - See [Project Tracker Example](../../showcase/project-tracker/) for YAML-based metadata
91
+ - Read the [Metadata Standard Spec](https://protocol.objectstack.ai) from @objectstack/spec
92
+ - Explore the [ObjectQL Documentation](../../../content/docs/)
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectql/example-hello-world",
3
- "version": "4.0.1",
3
+ "version": "4.0.3",
4
4
  "private": true,
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,14 +26,26 @@ async function main() {
26
26
  }
27
27
  });
28
28
 
29
- // 3. Define Metadata Inline
29
+ // 3. Define Metadata Inline (Following Latest ObjectStack Specification)
30
+ // Note: When using registerObject(), the 'name' is required in code
31
+ // When using YAML files, the name is inferred from filename (e.g., deal.object.yml)
30
32
  app.registerObject({
31
- name: 'deal',
33
+ name: 'deal', // Required for programmatic registration
34
+ label: 'Deal', // Human-readable label
32
35
  fields: {
33
- title: { type: 'text', required: true },
34
- amount: { type: 'currency' },
36
+ title: {
37
+ type: 'text',
38
+ required: true,
39
+ label: 'Deal Title'
40
+ },
41
+ amount: {
42
+ type: 'currency',
43
+ label: 'Deal Amount'
44
+ },
35
45
  stage: {
36
- type: 'select',
46
+ type: 'select',
47
+ label: 'Deal Stage',
48
+ // Options use label/value format (ObjectStack spec v4.0+)
37
49
  options: [
38
50
  { label: 'New', value: 'new' },
39
51
  { label: 'Negotiation', value: 'negotiation' },
@@ -1,5 +1,25 @@
1
1
  # @objectql/starter-basic
2
2
 
3
+ ## 4.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @objectql/core@4.0.3
9
+ - @objectql/driver-sql@4.0.3
10
+ - @objectql/platform-node@4.0.3
11
+ - @objectql/types@4.0.3
12
+
13
+ ## 4.0.2
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies
18
+ - @objectql/core@4.0.2
19
+ - @objectql/driver-sql@4.0.2
20
+ - @objectql/platform-node@4.0.2
21
+ - @objectql/types@4.0.2
22
+
3
23
  ## 4.0.1
4
24
 
5
25
  ### Patch Changes
@@ -13,10 +13,18 @@ module.exports = {
13
13
  moduleNameMapper: {
14
14
  },
15
15
  transform: {
16
- '^.+\\.ts$': ['ts-jest', {
16
+ '^.+\\.(t|j)sx?$': ['ts-jest', {
17
17
  isolatedModules: true,
18
+ tsconfig: {
19
+ esModuleInterop: true,
20
+ allowSyntheticDefaultImports: true,
21
+ allowJs: true,
22
+ }
18
23
  }],
19
24
  },
25
+ transformIgnorePatterns: [
26
+ "/node_modules/(?!(@objectstack|.pnpm))"
27
+ ],
20
28
  collectCoverageFrom: [
21
29
  'src/**/*.ts',
22
30
  '!src/**/*.d.ts',
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectql/example-project-tracker",
3
- "version": "4.0.1",
3
+ "version": "4.0.3",
4
4
  "description": "ObjectQL Basic Example Project",
5
5
  "private": true,
6
6
  "keywords": [
@@ -1,49 +1,108 @@
1
+ # File: projects.object.yml
2
+ # Object name is inferred from filename as 'projects'
1
3
  label: Project
2
4
  icon: building-line
5
+
6
+ ai_context:
7
+ intent: "Track and manage software development projects"
8
+ domain: project_management
9
+ aliases: [project, initiative]
10
+ common_queries:
11
+ - "Find active projects"
12
+ - "Show projects by priority"
13
+ - "List projects with high budget"
14
+
3
15
  fields:
4
16
  name:
5
17
  type: text
6
18
  required: true
19
+ label: Project Name
7
20
  index: true # Field-level index
21
+ ai_context:
22
+ intent: "Primary identifier for the project"
23
+ examples: ["Website Redesign", "Mobile App v2.0"]
8
24
 
9
25
  status:
26
+ type: select
27
+ label: Project Status
10
28
  options:
11
- - planned
12
- - in_progress
13
- - completed
29
+ - label: Planned
30
+ value: planned
31
+ - label: In Progress
32
+ value: in_progress
33
+ - label: Completed
34
+ value: completed
14
35
  defaultValue: planned
15
36
  index: true
37
+ ai_context:
38
+ intent: "Track project lifecycle stage"
39
+ is_state_machine: true
40
+ transitions:
41
+ planned: [in_progress, completed]
42
+ in_progress: [completed, planned]
43
+ completed: []
16
44
 
17
45
  priority:
46
+ type: select
47
+ label: Priority Level
18
48
  options:
19
- - low
20
- - normal
21
- - high
49
+ - label: Low
50
+ value: low
51
+ - label: Normal
52
+ value: normal
53
+ - label: High
54
+ value: high
22
55
  defaultValue: normal
56
+ ai_context:
57
+ intent: "Prioritize project execution order"
58
+ selection_guidance: "High priority for urgent or critical projects"
23
59
 
24
60
  description:
25
61
  type: textarea
62
+ label: Project Description
63
+ ai_context:
64
+ intent: "Detailed project overview and objectives"
26
65
 
27
66
  owner:
28
67
  type: text
68
+ label: Project Owner
69
+ ai_context:
70
+ intent: "Person responsible for project success"
71
+ semantic_type: ownership
29
72
 
30
73
  budget:
31
74
  type: currency
75
+ label: Project Budget
76
+ ai_context:
77
+ intent: "Allocated financial resources"
78
+ validation_notes: "Must be non-negative; >$10k requires detailed description"
32
79
 
33
80
  start_date:
34
81
  type: date
82
+ label: Start Date
83
+ ai_context:
84
+ intent: "Project commencement date"
35
85
 
36
86
  end_date:
37
87
  type: date
88
+ label: End Date
89
+ ai_context:
90
+ intent: "Target completion date"
91
+ validation_notes: "Must be on or after start_date"
38
92
 
39
93
  approved_by:
40
94
  type: text
95
+ label: Approved By
96
+ ai_context:
97
+ intent: "Approver identity for audit trail"
41
98
 
42
99
  approved_at:
43
100
  type: datetime
101
+ label: Approval Timestamp
44
102
 
45
103
  approval_comment:
46
104
  type: textarea
105
+ label: Approval Comment
47
106
 
48
107
  indexes:
49
108
  # Composite index for reporting
@@ -1,5 +1,5 @@
1
- name: projects_validation
2
- object: projects
1
+ # File: projects.validation.yml
2
+ # Object is inferred from filename as 'projects'
3
3
  description: "Validation rules for Projects"
4
4
 
5
5
  rules:
@@ -8,25 +8,33 @@ rules:
8
8
  ai_context:
9
9
  intent: "Ensure project timeline is valid"
10
10
  business_rule: "Projects cannot end before they start"
11
+ rationale: "Maintaining data integrity for project scheduling"
11
12
  rule:
12
13
  field: end_date
13
14
  operator: ">="
14
15
  compare_to: start_date
15
- message: "End Date must be after Start Date"
16
+ message: "End Date must be on or after Start Date"
17
+ error_code: "INVALID_DATE_RANGE"
16
18
 
17
19
  - name: positive_budget
18
20
  type: field
21
+ ai_context:
22
+ intent: "Prevent negative budget values"
23
+ business_rule: "Project budget must be zero or positive"
19
24
  rule:
20
25
  field: budget
21
26
  operator: ">="
22
27
  value: 0
23
28
  message: "Budget cannot be negative"
29
+ error_code: "NEGATIVE_BUDGET"
24
30
 
25
31
  - name: comment_required_if_high_budget
26
32
  type: conditional
27
33
  description: "Description is required for high budget projects"
28
34
  ai_context:
29
- business_rule: "High value projects (>10k) must have a detailed description"
35
+ intent: "Ensure governance for high-value projects"
36
+ business_rule: "High value projects (>$10k) must have a detailed description for stakeholder transparency"
37
+ rationale: "Projects over $10,000 require executive oversight and clear documentation"
30
38
  condition:
31
39
  field: budget
32
40
  operator: ">"
@@ -35,3 +43,4 @@ rules:
35
43
  field: description
36
44
  operator: "not_empty"
37
45
  message: "Description is required for high budget projects (> $10,000)"
46
+ error_code: "HIGH_BUDGET_REQUIRES_DESCRIPTION"