@fluentcommerce/ai-skills 0.1.0
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 +622 -0
- package/bin/cli.mjs +1973 -0
- package/content/cli/agents/fluent-cli/agent.json +149 -0
- package/content/cli/agents/fluent-cli.md +132 -0
- package/content/cli/skills/fluent-bootstrap/SKILL.md +181 -0
- package/content/cli/skills/fluent-cli-index/SKILL.md +63 -0
- package/content/cli/skills/fluent-cli-mcp-cicd/SKILL.md +77 -0
- package/content/cli/skills/fluent-cli-reference/SKILL.md +1031 -0
- package/content/cli/skills/fluent-cli-retailer/SKILL.md +85 -0
- package/content/cli/skills/fluent-cli-settings/SKILL.md +106 -0
- package/content/cli/skills/fluent-connect/SKILL.md +886 -0
- package/content/cli/skills/fluent-module-deploy/SKILL.md +349 -0
- package/content/cli/skills/fluent-profile/SKILL.md +180 -0
- package/content/cli/skills/fluent-workflow/SKILL.md +310 -0
- package/content/dev/agents/fluent-dev/agent.json +88 -0
- package/content/dev/agents/fluent-dev.md +525 -0
- package/content/dev/reference-modules/catalog.json +4754 -0
- package/content/dev/skills/fluent-build/SKILL.md +192 -0
- package/content/dev/skills/fluent-connection-analysis/SKILL.md +386 -0
- package/content/dev/skills/fluent-custom-code/SKILL.md +895 -0
- package/content/dev/skills/fluent-data-module-scaffold/SKILL.md +714 -0
- package/content/dev/skills/fluent-e2e-test/SKILL.md +394 -0
- package/content/dev/skills/fluent-event-api/SKILL.md +945 -0
- package/content/dev/skills/fluent-feature-explain/SKILL.md +603 -0
- package/content/dev/skills/fluent-feature-plan/PLAN_TEMPLATE.md +695 -0
- package/content/dev/skills/fluent-feature-plan/SKILL.md +227 -0
- package/content/dev/skills/fluent-job-batch/SKILL.md +138 -0
- package/content/dev/skills/fluent-mermaid-validate/SKILL.md +86 -0
- package/content/dev/skills/fluent-module-scaffold/SKILL.md +1928 -0
- package/content/dev/skills/fluent-module-validate/SKILL.md +775 -0
- package/content/dev/skills/fluent-pre-deploy-check/SKILL.md +1108 -0
- package/content/dev/skills/fluent-retailer-config/SKILL.md +1111 -0
- package/content/dev/skills/fluent-rule-scaffold/SKILL.md +385 -0
- package/content/dev/skills/fluent-scope-decompose/SKILL.md +1021 -0
- package/content/dev/skills/fluent-session-audit-export/SKILL.md +632 -0
- package/content/dev/skills/fluent-session-summary/SKILL.md +195 -0
- package/content/dev/skills/fluent-settings/SKILL.md +1058 -0
- package/content/dev/skills/fluent-source-onboard/SKILL.md +632 -0
- package/content/dev/skills/fluent-system-monitoring/SKILL.md +767 -0
- package/content/dev/skills/fluent-test-data/SKILL.md +513 -0
- package/content/dev/skills/fluent-trace/SKILL.md +1143 -0
- package/content/dev/skills/fluent-transition-api/SKILL.md +346 -0
- package/content/dev/skills/fluent-version-manage/SKILL.md +744 -0
- package/content/dev/skills/fluent-workflow-analyzer/SKILL.md +959 -0
- package/content/dev/skills/fluent-workflow-builder/SKILL.md +319 -0
- package/content/dev/skills/fluent-workflow-deploy/SKILL.md +267 -0
- package/content/mcp-extn/agents/fluent-mcp.md +69 -0
- package/content/mcp-extn/skills/fluent-mcp-tools/SKILL.md +461 -0
- package/content/mcp-official/agents/fluent-mcp-core.md +91 -0
- package/content/mcp-official/skills/fluent-mcp-core/SKILL.md +94 -0
- package/content/rfl/agents/fluent-rfl.md +56 -0
- package/content/rfl/skills/fluent-rfl-assess/SKILL.md +172 -0
- package/docs/CAPABILITY_MAP.md +77 -0
- package/docs/CLI_COVERAGE.md +47 -0
- package/docs/DEV_WORKFLOW.md +802 -0
- package/docs/FLOW_RUN.md +142 -0
- package/docs/USE_CASES.md +404 -0
- package/metadata.json +156 -0
- package/package.json +51 -0
|
@@ -0,0 +1,695 @@
|
|
|
1
|
+
# Feature Plan Template
|
|
2
|
+
|
|
3
|
+
> **Source of truth** for all implementation plans generated by planning-gated skills.
|
|
4
|
+
> Referenced from individual skill Planning Gate sections.
|
|
5
|
+
> Enhance this file to improve all future plans across all skills.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Universal Source Classification
|
|
10
|
+
|
|
11
|
+
Every table row in every section of a plan carries a **Source** column. This makes plans self-contained — a reviewer can scan any section and immediately see what's new (risky, needs review), what's reused (lower risk, proven pattern), and what's unchanged (context only).
|
|
12
|
+
|
|
13
|
+
| Label | Meaning | Required Detail |
|
|
14
|
+
|-------|---------|----------------|
|
|
15
|
+
| **NEW** | Doesn't exist yet, must be created | Full pseudo logic / value shape / trigger spec |
|
|
16
|
+
| **EXISTING** | Already deployed, no modification needed | State current value, confirm no change |
|
|
17
|
+
| **MODIFIED** | Already exists but needs changes | Show before → after diff |
|
|
18
|
+
| **REUSED** | Pattern exists in codebase, copy the approach | Reference source file/rule |
|
|
19
|
+
| **OOTB** | Platform rule, use with configuration only | State which props/values to configure |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Plan File Conventions
|
|
24
|
+
|
|
25
|
+
**Account-scoped path:** `accounts/<PROFILE>/plans/<YYYY-MM-DD>-<skill-short-name>-<brief-slug>.md`
|
|
26
|
+
|
|
27
|
+
**Repo-scoped path:** `.fluent-ai-skills/plans/<YYYY-MM-DD>-<skill-short-name>-<brief-slug>.md`
|
|
28
|
+
|
|
29
|
+
Use account-scoped when targeting a Fluent environment. Use repo-scoped for package-internal work.
|
|
30
|
+
|
|
31
|
+
**Naming rules:**
|
|
32
|
+
- `<PROFILE>` — active Fluent CLI profile (e.g., `HMDEV`, `SAGIRISH`)
|
|
33
|
+
- `<YYYY-MM-DD>` — creation date
|
|
34
|
+
- `<skill-short-name>` — generating skill without `fluent-` prefix (e.g., `feature-plan`, `rule-scaffold`, `workflow-builder`)
|
|
35
|
+
- `<brief-slug>` — 2-4 word kebab-case description (e.g., `curbside-pickup`, `order-hd-returns`)
|
|
36
|
+
|
|
37
|
+
**Status lifecycle:** `PENDING` → `APPROVED` / `REJECTED` → implementation → session summary references plan file.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Template
|
|
42
|
+
|
|
43
|
+
Every plan file MUST follow this structure. Omit sections marked _optional_ when they don't apply. Sections marked **required** must always be present.
|
|
44
|
+
|
|
45
|
+
````markdown
|
|
46
|
+
# Plan: <Feature Title>
|
|
47
|
+
|
|
48
|
+
| Field | Value |
|
|
49
|
+
|-------|-------|
|
|
50
|
+
| Status | `PENDING` |
|
|
51
|
+
| Created | <YYYY-MM-DD> |
|
|
52
|
+
| Skill | `/fluent-<skill-name>` |
|
|
53
|
+
| Profile | <PROFILE> |
|
|
54
|
+
| Retailer(s) | <RETAILER_REF> (ID: <N>) |
|
|
55
|
+
| Module(s) | <module names if applicable> |
|
|
56
|
+
| Approved by | --- |
|
|
57
|
+
| Revision | 1 |
|
|
58
|
+
|
|
59
|
+
## Table of Contents
|
|
60
|
+
|
|
61
|
+
1. [Business Context](#1-business-context)
|
|
62
|
+
2. [Scope](#2-scope)
|
|
63
|
+
3. [Architecture & Diagrams](#3-architecture--diagrams)
|
|
64
|
+
4. [Workflows](#4-workflows)
|
|
65
|
+
5. [Statuses](#5-statuses)
|
|
66
|
+
6. [Rulesets — Change Summary](#6-rulesets--change-summary)
|
|
67
|
+
- 6.1 [Complete Workflow Inventory](#61-complete-workflow-inventory) (full rules + props)
|
|
68
|
+
7. [Rules Inventory](#7-rules-inventory)
|
|
69
|
+
8. [Detailed Design (New Rules)](#8-detailed-design-new-rules)
|
|
70
|
+
9. [Settings](#9-settings)
|
|
71
|
+
10. [Webhooks](#10-webhooks)
|
|
72
|
+
11. [Scheduled Events](#11-scheduled-events)
|
|
73
|
+
12. [GraphQL Operations](#12-graphql-operations)
|
|
74
|
+
13. [Cross-Entity Impact](#13-cross-entity-impact)
|
|
75
|
+
14. [Files](#14-files)
|
|
76
|
+
15. [Risks & Mitigations](#15-risks--mitigations)
|
|
77
|
+
16. [Test Plan](#16-test-plan)
|
|
78
|
+
17. [Deployment Sequence](#17-deployment-sequence)
|
|
79
|
+
18. [Rollback Plan](#18-rollback-plan)
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 1. Business Context **[required]**
|
|
84
|
+
|
|
85
|
+
> **Business objective:** <What business problem does this solve?>
|
|
86
|
+
> **Trigger:** <What triggered this — user story, bug, go-live requirement?>
|
|
87
|
+
> **Success criteria:** <How do we know this is done? Measurable outcome.>
|
|
88
|
+
|
|
89
|
+
## 2. Scope **[required]**
|
|
90
|
+
|
|
91
|
+
<One paragraph: what this plan achieves technically. Reference specific workflow names, entity types, and module names.>
|
|
92
|
+
|
|
93
|
+
**In scope:**
|
|
94
|
+
- <bulleted list>
|
|
95
|
+
|
|
96
|
+
**Out of scope:**
|
|
97
|
+
- <bulleted list>
|
|
98
|
+
|
|
99
|
+
## 3. Architecture & Diagrams **[required — at least one diagram]**
|
|
100
|
+
|
|
101
|
+
### 3.1 State Machine
|
|
102
|
+
|
|
103
|
+
> Mermaid `stateDiagram-v2` for workflow creation or modification.
|
|
104
|
+
> Show ALL statuses. Annotate: `:::added`, `:::removed`, `:::modified`.
|
|
105
|
+
|
|
106
|
+
```mermaid
|
|
107
|
+
stateDiagram-v2
|
|
108
|
+
[*] --> CREATED
|
|
109
|
+
CREATED --> BOOKED : ConfirmOrder
|
|
110
|
+
BOOKED --> AWAITING_PICKUP : CurbsideRequested:::added
|
|
111
|
+
AWAITING_PICKUP --> COMPLETE : ConfirmPickup:::added
|
|
112
|
+
AWAITING_PICKUP --> CANCELLED : CurbsideTimeout:::added
|
|
113
|
+
BOOKED --> FULFILLED : FulfilmentComplete
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 3.2 Cross-Entity Event Flow
|
|
117
|
+
|
|
118
|
+
> Mermaid `sequenceDiagram` for cross-entity events, webhooks, or multi-step processing.
|
|
119
|
+
|
|
120
|
+
```mermaid
|
|
121
|
+
sequenceDiagram
|
|
122
|
+
participant WF as Workflow Engine
|
|
123
|
+
participant R1 as CreateCurbsidePickup [NEW]
|
|
124
|
+
participant R2 as ValidatePickupWindow [NEW]
|
|
125
|
+
participant GQL as GraphQL API
|
|
126
|
+
participant EXT as External Webhook
|
|
127
|
+
|
|
128
|
+
WF->>R2: run(context) [ORDER]
|
|
129
|
+
R2->>GQL: SettingUtils.getSettingByRef(curbside.pickup.config)
|
|
130
|
+
GQL-->>R2: {maxPickupHours: 48}
|
|
131
|
+
R2->>R2: Validate window
|
|
132
|
+
WF->>R1: run(context) [ORDER]
|
|
133
|
+
R1->>GQL: query order items
|
|
134
|
+
GQL-->>R1: OrderItem[]
|
|
135
|
+
R1->>GQL: createFulfilment(type=CURBSIDE)
|
|
136
|
+
GQL-->>R1: Fulfilment created
|
|
137
|
+
WF->>EXT: POST /curbside/notify (via SendWebhook OOTB)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 3.3 Data Flow _(optional)_
|
|
141
|
+
|
|
142
|
+
> Mermaid `flowchart` for complex processing, decision trees, or event propagation chains.
|
|
143
|
+
|
|
144
|
+
### 3.4 Before → After Diff _(optional)_
|
|
145
|
+
|
|
146
|
+
> For modifications to existing workflows. Use `workflow.diff` output or describe changes.
|
|
147
|
+
|
|
148
|
+
### 3.5 Entity Relationships _(optional)_
|
|
149
|
+
|
|
150
|
+
> For module scaffolding or retailer config. Show entity types and their edges.
|
|
151
|
+
|
|
152
|
+
### 3.6 Workflow Processing Flow **[required when modifying an existing workflow]**
|
|
153
|
+
|
|
154
|
+
> Mermaid `flowchart TD` showing the complete ruleset→status processing chain for each modified workflow.
|
|
155
|
+
> Highlights NEW and MODIFIED rulesets with green styling. Shows how new rulesets fit into the existing flow.
|
|
156
|
+
> This complements the state machine (§3.1) which shows statuses only — this shows the rulesets that drive transitions.
|
|
157
|
+
|
|
158
|
+
```mermaid
|
|
159
|
+
flowchart TD
|
|
160
|
+
subgraph "ORDER (order lifecycle)"
|
|
161
|
+
O1[CREATED] -->|CREATE| O2[ON_VALIDATION]
|
|
162
|
+
O2 -->|ValidateOrder| O2
|
|
163
|
+
O2 -->|"ConfirmValidation + ProcessOrder"| O3[IN_PROGRESS]
|
|
164
|
+
O3 -->|NotifyFulfilmentShipped| O4[SHIPPED]
|
|
165
|
+
O4 -->|"NotifyFulfilmentDelivered + TransitionToCompleted"| O5[COMPLETED]
|
|
166
|
+
end
|
|
167
|
+
subgraph "FULFILMENT_CHOICE (FC routing)"
|
|
168
|
+
FC1[FC CREATED] -->|RouteFulfilmentChoice| FC2{Route by type}
|
|
169
|
+
FC2 -->|HD| FC3[ProcessHDFC]
|
|
170
|
+
FC2 -->|CC| FC4[ProcessCCFC]
|
|
171
|
+
FC2 -->|CURBSIDE| FC5[ProcessCurbsideFC]:::added
|
|
172
|
+
end
|
|
173
|
+
subgraph "FULFILMENT (lifecycle by subtype)"
|
|
174
|
+
F1[FUL CREATED] -->|AssignFulfilment| F2[READY]
|
|
175
|
+
F2 -->|ConfirmAllocation| F3[RECEIVED]
|
|
176
|
+
F3 -->|CreateInvoice| F4[INVOICED]
|
|
177
|
+
F4 -->|ConfirmPick| F5[PICKPACK]
|
|
178
|
+
F5 -->|"ReadyForPickup (CURBSIDE)"| F6[READY_FOR_PICKUP]:::added
|
|
179
|
+
F6 -->|"ConfirmCollection (CURBSIDE)"| F7[COLLECTED]:::added
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
classDef added fill:#90EE90,stroke:#333
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
> **Format guidance:**
|
|
186
|
+
> - One `subgraph` per entity type in the workflow
|
|
187
|
+
> - Node labels show status names; edge labels show ruleset/event names
|
|
188
|
+
> - Use `:::added` class for NEW rulesets/statuses, bold edge labels for MODIFIED
|
|
189
|
+
> - Keep it high-level — show the routing and status flow, not individual rules within rulesets
|
|
190
|
+
> - This diagram pairs with §6.1 Complete Workflow Inventory which shows the detail per ruleset
|
|
191
|
+
|
|
192
|
+
## 4. Workflows **[required]**
|
|
193
|
+
|
|
194
|
+
| Workflow | Source | Current Ver | Action | Details |
|
|
195
|
+
|----------|--------|-------------|--------|---------|
|
|
196
|
+
| ORDER::HD | MODIFIED | v12 | Modify | Add CurbsidePickupRequested ruleset, add 2 statuses |
|
|
197
|
+
| FULFILMENT::CURBSIDE | NEW | — | Create | New workflow for curbside fulfilments |
|
|
198
|
+
| FULFILMENT::HD | EXISTING | v8 | — | No change — listed for context |
|
|
199
|
+
|
|
200
|
+
## 5. Statuses **[required when touching workflows]**
|
|
201
|
+
|
|
202
|
+
| Status | Source | Entity Type | Workflow | Added By |
|
|
203
|
+
|--------|--------|-------------|----------|----------|
|
|
204
|
+
| CREATED | EXISTING | ORDER | ORDER::HD | Already in workflow |
|
|
205
|
+
| BOOKED | EXISTING | ORDER | ORDER::HD | Already in workflow |
|
|
206
|
+
| AWAITING_PICKUP | NEW | ORDER | ORDER::HD | SetState in CurbsidePickupRequested ruleset |
|
|
207
|
+
| PICKED_UP | NEW | ORDER | ORDER::HD | SetState in ConfirmCurbsidePickup ruleset |
|
|
208
|
+
| READY_FOR_PICKUP | NEW | FULFILMENT | FULFILMENT::CURBSIDE | SetState in PrepareCurbside ruleset |
|
|
209
|
+
| COLLECTED | NEW | FULFILMENT | FULFILMENT::CURBSIDE | SetState in ConfirmCollection ruleset |
|
|
210
|
+
|
|
211
|
+
## 6. Rulesets — Change Summary **[required when touching workflows]**
|
|
212
|
+
|
|
213
|
+
> Quick-glance table of what rulesets are being added, modified, or referenced. Full detail (every rule, every prop) lives in §6.1.
|
|
214
|
+
|
|
215
|
+
| Ruleset | Source | Workflow | From Status | To Status | Change Summary |
|
|
216
|
+
|---------|--------|----------|-------------|-----------|----------------|
|
|
217
|
+
| CurbsidePickupRequested | NEW | ORDER::HD | BOOKED | AWAITING_PICKUP | 3 rules: ValidatePickupWindow (NEW), CreateCurbsidePickupRule (NEW), SendEvent (OOTB) |
|
|
218
|
+
| ConfirmCurbsidePickup | NEW | ORDER::HD | AWAITING_PICKUP | PICKED_UP | 2 rules: UpdateFulfilmentStatus (EXISTING), SetOrderStatus (OOTB) |
|
|
219
|
+
| BookOrder | EXISTING | ORDER::HD | CREATED | BOOKED | No change — listed for context |
|
|
220
|
+
|
|
221
|
+
### 6.1 Complete Workflow Inventory **[required when modifying an existing workflow]**
|
|
222
|
+
|
|
223
|
+
> The **single source of truth** for the entire workflow. Lists ALL rulesets — not just new/modified — with every rule and every prop value.
|
|
224
|
+
> This replaces the need to read the raw workflow JSON. Reviewers can see exactly where new rulesets fit, what's already there, and what each rule does.
|
|
225
|
+
|
|
226
|
+
**Format:** One block per ruleset, grouped by entity type. Each block shows:
|
|
227
|
+
- **Heading:** `# | RulesetName | Source marker` — bold for NEW/MODIFIED
|
|
228
|
+
- **Metadata:** Entity type, subtype (if filtered), trigger status, event type
|
|
229
|
+
- **Description:** What the ruleset does
|
|
230
|
+
- **Rules table:** Every rule in execution order with full prop values and source annotations
|
|
231
|
+
- **User actions:** If the ruleset exposes UI buttons
|
|
232
|
+
|
|
233
|
+
**Source markers:** `EXISTING` = no change, `MODIFIED` = changed by this plan (show what changed), `NEW` = added by this plan
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
#### ORDER Rulesets (N existing, N new, N modified)
|
|
238
|
+
|
|
239
|
+
##### 1. CREATE | EXISTING
|
|
240
|
+
**Entity:** ORDER | **Trigger:** CREATED | **EventType:** NORMAL
|
|
241
|
+
> Order created. Create missing products, send webhook, branch on fraud.
|
|
242
|
+
|
|
243
|
+
| # | Rule | Props | Source |
|
|
244
|
+
|---|------|-------|--------|
|
|
245
|
+
| 1 | CreateMissingVariantProducts | — | EXISTING |
|
|
246
|
+
| 2 | SendWebhookWithDynamicAttributes | `setting: webhook.order.created` | EXISTING |
|
|
247
|
+
| 3 | SendEventOnVerifyingAttributeValue | `attributeName: fraudCheckRequired, onMatchEventName: InitFraudCheck, noMatchEventName: SkipFraudCheck` | EXISTING |
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
##### 2. BookOrder | EXISTING
|
|
252
|
+
**Entity:** ORDER | **Trigger:** BOOKED | **EventType:** NORMAL
|
|
253
|
+
> Standard booking, no change.
|
|
254
|
+
|
|
255
|
+
| # | Rule | Props | Source |
|
|
256
|
+
|---|------|-------|--------|
|
|
257
|
+
| 1 | ... | ... | EXISTING |
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
##### 3. **CurbsidePickupRequested** | **NEW**
|
|
262
|
+
**Entity:** ORDER | **Trigger:** BOOKED | **EventType:** NORMAL
|
|
263
|
+
> Validates curbside request (time window, vehicle desc) and creates CURBSIDE fulfilment.
|
|
264
|
+
|
|
265
|
+
| # | Rule | Props | Source |
|
|
266
|
+
|---|------|-------|--------|
|
|
267
|
+
| 1 | **ValidatePickupWindow** | `configSettingName: curbside.pickup.config, pickupTimePath: event.requestedPickupTime, vehicleDescPath: event.vehicleDescription` | **NEW** |
|
|
268
|
+
| 2 | **CreateCurbsidePickupRule** | `fulfilmentType: CURBSIDE, pickupLocationPath: event.pickupLocationRef` | **NEW** |
|
|
269
|
+
| 3 | SendEvent | `eventName: FulfilmentCreated` | OOTB |
|
|
270
|
+
|
|
271
|
+
**User Actions:**
|
|
272
|
+
```json
|
|
273
|
+
[{"eventName": "CurbsidePickupRequested", "context": [{"label": "REQUEST CURBSIDE PICKUP", "type": "PRIMARY"}]}]
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
> _Repeat for every ruleset in the workflow. Use `...` only for large EXISTING blocks where props are unchanged and well-known. Never abbreviate NEW or MODIFIED rulesets._
|
|
279
|
+
|
|
280
|
+
#### Summary
|
|
281
|
+
|
|
282
|
+
| Entity | Existing | New | Modified | Total |
|
|
283
|
+
|--------|----------|-----|----------|-------|
|
|
284
|
+
| ORDER | N | N | N | N |
|
|
285
|
+
| FULFILMENT_CHOICE | N | N | N | N |
|
|
286
|
+
| FULFILMENT | N | N | N | N |
|
|
287
|
+
| **Total** | **N** | **N** | **N** | **N** |
|
|
288
|
+
|
|
289
|
+
> **Key rules for this section:**
|
|
290
|
+
> - **Every ruleset gets a block** — no exceptions. This is the complete workflow.
|
|
291
|
+
> - **Every rule in every ruleset gets a row** with its full props.
|
|
292
|
+
> - **Props must show actual values**, not placeholders. For EXISTING rulesets, read from the workflow JSON.
|
|
293
|
+
> - **NEW and MODIFIED blocks are bolded** in the heading and in rule rows.
|
|
294
|
+
> - **MODIFIED rulesets** must show what changed — add a note like "Added rule #3 (NEW)" or "Changed prop `type` from `CC` to `CURBSIDE`".
|
|
295
|
+
> - **Group by entity type** with entity-level count headers.
|
|
296
|
+
> - **User actions** are shown as JSON blocks below the rules table (only if the ruleset has them).
|
|
297
|
+
> - This section replaces the need to cross-reference §6 and §6.1 — it is the single comprehensive reference.
|
|
298
|
+
|
|
299
|
+
## 7. Rules Inventory **[required]**
|
|
300
|
+
|
|
301
|
+
> ALL rules involved in the feature. Every rule classified by source.
|
|
302
|
+
> A feature typically involves a mix of OOTB, existing custom, and new custom rules.
|
|
303
|
+
|
|
304
|
+
| ID | Rule Name | Source | Module / Plugin | Entity | Inline/Scheduled | Purpose |
|
|
305
|
+
|----|-----------|--------|----------------|--------|-----------------|---------|
|
|
306
|
+
| R1 | CreateCurbsidePickupRule | **NEW** | sagirish-extensions | ORDER | Inline | Creates CURBSIDE fulfilment with pickup location |
|
|
307
|
+
| R2 | ValidatePickupWindow | **NEW** | sagirish-extensions | ORDER | Inline | Validates pickup time is within allowed window |
|
|
308
|
+
| R3 | SendEvent | **OOTB** | fc-core | ORDER | Inline | Fires CurbsidePickupCreated → FULFILMENT. Config: `eventName=CurbsidePickupCreated` |
|
|
309
|
+
| R4 | SetAttributes | **OOTB** | fc-core | FULFILMENT | Inline | Sets estimatedPickupTime from event attribute. Config: `attributeMap={...}` |
|
|
310
|
+
| R5 | SendWebhook | **OOTB** | fc-plugin-webhook | ORDER | Inline | HTTP POST to curbside notification endpoint. Config: `settingName=webhook.curbside.notify` |
|
|
311
|
+
| R6 | ScheduleExpiry | **OOTB** | fc-plugin-order | ORDER | Inline | Schedules CurbsideTimeout event. Config: `delay=30m, eventName=CurbsideTimeout` |
|
|
312
|
+
| R7 | UpdateFulfilmentStatus | **EXISTING** | sagirish-extensions | FULFILMENT | Inline | Reused from HD flow — no code changes needed |
|
|
313
|
+
| R8 | SetOrderStatus | **OOTB** | fc-core | ORDER | Inline | Sets ORDER to target status. Config: `status=AWAITING_PICKUP` |
|
|
314
|
+
|
|
315
|
+
> **For OOTB rules:** state the prop/config values to set in the ruleset.
|
|
316
|
+
> **For EXISTING rules:** confirm no code changes needed, or if MODIFIED, note what changes.
|
|
317
|
+
> **For NEW rules:** full pseudo logic in §8.
|
|
318
|
+
|
|
319
|
+
## 8. Detailed Design (New Rules) **[required if any NEW rules exist]**
|
|
320
|
+
|
|
321
|
+
> For each **NEW** rule in §7, provide: class metadata, parameters table, pseudo logic, and GraphQL operations.
|
|
322
|
+
> Skip this section entirely if all rules are OOTB or EXISTING.
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
### R1: CreateCurbsidePickupRule
|
|
327
|
+
|
|
328
|
+
**Class:** `com.fluentcommerce.rule.order.CreateCurbsidePickupRule`
|
|
329
|
+
**Extends:** `BaseRule`
|
|
330
|
+
**Entity:** ORDER
|
|
331
|
+
|
|
332
|
+
#### Parameters
|
|
333
|
+
|
|
334
|
+
| Param | Type | Required | Default | Description |
|
|
335
|
+
|-------|------|----------|---------|-------------|
|
|
336
|
+
| pickupLocationPath | String | Yes | — | JSON path to pickup location ref |
|
|
337
|
+
| estimatedPickupTimePath | String | No | — | JSON path to estimated pickup time |
|
|
338
|
+
| fulfilmentType | String | No | `CURBSIDE` | Fulfilment subtype |
|
|
339
|
+
| vehicleDescriptionPath | String | No | — | JSON path to vehicle description |
|
|
340
|
+
|
|
341
|
+
#### Pseudo Logic
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
FUNCTION run(context):
|
|
345
|
+
order = context.getEntity()
|
|
346
|
+
event = context.getEvent()
|
|
347
|
+
|
|
348
|
+
// 1. Extract required fields
|
|
349
|
+
pickupLocationRef = extractFromPath(event, props.pickupLocationPath)
|
|
350
|
+
IF pickupLocationRef IS NULL:
|
|
351
|
+
THROW "Pickup location ref is required but was null at path: {pickupLocationPath}"
|
|
352
|
+
|
|
353
|
+
// 2. Extract optional fields
|
|
354
|
+
estimatedPickupTime = extractFromPath(event, props.estimatedPickupTimePath) // nullable
|
|
355
|
+
vehicleDescription = extractFromPath(event, props.vehicleDescriptionPath) // nullable
|
|
356
|
+
|
|
357
|
+
// 3. Fetch order items
|
|
358
|
+
items = DynamicUtils.queryList(context, "items", OrderItem.class, null)
|
|
359
|
+
IF items IS EMPTY:
|
|
360
|
+
THROW "Order has no items — cannot create fulfilment"
|
|
361
|
+
|
|
362
|
+
// 4. Build fulfilment
|
|
363
|
+
fulfilmentRef = "CURB-{order.ref}-{pickupLocationRef}"
|
|
364
|
+
fulfilmentInput = CreateFulfilmentInput {
|
|
365
|
+
ref: fulfilmentRef,
|
|
366
|
+
type: props.fulfilmentType OR "CURBSIDE",
|
|
367
|
+
deliveryType: "CURBSIDE",
|
|
368
|
+
order: { id: order.id },
|
|
369
|
+
fromLocation: { ref: pickupLocationRef },
|
|
370
|
+
items: items.map(i => { ref: i.ref, quantity: i.quantity }),
|
|
371
|
+
attributes: [
|
|
372
|
+
{ name: "pickupLocationRef", value: pickupLocationRef },
|
|
373
|
+
{ name: "estimatedPickupTime", value: estimatedPickupTime },
|
|
374
|
+
{ name: "vehicleDescription", value: vehicleDescription },
|
|
375
|
+
{ name: "deliveryType", value: "CURBSIDE" },
|
|
376
|
+
{ name: "createdByRule", value: "CreateCurbsidePickupRule" }
|
|
377
|
+
]
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// 5. Execute mutation
|
|
381
|
+
DynamicUtils.create(context, fulfilmentInput)
|
|
382
|
+
|
|
383
|
+
// 6. Log
|
|
384
|
+
context.addLog("Created curbside fulfilment {fulfilmentRef} for order {order.ref}")
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
#### GraphQL Operations
|
|
388
|
+
|
|
389
|
+
**Query — Fetch order items:** _(REUSED pattern from CreateFulfilmentFromSourcingLocation)_
|
|
390
|
+
```graphql
|
|
391
|
+
query {
|
|
392
|
+
orderById(id: $orderId) {
|
|
393
|
+
items { edges { node { id ref quantity productRef } } }
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
**Mutation — Create fulfilment:** _(REUSED pattern)_
|
|
399
|
+
```graphql
|
|
400
|
+
mutation($input: CreateFulfilmentInput!) {
|
|
401
|
+
createFulfilment(input: $input) { id ref status }
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
### R2: ValidatePickupWindow
|
|
408
|
+
|
|
409
|
+
**Class:** `com.fluentcommerce.rule.order.ValidatePickupWindowRule`
|
|
410
|
+
**Extends:** `BaseRule`
|
|
411
|
+
**Entity:** ORDER
|
|
412
|
+
|
|
413
|
+
#### Parameters
|
|
414
|
+
|
|
415
|
+
| Param | Type | Required | Default | Description |
|
|
416
|
+
|-------|------|----------|---------|-------------|
|
|
417
|
+
| configSettingName | String | Yes | — | Setting key for pickup config JSON |
|
|
418
|
+
| pickupTimePath | String | Yes | — | JSON path to requested pickup time in event |
|
|
419
|
+
|
|
420
|
+
#### Pseudo Logic
|
|
421
|
+
|
|
422
|
+
```
|
|
423
|
+
FUNCTION run(context):
|
|
424
|
+
order = context.getEntity()
|
|
425
|
+
event = context.getEvent()
|
|
426
|
+
|
|
427
|
+
// 1. Read config from setting
|
|
428
|
+
config = SettingUtils.getSettingByRef(context, props.configSettingName)
|
|
429
|
+
maxPickupHours = config.lobValue.maxPickupHours
|
|
430
|
+
|
|
431
|
+
// 2. Extract requested pickup time from event
|
|
432
|
+
requestedPickupTime = extractFromPath(event, props.pickupTimePath)
|
|
433
|
+
IF requestedPickupTime IS NULL:
|
|
434
|
+
THROW "Requested pickup time is required at path: {pickupTimePath}"
|
|
435
|
+
|
|
436
|
+
// 3. Validate window
|
|
437
|
+
orderCreatedOn = order.createdOn
|
|
438
|
+
deadline = orderCreatedOn + maxPickupHours hours
|
|
439
|
+
IF requestedPickupTime > deadline:
|
|
440
|
+
THROW "Pickup time {requestedPickupTime} exceeds allowed window of {maxPickupHours}h from order creation"
|
|
441
|
+
|
|
442
|
+
// 4. Pass — validation gate, no mutation
|
|
443
|
+
context.addLog("Order {order.ref} passed pickup window validation")
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
#### GraphQL Operations
|
|
447
|
+
|
|
448
|
+
**Query — Read setting:** _(REUSED pattern — SettingUtils utility)_
|
|
449
|
+
```graphql
|
|
450
|
+
query {
|
|
451
|
+
settings(first: 1, filter: { name: { eq: $settingName }, context: { eq: "RETAILER" } }) {
|
|
452
|
+
edges { node { lobValue } }
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
|
|
459
|
+
> _Repeat this pattern for each NEW rule._
|
|
460
|
+
|
|
461
|
+
## 9. Settings **[required when creating/modifying settings]**
|
|
462
|
+
|
|
463
|
+
| Setting Key | Source | Context | Context ID | Value Type | Shape / Example | Used By (Rule) |
|
|
464
|
+
|------------|--------|---------|-----------|-----------|-----------------|---------------|
|
|
465
|
+
| curbside.pickup.config | **NEW** | RETAILER | 5 | LOB | `{"maxPickupHours": 48, "zones": ["ZONE_A", "ZONE_B"], "requireVehicleDesc": true}` | R2: ValidatePickupWindow |
|
|
466
|
+
| webhook.curbside.notify | **NEW** | RETAILER | 5 | LOB | `{"url": "https://store-api.example.com/curbside/notify", "headers": {"X-Api-Key": "..."}}` | R5: SendWebhook |
|
|
467
|
+
| ORDER_HD_FULFILMENT_TYPE | **EXISTING** | RETAILER | 5 | STRING | Already exists, value `"HD"` — no change | — |
|
|
468
|
+
|
|
469
|
+
> **For NEW settings:** full JSON example showing all fields.
|
|
470
|
+
> **For EXISTING settings:** confirm current value and whether it needs modification.
|
|
471
|
+
> **For MODIFIED settings:** show before → after diff.
|
|
472
|
+
|
|
473
|
+
## 10. Webhooks _(optional)_
|
|
474
|
+
|
|
475
|
+
| Setting Name | Source | Method | Endpoint Pattern | Trigger Rule | Payload Shape |
|
|
476
|
+
|-------------|--------|--------|-----------------|-------------|---------------|
|
|
477
|
+
| webhook.curbside.notify | **NEW** | POST | `${url}` from setting | R5: SendWebhook (OOTB) | `{"orderRef": "...", "pickupTime": "...", "locationRef": "...", "vehicleDesc": "..."}` |
|
|
478
|
+
|
|
479
|
+
> Omit this section if no webhooks are involved.
|
|
480
|
+
|
|
481
|
+
## 11. Scheduled Events _(optional)_
|
|
482
|
+
|
|
483
|
+
| Event Name | Source | Delay | Entity Type | Triggered By (Rule) | Purpose |
|
|
484
|
+
|-----------|--------|-------|-------------|-------------------|---------|
|
|
485
|
+
| CurbsideTimeout | **NEW** | 30min | ORDER | R6: ScheduleExpiry (OOTB) | Cancel pickup if not collected |
|
|
486
|
+
|
|
487
|
+
> Omit this section if no scheduled events are involved.
|
|
488
|
+
|
|
489
|
+
## 12. GraphQL Operations **[required when rules make GraphQL calls]**
|
|
490
|
+
|
|
491
|
+
| Operation | Source | Type | Root Field | Selected Fields | Used By (Rule) | Purpose |
|
|
492
|
+
|-----------|--------|------|-----------|----------------|---------------|---------|
|
|
493
|
+
| Fetch order items | **REUSED** pattern from CreateFulfilmentFromSourcingLocation | Query | orderById.items | id, ref, quantity | R1: CreateCurbsidePickupRule | Get items for fulfilment creation |
|
|
494
|
+
| Create fulfilment | **REUSED** pattern | Mutation | createFulfilment | ref, type, order, items, attributes | R1: CreateCurbsidePickupRule | Create CURBSIDE fulfilment |
|
|
495
|
+
| Read setting | **REUSED** — SettingUtils | Query | settings | lobValue | R2: ValidatePickupWindow | Read pickup config |
|
|
496
|
+
|
|
497
|
+
> **"REUSED pattern"** means existing code in the codebase already does this — copy the approach.
|
|
498
|
+
> **"NEW"** would mean a novel GraphQL operation not seen in the codebase.
|
|
499
|
+
|
|
500
|
+
## 13. Cross-Entity Impact **[required for multi-entity features]**
|
|
501
|
+
|
|
502
|
+
| Source Entity | Target Entity | Mechanism | Source | Action |
|
|
503
|
+
|--------------|--------------|-----------|--------|--------|
|
|
504
|
+
| ORDER | FULFILMENT | createFulfilment mutation | **NEW** (in R1: CreateCurbsidePickupRule) | Creates CURBSIDE fulfilment |
|
|
505
|
+
| ORDER | FULFILMENT | SendEvent (OOTB R3) | **REUSED** | Fires CurbsidePickupCreated |
|
|
506
|
+
| FULFILMENT | ORDER | SendEvent (OOTB) | **REUSED** | Status update event back to ORDER |
|
|
507
|
+
|
|
508
|
+
> Omit this section for single-entity features.
|
|
509
|
+
|
|
510
|
+
## 14. Files **[required]**
|
|
511
|
+
|
|
512
|
+
| # | Action | Path | Source | Description |
|
|
513
|
+
|---|--------|------|--------|-------------|
|
|
514
|
+
| 1 | Create | `.../src/main/java/.../CreateCurbsidePickupRule.java` | NEW | Rule R1 |
|
|
515
|
+
| 2 | Create | `.../src/test/java/.../CreateCurbsidePickupRuleTest.java` | NEW | Tests for R1 (4 tests) |
|
|
516
|
+
| 3 | Create | `.../src/main/java/.../ValidatePickupWindowRule.java` | NEW | Rule R2 |
|
|
517
|
+
| 4 | Create | `.../src/test/java/.../ValidatePickupWindowRuleTest.java` | NEW | Tests for R2 (3 tests) |
|
|
518
|
+
| 5 | Modify | `.../resources/module.json` | MODIFIED | Wire R1, R2 registrations |
|
|
519
|
+
| 6 | Modify | `accounts/.../workflows/.../ORDER__HD.json` | MODIFIED | Add CurbsidePickupRequested + ConfirmCurbsidePickup rulesets |
|
|
520
|
+
| 7 | Create | `accounts/.../workflows/.../FULFILMENT__CURBSIDE.json` | NEW | New curbside fulfilment workflow |
|
|
521
|
+
|
|
522
|
+
> All paths relative to `accounts/<PROFILE>/SOURCE/<repo>/`.
|
|
523
|
+
|
|
524
|
+
## 15. Risks & Mitigations **[required]**
|
|
525
|
+
|
|
526
|
+
| Risk | Severity | Impact | Mitigation |
|
|
527
|
+
|------|----------|--------|-----------|
|
|
528
|
+
| Ruleset trigger overlaps with existing OnCreate | HIGH | Events route to wrong ruleset | Verify trigger uniqueness via workflow-analyzer |
|
|
529
|
+
| New rule throws on null pickup location | MEDIUM | Order stuck in current status | Unit test null/empty inputs; validation guard |
|
|
530
|
+
| Webhook endpoint not provisioned at go-live | LOW | Notification silently fails | Setting updated later; log warning |
|
|
531
|
+
|
|
532
|
+
## 16. Test Plan **[required]**
|
|
533
|
+
|
|
534
|
+
| # | Test | Type | Event | Expected Status | Assertion |
|
|
535
|
+
|---|------|------|-------|----------------|-----------|
|
|
536
|
+
| 1 | Happy path: curbside pickup | E2E | CurbsidePickupRequested | ORDER → AWAITING_PICKUP | status + fulfilment created |
|
|
537
|
+
| 2 | Pickup collected | E2E | ConfirmCurbsidePickup | ORDER → PICKED_UP | status + fulfilment COLLECTED |
|
|
538
|
+
| 3 | Timeout cancellation | E2E | (wait 30min) | ORDER → CANCELLED | scheduled event fired |
|
|
539
|
+
| 4 | Regression: normal HD | E2E | CreateOrder | ORDER → BOOKED | Existing flow unaffected |
|
|
540
|
+
| 5 | R1: creates fulfilment | Unit | — | — | Mutation called with correct args |
|
|
541
|
+
| 6 | R1: throws on missing location | Unit | — | — | RuntimeException |
|
|
542
|
+
| 7 | R2: rejects expired window | Unit | — | — | RuntimeException |
|
|
543
|
+
| 8 | R2: passes valid pickup time | Unit | — | — | No exception, log written |
|
|
544
|
+
|
|
545
|
+
## 17. Deployment Sequence **[required for environment changes]**
|
|
546
|
+
|
|
547
|
+
| # | Step | Depends On | Skill | Rollback |
|
|
548
|
+
|---|------|-----------|-------|----------|
|
|
549
|
+
| 1 | Validate module structure | — | `/fluent-module-validate` | N/A |
|
|
550
|
+
| 2 | Build module v1.2.4 | 1 | `/fluent-build` | N/A (local) |
|
|
551
|
+
| 3 | Pre-deploy check | 2 | `/fluent-pre-deploy-check` | N/A |
|
|
552
|
+
| 4 | Deploy module | 3 (READY) | `/fluent-module-deploy` | Re-deploy v1.2.3 |
|
|
553
|
+
| 5 | Upload ORDER::HD v13 | 4 | `/fluent-workflow-deploy` | Re-upload v12 |
|
|
554
|
+
| 6 | Upload FULFILMENT::CURBSIDE v1 | 4 | `/fluent-workflow-deploy` | Delete workflow |
|
|
555
|
+
| 7 | Create settings (2) | 5, 6 | `/fluent-settings` | Delete settings |
|
|
556
|
+
| 8 | E2E test | 7 | `/fluent-e2e-test` | — |
|
|
557
|
+
|
|
558
|
+
> **Ordering constraint:** Module deploy (step 4) must complete before workflow deploy (steps 5-6). Workflows reference rules that are registered during module deployment. Deploying workflows before the module causes NO_MATCH events.
|
|
559
|
+
|
|
560
|
+
## 18. Rollback Plan _(optional — recommended for production changes)_
|
|
561
|
+
|
|
562
|
+
> How to reverse this change:
|
|
563
|
+
> 1. Re-upload ORDER::HD v12 via `/fluent-workflow-deploy`
|
|
564
|
+
> 2. Delete FULFILMENT::CURBSIDE workflow (or leave dormant -- no triggers will route to it)
|
|
565
|
+
> 3. Delete/disable webhook and config settings
|
|
566
|
+
> 4. Re-deploy module v1.2.3 via `/fluent-module-deploy`
|
|
567
|
+
> 5. Note: New statuses (AWAITING_PICKUP, PICKED_UP) become dormant (no triggers route to them)
|
|
568
|
+
````
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## Section Applicability Guide
|
|
573
|
+
|
|
574
|
+
Not every plan needs every section. Use this guide:
|
|
575
|
+
|
|
576
|
+
| Section | When Required |
|
|
577
|
+
|---------|-------------|
|
|
578
|
+
| 1. Business Context | **Always** |
|
|
579
|
+
| 2. Scope | **Always** |
|
|
580
|
+
| 3. Architecture & Diagrams | **Always** (at least one diagram) |
|
|
581
|
+
| 4. Workflows | **Always** (even "No workflow changes" is valid) |
|
|
582
|
+
| 5. Statuses | When adding or modifying workflow statuses |
|
|
583
|
+
| 6. Rulesets — Change Summary | **Always** when touching workflows (quick-glance table of what's changing) |
|
|
584
|
+
| 6.1 Complete Workflow Inventory | When modifying an existing workflow. **Full rules + props for every ruleset** — the single source of truth |
|
|
585
|
+
| 7. Rules Inventory | **Always** when the feature involves rules |
|
|
586
|
+
| 8. Detailed Design (New Rules) | When any rule is **NEW** |
|
|
587
|
+
| 9. Settings | When creating/modifying settings |
|
|
588
|
+
| 10. Webhooks | When adding webhook-based rules |
|
|
589
|
+
| 11. Scheduled Events | When adding time-delayed events |
|
|
590
|
+
| 12. GraphQL Operations | When rules make GraphQL calls |
|
|
591
|
+
| 13. Cross-Entity Impact | When feature spans multiple entity types |
|
|
592
|
+
| 14. Files | **Always** |
|
|
593
|
+
| 15. Risks | **Always** |
|
|
594
|
+
| 16. Test Plan | **Always** |
|
|
595
|
+
| 17. Deployment Sequence | When deploying to an environment |
|
|
596
|
+
| 18. Rollback Plan | Recommended for production; optional for dev/sandbox |
|
|
597
|
+
|
|
598
|
+
## Rules Classification Decision Flow
|
|
599
|
+
|
|
600
|
+
Before classifying any rule, follow this decision tree:
|
|
601
|
+
|
|
602
|
+
1. **Search `plugin.list`** for an OOTB match by name or description
|
|
603
|
+
2. **If OOTB exists and fits** → label as **OOTB**, document the prop values to configure
|
|
604
|
+
3. **If OOTB exists but doesn't quite fit** → document why. Consider wrapping (OOTB + custom pre/post rule) vs writing from scratch
|
|
605
|
+
4. **Search existing custom source** (`accounts/<PROFILE>/SOURCE/`) for a similar rule
|
|
606
|
+
5. **If existing custom fits** → label as **EXISTING**, confirm no changes needed
|
|
607
|
+
6. **If existing custom needs tweaks** → label as **MODIFIED**, show before → after
|
|
608
|
+
7. **If pattern exists** but no reusable rule → label the approach as **REUSED** in GraphQL Operations (§12)
|
|
609
|
+
8. **Only when no viable alternative exists** → label as **NEW**, provide full pseudo logic in §8
|
|
610
|
+
|
|
611
|
+
## Diagram Requirements
|
|
612
|
+
|
|
613
|
+
Plans MUST include visual Mermaid diagrams. Include ALL that apply:
|
|
614
|
+
|
|
615
|
+
| Diagram | When Required | Mermaid Type |
|
|
616
|
+
|---------|-------------|-------------|
|
|
617
|
+
| State machine | Any workflow creation or modification | `stateDiagram-v2` |
|
|
618
|
+
| Cross-entity event flow | Cross-entity events, webhooks, multi-step processing | `sequenceDiagram` |
|
|
619
|
+
| Data flow | Complex processing, decision trees, event propagation | `flowchart` |
|
|
620
|
+
| Before → After diff | Modifications to existing workflows | Text or `workflow.diff` |
|
|
621
|
+
| Entity relationships | Module scaffolding, retailer config | `erDiagram` or `flowchart` |
|
|
622
|
+
| Workflow processing flow | Modifying an existing workflow with multiple rulesets | `flowchart TD` |
|
|
623
|
+
|
|
624
|
+
For workflow modifications, the state diagram MUST show ALL statuses (not just new ones) and annotate changes with `:::added`, `:::removed`, `:::modified`. The workflow processing flow (§3.6) MUST show all rulesets in execution context with NEW/MODIFIED highlighted.
|
|
625
|
+
|
|
626
|
+
**Syntax validation:** Before writing any plan file, validate all Mermaid blocks against `/fluent-mermaid-validate` and the Mermaid Syntax Rules below.
|
|
627
|
+
|
|
628
|
+
## Mermaid Syntax Rules
|
|
629
|
+
|
|
630
|
+
**MANDATORY: Validate every Mermaid block against these rules before outputting.**
|
|
631
|
+
|
|
632
|
+
### All Diagrams
|
|
633
|
+
- First line after the mermaid fence MUST be the diagram type (`stateDiagram-v2`, `sequenceDiagram`, `flowchart TD`, etc.) — no blank line between fence and type
|
|
634
|
+
- Node/state IDs: alphanumeric and underscores only. NO spaces, NO hyphens, NO special chars. Use `as` aliasing for display names
|
|
635
|
+
- Every `subgraph`, `alt`, `opt`, `loop`, `par`, `state { }` block MUST have a matching `end`
|
|
636
|
+
- No HTML tags in labels (use `<br/>` only in flowchart node labels, nowhere else)
|
|
637
|
+
- No trailing semicolons
|
|
638
|
+
|
|
639
|
+
### stateDiagram-v2
|
|
640
|
+
- MUST use `stateDiagram-v2` (NOT `stateDiagram` — v1 has different syntax)
|
|
641
|
+
- Start/end: `[*]` (brackets required)
|
|
642
|
+
- Transitions: `StateA --> StateB : EventName` (double dash + arrow)
|
|
643
|
+
- WRONG: `->` (single arrow), `=>`, `-->` without space before `:`
|
|
644
|
+
- Composite: `state "Display Name" as alias`
|
|
645
|
+
- Notes: `note right of StateName : text`
|
|
646
|
+
- Style annotations: `StateName:::className` (three colons)
|
|
647
|
+
|
|
648
|
+
### sequenceDiagram
|
|
649
|
+
- Declare participants: `participant A as "Display Name"` — MUST appear before first use
|
|
650
|
+
- Messages: `A->>B: text` (solid request), `A-->>B: text` (dashed response), `A-)B: text` (async)
|
|
651
|
+
- WRONG: `A->B` (renders as different arrow type, usually not what you want)
|
|
652
|
+
- WRONG: `A-->B` (this is a dotted line without arrowhead)
|
|
653
|
+
- Activations: `activate A` / `deactivate A` on separate lines, OR `A->>+B:` / `B-->>-A:`
|
|
654
|
+
- Blocks: `alt condition` / `else other` / `end` — every block needs `end`
|
|
655
|
+
- Notes: `Note over A,B: text` or `Note right of A: text` (capital N)
|
|
656
|
+
|
|
657
|
+
### flowchart
|
|
658
|
+
- MUST declare direction: `flowchart TD` (top-down), `flowchart LR` (left-right), `flowchart RL`, `flowchart BT`
|
|
659
|
+
- WRONG: `flowchart` alone (no direction = parse error), `graph TD` (deprecated, use `flowchart`)
|
|
660
|
+
- Node shapes: `A[rect]`, `A(rounded)`, `A{diamond}`, `A((circle))`, `A>flag]`, `A([stadium])`, `A[[subroutine]]`
|
|
661
|
+
- Arrows: `-->` solid, `-.->` dotted, `==>` thick
|
|
662
|
+
- Labels on arrows: `A -->|label text| B` (pipes around label)
|
|
663
|
+
- WRONG: `A --> label --> B`, `A --label--> B`
|
|
664
|
+
- Subgraphs: `subgraph Title` ... `end` — can be nested
|
|
665
|
+
- Node IDs MUST NOT start with a digit or contain spaces: `node1` OK, `1node` BAD, `my node` BAD
|
|
666
|
+
|
|
667
|
+
### classDiagram
|
|
668
|
+
- Class: `class ClassName { +String field; +method() }` — visibility prefixes: `+` public, `-` private, `#` protected
|
|
669
|
+
- Relationships: `A *-- B` composition, `A o-- B` aggregation, `A --> B` dependency, `A --|> B` inheritance
|
|
670
|
+
|
|
671
|
+
### erDiagram
|
|
672
|
+
- Entities: plain names `ORDER`, `FULFILMENT` (no brackets)
|
|
673
|
+
- Relationships: `ORDER ||--o{ FULFILMENT : "has"` — cardinality markers: `||` exactly one, `o|` zero-or-one, `}|` one-or-more, `}o` zero-or-more
|
|
674
|
+
- WRONG: using flowchart syntax, missing relationship label string
|
|
675
|
+
|
|
676
|
+
### Pre-Output Checklist
|
|
677
|
+
Before including any mermaid block in output:
|
|
678
|
+
1. Diagram type on first line? (no blank line after fence)
|
|
679
|
+
2. All IDs alphanumeric/underscore only?
|
|
680
|
+
3. All blocks closed with `end`?
|
|
681
|
+
4. Arrow syntax correct for this diagram type?
|
|
682
|
+
5. Participant/node declarations before first use?
|
|
683
|
+
6. No mixing of syntax from different diagram types?
|
|
684
|
+
|
|
685
|
+
## Plan Lifecycle
|
|
686
|
+
|
|
687
|
+
1. **Create** — Agent writes plan file with `Status: PENDING`, `Revision: 1`. Creates the plans directory if needed.
|
|
688
|
+
2. **Present** — Agent shows the full plan content to the user and waits for approval.
|
|
689
|
+
3. **Approve/Reject** — User responds:
|
|
690
|
+
- **Approved** ("yes", "go ahead", "approved", "do it") → update `Status: APPROVED`, `Approved by: user`, proceed
|
|
691
|
+
- **Rejected with feedback** → increment `Revision`, revise content, reset `Status: PENDING`, re-present
|
|
692
|
+
- **Questions** → answer without changing the file. If answers lead to changes, revise and increment revision
|
|
693
|
+
- **"Just do it" / "skip planning"** → write `Status: APPROVED (auto-skip)`, `Approved by: user (gate skipped)`, proceed
|
|
694
|
+
4. **Reference** — During implementation, the plan file is the single source of truth for what was agreed.
|
|
695
|
+
5. **Post-implementation** — Session summary references the plan file path. Future sessions can read approved plans.
|