@fluentcommerce/ai-skills 0.2.0 → 0.3.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.
Potentially problematic release.
This version of @fluentcommerce/ai-skills might be problematic. Click here for more details.
- package/README.md +866 -616
- package/bin/cli.mjs +2112 -1973
- package/content/cli/agents/fluent-cli/agent.json +149 -149
- package/content/cli/agents/fluent-cli.md +132 -132
- package/content/cli/skills/fluent-bootstrap/SKILL.md +214 -190
- package/content/cli/skills/fluent-cli-index/SKILL.md +1 -1
- package/content/cli/skills/fluent-cli-mcp-cicd/SKILL.md +117 -1
- package/content/cli/skills/fluent-cli-reference/SKILL.md +1040 -623
- package/content/cli/skills/fluent-cli-retailer/SKILL.md +27 -2
- package/content/cli/skills/fluent-cli-settings/SKILL.md +21 -1
- package/content/cli/skills/fluent-connect/SKILL.md +937 -886
- package/content/cli/skills/fluent-module-deploy/SKILL.md +181 -17
- package/content/cli/skills/fluent-profile/SKILL.md +73 -0
- package/content/cli/skills/fluent-workflow/SKILL.md +360 -310
- package/content/dev/agents/fluent-backend-dev/AGENT.md +58 -0
- package/content/dev/agents/fluent-backend-dev/agent.json +69 -0
- package/content/dev/agents/fluent-backend-dev.md +287 -0
- package/content/dev/agents/fluent-dev/AGENT.md +98 -76
- package/content/dev/agents/fluent-dev/agent.json +24 -2
- package/content/dev/agents/fluent-dev.md +194 -524
- package/content/dev/agents/fluent-frontend-dev/AGENT.md +63 -0
- package/content/dev/agents/fluent-frontend-dev/agent.json +52 -0
- package/content/dev/agents/fluent-frontend-dev.md +323 -0
- package/content/dev/skills/fluent-archive/SKILL.md +234 -0
- package/content/dev/skills/fluent-build/SKILL.md +312 -170
- package/content/dev/skills/fluent-connection-analysis/SKILL.md +422 -386
- package/content/dev/skills/fluent-custom-code/SKILL.md +15 -9
- package/content/dev/skills/fluent-data-module-scaffold/SKILL.md +731 -0
- package/content/dev/skills/fluent-e2e-test/SKILL.md +501 -394
- package/content/dev/skills/fluent-event-api/SKILL.md +962 -945
- package/content/dev/skills/fluent-feature-explain/SKILL.md +680 -603
- package/content/dev/skills/fluent-feature-plan/PLAN_TEMPLATE.md +40 -11
- package/content/dev/skills/fluent-feature-plan/SKILL.md +478 -221
- package/content/dev/skills/fluent-feature-status/SKILL.md +335 -0
- package/content/dev/skills/fluent-feedback/SKILL.md +221 -0
- package/content/dev/skills/fluent-implementation-map/SKILL.md +644 -0
- package/content/dev/skills/fluent-job-batch/SKILL.md +10 -0
- package/content/dev/skills/fluent-module-scaffold/SKILL.md +134 -3
- package/content/dev/skills/fluent-module-validate/SKILL.md +778 -775
- package/content/dev/skills/fluent-mystique-analyze/SKILL.md +817 -0
- package/content/dev/skills/fluent-mystique-builder/COMPONENT_TEMPLATE.md +81 -0
- package/content/dev/skills/fluent-mystique-builder/README.md +63 -0
- package/content/dev/skills/fluent-mystique-builder/SKILL.md +1294 -0
- package/content/dev/skills/fluent-mystique-builder/components/INDEX.md +92 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.accordion.md +48 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.action.field.fulfilmentpack.md +20 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.action.field.multiparcel.md +21 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.action.field.returnitems.md +21 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.action.field.wavepick.md +21 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.action.inline.md +24 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.activity.entity.md +25 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.analytics.viz.md +20 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.attribute.column.md +111 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.attribute.json.md +20 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.attribute.jsoneditor.md +54 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.attribute.locationId.md +51 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.attribute.retailerId.md +52 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.button.bar.md +57 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.button.print.download.md +53 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.button.print.inline.compatibility.md +60 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.button.print.inline.md +53 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.button.print.md +24 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.button.print.pick.md +61 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.buttons.add.reject.md +20 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.card.attribute.md +73 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.card.attributes.grid.md +40 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.card.image.md +37 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.card.map.point.md +24 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.card.multi.md +79 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.card.product.md +27 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.chart.area.md +34 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.chart.area.wrapper.feed.md +98 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.chart.bar.md +52 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.chart.bar.wrapper.source.md +104 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.chart.gauge.md +28 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.chart.gauge.wrapper.threshold.md +118 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.chart.line.md +32 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.conditional.md +62 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.dashboard.threshold.md +65 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.daterange.wrapper.forwarder.md +56 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.drawer.button.md +21 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.event.detail.md +20 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.events.search.md +21 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.field.daterange.md +83 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.field.filterComplex.md +106 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.field.intrange.md +82 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.field.multistring.md +50 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.filterPanel.md +53 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.json.editor.md +22 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.json.viewer.md +21 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.list.customAction.md +79 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.list.md +116 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.list.wrapper.bppmetrics.md +69 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.list.wrapper.feed.md +65 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.list.wrapper.source.md +64 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.modal.button.addItem.md +60 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.modal.button.md +21 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.mutation.inline.md +88 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.mystique.collapsible.attributes.md +83 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.mystique.collapsible.text.md +33 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.mystique.link.md +30 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.order.itemDetails.md +20 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.order.shipmentDetails.md +20 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.page.filter.select.md +87 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.page.md +64 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.page.refresh.md +48 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.page.section.column.md +71 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.page.section.header.md +61 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.page.section.md +59 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.page.wizard.md +45 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.page.wizard.summary.md +56 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.progress.circular.md +20 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.provider.graphql.md +71 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.quantity.list.md +87 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.repeater.md +56 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.reports.ipuipc.md +54 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.return.rowExpansion.md +19 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.scanner.barcode.md +21 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.scanner.barcodeFilter.md +72 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.scanner.camera.md +20 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.settingForm.md +64 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.sourcing.profile.drawer.button.md +19 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.sourcing.profile.modal.button.md +64 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.sourcing.strategy.modal.button.md +20 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.stepper.md +20 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.tab.content.md +56 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.tabs.card.md +64 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.tabs.md +69 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.tile.metric.md +73 -0
- package/content/dev/skills/fluent-mystique-builder/components/fc.workflow.provider.md +77 -0
- package/content/dev/skills/fluent-mystique-builder/validate-docs.ps1 +260 -0
- package/content/dev/skills/fluent-mystique-scaffold/SKILL.md +1830 -0
- package/content/dev/skills/fluent-mystique-validate/SKILL.md +646 -0
- package/content/dev/skills/fluent-pre-deploy-check/SKILL.md +1144 -1090
- package/content/dev/skills/fluent-retailer-config/SKILL.md +1162 -1120
- package/content/dev/skills/fluent-rollback/SKILL.md +387 -0
- package/content/dev/skills/fluent-rule-scaffold/SKILL.md +515 -394
- package/content/dev/skills/fluent-scope-decompose/SKILL.md +1123 -1021
- package/content/dev/skills/fluent-session-audit-export/SKILL.md +880 -632
- package/content/dev/skills/fluent-session-summary/SKILL.md +320 -195
- package/content/dev/skills/fluent-settings/SKILL.md +151 -2
- package/content/dev/skills/fluent-source-onboard/SKILL.md +23 -4
- package/content/dev/skills/fluent-sourcing/SKILL.md +14 -0
- package/content/dev/skills/fluent-system-monitoring/SKILL.md +771 -767
- package/content/dev/skills/fluent-test-data/SKILL.md +514 -513
- package/content/dev/skills/fluent-trace/SKILL.md +1169 -1143
- package/content/dev/skills/fluent-transition-api/SKILL.md +364 -346
- package/content/dev/skills/fluent-use-case-discover/SKILL.md +593 -471
- package/content/dev/skills/fluent-use-case-discover/SPEC_TEMPLATE.md +22 -1
- package/content/dev/skills/fluent-version-manage/SKILL.md +44 -3
- package/content/dev/skills/fluent-workflow-analyzer/SKILL.md +995 -959
- package/content/dev/skills/fluent-workflow-builder/SKILL.md +668 -326
- package/content/dev/skills/fluent-workflow-deploy/SKILL.md +480 -0
- package/content/dev/skills/fluent-workspace-tree/SKILL.md +281 -0
- package/content/mcp-extn/agents/fluent-mcp.md +133 -132
- package/content/mcp-extn/skills/fluent-mcp-tools/SKILL.md +812 -800
- package/content/mcp-official/agents/fluent-mcp-core.md +91 -91
- package/content/mcp-official/skills/fluent-mcp-core/SKILL.md +94 -94
- package/content/rfl/skills/fluent-rfl-assess/SKILL.md +172 -172
- package/docs/CAPABILITY_MAP.md +106 -73
- package/docs/DEPLOYMENT_PROMOTION_RUNBOOK.md +218 -0
- package/docs/DESIGN-implementation-map.md +698 -0
- package/docs/DEV_WORKFLOW.md +814 -802
- package/docs/FLOW_RUN.md +142 -142
- package/docs/GETTING_STARTED.md +427 -0
- package/docs/USE_CASES.md +906 -50
- package/metadata.json +184 -155
- package/package.json +7 -2
- package/docs/USE_CASES.pdf +0 -0
|
@@ -0,0 +1,1294 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fluent-mystique-builder
|
|
3
|
+
description: Build and edit Mystique manifest JSON definitions. Create pages, routes, component trees, data queries, and fragment compositions using the v2.0 schema. Triggers on "build manifest", "create mystique page", "add route", "mystique component", "edit manifest", "build ui", "add page to manifest".
|
|
4
|
+
user-invocable: true
|
|
5
|
+
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
|
|
6
|
+
argument-hint: <operation> [manifest-file] [--page <path>] [--section <name>] [--fragment]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Mystique Manifest Builder
|
|
10
|
+
|
|
11
|
+
Create, edit, and validate Fluent Commerce Mystique manifest JSON definitions. Mystique is the declarative, manifest-driven UI framework that powers the OMX frontend. Manifests are JSON documents that define the entire application structure: routes, pages, component trees, GraphQL data queries, role-based visibility, template strings, and plugin references. This skill understands the v2.0 manifest schema end-to-end and generates structurally correct JSON that passes `/fluent-mystique-validate`.
|
|
12
|
+
|
|
13
|
+
## Platform Fundamentals
|
|
14
|
+
|
|
15
|
+
**OMX vs Mystique naming:** "OMX" (Order Management Experience) is the umbrella framework covering UX + Workflows + Connect. "Mystique" is the internal/historical code name for the UX Framework layer specifically. All import paths and code references use `mystique/` (e.g., `mystique/hooks/useAuth`, `mystique/registry`), while documentation uses "OMX" or "UX Framework" externally. Both refer to the same thing for frontend purposes.
|
|
16
|
+
|
|
17
|
+
**Three registries:**
|
|
18
|
+
- **ComponentRegistry** — standard display components (`fc.list`, `fc.card.attribute`, custom components)
|
|
19
|
+
- **FieldRegistry** — form input components for user action attributes (auto-selected by type name)
|
|
20
|
+
- **TemplateRegistry** — Handlebars helper functions for template string expressions
|
|
21
|
+
|
|
22
|
+
**Configuration over code:** Most UI should be built via manifest JSON, not custom components. Only build custom components when: novel visualizations, drag-and-drop, external service integrations, real-time features, or interaction patterns not covered by user action forms. The framework is **versionless with guaranteed backward compatibility** — old configurations never break.
|
|
23
|
+
|
|
24
|
+
**Multi-tenancy context:** Account → Retailer → Location. Manifests can be scoped at ACCOUNT level. User context (`activeRetailer`, `activeLocation`) is available in template strings for query variables and conditional rendering.
|
|
25
|
+
|
|
26
|
+
**Workflow-UI integration:** User action buttons and forms appear automatically based on the entity's current workflow state. No manifest changes needed when workflows evolve — the UI adapts. Custom form field components are selected by matching the workflow `eventAttributes[].type` to FieldRegistry entries.
|
|
27
|
+
|
|
28
|
+
## Planning Gate
|
|
29
|
+
|
|
30
|
+
### Pre-flight: Plan Verification
|
|
31
|
+
|
|
32
|
+
Before proceeding, check for an existing approved plan:
|
|
33
|
+
|
|
34
|
+
1. **Search** `accounts/<PROFILE>/features/*/status.json` for an entry with `plan: "APPROVED"` that covers this UI work, OR check `accounts/<PROFILE>/tasks/` for a task plan with `Status: APPROVED`
|
|
35
|
+
2. **If multi-artifact work** (manifest + SDK component + settings + workflows): STOP. Invoke `/fluent-feature-plan` first — this skill cannot be used for multi-artifact work without a feature plan
|
|
36
|
+
3. **If approved plan found:** Skip to implementation, referencing the plan's UI/manifest sections
|
|
37
|
+
4. **If manifest-only work with no plan:** Continue to the Planning Gate below to write a plan for this skill
|
|
38
|
+
|
|
39
|
+
**Before creating or modifying any manifest JSON, write a plan using the template from `PLAN_TEMPLATE.md` in the `fluent-feature-plan` skill.** Every table row must carry a Source column (NEW/EXISTING/MODIFIED/REUSED/OOTB).
|
|
40
|
+
|
|
41
|
+
**If this manifest change is part of a larger feature** (rules + workflows + UI), use `/fluent-feature-plan` first. Then reference the approved plan during implementation.
|
|
42
|
+
|
|
43
|
+
**Manifest-builder specific emphasis — ensure these are covered:**
|
|
44
|
+
|
|
45
|
+
1. **Wireframe (ASCII/Mermaid)** — layout sketch showing page structure and component hierarchy
|
|
46
|
+
2. **Route table** — all routes with path, component, section, nav label, roles
|
|
47
|
+
3. **Component tree** — hierarchical component layout per page (nested list or tree diagram)
|
|
48
|
+
4. **Data requirements** — GraphQL queries needed per page with entity types and key fields
|
|
49
|
+
5. **Settings dependencies** — fragment references (`settingName`), feature flags, plugin settings
|
|
50
|
+
6. **i18n keys** — translatable strings requiring `i18n:` prefixed keys
|
|
51
|
+
7. **Plugin references** — custom SDK components needed and their bundle URLs
|
|
52
|
+
|
|
53
|
+
**Write the plan to:** `accounts/<PROFILE>/tasks/<YYYY-MM-DD>-mystique-builder-<slug>.md`. Set `Status: PENDING`.
|
|
54
|
+
|
|
55
|
+
Present the full plan content to the user and wait for approval before writing any manifest JSON. On approval, update the file to `Status: APPROVED`. If the user says "just do it", proceed directly (still write the file for audit trail).
|
|
56
|
+
|
|
57
|
+
## Post-Build: Manifest Validation
|
|
58
|
+
|
|
59
|
+
After building or modifying any manifest JSON, **always recommend running `/fluent-mystique-validate`** to check for:
|
|
60
|
+
- Schema compliance (manifestVersion, required fields, route types)
|
|
61
|
+
- Component alias resolution (unknown `fc.*` aliases or custom components)
|
|
62
|
+
- Data query syntax and dataSource path validity
|
|
63
|
+
- Template string syntax (balanced `{{`/`}}`, valid helper names)
|
|
64
|
+
- Cross-reference issues (homePath resolves, fragment settingName conventions)
|
|
65
|
+
- Component prop completeness (fc.list needs attributes, fc.conditional needs value/matches)
|
|
66
|
+
|
|
67
|
+
If the user skips this step, `/fluent-pre-deploy-check` will enforce it before deployment. But catching issues early avoids broken UI in production.
|
|
68
|
+
|
|
69
|
+
## Ownership Boundary
|
|
70
|
+
|
|
71
|
+
This skill owns manifest JSON creation/editing and component tree composition.
|
|
72
|
+
|
|
73
|
+
| This skill OWNS | Other skills OWN |
|
|
74
|
+
|-----------------|------------------|
|
|
75
|
+
| Manifest JSON creation/editing | Manifest validation -> `/fluent-mystique-validate` |
|
|
76
|
+
| Page and route structure | SDK component code -> `/fluent-mystique-scaffold` |
|
|
77
|
+
| Component tree composition | Deployed manifest analysis -> `/fluent-mystique-analyze` |
|
|
78
|
+
| GraphQL query scaffolding in pages | Live GraphQL execution -> MCP tools |
|
|
79
|
+
| i18n key generation in manifest | Settings management -> `/fluent-settings` |
|
|
80
|
+
| Fragment composition | Workflow actions -> `/fluent-workflow-builder` |
|
|
81
|
+
|
|
82
|
+
## Pre-flight: Plugin Availability
|
|
83
|
+
|
|
84
|
+
Before building a manifest that references custom SDK components (non-`fc.*` aliases), verify the plugin bundle is accessible:
|
|
85
|
+
|
|
86
|
+
1. **Identify custom components** in the plan — any component alias that does NOT start with `fc.`
|
|
87
|
+
2. **For each custom component**, check if an SDK project exists in `accounts/<PROFILE>/SOURCE/*/src/index.tsx` with matching `ComponentRegistry.register` calls
|
|
88
|
+
3. **If ALL custom components found locally:** Ensure the `plugins[]` array references the correct bundle URL (localhost for dev, CDN for production)
|
|
89
|
+
4. **If ANY custom component is MISSING:** **STOP.** Inform the user: *"Custom component `<alias>` is not registered in any local SDK project. Scaffold it first via `/fluent-mystique-scaffold`, then resume manifest building."*
|
|
90
|
+
5. **Exception:** If the manifest is being built as part of a feature plan where scaffolding comes later, note the dependency and proceed — but add a `DEPLOYMENT_ORDER_WARNING` comment
|
|
91
|
+
|
|
92
|
+
## Frontend Development and Deployment Model
|
|
93
|
+
|
|
94
|
+
Understanding how manifests and custom components reach users is critical for correct builder output.
|
|
95
|
+
|
|
96
|
+
### Manifests are JSON Configuration
|
|
97
|
+
|
|
98
|
+
Manifests are pure JSON — they are NOT compiled or bundled. They are deployed to Fluent UX Apps through one of:
|
|
99
|
+
- **Admin Console** — upload via the UX App configuration UI
|
|
100
|
+
- **Fluent API** — create/update as a Fluent Setting (key convention: `fc.mystique.manifest.<app-name>`)
|
|
101
|
+
- **Fragment references** — deploy manifest fragments as separate Settings, referenced via `type: "reference"` routes
|
|
102
|
+
|
|
103
|
+
### Custom Components are Externally Hosted Bundles
|
|
104
|
+
|
|
105
|
+
Custom SDK components (anything not `fc.*`) are React code compiled to a `bundle.js` file. Fluent does NOT host these bundles. The deployment model is:
|
|
106
|
+
|
|
107
|
+
1. **Development:** `yarn start` serves the bundle on `http://localhost:3001/bundle.[hash].js`
|
|
108
|
+
2. **Production:** `yarn build` produces `dist/bundle.[hash].js` — deploy to a CDN (Vercel, S3, CloudFront, etc.)
|
|
109
|
+
3. **Manifest references the bundle URL** via the `plugins[]` array
|
|
110
|
+
|
|
111
|
+
### Plugin Configuration
|
|
112
|
+
|
|
113
|
+
The `plugins[]` array in the manifest tells Mystique where to load external component bundles:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"plugins": [
|
|
118
|
+
{
|
|
119
|
+
"type": "url",
|
|
120
|
+
"src": "http://localhost:3001/bundle.46a734bac1cb3a54ba80.js"
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
For production deployment, replace with the CDN URL:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"plugins": [
|
|
131
|
+
{
|
|
132
|
+
"type": "url",
|
|
133
|
+
"src": "https://my-components.vercel.app/bundle.abc123.js"
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Plugins can also be loaded from a Fluent Setting:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"plugins": [
|
|
144
|
+
{
|
|
145
|
+
"type": "setting",
|
|
146
|
+
"setting": "fc.mystique.plugin.custom-components"
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Fragment Deployment
|
|
153
|
+
|
|
154
|
+
Manifest fragments are deployed as Fluent Settings with the naming convention:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
fc.mystique.manifest.<fragment-name>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The main manifest references them via:
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"type": "reference",
|
|
165
|
+
"settingName": "fc.mystique.manifest.inventory-section"
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
This allows sections to be independently deployed and versioned without editing the main manifest.
|
|
170
|
+
|
|
171
|
+
### Manifest Deployment via Settings API
|
|
172
|
+
|
|
173
|
+
Manifests are stored as **Fluent Settings**. To deploy a manifest or fragment, you create or update its corresponding setting.
|
|
174
|
+
|
|
175
|
+
**Storage model — setting names are app-scoped:**
|
|
176
|
+
|
|
177
|
+
| App | Root Manifest Setting | Example Fragment Setting |
|
|
178
|
+
|-----|----------------------|------------------------|
|
|
179
|
+
| OMS | `fc.mystique.manifest.oms` | `fc.mystique.manifest.oms.fragment.dashboard` |
|
|
180
|
+
| Store | `fc.mystique.manifest.store` | `fc.mystique.manifest.store.fragment.picking` |
|
|
181
|
+
| Service Point | `fc.mystique.manifest.servicepoint` | `fc.mystique.manifest.servicepoint.fragment.tasks` |
|
|
182
|
+
| Custom App | `fc.mystique.manifest.<app>` | `fc.mystique.manifest.<app>.fragment.<name>` |
|
|
183
|
+
|
|
184
|
+
All manifest settings use scope `ACCOUNT`, type `JSON`, and the body is stored in `lobValue`.
|
|
185
|
+
|
|
186
|
+
Each app serves at its own URL path: `/_plugins/<app>/manifests/...`
|
|
187
|
+
|
|
188
|
+
**CRITICAL: Always use `lobValue`, not `value`.** Manifests exceed the regular `value` field's size limit. Using `value` will **silently truncate** the JSON — this causes data loss with no error.
|
|
189
|
+
|
|
190
|
+
**Fetch an existing manifest or fragment:**
|
|
191
|
+
|
|
192
|
+
```graphql
|
|
193
|
+
query Manifest {
|
|
194
|
+
settings(name: "fc.mystique.manifest.oms") {
|
|
195
|
+
edges { node { id name lobValue } }
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Use the same query pattern for fragments — just change the `name` parameter:
|
|
201
|
+
```graphql
|
|
202
|
+
settings(name: "fc.mystique.manifest.oms.fragment.dashboard")
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
If a fragment has no ACCOUNT-level override, the platform loads the **global default** via HTTP:
|
|
206
|
+
```
|
|
207
|
+
https://<host>/_plugins/<app>/manifests/fc.mystique.manifest.<app>.fragment.<name>.json?v=<cachebuster>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Create a new fragment override** (first-time deployment):
|
|
211
|
+
|
|
212
|
+
```graphql
|
|
213
|
+
mutation CreateFragment {
|
|
214
|
+
createSetting(input: {
|
|
215
|
+
name: "fc.mystique.manifest.oms.fragment.dashboard"
|
|
216
|
+
context: "ACCOUNT"
|
|
217
|
+
contextId: 0
|
|
218
|
+
valueType: "JSON"
|
|
219
|
+
lobValue: { "manifestVersion": "2.0", "routes": [...] }
|
|
220
|
+
}) { id }
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Update an existing manifest** (requires setting ID — fetch first if unknown):
|
|
225
|
+
|
|
226
|
+
```graphql
|
|
227
|
+
mutation UpdateManifest {
|
|
228
|
+
updateSetting(input: {
|
|
229
|
+
id: 242
|
|
230
|
+
lobValue: { "manifestVersion": "2.0", "routes": [...] }
|
|
231
|
+
}) { id }
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
`lobValue` must be **raw JSON** (an object), not a stringified JSON string.
|
|
236
|
+
|
|
237
|
+
**Deployment workflow:**
|
|
238
|
+
1. Fetch current deployed manifest/fragment via `graphql.query` → save locally as `.json`
|
|
239
|
+
2. Make changes to the local copy (user reviews diff)
|
|
240
|
+
3. Upload via `createSetting` (new) or `updateSetting` (existing) — or use MCP `setting.upsert`
|
|
241
|
+
4. Verify in browser — Settings changes are immediate, no cache delay
|
|
242
|
+
|
|
243
|
+
## When to Use
|
|
244
|
+
|
|
245
|
+
- Creating a new Mystique app manifest from scratch
|
|
246
|
+
- Adding pages or sections to an existing manifest
|
|
247
|
+
- Composing component trees for entity detail or list pages
|
|
248
|
+
- Building manifest fragments for modular deployment
|
|
249
|
+
- Generating page-level GraphQL data queries for Fluent entities
|
|
250
|
+
- Editing existing manifest JSON (add/remove/update routes, components, props)
|
|
251
|
+
- Wiring custom SDK components into manifests via `plugins[]`
|
|
252
|
+
|
|
253
|
+
## Progress
|
|
254
|
+
|
|
255
|
+
Emit this block at each phase transition to show progress:
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
> /fluent-mystique-builder [1/6]
|
|
259
|
+
Done Plan verification -> Collect manifest requirements
|
|
260
|
+
Todo Build route structure Todo Compose component trees
|
|
261
|
+
Todo Generate data queries Todo Validate output
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Update the block as each phase completes — mark completed phases with `Done`, the active phase with `->`, and remaining phases with `Todo`. Replace `[1/6]` with the current phase number.
|
|
265
|
+
|
|
266
|
+
## Manifest v2.0 Schema
|
|
267
|
+
|
|
268
|
+
Every Mystique manifest follows this top-level structure:
|
|
269
|
+
|
|
270
|
+
```json
|
|
271
|
+
{
|
|
272
|
+
"manifestVersion": "2.0",
|
|
273
|
+
"name": "admin",
|
|
274
|
+
"title": "i18n:fc.admin.title",
|
|
275
|
+
"icon": "settings",
|
|
276
|
+
"context": {
|
|
277
|
+
"level": "retailer",
|
|
278
|
+
"role": "ADMIN"
|
|
279
|
+
},
|
|
280
|
+
"plugins": [
|
|
281
|
+
{ "type": "url", "src": "https://cdn.example.com/bundle.js" }
|
|
282
|
+
],
|
|
283
|
+
"homePath": "dashboard",
|
|
284
|
+
"routes": []
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Required Fields
|
|
289
|
+
|
|
290
|
+
| Field | Type | Description |
|
|
291
|
+
|-------|------|-------------|
|
|
292
|
+
| `manifestVersion` | `"2.0"` | Always `"2.0"` — the only supported schema version |
|
|
293
|
+
| `name` | `string` | App identifier used in logs and user action filtering. No spaces. |
|
|
294
|
+
| `title` | `string` | User-facing app name. Supports `i18n:` prefix for translation |
|
|
295
|
+
| `homePath` | `string` | Landing route path. Must match a defined route's `path` |
|
|
296
|
+
| `routes` | `MystiqueManifestRoute[]` | Array of sections, pages, and fragment references |
|
|
297
|
+
|
|
298
|
+
### Optional Fields
|
|
299
|
+
|
|
300
|
+
| Field | Type | Default | Description |
|
|
301
|
+
|-------|------|---------|-------------|
|
|
302
|
+
| `icon` | `string` | none | Material icon name for the app |
|
|
303
|
+
| `context` | `{ level, role? }` | `{ level: "retailer" }` | App context: `account`, `retailer`, or `location`. Optional `role` restricts access |
|
|
304
|
+
| `plugins` | `MystiquePlugin[]` | `[]` | External component bundle URLs or setting references |
|
|
305
|
+
| `orchestrationAlias` | `string` | none | Rename entity types for workflow resolution (e.g., `"store"` -> `"servicepoint"`) |
|
|
306
|
+
|
|
307
|
+
### Route Types
|
|
308
|
+
|
|
309
|
+
Routes come in three types:
|
|
310
|
+
|
|
311
|
+
**Section** — groups pages under a navigation header:
|
|
312
|
+
|
|
313
|
+
```json
|
|
314
|
+
{
|
|
315
|
+
"type": "section",
|
|
316
|
+
"path": "orders",
|
|
317
|
+
"nav": { "label": "i18n:fc.orders.nav", "icon": "shopping_cart" },
|
|
318
|
+
"roles": ["ADMIN", "OPERATOR"],
|
|
319
|
+
"pages": []
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**Page** — a routable screen with data and components:
|
|
324
|
+
|
|
325
|
+
```json
|
|
326
|
+
{
|
|
327
|
+
"type": "page",
|
|
328
|
+
"path": "orders",
|
|
329
|
+
"component": "fc.page",
|
|
330
|
+
"nav": { "label": "i18n:fc.orders.list.nav", "icon": "list" },
|
|
331
|
+
"data": {
|
|
332
|
+
"query": "query { orders(first: 25) { edges { node { id ref status type createdOn } } pageInfo { hasNextPage endCursor } } }"
|
|
333
|
+
},
|
|
334
|
+
"props": { "title": "i18n:fc.orders.list.title" },
|
|
335
|
+
"descendants": [],
|
|
336
|
+
"roles": ["ADMIN"],
|
|
337
|
+
"fullScreen": false
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Reference** — includes a manifest fragment stored as a Fluent Setting:
|
|
342
|
+
|
|
343
|
+
```json
|
|
344
|
+
{
|
|
345
|
+
"type": "reference",
|
|
346
|
+
"settingName": "fc.mystique.manifest.custom-inventory"
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Component Instance
|
|
351
|
+
|
|
352
|
+
The recursive building block used throughout `descendants[]`:
|
|
353
|
+
|
|
354
|
+
```json
|
|
355
|
+
{
|
|
356
|
+
"component": "fc.card.attribute",
|
|
357
|
+
"dataSource": "orderById",
|
|
358
|
+
"props": {
|
|
359
|
+
"title": "Order Details",
|
|
360
|
+
"width": "half",
|
|
361
|
+
"attributes": [
|
|
362
|
+
{ "label": "Reference", "value": "{{ref}}" },
|
|
363
|
+
{ "label": "Status", "value": "{{status}}" },
|
|
364
|
+
{ "label": "Type", "value": "{{type}}" },
|
|
365
|
+
{ "label": "Created", "value": "{{dateRelative createdOn}}" }
|
|
366
|
+
]
|
|
367
|
+
},
|
|
368
|
+
"descendants": [],
|
|
369
|
+
"roles": ["ADMIN"]
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
| Field | Type | Required | Description |
|
|
374
|
+
|-------|------|----------|-------------|
|
|
375
|
+
| `component` | `string` | yes | Registry alias — `fc.*` for core, `custom.*` for SDK components |
|
|
376
|
+
| `dataSource` | `string` | no | JSONPath scoping the data context for this component and its descendants |
|
|
377
|
+
| `props` | `Record<string, any>` | no | Component-specific configuration (varies by component) |
|
|
378
|
+
| `descendants` | `MystiqueComponentInstance[]` | no | Nested child components |
|
|
379
|
+
| `roles` | `string[]` | no | Role-based visibility — component hidden if user lacks listed roles |
|
|
380
|
+
|
|
381
|
+
### Page Data Query
|
|
382
|
+
|
|
383
|
+
The `data` block on a page defines the GraphQL query executed before rendering:
|
|
384
|
+
|
|
385
|
+
```json
|
|
386
|
+
{
|
|
387
|
+
"data": {
|
|
388
|
+
"query": "query($id: ID!) { orderById(id: $id) { id ref status type createdOn totalPrice customer { firstName lastName } items { edges { node { id ref quantity productRef } } } } }",
|
|
389
|
+
"variables": {
|
|
390
|
+
"id": "{{id}}"
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Variables support template strings (`{{id}}` resolves from URL params) and `ConvertableVariable` for non-string types:
|
|
397
|
+
|
|
398
|
+
```json
|
|
399
|
+
{
|
|
400
|
+
"variables": {
|
|
401
|
+
"id": { "value": "{{id}}", "parse": true }
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Manifest Fragment
|
|
407
|
+
|
|
408
|
+
Fragments are cut-down manifests for modular deployment:
|
|
409
|
+
|
|
410
|
+
```json
|
|
411
|
+
{
|
|
412
|
+
"manifestVersion": "2.0",
|
|
413
|
+
"routes": [
|
|
414
|
+
{
|
|
415
|
+
"type": "section",
|
|
416
|
+
"nav": { "label": "Custom Section", "icon": "extension" },
|
|
417
|
+
"pages": [
|
|
418
|
+
{
|
|
419
|
+
"type": "page",
|
|
420
|
+
"path": "custom-page",
|
|
421
|
+
"component": "fc.page",
|
|
422
|
+
"nav": { "label": "Custom Page", "icon": "build" },
|
|
423
|
+
"props": { "title": "Custom Page" },
|
|
424
|
+
"descendants": []
|
|
425
|
+
}
|
|
426
|
+
]
|
|
427
|
+
}
|
|
428
|
+
]
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Operations
|
|
433
|
+
|
|
434
|
+
### Operation 1: Create Manifest
|
|
435
|
+
|
|
436
|
+
Interactive wizard collecting:
|
|
437
|
+
|
|
438
|
+
```
|
|
439
|
+
1. App name (slug: "admin", "servicepoint", "store-ops")
|
|
440
|
+
2. Title (user-facing, supports i18n: prefix)
|
|
441
|
+
3. Context level (account / retailer / location)
|
|
442
|
+
4. Role restriction (optional)
|
|
443
|
+
5. Home page path
|
|
444
|
+
6. Initial sections and pages (from wireframe/plan)
|
|
445
|
+
7. Plugin references (if custom components needed)
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
Generates a complete `manifest.json` with:
|
|
449
|
+
- `manifestVersion: "2.0"` and all required top-level fields
|
|
450
|
+
- Route structure with sections and pages
|
|
451
|
+
- Page-level GraphQL data queries for each entity page
|
|
452
|
+
- Component trees with props wired to data sources
|
|
453
|
+
- Plugin references for custom SDK components
|
|
454
|
+
|
|
455
|
+
### Operation 2: Add Page
|
|
456
|
+
|
|
457
|
+
```
|
|
458
|
+
Input: manifest file + page definition
|
|
459
|
+
1. Determine target section (existing or new)
|
|
460
|
+
2. Define page path (validate uniqueness against existing routes)
|
|
461
|
+
3. Select page component (fc.page recommended as top-level)
|
|
462
|
+
4. Define data query (entity type -> auto-generate GraphQL using entity map)
|
|
463
|
+
5. Build component tree:
|
|
464
|
+
- Start with fc.page as the route component
|
|
465
|
+
- Add layout components (fc.column, fc.tabs.card)
|
|
466
|
+
- Add content components (fc.list, fc.card.attribute, fc.provider.graphql)
|
|
467
|
+
- Wire dataSource paths to connect components to query results
|
|
468
|
+
- Set component props per component documentation
|
|
469
|
+
6. Add nav config if page should appear in sidebar
|
|
470
|
+
7. Add role restrictions (optional)
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
### Operation 3: Add Component to Page
|
|
474
|
+
|
|
475
|
+
```
|
|
476
|
+
Input: manifest file + page path + component spec
|
|
477
|
+
1. Load manifest and locate the target page by path
|
|
478
|
+
2. Find insertion point in descendants tree (by index or parent component)
|
|
479
|
+
3. Generate component instance:
|
|
480
|
+
- Select component alias from known registry
|
|
481
|
+
- Set props from component schema (see Component Props Reference below)
|
|
482
|
+
- Wire dataSource if the component consumes query data
|
|
483
|
+
- Add descendants recursively for container components
|
|
484
|
+
4. Validate resulting tree structure
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### Operation 4: Build Fragment
|
|
488
|
+
|
|
489
|
+
```
|
|
490
|
+
Input: fragment definition (sections and pages)
|
|
491
|
+
1. Generate MystiqueManifestFragment JSON structure
|
|
492
|
+
2. Define fragment routes (sections + pages with full component trees)
|
|
493
|
+
3. Output as standalone JSON file
|
|
494
|
+
4. Generate Fluent setting key: fc.mystique.manifest.<fragment-name>
|
|
495
|
+
5. Generate setting.upsert command for deployment via /fluent-settings
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Operation 5: Generate Data Query
|
|
499
|
+
|
|
500
|
+
```
|
|
501
|
+
Input: entity type + required fields + query type (list or detail)
|
|
502
|
+
1. Map entity type to GraphQL root query using Entity Type Query Map
|
|
503
|
+
2. Build query with requested fields plus standard fields
|
|
504
|
+
3. Handle connections/edges/node patterns for nested entities
|
|
505
|
+
4. Add variables for dynamic filtering (pagination, URL params)
|
|
506
|
+
5. Output as a page.data block ready to embed in the manifest
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### Operation 6: Edit Existing Manifest
|
|
510
|
+
|
|
511
|
+
```
|
|
512
|
+
Input: manifest file + edit instructions
|
|
513
|
+
1. Load and parse the manifest JSON
|
|
514
|
+
2. Locate target element (route by path, component by tree position)
|
|
515
|
+
3. Apply modifications (add/remove/update routes, components, props)
|
|
516
|
+
4. Preserve existing structure — minimal diff approach
|
|
517
|
+
5. Validate modified manifest against v2.0 schema
|
|
518
|
+
6. Write back to the same file path
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
## Component Composition Patterns
|
|
522
|
+
|
|
523
|
+
### Pattern 1: Entity Detail Page
|
|
524
|
+
|
|
525
|
+
The standard layout for viewing a single entity with attributes and related data:
|
|
526
|
+
|
|
527
|
+
```json
|
|
528
|
+
{
|
|
529
|
+
"type": "page",
|
|
530
|
+
"path": "orders/:id",
|
|
531
|
+
"component": "fc.page",
|
|
532
|
+
"data": {
|
|
533
|
+
"query": "query($id: ID!) { orderById(id: $id) { id ref status type totalPrice totalTaxPrice createdOn updatedOn customer { id firstName lastName primaryEmail } items { edges { node { id ref productRef quantity paidPrice currency } } } fulfilments { edges { node { id ref status type fromAddress { name } } } } attributes { name value type } } }",
|
|
534
|
+
"variables": { "id": { "value": "{{id}}", "parse": true } }
|
|
535
|
+
},
|
|
536
|
+
"props": {
|
|
537
|
+
"title": "{{capitalise status}} - Order {{ref}}",
|
|
538
|
+
"backButtons": [{ "label": "Orders", "path": "/orders" }],
|
|
539
|
+
"actions": true
|
|
540
|
+
},
|
|
541
|
+
"descendants": [
|
|
542
|
+
{
|
|
543
|
+
"component": "fc.card.attribute",
|
|
544
|
+
"props": {
|
|
545
|
+
"title": "Order Summary",
|
|
546
|
+
"width": "half",
|
|
547
|
+
"attributes": [
|
|
548
|
+
{ "label": "Reference", "value": "{{ref}}" },
|
|
549
|
+
{ "label": "Status", "value": "{{status}}", "options": { "styles": [
|
|
550
|
+
{ "matches": "COMPLETE", "icon": { "name": "MdCheckCircle", "colour": "success" } },
|
|
551
|
+
{ "matches": "CANCELLED", "icon": { "name": "MdCancel", "colour": "error" } }
|
|
552
|
+
]}},
|
|
553
|
+
{ "label": "Type", "value": "{{type}}" },
|
|
554
|
+
{ "label": "Created", "value": "{{dateRelative createdOn}}" },
|
|
555
|
+
{ "label": "Total", "value": "${{totalPrice}}" }
|
|
556
|
+
]
|
|
557
|
+
}
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
"component": "fc.card.attribute",
|
|
561
|
+
"props": {
|
|
562
|
+
"title": "Customer",
|
|
563
|
+
"width": "half",
|
|
564
|
+
"attributes": [
|
|
565
|
+
{ "label": "Name", "value": "{{customer.firstName}} {{customer.lastName}}" },
|
|
566
|
+
{ "label": "Email", "value": "{{customer.primaryEmail}}" }
|
|
567
|
+
]
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
"component": "fc.tabs.card",
|
|
572
|
+
"props": {
|
|
573
|
+
"tabs": [
|
|
574
|
+
{ "label": "Items" },
|
|
575
|
+
{ "label": "Fulfilments" },
|
|
576
|
+
{ "label": "Attributes" }
|
|
577
|
+
]
|
|
578
|
+
},
|
|
579
|
+
"descendants": [
|
|
580
|
+
{
|
|
581
|
+
"component": "fc.list",
|
|
582
|
+
"dataSource": "items",
|
|
583
|
+
"props": {
|
|
584
|
+
"defaultPageSize": 25,
|
|
585
|
+
"attributes": [
|
|
586
|
+
{ "label": "Product", "value": "{{node.productRef}}" },
|
|
587
|
+
{ "label": "Quantity", "value": "{{node.quantity}}" },
|
|
588
|
+
{ "label": "Price", "value": "${{node.paidPrice}}", "align": "right" }
|
|
589
|
+
]
|
|
590
|
+
}
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
"component": "fc.list",
|
|
594
|
+
"dataSource": "fulfilments",
|
|
595
|
+
"props": {
|
|
596
|
+
"defaultPageSize": 10,
|
|
597
|
+
"rowLink": "/fulfilments/{{node.id}}",
|
|
598
|
+
"attributes": [
|
|
599
|
+
{ "label": "Reference", "value": "{{node.ref}}" },
|
|
600
|
+
{ "label": "Status", "value": "{{node.status}}" },
|
|
601
|
+
{ "label": "Type", "value": "{{node.type}}" }
|
|
602
|
+
]
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
{
|
|
606
|
+
"component": "fc.list",
|
|
607
|
+
"dataSource": "attributes",
|
|
608
|
+
"props": {
|
|
609
|
+
"defaultPageSize": 25,
|
|
610
|
+
"attributes": [
|
|
611
|
+
{ "label": "Name", "value": "{{node.name}}" },
|
|
612
|
+
{ "label": "Value", "value": "{{node.value}}" },
|
|
613
|
+
{ "label": "Type", "value": "{{node.type}}" }
|
|
614
|
+
]
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
]
|
|
618
|
+
}
|
|
619
|
+
]
|
|
620
|
+
}
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
### Pattern 2: Entity List Page
|
|
624
|
+
|
|
625
|
+
The standard paginated list page with filtering:
|
|
626
|
+
|
|
627
|
+
```json
|
|
628
|
+
{
|
|
629
|
+
"type": "page",
|
|
630
|
+
"path": "orders",
|
|
631
|
+
"component": "fc.page",
|
|
632
|
+
"nav": { "label": "i18n:fc.orders.list.nav", "icon": "shopping_cart" },
|
|
633
|
+
"data": {
|
|
634
|
+
"query": "query($retailerId: [Int!], $orders_first: Int, $status: [String], $type: [String], $createdOn: DateRange) { orders(retailerId: $retailerId, first: $orders_first, status: $status, type: $type, createdOn: $createdOn) { edges { node { id ref status type totalPrice createdOn customer { firstName lastName } } } pageInfo { hasNextPage endCursor } } }",
|
|
635
|
+
"variables": {
|
|
636
|
+
"orders_first": 25,
|
|
637
|
+
"retailerId": "{{activeRetailer.id}}"
|
|
638
|
+
}
|
|
639
|
+
},
|
|
640
|
+
"props": { "title": "i18n:fc.orders.list.title" },
|
|
641
|
+
"descendants": [
|
|
642
|
+
{
|
|
643
|
+
"component": "fc.list",
|
|
644
|
+
"dataSource": "orders",
|
|
645
|
+
"props": {
|
|
646
|
+
"defaultPageSize": 25,
|
|
647
|
+
"rowLink": "/orders/{{node.id}}",
|
|
648
|
+
"filter": { "enabled": true },
|
|
649
|
+
"attributes": [
|
|
650
|
+
{ "label": "Reference", "value": "{{node.ref}}" },
|
|
651
|
+
{ "label": "Customer", "value": "{{node.customer.firstName}} {{node.customer.lastName}}" },
|
|
652
|
+
{ "label": "Status", "value": "{{node.status}}" },
|
|
653
|
+
{ "label": "Type", "value": "{{node.type}}" },
|
|
654
|
+
{ "label": "Total", "value": "${{node.totalPrice}}", "align": "right" },
|
|
655
|
+
{ "label": "Created", "value": "{{dateRelative node.createdOn}}", "hideBelow": "sm" }
|
|
656
|
+
]
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
]
|
|
660
|
+
}
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
### Pattern 3: Dashboard with Metrics
|
|
664
|
+
|
|
665
|
+
```json
|
|
666
|
+
{
|
|
667
|
+
"type": "page",
|
|
668
|
+
"path": "dashboard",
|
|
669
|
+
"component": "fc.page",
|
|
670
|
+
"data": {
|
|
671
|
+
"query": "query($todayStart: DateTime!, $weekStart: DateTime!) { ordersToday: orders(createdOn: {from: $todayStart}) { edges { node { id } } } ordersWeek: orders(createdOn: {from: $weekStart}) { edges { node { id } } } escalations: fulfilments(status: \"ESCALATED\") { edges { node { id } } } }",
|
|
672
|
+
"variables": {
|
|
673
|
+
"todayStart": "{{dateStringFormatter (dateAdd day=-1) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'}}",
|
|
674
|
+
"weekStart": "{{dateStringFormatter (dateAdd day=-7) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'}}"
|
|
675
|
+
}
|
|
676
|
+
},
|
|
677
|
+
"props": { "title": "Overview Dashboard" },
|
|
678
|
+
"descendants": [
|
|
679
|
+
{
|
|
680
|
+
"component": "fc.dashboard.threshold",
|
|
681
|
+
"props": {
|
|
682
|
+
"label": "Orders Today",
|
|
683
|
+
"value": "{{ordersToday.edges.length}}",
|
|
684
|
+
"thresholdLow": 100,
|
|
685
|
+
"thresholdHigh": 500,
|
|
686
|
+
"link": "#/orders"
|
|
687
|
+
}
|
|
688
|
+
},
|
|
689
|
+
{
|
|
690
|
+
"component": "fc.dashboard.threshold",
|
|
691
|
+
"props": {
|
|
692
|
+
"label": "Orders This Week",
|
|
693
|
+
"value": "{{ordersWeek.edges.length}}",
|
|
694
|
+
"thresholdLow": 500,
|
|
695
|
+
"thresholdHigh": 2000,
|
|
696
|
+
"link": "#/orders"
|
|
697
|
+
}
|
|
698
|
+
},
|
|
699
|
+
{
|
|
700
|
+
"component": "fc.dashboard.threshold",
|
|
701
|
+
"props": {
|
|
702
|
+
"label": "Escalations",
|
|
703
|
+
"value": "{{escalations.edges.length}}",
|
|
704
|
+
"thresholdLow": 5,
|
|
705
|
+
"thresholdHigh": 20,
|
|
706
|
+
"link": "#/fulfilments"
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
]
|
|
710
|
+
}
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
### Pattern 4: Conditional Content
|
|
714
|
+
|
|
715
|
+
Show different components based on entity data using `fc.conditional`:
|
|
716
|
+
|
|
717
|
+
```json
|
|
718
|
+
{
|
|
719
|
+
"component": "fc.conditional",
|
|
720
|
+
"props": {
|
|
721
|
+
"value": "{{type}}",
|
|
722
|
+
"matches": "HD"
|
|
723
|
+
},
|
|
724
|
+
"descendants": [
|
|
725
|
+
{
|
|
726
|
+
"component": "fc.card.attribute",
|
|
727
|
+
"props": {
|
|
728
|
+
"title": "Home Delivery Details",
|
|
729
|
+
"attributes": [
|
|
730
|
+
{ "label": "Delivery Address", "value": "{{fulfilmentChoice.deliveryAddress.street}}" },
|
|
731
|
+
{ "label": "Postcode", "value": "{{fulfilmentChoice.deliveryAddress.postcode}}" }
|
|
732
|
+
]
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
]
|
|
736
|
+
}
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
Use multiple `fc.conditional` siblings for if/else-if patterns:
|
|
740
|
+
|
|
741
|
+
```json
|
|
742
|
+
[
|
|
743
|
+
{
|
|
744
|
+
"component": "fc.conditional",
|
|
745
|
+
"props": { "value": "{{type}}", "matches": "HD" },
|
|
746
|
+
"descendants": [{ "component": "fc.card.attribute", "props": { "title": "Home Delivery" } }]
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
"component": "fc.conditional",
|
|
750
|
+
"props": { "value": "{{type}}", "matches": "CC" },
|
|
751
|
+
"descendants": [{ "component": "fc.card.attribute", "props": { "title": "Click & Collect" } }]
|
|
752
|
+
}
|
|
753
|
+
]
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
### Pattern 5: Data Provider Nesting
|
|
757
|
+
|
|
758
|
+
Use `fc.provider.graphql` to fetch additional data within a page:
|
|
759
|
+
|
|
760
|
+
```json
|
|
761
|
+
{
|
|
762
|
+
"component": "fc.provider.graphql",
|
|
763
|
+
"props": {
|
|
764
|
+
"query": "query($ref: [String]) { locations(ref: $ref) { edges { node { id ref name type status primaryAddress { street city state postcode country } } } } }",
|
|
765
|
+
"variables": { "ref": "{{fromLocation.ref}}" },
|
|
766
|
+
"path": "locations"
|
|
767
|
+
},
|
|
768
|
+
"descendants": [
|
|
769
|
+
{
|
|
770
|
+
"component": "fc.card.attribute",
|
|
771
|
+
"dataSource": "locations",
|
|
772
|
+
"props": {
|
|
773
|
+
"title": "Fulfilment Location",
|
|
774
|
+
"attributes": [
|
|
775
|
+
{ "label": "Name", "value": "{{node.name}}" },
|
|
776
|
+
{ "label": "Address", "value": "{{node.primaryAddress.street}}, {{node.primaryAddress.city}}" },
|
|
777
|
+
{ "label": "Status", "value": "{{node.status}}" }
|
|
778
|
+
]
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
]
|
|
782
|
+
}
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
The `path` prop enables auto-pagination for connections. The `loadingBehavior` prop controls rendering during fetch: `"wait"`, `"wait-with-animation"`, or `"pass-immediately"` (default).
|
|
786
|
+
|
|
787
|
+
### Pattern 6: Tab Card with Multiple Views
|
|
788
|
+
|
|
789
|
+
Use `fc.tabs.card` to organize related content into tabs. Descendants are matched to tabs by index:
|
|
790
|
+
|
|
791
|
+
```json
|
|
792
|
+
{
|
|
793
|
+
"component": "fc.tabs.card",
|
|
794
|
+
"props": {
|
|
795
|
+
"tabs": [
|
|
796
|
+
{ "label": "i18n:fc.order.items.tab" },
|
|
797
|
+
{ "label": "i18n:fc.order.fulfilments.tab" },
|
|
798
|
+
{ "label": "i18n:fc.order.activity.tab" }
|
|
799
|
+
],
|
|
800
|
+
"urlKey": "orderTab"
|
|
801
|
+
},
|
|
802
|
+
"descendants": [
|
|
803
|
+
{
|
|
804
|
+
"component": "fc.list",
|
|
805
|
+
"dataSource": "items",
|
|
806
|
+
"props": {
|
|
807
|
+
"defaultPageSize": 25,
|
|
808
|
+
"attributes": [
|
|
809
|
+
{ "label": "Product", "value": "{{node.productRef}}" },
|
|
810
|
+
{ "label": "Qty", "value": "{{node.quantity}}" }
|
|
811
|
+
]
|
|
812
|
+
}
|
|
813
|
+
},
|
|
814
|
+
{
|
|
815
|
+
"component": "fc.list",
|
|
816
|
+
"dataSource": "fulfilments",
|
|
817
|
+
"props": {
|
|
818
|
+
"defaultPageSize": 10,
|
|
819
|
+
"rowLink": "/fulfilments/{{node.id}}",
|
|
820
|
+
"attributes": [
|
|
821
|
+
{ "label": "Ref", "value": "{{node.ref}}" },
|
|
822
|
+
{ "label": "Status", "value": "{{node.status}}" }
|
|
823
|
+
]
|
|
824
|
+
}
|
|
825
|
+
},
|
|
826
|
+
{
|
|
827
|
+
"component": "fc.list",
|
|
828
|
+
"dataSource": "events",
|
|
829
|
+
"props": {
|
|
830
|
+
"defaultPageSize": 50,
|
|
831
|
+
"attributes": [
|
|
832
|
+
{ "label": "Event", "value": "{{node.name}}" },
|
|
833
|
+
{ "label": "Time", "value": "{{dateRelative node.createdOn}}" }
|
|
834
|
+
]
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
]
|
|
838
|
+
}
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
### Pattern 7: Page Actions (User Actions, Mutations, Navigation)
|
|
842
|
+
|
|
843
|
+
Configure page-level action buttons via the `actions` prop on `fc.page`:
|
|
844
|
+
|
|
845
|
+
```json
|
|
846
|
+
{
|
|
847
|
+
"props": {
|
|
848
|
+
"title": "Order {{ref}}",
|
|
849
|
+
"actions": {
|
|
850
|
+
"primary": [
|
|
851
|
+
{
|
|
852
|
+
"type": "userAction",
|
|
853
|
+
"name": "ConfirmShipment",
|
|
854
|
+
"condition": "{{eq status 'PICK_PACK'}}"
|
|
855
|
+
},
|
|
856
|
+
{
|
|
857
|
+
"type": "navigate",
|
|
858
|
+
"label": "View Fulfilments",
|
|
859
|
+
"link": "/orders/{{id}}/fulfilments"
|
|
860
|
+
}
|
|
861
|
+
],
|
|
862
|
+
"secondary": [
|
|
863
|
+
{
|
|
864
|
+
"type": "mutation",
|
|
865
|
+
"name": "updateOrder",
|
|
866
|
+
"label": "Edit Order",
|
|
867
|
+
"args": { "id": "{{id}}" },
|
|
868
|
+
"filter": { "type": "include", "names": ["status", "attributes"] },
|
|
869
|
+
"extensions": {
|
|
870
|
+
"postSubmit": { "type": "navigate", "link": "/orders/{{id}}" }
|
|
871
|
+
}
|
|
872
|
+
},
|
|
873
|
+
{
|
|
874
|
+
"type": "component",
|
|
875
|
+
"component": "custom.order-export-button",
|
|
876
|
+
"props": { "orderId": "{{id}}" }
|
|
877
|
+
}
|
|
878
|
+
],
|
|
879
|
+
"userActionFilter": { "type": "exclude", "names": ["CancelOrder"] }
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
```
|
|
884
|
+
|
|
885
|
+
Action types:
|
|
886
|
+
- `userAction` — triggers a workflow user action. Auto-appended from workflow but can be reordered or conditionally shown.
|
|
887
|
+
- `mutation` — executes a GraphQL mutation with auto-generated form. Use `overrides` to customize field labels, sources, and components.
|
|
888
|
+
- `navigate` — navigates to another page. `link` supports template strings.
|
|
889
|
+
- `component` — renders a custom SDK component in the action bar.
|
|
890
|
+
|
|
891
|
+
## Entity Type to GraphQL Query Map
|
|
892
|
+
|
|
893
|
+
Use this mapping to auto-generate page data queries:
|
|
894
|
+
|
|
895
|
+
| Entity Type | Root Query (list) | Root Query (detail) | Key Fields |
|
|
896
|
+
|-------------|-------------------|---------------------|------------|
|
|
897
|
+
| ORDER | `orders(first, after, status, type, retailerId, createdOn)` | `orderById(id)` | id, ref, status, type, createdOn, totalPrice, customer, items, fulfilments, fulfilmentChoice, attributes |
|
|
898
|
+
| FULFILMENT | `fulfilments(first, after, status, type, retailerId)` | `fulfilmentById(id)` | id, ref, status, type, createdOn, order, items, fromAddress, toAddress, attributes |
|
|
899
|
+
| ARTICLE | `articles(first, after, status, retailerId)` | `articleById(id)` | id, ref, status, type, items, consignmentArticles, attributes |
|
|
900
|
+
| WAVE | `waves(first, after, status, retailerId)` | `waveById(id)` | id, ref, status, type, fulfilments, retailer, attributes |
|
|
901
|
+
| LOCATION | `locations(first, after, status, type, retailerId)` | `locationById(id)` | id, ref, name, type, status, primaryAddress, networks, openingSchedule, attributes |
|
|
902
|
+
| INVENTORY_POSITION | `inventoryPositions(first, after, productRef, locationRef)` | `inventoryPositionById(id)` | id, ref, productRef, locationRef, onHand, status, type, attributes |
|
|
903
|
+
| PRODUCT_CATALOGUE | `productCatalogues(first, after, retailerId)` | `productCatalogueById(id)` | id, ref, name, type, retailer, attributes |
|
|
904
|
+
| VIRTUAL_CATALOGUE | `virtualCatalogues(first, after, retailerId)` | `virtualCatalogueById(id)` | id, ref, name, type, retailer, attributes |
|
|
905
|
+
| CARRIER | `carriers(first, after, retailerId)` | `carrierById(id)` | id, ref, name, type, status, retailer, attributes |
|
|
906
|
+
| RETURN_ORDER | `returnOrders(first, after, status, retailerId)` | `returnOrderById(id)` | id, ref, status, type, order, returnAuthorisation, items, attributes |
|
|
907
|
+
| NETWORK | `networks(first, after, retailerId)` | `networkById(id)` | id, ref, name, type, status, locations, retailers, attributes |
|
|
908
|
+
| SETTING | `settings(first, after, name, context)` | n/a | id, name, value, lobValue, valueType, context, contextId |
|
|
909
|
+
|
|
910
|
+
### Connection Pattern for Nested Entities
|
|
911
|
+
|
|
912
|
+
All list queries return connections with edges/node pattern. Always include `pageInfo` for pagination:
|
|
913
|
+
|
|
914
|
+
```graphql
|
|
915
|
+
query($first: Int, $after: String) {
|
|
916
|
+
orders(first: $first, after: $after) {
|
|
917
|
+
edges {
|
|
918
|
+
node {
|
|
919
|
+
id
|
|
920
|
+
ref
|
|
921
|
+
status
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
pageInfo {
|
|
925
|
+
hasNextPage
|
|
926
|
+
endCursor
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
Nested connections follow the same pattern:
|
|
933
|
+
|
|
934
|
+
```graphql
|
|
935
|
+
{
|
|
936
|
+
orderById(id: $id) {
|
|
937
|
+
items {
|
|
938
|
+
edges {
|
|
939
|
+
node { id ref quantity productRef }
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
```
|
|
945
|
+
|
|
946
|
+
## Component Knowledge
|
|
947
|
+
|
|
948
|
+
Each OOTB component is documented in its own `.md` file under `components/` (same directory as this skill). `COMPONENT_TEMPLATE.md` defines the standard format — used for both OOTB and client custom component documentation.
|
|
949
|
+
|
|
950
|
+
Use this lookup order for fastest and most reliable component selection:
|
|
951
|
+
1. Start with `components/INDEX.md` for alias/category/module lookup (AI-friendly table).
|
|
952
|
+
2. Open matching `components/<alias>.md` files for detailed props, data binding, and composition guidance.
|
|
953
|
+
3. Use each file's frontmatter (`alias`, `aliases`, `category`, `module`) and `## AI Parse Notes` section for deterministic parsing.
|
|
954
|
+
|
|
955
|
+
**Before building ANY manifest:**
|
|
956
|
+
1. Grep `components/*.md` for the user's UI need (e.g., "list", "filter", "tabs")
|
|
957
|
+
2. Read matching component files for props, data binding, and composition patterns
|
|
958
|
+
3. Propose a composition plan → get user approval → build manifest JSON
|
|
959
|
+
4. Only if no OOTB combination works → escalate to `/fluent-mystique-scaffold`
|
|
960
|
+
|
|
961
|
+
### Build vs Configure Decision (use EVERY time)
|
|
962
|
+
|
|
963
|
+
```
|
|
964
|
+
Step 1: Check Need → Grep components/*.md for matching capability
|
|
965
|
+
├── Found a match? → Configure via manifest using the documented props
|
|
966
|
+
├── Close match? → Step 2: Creative composition of OOTB components
|
|
967
|
+
│ ├── Combine fc.conditional + fc.repeater + fc.provider.graphql?
|
|
968
|
+
│ ├── Nest tabs inside providers? Use multiple data providers?
|
|
969
|
+
│ └── Found a working composition? → Build manifest JSON
|
|
970
|
+
├── Need a custom form field or template? → Step 3: Lightweight SDK extension
|
|
971
|
+
│ └── FieldRegistry.register() or TemplateRegistry.register()
|
|
972
|
+
└── Genuinely no OOTB equivalent? → Step 4: Full custom component
|
|
973
|
+
└── Scaffold via /fluent-mystique-scaffold → ComponentRegistry.register()
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
**Most requests resolve at Step 1 or 2.** Only proceed to Step 4 for: novel visualizations, drag-and-drop, external service integrations, real-time features, or interaction patterns not covered by user action forms.
|
|
977
|
+
|
|
978
|
+
### Quick Alias Reference (86 components in `components/`)
|
|
979
|
+
|
|
980
|
+
**Page:** `fc.page`, `fc.page.section`, `fc.page.section.column`, `fc.page.section.header`, `fc.page.wizard`, `fc.page.wizard.summary`, `fc.page.refresh`, `fc.page.filter.select`
|
|
981
|
+
|
|
982
|
+
**Layout:** `fc.conditional`, `fc.repeater`, `fc.provider.graphql`, `fc.workflow.provider`, `fc.tabs`, `fc.tabs.card`, `fc.tab.content`, `fc.accordion`, `fc.filterPanel`
|
|
983
|
+
|
|
984
|
+
**Content:** `fc.list`, `fc.list.customAction`, `fc.card.attribute`, `fc.card.image`, `fc.card.product`, `fc.card.multi`, `fc.card.attributes.grid`, `fc.card.map.point`, `fc.tile.metric`, `fc.dashboard.threshold`, `fc.stepper`, `fc.progress.circular`, `fc.attribute.json`, `fc.attribute.column`, `fc.mystique.collapsible.text`, `fc.mystique.collapsible.attributes`, `fc.mystique.link`, `fc.json.viewer`, `fc.json.editor`, `fc.quantity.list`, `fc.settingForm`
|
|
985
|
+
|
|
986
|
+
**Charts:** `fc.chart.line`, `fc.chart.bar`, `fc.chart.area`, `fc.chart.gauge` (+ wrapper variants)
|
|
987
|
+
|
|
988
|
+
**Actions:** `fc.action.inline`, `fc.mutation.inline`, `fc.button.print` (+ `.pick`, `.inline`, `.download`), `fc.button.bar`, `fc.modal.button`, `fc.modal.button.addItem`, `fc.drawer.button`, `fc.sourcing.strategy.modal.button`, `fc.sourcing.profile.drawer.button`, `fc.sourcing.profile.modal.button`
|
|
989
|
+
|
|
990
|
+
**Forms/Fields:** `select`, `fc.field.daterange`, `fc.field.intrange`, `fc.field.multistring`, `fc.field.filterComplex`, `fc.scanner.barcode`, `fc.scanner.camera`, `fc.scanner.barcodeFilter`
|
|
991
|
+
|
|
992
|
+
**OMS:** `fc.events.search`, `fc.activity.entity`, `fc.event.detail`, `fc.order.itemDetails`, `fc.order.shipmentDetails`, `fc.return.rowExpansion`
|
|
993
|
+
|
|
994
|
+
**Store:** `fc.buttons.add.reject`, `fc.action.field.wavepick`, `fc.action.field.fulfilmentpack`, `fc.action.field.multiparcel`, `fc.action.field.returnitems`
|
|
995
|
+
|
|
996
|
+
**Analytics:** `fc.analytics.viz` (Looker embed)
|
|
997
|
+
|
|
998
|
+
**Legacy aliases** (v1 → v2): `shared.components.material.DynamicPage` → `fc.page`, `shared.components.material.DynamicList` → `fc.list`, `shared.components.material.DynamicCard` → `fc.card.attribute`, `shared.components.material.MaterialTabsSet` → `fc.tabs`
|
|
999
|
+
|
|
1000
|
+
## Template String Reference
|
|
1001
|
+
|
|
1002
|
+
Mystique uses Handlebars-based template strings throughout manifests. **Only use documented helpers — guessing undocumented helpers produces broken manifests.**
|
|
1003
|
+
|
|
1004
|
+
### Field Access
|
|
1005
|
+
|
|
1006
|
+
| Expression | Purpose | Example |
|
|
1007
|
+
|-----------|---------|---------|
|
|
1008
|
+
| `{{fieldName}}` | Direct field access | `{{ref}}`, `{{status}}` |
|
|
1009
|
+
| `{{nested.path}}` | Nested field access | `{{customer.firstName}}` |
|
|
1010
|
+
| `{{attributes.byName.X}}` | Attribute by name shorthand | `{{order.attributes.byName.vipStatus}}` |
|
|
1011
|
+
| `{{node.field}}` | List row data access | `{{node.ref}}` in fc.list attributes |
|
|
1012
|
+
| `{{edges.length}}` | Connection count | `{{orders.edges.length}}` |
|
|
1013
|
+
|
|
1014
|
+
### Context Variables
|
|
1015
|
+
|
|
1016
|
+
| Expression | Purpose |
|
|
1017
|
+
|-----------|---------|
|
|
1018
|
+
| `{{activeUser.username}}` | Current user's username |
|
|
1019
|
+
| `{{activeUser.firstName}}` | Current user's first name |
|
|
1020
|
+
| `{{activeUser.timezone}}` | Current user's timezone |
|
|
1021
|
+
| `{{activeContext.id}}` | Current context ID (retailer or location) |
|
|
1022
|
+
| `{{activeContext.ref}}` | Current context ref |
|
|
1023
|
+
| `{{activeRetailer.id}}` | Current retailer ID |
|
|
1024
|
+
| `{{activeRetailer.ref}}` | Current retailer ref |
|
|
1025
|
+
| `{{activeLocation.id}}` | Current location ID |
|
|
1026
|
+
| `{{activeLocation.ref}}` | Current location ref |
|
|
1027
|
+
| `{{params.id}}` | Route parameter access |
|
|
1028
|
+
| `{{params.filter_status}}` | Query parameter access |
|
|
1029
|
+
|
|
1030
|
+
### String Helpers
|
|
1031
|
+
|
|
1032
|
+
| Expression | Purpose | Example |
|
|
1033
|
+
|-----------|---------|---------|
|
|
1034
|
+
| `{{capitalise value}}` | Capitalize string | `{{capitalise status}}` |
|
|
1035
|
+
| `{{humanify value}}` | Human-readable (underscore/camel to spaced) | `{{humanify entityType}}` |
|
|
1036
|
+
| `{{toLowerCase value}}` | Lowercase | `{{toLowerCase order.type}}` |
|
|
1037
|
+
| `{{toUpperCase value}}` | Uppercase | `{{toUpperCase lastName}}` |
|
|
1038
|
+
| `{{concat a b separator='X'}}` | Concatenate with separator | `{{concat firstName lastName separator=' '}}` |
|
|
1039
|
+
| `{{stringify value}}` | JSON stringify | `{{stringify order.attributes.byName.payload}}` |
|
|
1040
|
+
| `{{preserveWhitespace text}}` | Preserve whitespace in rendering | `{{preserveWhitespace notes}}` |
|
|
1041
|
+
| `{{partialStringMatch a b}}` | Case-insensitive partial match | `{{partialStringMatch 'item1' 'eM1'}}` returns true |
|
|
1042
|
+
| `{{decodeUrlParams value}}` | URL decode | `{{decodeUrlParams 'TEST%3A%3AL%2FXL'}}` returns `TEST::L/XL` |
|
|
1043
|
+
| `{{{currentUrlParams}}}` | Inject current URL params (triple-brace, unescaped) | `"#/search?{{{currentUrlParams}}}"` |
|
|
1044
|
+
| `{{placeholderText text color='X' defaultValue='X'}}` | Styled fallback text | `{{placeholderText value defaultValue='-'}}` |
|
|
1045
|
+
|
|
1046
|
+
### Date Helpers
|
|
1047
|
+
|
|
1048
|
+
**CRITICAL: Always use `_locale='en'` for dates in query variables.** Without it, user locale may produce non-ASCII digits (e.g., Arabic numerals) that break backend queries.
|
|
1049
|
+
|
|
1050
|
+
| Expression | Purpose | Example |
|
|
1051
|
+
|-----------|---------|---------|
|
|
1052
|
+
| `{{dateFormat date fmt}}` | Formatted date (display) | `{{dateFormat createdOn 'MMM DD, YYYY'}}` |
|
|
1053
|
+
| `{{dateFormat date fmt true _locale='en'}}` | **Backend-safe** formatted date | `{{dateFormat (dateAdd day=-1) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true _locale='en'}}` |
|
|
1054
|
+
| `{{dateRelative date}}` | Relative time ("10 minutes ago") | `{{dateRelative order.expiryTime}}` |
|
|
1055
|
+
| `{{dateFormatByLocale date}}` | Locale-aware format (dd/mm or mm/dd) | `{{dateFormatByLocale order.createdOn}}` |
|
|
1056
|
+
| `{{dateAdd date day=N}}` | Date arithmetic (add) | `{{dateAdd order.createdOn day=3}}` |
|
|
1057
|
+
| `{{dateSubtract date day=N}}` | Date arithmetic (subtract) | `{{dateSubtract order.createdOn day=5}}` |
|
|
1058
|
+
| `{{dateStringFormatter (dateAdd day=N) fmt}}` | Date arithmetic + format | `{{dateStringFormatter (dateAdd day=-7) 'YYYY-MM-DD'}}` |
|
|
1059
|
+
| `{{placeholderDate date color='X' defaultValue='X'}}` | Date with styled fallback | `{{placeholderDate date defaultValue='[...]'}}` |
|
|
1060
|
+
|
|
1061
|
+
### Number and Currency Helpers
|
|
1062
|
+
|
|
1063
|
+
| Expression | Purpose | Example |
|
|
1064
|
+
|-----------|---------|---------|
|
|
1065
|
+
| `{{currency value code}}` | Format as currency | `{{currency totalPrice 'AUD'}}` |
|
|
1066
|
+
| `{{currency value code _locale='X' _decimalPlaces=N}}` | Currency with locale control | `{{currency 123.87 'AUD' _locale='en-AU' _decimalPlaces=3}}` |
|
|
1067
|
+
| `{{add a b}}` | Addition | `{{add 1 2}}` returns 3 |
|
|
1068
|
+
| `{{subtract a b _decimalPlaces=N}}` | Subtraction | `{{subtract 50.32 20.11 _decimalPlaces=2}}` returns 30.21 |
|
|
1069
|
+
| `{{multiply a b}}` | Multiplication | `{{multiply 3 4}}` returns 12 |
|
|
1070
|
+
| `{{divide a b _decimalPlaces=N}}` | Division | `{{divide 12 4 _decimalPlaces=3}}` returns 3.000 |
|
|
1071
|
+
| `{{pow base exp}}` | Exponent | `{{pow 3 2}}` returns 9 |
|
|
1072
|
+
|
|
1073
|
+
### Array Helpers
|
|
1074
|
+
|
|
1075
|
+
| Expression | Purpose | Example |
|
|
1076
|
+
|-----------|---------|---------|
|
|
1077
|
+
| `{{len array}}` | Array length | `{{len items.edges}}` |
|
|
1078
|
+
| `{{arraySum array 'path'}}` | Sum numeric field across array | `{{arraySum order.items 'node.totalPrice'}}` |
|
|
1079
|
+
| `{{placeholderArray arr separator='X' charCutoff=N}}` | Array display with truncation | `{{placeholderArray tags separator=', ' charCutoff=50}}` |
|
|
1080
|
+
|
|
1081
|
+
### Logic Helpers
|
|
1082
|
+
|
|
1083
|
+
| Expression | Purpose | Example |
|
|
1084
|
+
|-----------|---------|---------|
|
|
1085
|
+
| `{{eq a b}}` | Equality | `{{eq status 'ACTIVE'}}` |
|
|
1086
|
+
| `{{ne a b}}` | Not equal | `{{ne status 'CANCELLED'}}` |
|
|
1087
|
+
| `{{gt a b}}` | Greater than | `{{gt totalPrice 0}}` |
|
|
1088
|
+
| `{{lt a b}}` | Less than | `{{lt items.count 3}}` |
|
|
1089
|
+
| `{{gte a b}}` | Greater or equal | `{{gte items.count 5}}` |
|
|
1090
|
+
| `{{lte a b}}` | Less or equal | `{{lte items.count 10}}` |
|
|
1091
|
+
| `{{and a b}}` | Logical AND | `{{and (eq status 'BOOKED') (gt items.count 0)}}` |
|
|
1092
|
+
| `{{or a b}}` | Logical OR | `{{or order.status order.items.count}}` |
|
|
1093
|
+
| `{{in value ...options}}` | Inclusion check | `{{in type 'HD' 'CC' 'MULTI'}}` |
|
|
1094
|
+
| `{{switch val k1 v1 k2 v2 default}}` | Switch expression | `{{switch status 'COMPLETE' 'green' 'red'}}` |
|
|
1095
|
+
| `{{hasRole 'ROLE'}}` | Role check | `{{hasRole 'admin'}}` |
|
|
1096
|
+
| `{{firstDefinedValue a b c}}` | First non-null value | `{{firstDefinedValue null undefined 10}}` returns 10 |
|
|
1097
|
+
| `{{anyMatch 'path' 'val' 'op'}}` | Array element match | `{{anyMatch 'node.entity.field' 'delta' 'eq'}}` |
|
|
1098
|
+
|
|
1099
|
+
### i18n Helpers
|
|
1100
|
+
|
|
1101
|
+
| Expression | Purpose | Example |
|
|
1102
|
+
|-----------|---------|---------|
|
|
1103
|
+
| `{{i18n 'key'}}` | Translate key | `{{i18n 'fc.om.orders.title'}}` |
|
|
1104
|
+
| `{{i18n 'prefix' value _fallback=val}}` | Dynamic key with fallback | `{{i18n 'fc.om.order.type.' node.type _fallback=node.type}}` |
|
|
1105
|
+
| `{{i18n 'a' '.' 'b'}}` | Concatenated key | `{{i18n 'fc.om.order' '.' 'status'}}` |
|
|
1106
|
+
|
|
1107
|
+
### Special Helpers
|
|
1108
|
+
|
|
1109
|
+
| Expression | Purpose | Example |
|
|
1110
|
+
|-----------|---------|---------|
|
|
1111
|
+
| `{{barcode value format}}` | Generate barcode SVG | `{{barcode '1234 abc' 'CODE128B'}}` |
|
|
1112
|
+
| `{{barcode value}}` | Barcode with auto-detected format | `{{barcode fulfilmentById.ref}}` |
|
|
1113
|
+
| `{{barcode value format false}}` | Barcode without text below | `{{barcode '1234' 'EAN-13' false}}` |
|
|
1114
|
+
|
|
1115
|
+
Supported barcode formats: CODE128, CODE128A, CODE128B, CODE128C, EAN-13, EAN-8, EAN-5, EAN-2, UPC-A, UPC-E, CODE39, ITF, ITF-14, MSI, MSI10, MSI11, MSI1010, MSI1110, Pharmacode, Codabar.
|
|
1116
|
+
|
|
1117
|
+
## Dynamic Attribute Types
|
|
1118
|
+
|
|
1119
|
+
Dynamic attributes are configurable value displays used in `fc.list` columns, `fc.card.attribute` rows, and similar components. Three types: **standard** (text), **image**, and **component**.
|
|
1120
|
+
|
|
1121
|
+
### Standard (Text) with Conditional Styling
|
|
1122
|
+
|
|
1123
|
+
```json
|
|
1124
|
+
{
|
|
1125
|
+
"label": "i18n:fc.om.orders.column.status",
|
|
1126
|
+
"value": "{{status}}",
|
|
1127
|
+
"link": "#/order/{{id}}",
|
|
1128
|
+
"condition": "{{and id}}",
|
|
1129
|
+
"enableCopyIcon": "displayOnHover",
|
|
1130
|
+
"options": {
|
|
1131
|
+
"styles": [
|
|
1132
|
+
{
|
|
1133
|
+
"value": "{{status}}",
|
|
1134
|
+
"matches": ["BOOKED", "CONFIRMED"],
|
|
1135
|
+
"icon": { "name": "MdCheckCircle", "colour": "primary" },
|
|
1136
|
+
"text": { "colour": "green" }
|
|
1137
|
+
},
|
|
1138
|
+
{
|
|
1139
|
+
"matches": ["CANCELLED"],
|
|
1140
|
+
"icon": { "name": "MdCancel", "colour": "error" },
|
|
1141
|
+
"text": { "colour": "red" }
|
|
1142
|
+
},
|
|
1143
|
+
{ "icon": { "name": "MdInfo" } }
|
|
1144
|
+
]
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
```
|
|
1148
|
+
|
|
1149
|
+
Style matching: entries with `matches` checked in order — first match wins. Entry without `matches` is the default. Icon `name` must include library prefix: `Md*` (Material Design) or `Fa*` (Font Awesome).
|
|
1150
|
+
|
|
1151
|
+
### Image Attribute
|
|
1152
|
+
|
|
1153
|
+
```json
|
|
1154
|
+
{ "type": "image", "label": "Product", "value": "{{node.attributes.byName.imageUrl}}", "options": { "width": 50, "height": 50 } }
|
|
1155
|
+
```
|
|
1156
|
+
|
|
1157
|
+
### Component Attribute
|
|
1158
|
+
|
|
1159
|
+
Embed another component inside an attribute slot:
|
|
1160
|
+
|
|
1161
|
+
```json
|
|
1162
|
+
{ "type": "component", "label": "Actions", "options": { "component": "fc.button.print.download", "props": { "label": "Print", "href": "api/v4/consignment/{{id}}/labelStream", "filename": "label.pdf" } } }
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
## CardActions Pattern
|
|
1166
|
+
|
|
1167
|
+
CardActions configure action buttons on cards and list rows. Primary actions render as buttons; secondary actions group under "More".
|
|
1168
|
+
|
|
1169
|
+
```json
|
|
1170
|
+
{
|
|
1171
|
+
"cardActions": {
|
|
1172
|
+
"primary": [{ "type": "userAction", "name": "ConfirmShipment", "label": "i18n:fc.action.confirm" }],
|
|
1173
|
+
"secondary": [{ "type": "userAction", "name": "CancelOrder", "condition": "{{ne status 'SHIPPED'}}" }],
|
|
1174
|
+
"showAtLeast": 1
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
```
|
|
1178
|
+
|
|
1179
|
+
- `type: "userAction"` triggers a workflow user action. `name` matches the ruleset name.
|
|
1180
|
+
- Workflow-defined user actions are **automatically appended** — only add to manifest when reordering or adding conditions.
|
|
1181
|
+
- `showAtLeast` — primary actions to keep visible on mobile (rest collapse into "More").
|
|
1182
|
+
- `condition` — template string; action hidden when evaluates to `"false"`.
|
|
1183
|
+
|
|
1184
|
+
## Settings vs Manifest Decision Matrix
|
|
1185
|
+
|
|
1186
|
+
| Use **Settings** when | Use **Manifest** when |
|
|
1187
|
+
|---|---|
|
|
1188
|
+
| Config varies by retailer/location | Structure is stable across tenants |
|
|
1189
|
+
| Values change frequently | Routes, pages, component layout |
|
|
1190
|
+
| Non-developers need to update | Developers manage changes |
|
|
1191
|
+
| API keys, external URLs, thresholds | Static labels, i18n keys |
|
|
1192
|
+
|
|
1193
|
+
## Troubleshooting
|
|
1194
|
+
|
|
1195
|
+
Common manifest issues and fixes:
|
|
1196
|
+
|
|
1197
|
+
1. **Template not resolving** — Missing `{{ }}` syntax. `"value": "order.ref"` shows literal text. Fix: `"value": "{{order.ref}}"`
|
|
1198
|
+
2. **Date query returns localized digits** — User locale produces Arabic/Thai numerals that break backend. Fix: Add `_locale='en'`: `{{dateFormat (dateSubtract day=1) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true _locale='en'}}`
|
|
1199
|
+
3. **Condition not working** — String `"false"` is truthy. Fix: Use a template expression: `"condition": "{{and field1 field2}}"`
|
|
1200
|
+
4. **Link not rendering** — The data value is null/undefined. Fix: Add `"condition": "{{and customer.id}}"` alongside the link
|
|
1201
|
+
5. **Icon not showing** — Missing library prefix. `"CheckCircle"` is wrong. Fix: `"MdCheckCircle"` (Material Design) or `"FaCheck"` (Font Awesome)
|
|
1202
|
+
6. **Debugging tips** — Check browser DevTools Network tab for actual GraphQL response shape. Use React DevTools to inspect component props. Validate JSON syntax with `jq .`
|
|
1203
|
+
|
|
1204
|
+
## Output Locations
|
|
1205
|
+
|
|
1206
|
+
| Artifact | Path |
|
|
1207
|
+
|----------|------|
|
|
1208
|
+
| New manifest | `accounts/<PROFILE>/SOURCE/<sdk-project>/manifests/<name>.json` |
|
|
1209
|
+
| Fragment | `accounts/<PROFILE>/SOURCE/<sdk-project>/manifests/fragments/<name>.json` |
|
|
1210
|
+
| Standalone manifest (no SDK project) | `accounts/<PROFILE>/manifests/<name>.json` |
|
|
1211
|
+
| Build plan | `accounts/<PROFILE>/tasks/<YYYY-MM-DD>-mystique-builder-<slug>.md` |
|
|
1212
|
+
|
|
1213
|
+
## Handoff Protocol
|
|
1214
|
+
|
|
1215
|
+
### Signals emitted by this skill
|
|
1216
|
+
|
|
1217
|
+
| Signal | Condition | Example |
|
|
1218
|
+
|--------|-----------|---------|
|
|
1219
|
+
| `-> READY: <path>` | Manifest JSON created/modified | `-> READY: accounts/SAGIRISH/SOURCE/mystique-plugin/manifests/admin.json` |
|
|
1220
|
+
| `-> NEXT: /fluent-<skill>` | Always validate after build | `-> NEXT: /fluent-mystique-validate` |
|
|
1221
|
+
| `-> BLOCKED: <reason>` | Prerequisite missing | `-> BLOCKED: PREREQ_MISSING -- Custom component custom.order-tracker not registered. Run /fluent-mystique-scaffold` |
|
|
1222
|
+
| `-> SKIP: <reason>` | No manifest changes needed | `-> SKIP: No UI changes in this feature plan` |
|
|
1223
|
+
|
|
1224
|
+
### Error codes
|
|
1225
|
+
|
|
1226
|
+
| Code | Condition | Recovery |
|
|
1227
|
+
|------|-----------|----------|
|
|
1228
|
+
| `PLAN_REQUIRED` | Multi-artifact work attempted without approved plan | Run `/fluent-feature-plan` first |
|
|
1229
|
+
| `PREREQ_MISSING` | Custom SDK components not scaffolded or plugins missing | Scaffold component via `/fluent-mystique-scaffold` |
|
|
1230
|
+
| `VALIDATION_FAILED` | Manifest JSON structure invalid after editing | Fix JSON structure per validation checklist |
|
|
1231
|
+
|
|
1232
|
+
## Session Tracking
|
|
1233
|
+
|
|
1234
|
+
When invoked, log the following to the session tracking protocol (consumed by `/fluent-session-summary` and `/fluent-session-audit-export`):
|
|
1235
|
+
|
|
1236
|
+
**On entry:**
|
|
1237
|
+
```json
|
|
1238
|
+
{ "skill": "fluent-mystique-builder", "timestamp": "<ISO-8601>", "arguments": { "operation": "<op>", "manifest": "<file>", "page": "<path>" } }
|
|
1239
|
+
```
|
|
1240
|
+
|
|
1241
|
+
**On exit:**
|
|
1242
|
+
```json
|
|
1243
|
+
{ "skill": "fluent-mystique-builder", "outcome": "<completed|failed|skipped>", "changesProduced": ["<seq-numbers>"], "toolCallsProduced": ["<seq-numbers>"], "nextRecommended": "/fluent-mystique-validate" }
|
|
1244
|
+
```
|
|
1245
|
+
|
|
1246
|
+
## Error Reporting
|
|
1247
|
+
|
|
1248
|
+
Errors from this skill follow the standard format:
|
|
1249
|
+
|
|
1250
|
+
| Field | Description |
|
|
1251
|
+
|-------|-------------|
|
|
1252
|
+
| `phase` | Skill phase where error occurred (e.g., `pre-flight`, `route-design`, `component-tree`, `query-generation`, `validation`) |
|
|
1253
|
+
| `severity` | `CRITICAL` (blocks downstream), `HIGH` (needs fix), `MEDIUM` (advisory), `LOW` (informational) |
|
|
1254
|
+
| `message` | Human-readable error description |
|
|
1255
|
+
| `resolution` | Suggested fix or downstream skill to invoke |
|
|
1256
|
+
|
|
1257
|
+
## Validation Checklist
|
|
1258
|
+
|
|
1259
|
+
Run through this before considering any manifest complete:
|
|
1260
|
+
|
|
1261
|
+
1. **JSON syntax** — Valid JSON (no trailing commas, correct brackets)
|
|
1262
|
+
2. **manifestVersion** — Must be `"2.0"`
|
|
1263
|
+
3. **Required fields** — `name`, `title`, `homePath`, `routes` all present
|
|
1264
|
+
4. **homePath resolves** — Must match a defined route's `path`
|
|
1265
|
+
5. **Route types valid** — Every route is `section`, `page`, or `reference`
|
|
1266
|
+
6. **Page paths unique** — No duplicate `path` values across all pages
|
|
1267
|
+
7. **Component aliases** — All `fc.*` aliases exist in the known registry; custom aliases have corresponding plugin
|
|
1268
|
+
8. **dataSource paths** — JSONPath notation valid; references query result fields
|
|
1269
|
+
9. **Template strings** — Balanced `{{`/`}}`, valid helper names
|
|
1270
|
+
10. **Plugin URLs** — `src` is a valid URL (http/https for dev, https for production)
|
|
1271
|
+
11. **Fragment settingName** — Follows `fc.mystique.manifest.*` convention
|
|
1272
|
+
12. **Roles** — Role strings are valid and consistent across the manifest
|
|
1273
|
+
13. **i18n keys** — Translatable strings use `i18n:` prefix consistently
|
|
1274
|
+
|
|
1275
|
+
## Integration with Other Skills
|
|
1276
|
+
|
|
1277
|
+
| Task | Skill |
|
|
1278
|
+
|------|-------|
|
|
1279
|
+
| Validate manifest structure before deploy | `/fluent-mystique-validate` |
|
|
1280
|
+
| Scaffold custom SDK component project | `/fluent-mystique-scaffold` |
|
|
1281
|
+
| Analyze existing manifests for patterns | `/fluent-mystique-analyze` |
|
|
1282
|
+
| Deploy manifest as Fluent Setting | `/fluent-settings` |
|
|
1283
|
+
| Build workflows that power user actions | `/fluent-workflow-builder` |
|
|
1284
|
+
| Create feature plan covering UI work | `/fluent-feature-plan` |
|
|
1285
|
+
| Run pre-deploy checks including manifest validation | `/fluent-pre-deploy-check` |
|
|
1286
|
+
|
|
1287
|
+
## Handoff
|
|
1288
|
+
|
|
1289
|
+
| Output Artifact | Consumed By | Path |
|
|
1290
|
+
|----------------|-------------|------|
|
|
1291
|
+
| Manifest JSON file | `/fluent-mystique-validate` (validation) | `accounts/<PROFILE>/SOURCE/<project>/manifests/<name>.json` |
|
|
1292
|
+
| Manifest JSON file | `/fluent-settings` (deploy as setting) | `accounts/<PROFILE>/SOURCE/<project>/manifests/<name>.json` |
|
|
1293
|
+
| Fragment JSON file | `/fluent-settings` (deploy as setting) | `accounts/<PROFILE>/SOURCE/<project>/manifests/fragments/<name>.json` |
|
|
1294
|
+
| Build plan | User review | `accounts/<PROFILE>/tasks/<YYYY-MM-DD>-mystique-builder-<slug>.md` |
|