@objectql/starter-basic 1.6.1
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/LICENSE +21 -0
- package/README.md +17 -0
- package/dist/demo.app.yml +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/main.menu.yml +30 -0
- package/dist/modules/kitchen-sink/kitchen_sink.data.yml +18 -0
- package/dist/modules/kitchen-sink/kitchen_sink.object.yml +154 -0
- package/dist/modules/projects/pages/create_project_wizard.page.yml +244 -0
- package/dist/modules/projects/pages/project_detail.page.yml +258 -0
- package/dist/modules/projects/project_approval.workflow.yml +51 -0
- package/dist/modules/projects/project_status.report.yml +39 -0
- package/dist/modules/projects/projects.action.d.ts +104 -0
- package/dist/modules/projects/projects.action.js +363 -0
- package/dist/modules/projects/projects.action.js.map +1 -0
- package/dist/modules/projects/projects.data.yml +13 -0
- package/dist/modules/projects/projects.form.yml +41 -0
- package/dist/modules/projects/projects.hook.d.ts +15 -0
- package/dist/modules/projects/projects.hook.js +302 -0
- package/dist/modules/projects/projects.hook.js.map +1 -0
- package/dist/modules/projects/projects.object.yml +148 -0
- package/dist/modules/projects/projects.permission.yml +141 -0
- package/dist/modules/projects/projects.validation.yml +37 -0
- package/dist/modules/projects/projects.view.yml +35 -0
- package/dist/modules/tasks/tasks.data.yml +23 -0
- package/dist/modules/tasks/tasks.object.yml +34 -0
- package/dist/modules/tasks/tasks.permission.yml +167 -0
- package/dist/pages/dashboard.page.yml +206 -0
- package/dist/pages/landing.page.yml +275 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.js +20 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/kitchen_sink.d.ts +99 -0
- package/dist/types/kitchen_sink.js +3 -0
- package/dist/types/kitchen_sink.js.map +1 -0
- package/dist/types/projects.d.ts +47 -0
- package/dist/types/projects.js +3 -0
- package/dist/types/projects.js.map +1 -0
- package/dist/types/tasks.d.ts +31 -0
- package/dist/types/tasks.js +3 -0
- package/dist/types/tasks.js.map +1 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ObjectQL Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Basic Script Example
|
|
2
|
+
|
|
3
|
+
This is a minimal example demonstrating how to use ObjectQL as a library in a simple Node.js/TypeScript script.
|
|
4
|
+
|
|
5
|
+
It demonstrates:
|
|
6
|
+
1. How to initialize ObjectQL (`new ObjectQL(...)`)
|
|
7
|
+
2. How to connect to a SQLite database
|
|
8
|
+
3. How to define objects (`projects.object.yml`)
|
|
9
|
+
4. How to perform CRUD operations in a script
|
|
10
|
+
|
|
11
|
+
## Run
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm install
|
|
15
|
+
pnpm run build
|
|
16
|
+
node dist/index.js
|
|
17
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './types';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: main
|
|
2
|
+
label: Main Menu
|
|
3
|
+
type: sidebar
|
|
4
|
+
app: demo_app
|
|
5
|
+
|
|
6
|
+
items:
|
|
7
|
+
- name: core_business
|
|
8
|
+
label: Core Business
|
|
9
|
+
icon: briefcase
|
|
10
|
+
type: section
|
|
11
|
+
items:
|
|
12
|
+
- object: projects
|
|
13
|
+
- object: tasks
|
|
14
|
+
|
|
15
|
+
- name: showcase
|
|
16
|
+
label: Showcase
|
|
17
|
+
icon: flask
|
|
18
|
+
type: section
|
|
19
|
+
items:
|
|
20
|
+
- object: kitchen_sink
|
|
21
|
+
label: Component Gallery
|
|
22
|
+
|
|
23
|
+
- name: reporting
|
|
24
|
+
label: Reporting
|
|
25
|
+
icon: bar-chart
|
|
26
|
+
type: section
|
|
27
|
+
items:
|
|
28
|
+
- type: url
|
|
29
|
+
label: Dashboard
|
|
30
|
+
path: /dashboard
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
- simple_text: "Hello World"
|
|
2
|
+
long_text: |
|
|
3
|
+
This is a long text.
|
|
4
|
+
It spans multiple lines.
|
|
5
|
+
rich_content: "# Markdown Header\n\n- List Item 1\n- List Item 2"
|
|
6
|
+
count: 42
|
|
7
|
+
price: 99.99
|
|
8
|
+
progress: 0.75
|
|
9
|
+
is_active: true
|
|
10
|
+
due_date: "2024-12-31"
|
|
11
|
+
meeting_time: "2024-12-31T10:00:00Z"
|
|
12
|
+
status: "published"
|
|
13
|
+
tags: ["tech", "blog"]
|
|
14
|
+
email_address: "test@example.com"
|
|
15
|
+
website: "https://objectql.org"
|
|
16
|
+
metadata:
|
|
17
|
+
source: "seed_data"
|
|
18
|
+
version: 1
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
label: "Kitchen Sink (All Fields)"
|
|
2
|
+
description: "A demonstration of every supported field type in ObjectQL"
|
|
3
|
+
icon: "layout-grid-line"
|
|
4
|
+
|
|
5
|
+
fields:
|
|
6
|
+
# --- String Types ---
|
|
7
|
+
simple_text:
|
|
8
|
+
type: text
|
|
9
|
+
label: Simple Text
|
|
10
|
+
required: true
|
|
11
|
+
min_length: 3
|
|
12
|
+
max_length: 100
|
|
13
|
+
help_text: "Basic single-line text"
|
|
14
|
+
|
|
15
|
+
long_text:
|
|
16
|
+
type: textarea
|
|
17
|
+
label: Multi-line Text
|
|
18
|
+
rows: 4
|
|
19
|
+
|
|
20
|
+
rich_content:
|
|
21
|
+
type: markdown
|
|
22
|
+
label: Markdown Content
|
|
23
|
+
|
|
24
|
+
raw_html:
|
|
25
|
+
type: html
|
|
26
|
+
label: HTML Content
|
|
27
|
+
readonly: true # Usually HTML is generated or read-only
|
|
28
|
+
|
|
29
|
+
# --- Number Types ---
|
|
30
|
+
count:
|
|
31
|
+
type: number
|
|
32
|
+
label: Integer Count
|
|
33
|
+
scale: 0
|
|
34
|
+
|
|
35
|
+
price:
|
|
36
|
+
type: currency
|
|
37
|
+
label: Price
|
|
38
|
+
currency: USD
|
|
39
|
+
scale: 2
|
|
40
|
+
|
|
41
|
+
progress:
|
|
42
|
+
type: percent
|
|
43
|
+
label: Progress
|
|
44
|
+
min: 0
|
|
45
|
+
max: 1
|
|
46
|
+
scale: 2 # 0.55 -> 55%
|
|
47
|
+
|
|
48
|
+
# --- Boolean ---
|
|
49
|
+
is_active:
|
|
50
|
+
type: boolean
|
|
51
|
+
label: Is Active
|
|
52
|
+
defaultValue: true
|
|
53
|
+
|
|
54
|
+
# --- Date & Time ---
|
|
55
|
+
due_date:
|
|
56
|
+
type: date
|
|
57
|
+
label: Due Date
|
|
58
|
+
|
|
59
|
+
meeting_time:
|
|
60
|
+
type: datetime
|
|
61
|
+
label: Meeting (Date & Time)
|
|
62
|
+
|
|
63
|
+
alarm:
|
|
64
|
+
type: time
|
|
65
|
+
label: Alarm Time
|
|
66
|
+
|
|
67
|
+
# --- Selection ---
|
|
68
|
+
status:
|
|
69
|
+
type: select
|
|
70
|
+
label: Status
|
|
71
|
+
options:
|
|
72
|
+
- label: Draft
|
|
73
|
+
value: draft
|
|
74
|
+
- label: Published
|
|
75
|
+
value: published
|
|
76
|
+
- label: Archived
|
|
77
|
+
value: archived
|
|
78
|
+
defaultValue: draft
|
|
79
|
+
|
|
80
|
+
tags:
|
|
81
|
+
type: select
|
|
82
|
+
label: Tags
|
|
83
|
+
multiple: true
|
|
84
|
+
options:
|
|
85
|
+
- tech
|
|
86
|
+
- news
|
|
87
|
+
- blog # Simple string array shorthand
|
|
88
|
+
|
|
89
|
+
# --- Contact & Web ---
|
|
90
|
+
email_address:
|
|
91
|
+
type: email
|
|
92
|
+
label: Email
|
|
93
|
+
|
|
94
|
+
phone_number:
|
|
95
|
+
type: phone
|
|
96
|
+
label: Phone
|
|
97
|
+
|
|
98
|
+
website:
|
|
99
|
+
type: url
|
|
100
|
+
label: Website URL
|
|
101
|
+
|
|
102
|
+
# --- Media ---
|
|
103
|
+
profile_pic:
|
|
104
|
+
type: avatar
|
|
105
|
+
label: Avatar
|
|
106
|
+
|
|
107
|
+
attachment:
|
|
108
|
+
type: file
|
|
109
|
+
label: Attachment document
|
|
110
|
+
|
|
111
|
+
gallery:
|
|
112
|
+
type: image
|
|
113
|
+
label: Image Gallery
|
|
114
|
+
multiple: true
|
|
115
|
+
|
|
116
|
+
# --- Security ---
|
|
117
|
+
secret_code:
|
|
118
|
+
type: password
|
|
119
|
+
label: Secret Code
|
|
120
|
+
|
|
121
|
+
# --- Advanced / Complex ---
|
|
122
|
+
coords:
|
|
123
|
+
type: location
|
|
124
|
+
label: GPS Coordinates
|
|
125
|
+
|
|
126
|
+
metadata:
|
|
127
|
+
type: object
|
|
128
|
+
label: JSON Metadata
|
|
129
|
+
|
|
130
|
+
embedding:
|
|
131
|
+
type: vector
|
|
132
|
+
label: Vector Embedding
|
|
133
|
+
dimension: 1536 # e.g. OpenAI ada-002
|
|
134
|
+
|
|
135
|
+
# --- Relationships ---
|
|
136
|
+
related_project:
|
|
137
|
+
type: lookup
|
|
138
|
+
label: Related Project
|
|
139
|
+
reference_to: projects
|
|
140
|
+
|
|
141
|
+
# Note: master_detail requires this object to be the detail side
|
|
142
|
+
# parent_project:
|
|
143
|
+
# type: master_detail
|
|
144
|
+
# reference_to: projects
|
|
145
|
+
|
|
146
|
+
# --- Computed ---
|
|
147
|
+
# auto_id:
|
|
148
|
+
# type: auto_number
|
|
149
|
+
# prefix: "KS-"
|
|
150
|
+
|
|
151
|
+
# calc_value:
|
|
152
|
+
# type: formula
|
|
153
|
+
# expression: "{count} * 10"
|
|
154
|
+
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Project Creation Wizard
|
|
2
|
+
# A multi-step wizard for creating new projects
|
|
3
|
+
|
|
4
|
+
name: create_project_wizard
|
|
5
|
+
label: Create New Project
|
|
6
|
+
description: Step-by-step wizard for creating a project
|
|
7
|
+
icon: plus-circle
|
|
8
|
+
layout: wizard
|
|
9
|
+
|
|
10
|
+
# Only admins and managers can create projects
|
|
11
|
+
permissions:
|
|
12
|
+
view: ['admin', 'manager']
|
|
13
|
+
|
|
14
|
+
# Wizard steps
|
|
15
|
+
components:
|
|
16
|
+
# Step 1: Basic Information
|
|
17
|
+
- id: step_basic
|
|
18
|
+
type: container
|
|
19
|
+
label: Basic Information
|
|
20
|
+
description: Enter the project name and description
|
|
21
|
+
config:
|
|
22
|
+
step: 1
|
|
23
|
+
icon: info
|
|
24
|
+
components:
|
|
25
|
+
- id: basic_form
|
|
26
|
+
type: form
|
|
27
|
+
config:
|
|
28
|
+
layout: vertical
|
|
29
|
+
fields:
|
|
30
|
+
- name: name
|
|
31
|
+
label: Project Name
|
|
32
|
+
type: text
|
|
33
|
+
required: true
|
|
34
|
+
placeholder: My Awesome Project
|
|
35
|
+
help_text: Choose a descriptive name for your project
|
|
36
|
+
- name: description
|
|
37
|
+
label: Project Description
|
|
38
|
+
type: textarea
|
|
39
|
+
rows: 5
|
|
40
|
+
placeholder: Describe what this project is about
|
|
41
|
+
- name: category
|
|
42
|
+
label: Category
|
|
43
|
+
type: select
|
|
44
|
+
options:
|
|
45
|
+
- label: Development
|
|
46
|
+
value: development
|
|
47
|
+
- label: Marketing
|
|
48
|
+
value: marketing
|
|
49
|
+
- label: Research
|
|
50
|
+
value: research
|
|
51
|
+
- label: Operations
|
|
52
|
+
value: operations
|
|
53
|
+
actions:
|
|
54
|
+
on_validate:
|
|
55
|
+
type: custom
|
|
56
|
+
handler: validateBasicInfo
|
|
57
|
+
|
|
58
|
+
# Step 2: Team & Resources
|
|
59
|
+
- id: step_team
|
|
60
|
+
type: container
|
|
61
|
+
label: Team & Resources
|
|
62
|
+
description: Assign team members and set budget
|
|
63
|
+
config:
|
|
64
|
+
step: 2
|
|
65
|
+
icon: users
|
|
66
|
+
components:
|
|
67
|
+
- id: team_form
|
|
68
|
+
type: form
|
|
69
|
+
config:
|
|
70
|
+
layout: vertical
|
|
71
|
+
fields:
|
|
72
|
+
- name: owner
|
|
73
|
+
label: Project Manager
|
|
74
|
+
type: lookup
|
|
75
|
+
reference_to: users
|
|
76
|
+
required: true
|
|
77
|
+
help_text: Select the person responsible for this project
|
|
78
|
+
- name: team_members
|
|
79
|
+
label: Team Members
|
|
80
|
+
type: lookup
|
|
81
|
+
reference_to: users
|
|
82
|
+
multiple: true
|
|
83
|
+
help_text: Add team members who will work on this project
|
|
84
|
+
- name: budget
|
|
85
|
+
label: Budget
|
|
86
|
+
type: currency
|
|
87
|
+
currency: USD
|
|
88
|
+
help_text: Estimated budget for this project
|
|
89
|
+
- name: department
|
|
90
|
+
label: Department
|
|
91
|
+
type: select
|
|
92
|
+
options:
|
|
93
|
+
- label: Engineering
|
|
94
|
+
value: engineering
|
|
95
|
+
- label: Product
|
|
96
|
+
value: product
|
|
97
|
+
- label: Sales
|
|
98
|
+
value: sales
|
|
99
|
+
- label: Marketing
|
|
100
|
+
value: marketing
|
|
101
|
+
|
|
102
|
+
# Step 3: Timeline
|
|
103
|
+
- id: step_timeline
|
|
104
|
+
type: container
|
|
105
|
+
label: Timeline
|
|
106
|
+
description: Set project dates and milestones
|
|
107
|
+
config:
|
|
108
|
+
step: 3
|
|
109
|
+
icon: calendar
|
|
110
|
+
components:
|
|
111
|
+
- id: timeline_form
|
|
112
|
+
type: form
|
|
113
|
+
config:
|
|
114
|
+
layout: vertical
|
|
115
|
+
fields:
|
|
116
|
+
- name: start_date
|
|
117
|
+
label: Start Date
|
|
118
|
+
type: date
|
|
119
|
+
required: true
|
|
120
|
+
defaultValue: '{{today}}'
|
|
121
|
+
- name: end_date
|
|
122
|
+
label: Target End Date
|
|
123
|
+
type: date
|
|
124
|
+
required: true
|
|
125
|
+
help_text: Expected completion date
|
|
126
|
+
- name: priority
|
|
127
|
+
label: Priority
|
|
128
|
+
type: select
|
|
129
|
+
required: true
|
|
130
|
+
options:
|
|
131
|
+
- label: Low
|
|
132
|
+
value: low
|
|
133
|
+
- label: Medium
|
|
134
|
+
value: medium
|
|
135
|
+
- label: High
|
|
136
|
+
value: high
|
|
137
|
+
- label: Critical
|
|
138
|
+
value: critical
|
|
139
|
+
defaultValue: medium
|
|
140
|
+
- name: milestones
|
|
141
|
+
label: Key Milestones
|
|
142
|
+
type: grid
|
|
143
|
+
help_text: Define important project milestones
|
|
144
|
+
config:
|
|
145
|
+
columns:
|
|
146
|
+
- name: name
|
|
147
|
+
label: Milestone
|
|
148
|
+
type: text
|
|
149
|
+
- name: date
|
|
150
|
+
label: Target Date
|
|
151
|
+
type: date
|
|
152
|
+
- name: description
|
|
153
|
+
label: Description
|
|
154
|
+
type: text
|
|
155
|
+
allow_add: true
|
|
156
|
+
allow_delete: true
|
|
157
|
+
|
|
158
|
+
# Step 4: Review & Create
|
|
159
|
+
- id: step_review
|
|
160
|
+
type: container
|
|
161
|
+
label: Review & Create
|
|
162
|
+
description: Review your project details before creating
|
|
163
|
+
config:
|
|
164
|
+
step: 4
|
|
165
|
+
icon: check-square
|
|
166
|
+
components:
|
|
167
|
+
- id: review_summary
|
|
168
|
+
type: detail_view
|
|
169
|
+
label: Project Summary
|
|
170
|
+
config:
|
|
171
|
+
mode: readonly
|
|
172
|
+
sections:
|
|
173
|
+
- label: Basic Information
|
|
174
|
+
fields: ['name', 'description', 'category']
|
|
175
|
+
- label: Team
|
|
176
|
+
fields: ['owner', 'team_members', 'budget', 'department']
|
|
177
|
+
- label: Timeline
|
|
178
|
+
fields: ['start_date', 'end_date', 'priority']
|
|
179
|
+
|
|
180
|
+
- id: terms_checkbox
|
|
181
|
+
type: container
|
|
182
|
+
components:
|
|
183
|
+
- id: accept_terms
|
|
184
|
+
type: boolean
|
|
185
|
+
label: I confirm that all information is correct
|
|
186
|
+
required: true
|
|
187
|
+
|
|
188
|
+
# Wizard navigation actions
|
|
189
|
+
actions:
|
|
190
|
+
next_step:
|
|
191
|
+
type: custom
|
|
192
|
+
handler: validateAndProceed
|
|
193
|
+
|
|
194
|
+
previous_step:
|
|
195
|
+
type: custom
|
|
196
|
+
handler: goToPreviousStep
|
|
197
|
+
|
|
198
|
+
submit_wizard:
|
|
199
|
+
type: run_action
|
|
200
|
+
object: projects
|
|
201
|
+
action: create
|
|
202
|
+
success_message: Project created successfully!
|
|
203
|
+
on_error: show_modal
|
|
204
|
+
|
|
205
|
+
save_draft:
|
|
206
|
+
type: custom
|
|
207
|
+
handler: saveDraft
|
|
208
|
+
success_message: Draft saved
|
|
209
|
+
|
|
210
|
+
# Page state to track wizard progress
|
|
211
|
+
state:
|
|
212
|
+
initial:
|
|
213
|
+
current_step: 1
|
|
214
|
+
completed_steps: []
|
|
215
|
+
form_data:
|
|
216
|
+
name: ''
|
|
217
|
+
description: ''
|
|
218
|
+
category: ''
|
|
219
|
+
owner: null
|
|
220
|
+
team_members: []
|
|
221
|
+
budget: 0
|
|
222
|
+
department: ''
|
|
223
|
+
start_date: null
|
|
224
|
+
end_date: null
|
|
225
|
+
priority: medium
|
|
226
|
+
milestones: []
|
|
227
|
+
persist: true
|
|
228
|
+
storage_key: project_wizard_draft
|
|
229
|
+
|
|
230
|
+
# Page styling
|
|
231
|
+
style:
|
|
232
|
+
max_width: 800px
|
|
233
|
+
margin: 0 auto
|
|
234
|
+
padding: 40px 20px
|
|
235
|
+
|
|
236
|
+
# AI context
|
|
237
|
+
ai_context:
|
|
238
|
+
intent: Guide users through project creation with validation
|
|
239
|
+
persona: Project managers and team leads
|
|
240
|
+
tasks:
|
|
241
|
+
- Create new projects step by step
|
|
242
|
+
- Validate input at each stage
|
|
243
|
+
- Review before submission
|
|
244
|
+
- Save drafts for later
|