create-flowdular 0.2.3 → 0.2.5
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/README.md +11 -0
- package/agent-template/.agents/skills/agent-tool-design/SKILL.md +203 -0
- package/agent-template/.agents/skills/auth-security-review/SKILL.md +90 -0
- package/agent-template/.agents/skills/auto-review/SKILL.md +103 -0
- package/agent-template/.agents/skills/bug-hunt/SKILL.md +104 -0
- package/agent-template/.agents/skills/business-agent-design/SKILL.md +182 -0
- package/agent-template/.agents/skills/cli-extension/SKILL.md +108 -0
- package/agent-template/.agents/skills/core-extend/SKILL.md +99 -0
- package/agent-template/.agents/skills/database-adapter/SKILL.md +198 -0
- package/agent-template/.agents/skills/database-adapter/references/first-run-and-matrix.md +105 -0
- package/agent-template/.agents/skills/migration-authoring/SKILL.md +161 -0
- package/agent-template/.agents/skills/module-new/SKILL.md +171 -0
- package/agent-template/.agents/skills/module-update/SKILL.md +91 -0
- package/agent-template/.agents/skills/perf-audit/SKILL.md +98 -0
- package/agent-template/.agents/skills/release-eject-pr/SKILL.md +107 -0
- package/agent-template/.agents/skills/spec-approval/SKILL.md +106 -0
- package/agent-template/.agents/skills/test-hardening/SKILL.md +79 -0
- package/agent-template/.agents/skills/translations-i18n/SKILL.md +78 -0
- package/agent-template/.agents/skills/ux-design/SKILL.md +92 -0
- package/agent-template/.agents/skills/variables/SKILL.md +156 -0
- package/agent-template/.agents/skills/workflow-development/SKILL.md +192 -0
- package/agent-template/.ai/README.md +62 -0
- package/agent-template/.ai/agents/README.md +27 -0
- package/agent-template/.ai/agents/module-executor.md +36 -0
- package/agent-template/.ai/agents/reviewer.md +23 -0
- package/agent-template/.ai/agents/sandbox/agentic-engineer.md +31 -0
- package/agent-template/.ai/agents/sandbox/backend-engineer.md +36 -0
- package/agent-template/.ai/agents/sandbox/business-manager.md +23 -0
- package/agent-template/.ai/agents/sandbox/frontend-engineer.md +27 -0
- package/agent-template/.ai/agents/sandbox/ux-designer.md +23 -0
- package/agent-template/.ai/agents/spec-author.md +29 -0
- package/agent-template/.ai/blueprints/add-migration/README.md +5 -0
- package/agent-template/.ai/blueprints/add-migration/allowed-paths.yaml +23 -0
- package/agent-template/.ai/blueprints/add-migration/blueprint.json +14 -0
- package/agent-template/.ai/blueprints/add-migration/examples/invalid/input-destructive.json +6 -0
- package/agent-template/.ai/blueprints/add-migration/examples/invalid/plan-unnumbered-file.json +9 -0
- package/agent-template/.ai/blueprints/add-migration/examples/valid/input.json +6 -0
- package/agent-template/.ai/blueprints/add-migration/examples/valid/plan.json +9 -0
- package/agent-template/.ai/blueprints/add-migration/gates.yaml +30 -0
- package/agent-template/.ai/blueprints/add-migration/input.schema.json +23 -0
- package/agent-template/.ai/blueprints/add-migration/plan.schema.json +54 -0
- package/agent-template/.ai/blueprints/add-migration/required-files.yaml +18 -0
- package/agent-template/.ai/blueprints/add-migration/spec-requirements.yaml +13 -0
- package/agent-template/.ai/blueprints/add-migration/steps.yaml +62 -0
- package/agent-template/.ai/blueprints/author-spec/README.md +5 -0
- package/agent-template/.ai/blueprints/author-spec/allowed-paths.yaml +7 -0
- package/agent-template/.ai/blueprints/author-spec/blueprint.json +14 -0
- package/agent-template/.ai/blueprints/author-spec/examples/invalid/input-missing-outcome.json +5 -0
- package/agent-template/.ai/blueprints/author-spec/examples/valid/input.json +6 -0
- package/agent-template/.ai/blueprints/author-spec/gates.yaml +13 -0
- package/agent-template/.ai/blueprints/author-spec/input.schema.json +20 -0
- package/agent-template/.ai/blueprints/author-spec/plan.schema.json +14 -0
- package/agent-template/.ai/blueprints/author-spec/required-files.yaml +6 -0
- package/agent-template/.ai/blueprints/author-spec/spec-requirements.yaml +35 -0
- package/agent-template/.ai/blueprints/author-spec/steps.yaml +28 -0
- package/agent-template/.ai/blueprints/author-spec/templates/module.yaml +45 -0
- package/agent-template/.ai/blueprints/bug-fix/README.md +5 -0
- package/agent-template/.ai/blueprints/bug-fix/allowed-paths.yaml +29 -0
- package/agent-template/.ai/blueprints/bug-fix/blueprint.json +14 -0
- package/agent-template/.ai/blueprints/bug-fix/examples/invalid/input-no-symptom.json +4 -0
- package/agent-template/.ai/blueprints/bug-fix/examples/invalid/plan-no-test.json +8 -0
- package/agent-template/.ai/blueprints/bug-fix/examples/valid/input.json +6 -0
- package/agent-template/.ai/blueprints/bug-fix/examples/valid/plan.json +8 -0
- package/agent-template/.ai/blueprints/bug-fix/gates.yaml +30 -0
- package/agent-template/.ai/blueprints/bug-fix/input.schema.json +25 -0
- package/agent-template/.ai/blueprints/bug-fix/plan.schema.json +53 -0
- package/agent-template/.ai/blueprints/bug-fix/required-files.yaml +7 -0
- package/agent-template/.ai/blueprints/bug-fix/spec-requirements.yaml +7 -0
- package/agent-template/.ai/blueprints/bug-fix/steps.yaml +51 -0
- package/agent-template/.ai/blueprints/core-extend/README.md +5 -0
- package/agent-template/.ai/blueprints/core-extend/allowed-paths.yaml +49 -0
- package/agent-template/.ai/blueprints/core-extend/blueprint.json +14 -0
- package/agent-template/.ai/blueprints/core-extend/examples/invalid/input-unknown-package.json +5 -0
- package/agent-template/.ai/blueprints/core-extend/examples/invalid/plan-missing-gates.json +7 -0
- package/agent-template/.ai/blueprints/core-extend/examples/valid/input.json +6 -0
- package/agent-template/.ai/blueprints/core-extend/examples/valid/plan.json +10 -0
- package/agent-template/.ai/blueprints/core-extend/gates.yaml +16 -0
- package/agent-template/.ai/blueprints/core-extend/input.schema.json +54 -0
- package/agent-template/.ai/blueprints/core-extend/plan.schema.json +39 -0
- package/agent-template/.ai/blueprints/core-extend/required-files.yaml +36 -0
- package/agent-template/.ai/blueprints/core-extend/spec-requirements.yaml +17 -0
- package/agent-template/.ai/blueprints/core-extend/steps.yaml +54 -0
- package/agent-template/.ai/blueprints/edit-module/README.md +9 -0
- package/agent-template/.ai/blueprints/edit-module/allowed-paths.yaml +27 -0
- package/agent-template/.ai/blueprints/edit-module/blueprint.json +20 -0
- package/agent-template/.ai/blueprints/edit-module/examples/invalid/input-unknown-change.json +5 -0
- package/agent-template/.ai/blueprints/edit-module/examples/invalid/plan-touches-platform.json +15 -0
- package/agent-template/.ai/blueprints/edit-module/examples/valid/input.json +5 -0
- package/agent-template/.ai/blueprints/edit-module/examples/valid/plan.json +25 -0
- package/agent-template/.ai/blueprints/edit-module/gates.yaml +30 -0
- package/agent-template/.ai/blueprints/edit-module/input.schema.json +31 -0
- package/agent-template/.ai/blueprints/edit-module/plan.schema.json +65 -0
- package/agent-template/.ai/blueprints/edit-module/required-files.yaml +80 -0
- package/agent-template/.ai/blueprints/edit-module/spec-requirements.yaml +15 -0
- package/agent-template/.ai/blueprints/edit-module/steps.yaml +115 -0
- package/agent-template/.ai/blueprints/new-module/README.md +7 -0
- package/agent-template/.ai/blueprints/new-module/allowed-paths.yaml +27 -0
- package/agent-template/.ai/blueprints/new-module/blueprint.json +20 -0
- package/agent-template/.ai/blueprints/new-module/examples/invalid/input-spec-outside-modules.json +4 -0
- package/agent-template/.ai/blueprints/new-module/examples/invalid/plan-unknown-gate.json +8 -0
- package/agent-template/.ai/blueprints/new-module/examples/valid/input.json +5 -0
- package/agent-template/.ai/blueprints/new-module/examples/valid/plan.json +22 -0
- package/agent-template/.ai/blueprints/new-module/gates.yaml +30 -0
- package/agent-template/.ai/blueprints/new-module/input.schema.json +21 -0
- package/agent-template/.ai/blueprints/new-module/plan.schema.json +58 -0
- package/agent-template/.ai/blueprints/new-module/required-files.yaml +73 -0
- package/agent-template/.ai/blueprints/new-module/spec-requirements.yaml +30 -0
- package/agent-template/.ai/blueprints/new-module/steps.yaml +138 -0
- package/agent-template/.ai/blueprints/release/README.md +5 -0
- package/agent-template/.ai/blueprints/release/allowed-paths.yaml +19 -0
- package/agent-template/.ai/blueprints/release/blueprint.json +14 -0
- package/agent-template/.ai/blueprints/release/examples/invalid/input-bad-version.json +4 -0
- package/agent-template/.ai/blueprints/release/examples/invalid/plan-bad-branch.json +7 -0
- package/agent-template/.ai/blueprints/release/examples/valid/input.json +5 -0
- package/agent-template/.ai/blueprints/release/examples/valid/plan.json +20 -0
- package/agent-template/.ai/blueprints/release/gates.yaml +20 -0
- package/agent-template/.ai/blueprints/release/input.schema.json +24 -0
- package/agent-template/.ai/blueprints/release/plan.schema.json +46 -0
- package/agent-template/.ai/blueprints/release/required-files.yaml +19 -0
- package/agent-template/.ai/blueprints/release/spec-requirements.yaml +8 -0
- package/agent-template/.ai/blueprints/release/steps.yaml +47 -0
- package/agent-template/.ai/blueprints/security-review/README.md +5 -0
- package/agent-template/.ai/blueprints/security-review/allowed-paths.yaml +6 -0
- package/agent-template/.ai/blueprints/security-review/blueprint.json +14 -0
- package/agent-template/.ai/blueprints/security-review/examples/invalid/input-unknown-kind.json +4 -0
- package/agent-template/.ai/blueprints/security-review/examples/invalid/plan-finding-without-scenario.json +14 -0
- package/agent-template/.ai/blueprints/security-review/examples/valid/input.json +4 -0
- package/agent-template/.ai/blueprints/security-review/examples/valid/plan.json +19 -0
- package/agent-template/.ai/blueprints/security-review/gates.yaml +22 -0
- package/agent-template/.ai/blueprints/security-review/input.schema.json +20 -0
- package/agent-template/.ai/blueprints/security-review/plan.schema.json +65 -0
- package/agent-template/.ai/blueprints/security-review/required-files.yaml +6 -0
- package/agent-template/.ai/blueprints/security-review/spec-requirements.yaml +9 -0
- package/agent-template/.ai/blueprints/security-review/steps.yaml +38 -0
- package/agent-template/.ai/examples/README.md +8 -0
- package/agent-template/.ai/examples/bad/client-imports-server/README.md +20 -0
- package/agent-template/.ai/examples/bad/client-imports-server/api.ts +12 -0
- package/agent-template/.ai/examples/bad/missing-acl/README.md +23 -0
- package/agent-template/.ai/examples/bad/missing-acl/endpoints.ts +12 -0
- package/agent-template/.ai/examples/bad/tenant-from-body/README.md +19 -0
- package/agent-template/.ai/examples/bad/tenant-from-body/endpoints.ts +33 -0
- package/agent-template/.ai/examples/client-contribution/CustomerListView.tsrx +34 -0
- package/agent-template/.ai/examples/client-contribution/README.md +11 -0
- package/agent-template/.ai/examples/client-contribution/contribution.tsrx +48 -0
- package/agent-template/.ai/examples/client-contribution/index.ts +20 -0
- package/agent-template/.ai/examples/client-contribution/permissions.ts +8 -0
- package/agent-template/.ai/examples/customer-cli-extension/README.md +14 -0
- package/agent-template/.ai/examples/customer-cli-extension/commands.json +17 -0
- package/agent-template/.ai/examples/customer-cli-extension/index.ts +36 -0
- package/agent-template/.ai/examples/module-create/task-packet.json +11 -0
- package/agent-template/.ai/guides/application-development.md +97 -0
- package/agent-template/.ai/policies/capabilities.yaml +164 -0
- package/agent-template/.ai/policies/model-routing.yaml +72 -0
- package/agent-template/.ai/policies/path-ownership.yaml +65 -0
- package/agent-template/.ai/policies/task-budgets.yaml +37 -0
- package/agent-template/.ai/references/catalog/LICENSE +21 -0
- package/agent-template/.ai/references/catalog/migrations/0001_catalog_core.down.sql +2 -0
- package/agent-template/.ai/references/catalog/migrations/0001_catalog_core.up.sql +21 -0
- package/agent-template/.ai/references/catalog/migrations/0002_catalog_history.down.sql +3 -0
- package/agent-template/.ai/references/catalog/migrations/0002_catalog_history.up.sql +20 -0
- package/agent-template/.ai/references/catalog/migrations/0003_catalog_history_service_actors.down.sql +3 -0
- package/agent-template/.ai/references/catalog/migrations/0003_catalog_history_service_actors.up.sql +36 -0
- package/agent-template/.ai/references/catalog/migrations/0004_catalog_idempotency_ledger.down.sql +3 -0
- package/agent-template/.ai/references/catalog/migrations/0004_catalog_idempotency_ledger.up.sql +19 -0
- package/agent-template/.ai/references/catalog/migrations/README.md +3 -0
- package/agent-template/.ai/references/catalog/module.json +27 -0
- package/agent-template/.ai/references/catalog/package.json +49 -0
- package/agent-template/.ai/references/catalog/spec/module.yaml +86 -0
- package/agent-template/.ai/references/catalog/src/acl/permissions.ts +6 -0
- package/agent-template/.ai/references/catalog/src/agent/tools.ts +164 -0
- package/agent-template/.ai/references/catalog/src/api/endpoints.ts +243 -0
- package/agent-template/.ai/references/catalog/src/client/CatalogHistoryDrawer.tsrx +123 -0
- package/agent-template/.ai/references/catalog/src/client/CatalogItemForm.tsrx +190 -0
- package/agent-template/.ai/references/catalog/src/client/CatalogView.tsrx +473 -0
- package/agent-template/.ai/references/catalog/src/client/api.ts +111 -0
- package/agent-template/.ai/references/catalog/src/client/contribution.tsrx +61 -0
- package/agent-template/.ai/references/catalog/src/client/index.ts +18 -0
- package/agent-template/.ai/references/catalog/src/client/navigation-copy.ts +9 -0
- package/agent-template/.ai/references/catalog/src/client/state.ts +24 -0
- package/agent-template/.ai/references/catalog/src/domain/types.ts +32 -0
- package/agent-template/.ai/references/catalog/src/domain/variables.ts +111 -0
- package/agent-template/.ai/references/catalog/src/index.ts +31 -0
- package/agent-template/.ai/references/catalog/src/platform.ts +35 -0
- package/agent-template/.ai/references/catalog/src/server/index.ts +4 -0
- package/agent-template/.ai/references/catalog/src/server/runtime.ts +86 -0
- package/agent-template/.ai/references/catalog/src/services/catalog-service.ts +306 -0
- package/agent-template/.ai/references/catalog/src/services/database-repository.ts +440 -0
- package/agent-template/.ai/references/catalog/src/services/index.ts +4 -0
- package/agent-template/.ai/references/catalog/src/services/migration.ts +171 -0
- package/agent-template/.ai/references/catalog/src/services/repository.ts +36 -0
- package/agent-template/.ai/references/catalog/src/services/target-idempotency.ts +59 -0
- package/agent-template/.ai/references/catalog/tests/agent-tools.test.ts +277 -0
- package/agent-template/.ai/references/catalog/tests/endpoints.test.ts +320 -0
- package/agent-template/.ai/references/catalog/tests/idempotency.test.ts +297 -0
- package/agent-template/.ai/references/catalog/tests/migrations.test.ts +149 -0
- package/agent-template/.ai/references/catalog/tests/module.test.ts +271 -0
- package/agent-template/.ai/references/catalog/tests/support/database.ts +76 -0
- package/agent-template/.ai/references/catalog/translations/en.json +101 -0
- package/agent-template/.ai/references/catalog/translations/pl.json +101 -0
- package/agent-template/.ai/references/catalog/tsconfig.json +15 -0
- package/agent-template/.ai/references/catalog/vitest.config.ts +16 -0
- package/agent-template/.ai/references/catalog.provenance.json +55 -0
- package/agent-template/.ai/rules/flowdular.md +86 -0
- package/agent-template/.ai/skills/README.md +36 -0
- package/agent-template/.ai/skills/agent-tool-design/SKILL.md +209 -0
- package/agent-template/.ai/skills/auth-security-review/SKILL.md +96 -0
- package/agent-template/.ai/skills/auto-review/SKILL.md +112 -0
- package/agent-template/.ai/skills/bug-hunt/SKILL.md +110 -0
- package/agent-template/.ai/skills/business-agent-design/SKILL.md +188 -0
- package/agent-template/.ai/skills/cli-extension/SKILL.md +114 -0
- package/agent-template/.ai/skills/core-extend/SKILL.md +104 -0
- package/agent-template/.ai/skills/database-adapter/SKILL.md +204 -0
- package/agent-template/.ai/skills/database-adapter/references/first-run-and-matrix.md +105 -0
- package/agent-template/.ai/skills/migration-authoring/SKILL.md +167 -0
- package/agent-template/.ai/skills/module-new/SKILL.md +180 -0
- package/agent-template/.ai/skills/module-update/SKILL.md +100 -0
- package/agent-template/.ai/skills/perf-audit/SKILL.md +105 -0
- package/agent-template/.ai/skills/release-eject-pr/SKILL.md +113 -0
- package/agent-template/.ai/skills/spec-approval/SKILL.md +112 -0
- package/agent-template/.ai/skills/test-hardening/SKILL.md +86 -0
- package/agent-template/.ai/skills/translations-i18n/SKILL.md +85 -0
- package/agent-template/.ai/skills/ux-design/SKILL.md +97 -0
- package/agent-template/.ai/skills/variables/SKILL.md +164 -0
- package/agent-template/.ai/skills/workflow-development/SKILL.md +199 -0
- package/agent-template/.claude/skills/agent-tool-design/SKILL.md +203 -0
- package/agent-template/.claude/skills/auth-security-review/SKILL.md +90 -0
- package/agent-template/.claude/skills/auto-review/SKILL.md +103 -0
- package/agent-template/.claude/skills/bug-hunt/SKILL.md +104 -0
- package/agent-template/.claude/skills/business-agent-design/SKILL.md +182 -0
- package/agent-template/.claude/skills/cli-extension/SKILL.md +108 -0
- package/agent-template/.claude/skills/core-extend/SKILL.md +99 -0
- package/agent-template/.claude/skills/database-adapter/SKILL.md +198 -0
- package/agent-template/.claude/skills/database-adapter/references/first-run-and-matrix.md +105 -0
- package/agent-template/.claude/skills/migration-authoring/SKILL.md +161 -0
- package/agent-template/.claude/skills/module-new/SKILL.md +171 -0
- package/agent-template/.claude/skills/module-update/SKILL.md +91 -0
- package/agent-template/.claude/skills/perf-audit/SKILL.md +98 -0
- package/agent-template/.claude/skills/release-eject-pr/SKILL.md +107 -0
- package/agent-template/.claude/skills/spec-approval/SKILL.md +106 -0
- package/agent-template/.claude/skills/test-hardening/SKILL.md +79 -0
- package/agent-template/.claude/skills/translations-i18n/SKILL.md +78 -0
- package/agent-template/.claude/skills/ux-design/SKILL.md +92 -0
- package/agent-template/.claude/skills/variables/SKILL.md +156 -0
- package/agent-template/.claude/skills/workflow-development/SKILL.md +192 -0
- package/agent-template/AGENTS.md +77 -0
- package/agent-template/CLAUDE.md +77 -0
- package/agent-template/docs/adr/0001-development-reload.md +16 -0
- package/agent-template/docs/adr/0002-durable-agent-execution.md +21 -0
- package/agent-template/docs/adr/0003-module-settings.md +22 -0
- package/agent-template/docs/adr/0004-enterprise-access-and-audit.md +36 -0
- package/agent-template/docs/adr/0005-sandbox-runtime-and-coding-agents.md +81 -0
- package/agent-template/docs/adr/0006-agentic-workflows.md +1702 -0
- package/agent-template/docs/adr/0007-module-owned-agents.md +429 -0
- package/agent-template/docs/adr/0008-database-adapter-contract.md +90 -0
- package/agent-template/docs/agent-contract.md +45 -0
- package/agent-template/docs/configuration.md +122 -0
- package/agent-template/docs/database-adapters.md +346 -0
- package/agent-template/docs/design-system.md +217 -0
- package/agent-template/docs/modules.md +146 -0
- package/agent-template/platform/scripts/build.mjs +38 -0
- package/agent-template/rulesync.jsonc +11 -0
- package/dist/bin.js +3 -1
- package/package.json +3 -2
- package/template/default/.prettierignore +9 -0
- package/template/default/README.md +12 -0
- package/template/default/flowdular.json +3 -3
- package/template/default/modules/example/package.json +1 -1
- package/template/default/package.json +6 -2
- package/template/default/platform/octane.config.ts +17 -6
- package/template/default/platform/package.json +3 -2
- package/template/default/platform/scripts/dev.mjs +39 -6
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Flowdular design system
|
|
2
|
+
|
|
3
|
+
Identity 1.0 (2026-08-31). The implementation reference for humans and agents:
|
|
4
|
+
shared primitives, tokens, and the rules for using them.
|
|
5
|
+
|
|
6
|
+
## Where things live
|
|
7
|
+
|
|
8
|
+
- `packages/ui` (`@flowdular/sdk/ui`): the only source of visual primitives.
|
|
9
|
+
Design tokens (`src/styles/tokens.css`), base styles, `ui-*` component
|
|
10
|
+
classes, TSRX components, icons, and the brand mark. Fonts (IBM Plex Sans
|
|
11
|
+
Variable, IBM Plex Mono) are self-hosted through `@fontsource` packages.
|
|
12
|
+
- `packages/client`: the application shell (sidebar, topbar, command palette,
|
|
13
|
+
dashboard, contribution outlets). Shell-only layout lives in
|
|
14
|
+
`src/shell/shell.css`.
|
|
15
|
+
- Modules: compose screens from `@flowdular/sdk/ui`. Module CSS may only add
|
|
16
|
+
module-specific composites built on the tokens (example:
|
|
17
|
+
`modules/agents/src/client/agents.css`).
|
|
18
|
+
- `platform/public`: `favicon.svg`, `og.png` (1200x630 Open Graph image).
|
|
19
|
+
- Brand mark geometry is generated: `node packages/ui/scripts/gen-mark.mjs`
|
|
20
|
+
rewrites `packages/ui/src/brand/mark.ts` from the weave parameters.
|
|
21
|
+
|
|
22
|
+
## Rules
|
|
23
|
+
|
|
24
|
+
1. Primitives first. Use a `ui-*` class or an exported component before
|
|
25
|
+
writing any new visual code.
|
|
26
|
+
2. Colors, fonts, sizes, radii, and shadows come only from tokens
|
|
27
|
+
(`var(--...)`). No hex values in shell or module CSS.
|
|
28
|
+
3. Never restyle or override a `ui-*` class outside `packages/ui`.
|
|
29
|
+
4. A missing primitive is added per use case as a module-local component built
|
|
30
|
+
on the tokens, and flagged as a promotion candidate for `packages/ui`.
|
|
31
|
+
5. Blue means action and selection. Green, amber, and red mean state. Copper
|
|
32
|
+
is reserved for the brand (mark, splash, sign-in) and is never a button or
|
|
33
|
+
a state color.
|
|
34
|
+
6. Minimum text size is 12 px (`--text-sm`); labels use `--text-xs` uppercase.
|
|
35
|
+
Numbers in tables and KPIs are tabular (`.num`, `ui-kpi__value`).
|
|
36
|
+
7. Layout containment is owned by the primitives, not by the screen. Children
|
|
37
|
+
of `ui-view`, `ui-two-col`, `ui-grid-2`, and `ui-kpi-grid` are shrinkable
|
|
38
|
+
tracks, long words wrap, and the workspace never scrolls horizontally. Wide
|
|
39
|
+
content scrolls inside its own container (`ui-table-wrap`), so one long
|
|
40
|
+
value can never push the page sideways.
|
|
41
|
+
8. `Kpi` is a stat tile. Its value is a number or a short state word; addresses,
|
|
42
|
+
identifiers, and paths belong in `note` or a `ui-mono` line.
|
|
43
|
+
9. A screen never splits its width between records and a form. Records own the
|
|
44
|
+
page; creating and editing happens in a `Drawer`.
|
|
45
|
+
10. `Tag` carries state or a value with meaning (a status, a count, a scope).
|
|
46
|
+
Never decoration: no "Secure", "Master data", or "Suggested setup" badges.
|
|
47
|
+
A card head is a title, a one-line description in its `small`, and at most
|
|
48
|
+
one right-aligned cluster (`ui-card__actions`: a count, a state, buttons).
|
|
49
|
+
11. A row is title and description on the left and its controls on one line on
|
|
50
|
+
the right, vertically centered (`SettingRow`). The row title is the label;
|
|
51
|
+
the control inside carries `aria-label`, never a second visible label.
|
|
52
|
+
12. Large sets are summarized where they are read (`ScopeSummary`, grouped by
|
|
53
|
+
module) and edited in full only inside the drawer (`CheckGrid`).
|
|
54
|
+
13. Destructive actions close a drawer in their own `ui-form__section--danger`:
|
|
55
|
+
one title, one line of consequence, one `Button variant="danger"`. They are
|
|
56
|
+
never mixed into a status row.
|
|
57
|
+
14. Menus (workspace switcher, account menu, session actions) are `ui-menu`
|
|
58
|
+
with `ui-menu__item` rows: 40 px, 10 px inset, the same hover and selected
|
|
59
|
+
background, a 32 px avatar, two lines of text, and the trailing check
|
|
60
|
+
pushed to the right edge.
|
|
61
|
+
|
|
62
|
+
## Screen pattern
|
|
63
|
+
|
|
64
|
+
Every record screen is built the same way, so a user who learns one learns all
|
|
65
|
+
of them:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
PageHeader eyebrow, title, description, [Refresh] [+ New ...]
|
|
69
|
+
Alert only when the last action failed
|
|
70
|
+
TableCard
|
|
71
|
+
ui-card__head title, count, SearchField and Filters on one line
|
|
72
|
+
Table the records, full width
|
|
73
|
+
ui-note the constraint worth stating (permissions, boundaries)
|
|
74
|
+
Drawer the create or edit form, opened from the header or a row
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`TableCard` is the default for a record screen. It owns the card, the one-line
|
|
78
|
+
head (title, `count`, and the `search` and `filters` slots inside
|
|
79
|
+
`ui-card__filters`), the `Table`, and the optional `ui-note` footer, so every
|
|
80
|
+
screen shows the same head, loading row, empty state, and filtered-empty
|
|
81
|
+
message. A screen passes data and slots, never table markup. Row actions are
|
|
82
|
+
compact, visible buttons in a narrow trailing column with an accessible but
|
|
83
|
+
visually empty header. The column is part of the same `colgroup` in loading,
|
|
84
|
+
empty and populated states, so widths do not drift. `Table` on its own covers
|
|
85
|
+
what needs a bare table, such as the list side of a master-detail screen.
|
|
86
|
+
|
|
87
|
+
`Table` is backed by the official `@octanejs/tanstack-table` adapter. Modules
|
|
88
|
+
still use the smaller Flowdular `Table` and `TableCard` contract from
|
|
89
|
+
`@flowdular/sdk/ui`; they never import TanStack directly. The shared primitive owns
|
|
90
|
+
the TanStack features, row model, header model and cell rendering so every
|
|
91
|
+
screen keeps the same states, widths and actions.
|
|
92
|
+
|
|
93
|
+
Every column declares a semantic CSS `width`. Give the primary record and its
|
|
94
|
+
description the largest share, medium shares to dates and identifiers, and the
|
|
95
|
+
smallest share to counts and lifecycle state. In a table with row actions, data
|
|
96
|
+
columns normally add up to about 90 percent; the shared 160 px action column
|
|
97
|
+
uses the rest. In a read-only table, data columns add up to 100 percent. The
|
|
98
|
+
table keeps these widths in loading, empty and populated states and scrolls
|
|
99
|
+
horizontally below its minimum readable width.
|
|
100
|
+
|
|
101
|
+
The drawer holds one `ui-drawer__form`: fields scroll inside
|
|
102
|
+
`ui-drawer__body`, and the primary action stays pinned in `ui-drawer__foot`.
|
|
103
|
+
Escape and the scrim close it. Master-detail screens that only read (agent runs,
|
|
104
|
+
the playground) keep `ui-two-col`; the list side is a `ui-table` whose open
|
|
105
|
+
record carries `is-selected`.
|
|
106
|
+
|
|
107
|
+
A drawer that edits several independent things (a member, a module) stacks
|
|
108
|
+
`ui-form__section` blocks inside its `ui-form`: an uppercase title and one-line
|
|
109
|
+
description in `ui-form__section-head`, then the fields and a right-aligned
|
|
110
|
+
`ui-form__actions` row with one primary per section. An input paired with one
|
|
111
|
+
action (a temporary password and its Reset) sits in a `ui-control-row`. The
|
|
112
|
+
danger section comes last, and the foot then keeps only Close.
|
|
113
|
+
|
|
114
|
+
Administration > Settings holds only workspace settings: full-width cards
|
|
115
|
+
(Workspace, Preferences), each `SettingRow` one setting. A module's declared
|
|
116
|
+
settings are edited in its Drawer under Administration > Modules, as
|
|
117
|
+
`SettingRow`s inside the drawer's Settings `ui-form__section`; a module
|
|
118
|
+
without settings shows a one-line empty state there.
|
|
119
|
+
|
|
120
|
+
## Components
|
|
121
|
+
|
|
122
|
+
| Component | Use |
|
|
123
|
+
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
124
|
+
| `Button` | Actions: `variant` primary, secondary (default), ghost, danger; `size` sm, md, lg; `block` |
|
|
125
|
+
| `FormField` | Label + control + help or error. Put `ui-input`, `ui-select`, or `ui-textarea` inside |
|
|
126
|
+
| `VariableTextarea` | Multiline template field: `value`, `onInput`, `variables` (scope-filtered `VariableDefinition[]`), `sampleValues`, `label`, `name`; a `braces` menu inserts `{{ key }}` and tokens highlight as pills (error pill when unknown). Presentational, never fetches |
|
|
127
|
+
| `VariableInput` | Single-line variant of `VariableTextarea` with the same props |
|
|
128
|
+
| `VariableSelect` | Native select that stores either a literal option value or one allowed `{{ key }}` token. Takes scope-filtered `variables`, `sampleValues`, literal `options`, `value`, `onInput`, `name`, `label`, and native required/disabled state. It preserves keyboard, validation, accessibility, and `FormData` semantics and never fetches or resolves data |
|
|
129
|
+
| `Tag` | Status and metadata: `tone` neutral, success, warning, danger, info, ink; `dot` adds a state dot; `mono` |
|
|
130
|
+
| `Kpi` | Stat tile: `label`, `value`, `unit`, `badge`, `note`, `href`, `linkLabel` |
|
|
131
|
+
| `Chart` | Token-driven Chart.js wrapper on a client-only canvas: `type` area, bar, line; `data`, `series` (`key`, `label`, `token`), `xKey`, `height`, `title`, `xTickFormatter`; series colors come from `--chart-1..5`; shows an EmptyState for empty or all-zero data |
|
|
132
|
+
| `Table` | The one data table, backed by `@octanejs/tanstack-table`: `columns` (`key`, `header`, required `width`, `numeric`, `cell`), `rows`, `rowKey`, `status` idle/loading, `loadingLabel`, `empty` and `emptyFiltered` picked by `filtered`, `actions(row): TableAction[]`, `actionsLabel`, optional stable `actionsWidth` (160 px by default, 280 px for two actions), `onSelect` with `selectedKey`, `caption`; fixed layout and `colgroup` keep columns stable across states |
|
|
133
|
+
| `TableCard` | The record card around `Table`: `title`, `count`, the `head`, `search`, and `filters` head slots, `before` and `after` around the table, `note` with `noteIcon` as the footer |
|
|
134
|
+
| `PageHeader` | Every view starts with it: `eyebrow`, `title`, `description`; children render as right-side actions |
|
|
135
|
+
| `EmptyState` | `icon`, `title`, children, optional `code` |
|
|
136
|
+
| `Alert` | Inline message: `tone` danger (default), warning, info |
|
|
137
|
+
| `Drawer` | Editor panel over the records: `open`, `title`, `subtitle`, `width` md/lg, `onClose` |
|
|
138
|
+
| `SearchField` | Filter control for a panel head: `value`, `placeholder`, `label`, `onInput` |
|
|
139
|
+
| `CheckGrid` | Grouped multi-select for scopes, tools, and long option sets: `groups` (`label`, `options` of `value`, `label`, `hint`), `value`, `mono`, `disabled`, `onChange` |
|
|
140
|
+
| `ScopeSummary` | Read-only summary of `module.entity.action` scopes: one row per module, one chip per entity with its actions: `scopes`, `labels` (module id to display name) |
|
|
141
|
+
| `SettingRow` | One setting: `label`, `description` (node, one line), `scopeLabel` (small neutral tag), `status` (`ok`, `message` of the last save), children as the control cluster |
|
|
142
|
+
| `Avatar` | Initials from `name`: `square` for organizations, round for people; `large` in profile and account headers |
|
|
143
|
+
| `Switch` | Boolean setting that applies on its own (no form submit): `checked`, `label` as the accessible name, `disabled`, `onChange` |
|
|
144
|
+
| `ConfirmDialog` | One question before an irreversible action: `open`, `title`, children, `confirmLabel`, `tone` danger (default) or primary, `busy`, `onConfirm`, `onCancel` |
|
|
145
|
+
| `Icon` | Stroke icon by `name` from `ICON_PATHS`; `size` 18 default, 16 in controls, 14 in `Button size="sm"`; `strokeWidth` 1.75 default |
|
|
146
|
+
| `BrandMark` | The weave: `size`, `signature` (copper weft, large brand moments only), `tone` brand, current, inverse |
|
|
147
|
+
|
|
148
|
+
`Drawer` takes one child, a `ui-drawer__form` (fields in `ui-drawer__body`, actions in `ui-drawer__foot`) or a plain `ui-drawer__body`; it closes on Escape and on the scrim. `SearchField` carries no visible label, so pass `label` as its accessible name. `FormField` renders `error` in place of `help` and marks it `role="alert"`. `SettingRow` is presentation only: the caller owns the draft value, the save call, and passes the result back as `status`. `ScopeSummary` is the read side of `CheckGrid`; both keep the first-seen module order, and `summarizeScopes` is exported for callers that need the grouping without the markup.
|
|
149
|
+
|
|
150
|
+
Icon names (`packages/ui/src/icons/Icon.tsrx`): `dashboard`, `parties`, `catalog`,
|
|
151
|
+
`user`, `users`, `shield`, `code`, `modules`, `file-text`, `play`, `bot`,
|
|
152
|
+
`flask`, `activity`, `plug`, `search`, `chevron-down`, `chevrons-up-down`,
|
|
153
|
+
`plus`, `panel-left`, `check`, `filter`, `download`, `more`, `external`,
|
|
154
|
+
`alert`, `x`, `sign-out`, `refresh`, `help`, `key`, `settings`, `braces`. An unknown name renders
|
|
155
|
+
`modules` without a warning; a new icon is one 24x24 stroke path added there.
|
|
156
|
+
|
|
157
|
+
## Classes
|
|
158
|
+
|
|
159
|
+
- Layout: `ui-view`, `ui-two-col` (+`--wide-aside`), `ui-grid-2`,
|
|
160
|
+
`ui-kpi-grid`, `ui-tag-cloud`, `ui-section-head` (an `h2` with actions
|
|
161
|
+
inside a view)
|
|
162
|
+
- Surfaces: `ui-card` (+`__head`, `__title` with a `small` description,
|
|
163
|
+
`__actions` for the right-aligned cluster, `__body`), `ui-toolbar`
|
|
164
|
+
(+`__spacer` to push actions right; a bare `ui-input` or `ui-select` inside
|
|
165
|
+
it takes the button height and an `aria-label`)
|
|
166
|
+
- Data: `ui-table` (+`ui-table-wrap`, `ui-table__empty`, `ui-table__actions`
|
|
167
|
+
for the component-owned trailing button column, `ui-table__state` for a dot plus label,
|
|
168
|
+
`ui-table__placeholder` for the loading and empty rows inside the table,
|
|
169
|
+
`.num`, row states `is-clickable` and `is-selected`), `ui-cell`
|
|
170
|
+
(+`ui-cell__muted`), `ui-mono`, `ui-code`
|
|
171
|
+
- Forms: `ui-form` (+`__row`, `__row--4`, `__foot`, `__actions`, `__section`
|
|
172
|
+
with `__section-head` (`b` title, `small` description) and
|
|
173
|
+
`__section--danger`), `ui-control-row` (a growing control beside one fixed
|
|
174
|
+
button), `ui-choices` (a short wrapping row of `ui-checkbox`), `ui-input`
|
|
175
|
+
(+`--error`), `ui-select`, `ui-textarea` (+`--error`), `ui-checkbox`,
|
|
176
|
+
`ui-label`, `ui-help` (+`--error`)
|
|
177
|
+
- Drawer: `ui-drawer__form` (scrolling body plus pinned footer),
|
|
178
|
+
`ui-drawer__body`, `ui-drawer__foot`
|
|
179
|
+
- Settings rows inside a `ui-card` or a drawer `ui-form__section`, rendered
|
|
180
|
+
by `SettingRow`: `ui-setting`
|
|
181
|
+
(+`__text` for title, scope tag, and help, `__control` for the one-line
|
|
182
|
+
control cluster, `__status` (+`--error`) for the inline result)
|
|
183
|
+
- Buttons: `ui-btn` with `--primary`, `--secondary`, `--ghost`, `--danger`,
|
|
184
|
+
`--sm`, `--lg`, `--block`, and `--icon` for an icon-only square button
|
|
185
|
+
(the `Button` component renders all but `--icon`)
|
|
186
|
+
- Bits: `ui-kbd`, `ui-dot` (+`--muted`), `ui-note`, `ui-menu` (+`__label`,
|
|
187
|
+
`__section` for a static identity or connection block, `__item`,
|
|
188
|
+
`__item--active`, `__item--danger`, `__sep`), `ui-icon`
|
|
189
|
+
|
|
190
|
+
Rendered by components, not written by hand: `ui-page-head*`, `ui-search`,
|
|
191
|
+
`ui-field`, `ui-switch` (+`--on`), `ui-dialog` (+`__panel`, `__title`,
|
|
192
|
+
`__body`, `__actions`), `ui-empty` (+`__icon`), `ui-alert` (+`--danger`, `--warning`,
|
|
193
|
+
`--info`), `ui-tag` (+tone and `--mono`), `ui-kpi` (+`__label`, `__value`,
|
|
194
|
+
`__note`, `__link`), `ui-avatar` (+`--sq`, `--lg`), `ui-checks` (+`__group`,
|
|
195
|
+
`__head`, `__count`, `__all`, `__items`, `__option`), `ui-scopes` (+`__row`,
|
|
196
|
+
`__chip`), `ui-drawer-slot`, `ui-drawer` (+`__panel`, `__panel--lg`, `__head`,
|
|
197
|
+
`__close`), `ui-varfield` (+`__control`, `__highlight`, `__input`, `__pill`
|
|
198
|
+
(+`--error`), `__trigger`, `__menu`, `__value`, `__empty`; the overlay layer
|
|
199
|
+
that highlights `{{ key }}` tokens, rendered by `VariableTextarea` and
|
|
200
|
+
`VariableInput`).
|
|
201
|
+
|
|
202
|
+
## Token cheat sheet
|
|
203
|
+
|
|
204
|
+
- Surfaces: `--bg`, `--surface`, `--surface-2`; lines: `--line`, `--line-2`
|
|
205
|
+
- Text: `--ink`, `--ink-2` (labels), `--ink-3` (descriptions), `--ink-4`
|
|
206
|
+
(placeholders only, below AA for text)
|
|
207
|
+
- Action: `--primary`, `--primary-hover`, `--primary-soft`, `--primary-tint`,
|
|
208
|
+
`--focus`
|
|
209
|
+
- State: `--success`, `--warning`, `--danger` with `-bg` and `-line` pairs
|
|
210
|
+
- Brand: `--brand`, `--brand-weft` (copper)
|
|
211
|
+
- Type: `--font-sans`, `--font-mono`, `--text-xs` 11 to `--text-display` 36
|
|
212
|
+
- Dimensions: `--sidebar-w` 260, `--rail-w` 60, `--topbar-h` 52, `--control-h`
|
|
213
|
+
36, `--button-h` 32, `--row-h` 44, radii `--r-sm` 4, `--r` 6, `--r-md` 8,
|
|
214
|
+
`--r-lg` 12
|
|
215
|
+
|
|
216
|
+
Components reference the semantic layer only, so a dark theme is one token
|
|
217
|
+
override block, not a rewrite.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Modules
|
|
2
|
+
|
|
3
|
+
A module is a self-contained slice of the product: its own permissions,
|
|
4
|
+
endpoints, migrations, services, screens, translations and tests, wired into the
|
|
5
|
+
platform without touching a core file. `.ai/references/catalog` is the pinned reference
|
|
6
|
+
implementation; copy its shape.
|
|
7
|
+
|
|
8
|
+
## Lifecycle
|
|
9
|
+
|
|
10
|
+
```text
|
|
11
|
+
approved spec -> module new -> implement -> gates -> module enable -> verify
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### 1. Specification
|
|
15
|
+
|
|
16
|
+
A module is created only from a `spec/module.yaml` with `status: approved`. The
|
|
17
|
+
spec is the contract: `permissions[].id` equal the constants in
|
|
18
|
+
`src/acl/permissions.ts`, and those permissions are exactly what
|
|
19
|
+
`auth sync-scopes` grants. An agent never approves a spec on its own judgment.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm flowdular spec validate --all
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 2. Scaffold
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm flowdular module new sales.orders \
|
|
29
|
+
--spec modules/sales-orders/spec/module.yaml # dry run
|
|
30
|
+
pnpm flowdular module new sales.orders \
|
|
31
|
+
--spec modules/sales-orders/spec/module.yaml --apply
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The scaffold derives everything from the spec: `platform.server` and
|
|
35
|
+
`platform.client` flags from the capabilities, `src/platform.ts` and
|
|
36
|
+
`src/client/index.ts` with the canonical `createServerComposition` and
|
|
37
|
+
`createClientContribution` entries, one `defineEndpoint` per
|
|
38
|
+
`<ns>.<entity>.read` (list) and `.manage` (create) permission of the first
|
|
39
|
+
entity, and, with the `database` capability, an asynchronous repository on the
|
|
40
|
+
`@flowdular/sdk/database` provider, a runtime that acquires and releases its lease,
|
|
41
|
+
and `migrations/0001_*.up.sql` and `.down.sql` with the tenant table and its
|
|
42
|
+
forced row-level security block. The contract is in
|
|
43
|
+
[Database adapters](database-adapters.md) and the `database-adapter` skill.
|
|
44
|
+
|
|
45
|
+
Files are written through the workspace Prettier, so the format gate passes
|
|
46
|
+
without a rewrite. A directory that already holds `spec/module.yaml` or
|
|
47
|
+
`translations/**` is extended, not rejected, and a failed run leaves nothing
|
|
48
|
+
behind.
|
|
49
|
+
|
|
50
|
+
### 3. Implement
|
|
51
|
+
|
|
52
|
+
Rules that bite first (the full contract is in [../AGENTS.md](../AGENTS.md)):
|
|
53
|
+
|
|
54
|
+
- Tenant id comes only from `principalFromContext(octane)!.tenantId`; every
|
|
55
|
+
query on a tenant-owned table filters by `tenant_id`.
|
|
56
|
+
- Every endpoint is `defineEndpoint` with an explicit permission; every mutation
|
|
57
|
+
starts with `sessionMutationDenial(octane, auth)`.
|
|
58
|
+
- Numbered `migrations/000N_*.up.sql` files are the schema source and are
|
|
59
|
+
immutable once applied; add a new additive migration instead of editing one.
|
|
60
|
+
- Repositories acquire their database through `context.databases`, keep service
|
|
61
|
+
and endpoint callers asynchronous, run every operation inside
|
|
62
|
+
`database.transaction(..., { tenantId, access })`, and ship explicit
|
|
63
|
+
PostgreSQL SQL plus migration adoption checks.
|
|
64
|
+
- UI is built only from `@flowdular/sdk/ui` components, `ui-*` classes and tokens
|
|
65
|
+
([design-system.md](design-system.md)).
|
|
66
|
+
- Cross-module operations go through a typed public service registered in
|
|
67
|
+
`context.capabilities`, never another module's database.
|
|
68
|
+
- Every imported package is declared in the module `package.json`; relative
|
|
69
|
+
imports carry `.ts` or `.tsrx`.
|
|
70
|
+
|
|
71
|
+
### 4. Validate
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pnpm flowdular module validate
|
|
75
|
+
pnpm --filter @flowdular/module-<dir> typecheck
|
|
76
|
+
pnpm --filter @flowdular/module-<dir> test
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`module validate` checks more than the schema: `platform.server` requires
|
|
80
|
+
`src/platform.ts` and a `./platform` export, `platform.client` requires
|
|
81
|
+
`src/client/index.ts` and a `./client` export, and every declared locale needs a
|
|
82
|
+
`translations/<locale>.json` with the same key set as the others (an error).
|
|
83
|
+
`module.json` version drift against `specVersion`, or a locale missing from
|
|
84
|
+
`flowdular.json`, is reported as a warning.
|
|
85
|
+
|
|
86
|
+
### 5. Enable
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pnpm flowdular module enable sales.orders --apply
|
|
90
|
+
pnpm flowdular module disable sales.orders --apply
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`enable` resolves the module's complete dependency closure, writes every newly
|
|
94
|
+
enabled module to `flowdular.json` in deterministic dependency-first order, adds
|
|
95
|
+
the required packages to `platform/package.json`, runs `pnpm install` when a
|
|
96
|
+
package is not linked yet, and regenerates
|
|
97
|
+
`platform/src/generated/modules.{server,client}.ts`. With `--apply` it also
|
|
98
|
+
grants the scopes declared by each newly enabled module to every workspace owner
|
|
99
|
+
through `auth sync-scopes`; a failed grant is reported as
|
|
100
|
+
`MODULE_SCOPES_SYNC_FAILED`, and when `auth.core` is unavailable the grant is
|
|
101
|
+
skipped with a warning.
|
|
102
|
+
|
|
103
|
+
`disable` refuses while another enabled module depends on the target, then
|
|
104
|
+
removes it and regenerates. `system.core` and `auth.core` are protected.
|
|
105
|
+
|
|
106
|
+
A running `pnpm dev` picks the change up live: the octane plugin reloads server
|
|
107
|
+
routes when the generated composition changes and the client hot-reloads, so no
|
|
108
|
+
rebuild is needed. `pnpm dev` and `pnpm build` run the sync automatically.
|
|
109
|
+
|
|
110
|
+
## Files the CLI owns
|
|
111
|
+
|
|
112
|
+
Never edit these by hand:
|
|
113
|
+
|
|
114
|
+
- `flowdular.json` `modules.enabled`
|
|
115
|
+
- `platform/package.json` dependencies
|
|
116
|
+
- `platform/src/generated/**`
|
|
117
|
+
- `platform/octane.config.ts` and `platform/src/App.tsrx`
|
|
118
|
+
|
|
119
|
+
## Module settings
|
|
120
|
+
|
|
121
|
+
Modules can also contribute standalone public or protected web pages outside the
|
|
122
|
+
workspace shell. See [Module web surfaces](module-web-surfaces.md) for page
|
|
123
|
+
entries, layouts, tenant-bound path mounts, loaders and access rules.
|
|
124
|
+
|
|
125
|
+
Settings are declared with `defineModuleSettings` from `@flowdular/sdk/kernel`,
|
|
126
|
+
returned as `settings` from the composition, read live with
|
|
127
|
+
`context.settings.get(tenantId, '<module>.core', key)`, and rendered in that
|
|
128
|
+
module's drawer under Administration, Modules. Administration, Settings holds
|
|
129
|
+
only workspace and organization settings.
|
|
130
|
+
|
|
131
|
+
## Adding a CLI command
|
|
132
|
+
|
|
133
|
+
Module commands live in `src/cli/commands.json` and `src/cli/index.ts`,
|
|
134
|
+
metadata-identical, inside the module namespace. See
|
|
135
|
+
[cli-extensions.md](cli-extensions.md).
|
|
136
|
+
|
|
137
|
+
## Guided procedures
|
|
138
|
+
|
|
139
|
+
Each change class has a canonical skill in [`.ai/skills`](../.ai/skills).
|
|
140
|
+
RuleSync generates the discovery copies for supported coding agents:
|
|
141
|
+
`module-new`, `module-update`, `migration-authoring`, `ux-design`,
|
|
142
|
+
`database-adapter`, `translations-i18n`, `auth-security-review`,
|
|
143
|
+
`test-hardening`, `cli-extension`, `agent-tool-design`,
|
|
144
|
+
`business-agent-design`, `workflow-development`, `release-eject-pr`.
|
|
145
|
+
|
|
146
|
+
Official business modules are maintained outside core. See [module distribution](module-distribution.md) for install, update, lock verification and release checks.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import { mkdtempSync, rmSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
|
|
7
|
+
const stateDirectory = mkdtempSync(join(tmpdir(), 'flowdular-build-'));
|
|
8
|
+
const buildSecret = () => randomBytes(32).toString('base64');
|
|
9
|
+
|
|
10
|
+
/* The Octane plugin evaluates the server composition while bundling it. Give
|
|
11
|
+
that build-time process isolated state and ephemeral keys, without using deployment database settings or encryption keys. The emitted server still reads its real
|
|
12
|
+
production environment when it starts. */
|
|
13
|
+
const environment = {
|
|
14
|
+
...process.env,
|
|
15
|
+
/* A production bundle is evaluated while it is built, but the build must not
|
|
16
|
+
connect to the deployment database. The embedded engine writes into the
|
|
17
|
+
throwaway state directory below; runtime still reads its real adapter. */
|
|
18
|
+
FD_ENV: 'development',
|
|
19
|
+
FD_INTERNAL_BUILD: 'true',
|
|
20
|
+
FD_DATABASE_ADAPTER: 'pglite',
|
|
21
|
+
FD_DATABASE_PGLITE_DIRECTORY: join(stateDirectory, 'pglite'),
|
|
22
|
+
FD_AGENT_CREDENTIAL_KEY: buildSecret(),
|
|
23
|
+
FD_AGENT_RUN_GRANT_KEY: buildSecret(),
|
|
24
|
+
FD_AUTOMATIONS_CREDENTIAL_KEY: buildSecret(),
|
|
25
|
+
FD_WORKFLOWS_PAYLOAD_KEY: buildSecret(),
|
|
26
|
+
FD_WORKFLOWS_CURSOR_KEY: buildSecret(),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const result = spawnSync('vite', ['build'], {
|
|
31
|
+
env: environment,
|
|
32
|
+
stdio: 'inherit',
|
|
33
|
+
});
|
|
34
|
+
if (result.error) throw result.error;
|
|
35
|
+
process.exitCode = result.status ?? 1;
|
|
36
|
+
} finally {
|
|
37
|
+
rmSync(stateDirectory, { recursive: true, force: true });
|
|
38
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://github.com/dyoshikawa/rulesync/releases/latest/download/config-schema.json",
|
|
3
|
+
"inputRoots": [".ai"],
|
|
4
|
+
"outputRoots": ["."],
|
|
5
|
+
"targets": ["codexcli", "claudecode"],
|
|
6
|
+
"features": ["rules", "skills"],
|
|
7
|
+
"delete": true,
|
|
8
|
+
"verbose": false,
|
|
9
|
+
"silent": false,
|
|
10
|
+
"global": false,
|
|
11
|
+
}
|
package/dist/bin.js
CHANGED
|
@@ -438,7 +438,9 @@ async function scaffold(request) {
|
|
|
438
438
|
`${directory} is not empty. Pass --force to scaffold into it anyway.`
|
|
439
439
|
);
|
|
440
440
|
}
|
|
441
|
-
const
|
|
441
|
+
const agentTemplate = resolve2(templatesRoot(), "..", "agent-template");
|
|
442
|
+
await assertTemplateExists(agentTemplate, "agent guidance");
|
|
443
|
+
const files = await copyTemplate(template, directory) + await copyTemplate(agentTemplate, directory);
|
|
442
444
|
await rewritePackageName(directory, name);
|
|
443
445
|
await writeFile(
|
|
444
446
|
join2(directory, ".env"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-flowdular",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Scaffold a Flowdular application: the platform, one example module and the secrets a fresh install needs.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
"dist",
|
|
26
26
|
"template",
|
|
27
27
|
"README.md",
|
|
28
|
-
"assets"
|
|
28
|
+
"assets",
|
|
29
|
+
"agent-template"
|
|
29
30
|
],
|
|
30
31
|
"engines": {
|
|
31
32
|
"node": ">=22.22.2"
|
|
@@ -27,6 +27,18 @@ install. Data lives under `.flowdular/data`.
|
|
|
27
27
|
| `flowdular.json` | Enabled modules and locales, owned by the CLI |
|
|
28
28
|
| `.env` | The keys generated for this app. Never commit it |
|
|
29
29
|
|
|
30
|
+
## Work with coding agents
|
|
31
|
+
|
|
32
|
+
`AGENTS.md` and `CLAUDE.md` introduce the application contract. `.ai` contains the
|
|
33
|
+
editable rules, skills, role prompts, policies, blueprints and reference module.
|
|
34
|
+
Codex and Claude Code discover generated skills in `.agents/skills` and
|
|
35
|
+
`.claude/skills`. Supporting guides are in `docs`.
|
|
36
|
+
|
|
37
|
+
After editing `.ai/rules` or `.ai/skills`, run `pnpm rules:generate`.
|
|
38
|
+
`pnpm rules:check` detects drift and also runs as part of `pnpm verify`.
|
|
39
|
+
Extend local modules using the published `@flowdular/sdk` imports. Installed
|
|
40
|
+
SDK source is reference material and must not be edited in `node_modules`.
|
|
41
|
+
|
|
30
42
|
## Build your first module
|
|
31
43
|
|
|
32
44
|
```bash
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
},
|
|
24
24
|
"locales": ["en", "pl"],
|
|
25
25
|
"agent": {
|
|
26
|
-
"policy": "
|
|
27
|
-
"modelRouting": "
|
|
28
|
-
"blueprints": "
|
|
26
|
+
"policy": ".ai/policies/capabilities.yaml",
|
|
27
|
+
"modelRouting": ".ai/policies/model-routing.yaml",
|
|
28
|
+
"blueprints": ".ai/blueprints"
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -16,11 +16,15 @@
|
|
|
16
16
|
"flowdular": "flowdular",
|
|
17
17
|
"cl": "flowdular",
|
|
18
18
|
"doctor": "flowdular doctor",
|
|
19
|
-
"verify": "pnpm typecheck && pnpm test && flowdular module validate && pnpm format:check"
|
|
19
|
+
"verify": "pnpm rules:check && pnpm typecheck && pnpm test && flowdular module validate && pnpm format:check",
|
|
20
|
+
"rules:generate": "rulesync generate",
|
|
21
|
+
"rules:check": "rulesync generate --check",
|
|
22
|
+
"build": "flowdular module sync --apply && pnpm --filter @app/platform build"
|
|
20
23
|
},
|
|
21
24
|
"devDependencies": {
|
|
22
25
|
"@tsrx/prettier-plugin": "0.3.120",
|
|
23
26
|
"prettier": "3.6.2",
|
|
24
|
-
"flowdular": "0.2.
|
|
27
|
+
"flowdular": "0.2.3",
|
|
28
|
+
"rulesync": "16.21.0"
|
|
25
29
|
}
|
|
26
30
|
}
|
|
@@ -34,9 +34,13 @@ function checkedRoutes<T extends Parameters<typeof assertRouteConflicts>[0]>(
|
|
|
34
34
|
|
|
35
35
|
const SHELL = ['App', '/src/App.tsrx'] as const;
|
|
36
36
|
const workspaceRoot = resolve(import.meta.dirname, '..');
|
|
37
|
+
const building = process.env.FD_INTERNAL_BUILD === 'true';
|
|
37
38
|
|
|
38
39
|
const databases = createPlatformDatabaseProvider(
|
|
39
|
-
databaseProviderConfigFromEnvironment(
|
|
40
|
+
databaseProviderConfigFromEnvironment(
|
|
41
|
+
building ? { ...process.env, NODE_ENV: 'development' } : process.env,
|
|
42
|
+
workspaceRoot,
|
|
43
|
+
),
|
|
40
44
|
);
|
|
41
45
|
const configuredApplicationPath = validateApplicationPath(
|
|
42
46
|
process.env.FD_APPLICATION_PATH ?? applicationBasePath,
|
|
@@ -68,9 +72,11 @@ agentDefinitions.seal();
|
|
|
68
72
|
|
|
69
73
|
/* check() proves the runtime role holds neither SUPERUSER nor BYPASSRLS before
|
|
70
74
|
any module reads a row. */
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
for (const composition of moduleCompositions) composition.
|
|
75
|
+
if (!building) {
|
|
76
|
+
await databases.check();
|
|
77
|
+
for (const composition of moduleCompositions) await composition.prepare?.();
|
|
78
|
+
for (const composition of moduleCompositions) composition.start?.();
|
|
79
|
+
}
|
|
74
80
|
|
|
75
81
|
let stopping = false;
|
|
76
82
|
const shutdown = async () => {
|
|
@@ -83,8 +89,13 @@ const shutdown = async () => {
|
|
|
83
89
|
await authRuntime.dispose();
|
|
84
90
|
await databases.dispose();
|
|
85
91
|
};
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
// Bundling needs route declarations without background work or retained leases.
|
|
93
|
+
if (building) {
|
|
94
|
+
await shutdown();
|
|
95
|
+
} else {
|
|
96
|
+
process.once('SIGINT', () => void shutdown());
|
|
97
|
+
process.once('SIGTERM', () => void shutdown());
|
|
98
|
+
}
|
|
88
99
|
|
|
89
100
|
export default defineConfig({
|
|
90
101
|
middlewares: [authRuntime.middleware],
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
"scripts": {
|
|
7
7
|
"dev": "node scripts/dev.mjs",
|
|
8
8
|
"preview": "octane-preview --host 127.0.0.1 --port 4310 --strictPort",
|
|
9
|
-
"typecheck": "tsrx-tsc --noEmit -p tsconfig.json"
|
|
9
|
+
"typecheck": "tsrx-tsc --noEmit -p tsconfig.json",
|
|
10
|
+
"build": "node scripts/build.mjs"
|
|
10
11
|
},
|
|
11
12
|
"dependencies": {
|
|
12
13
|
"@app/module-example": "workspace:*",
|
|
@@ -14,7 +15,7 @@
|
|
|
14
15
|
"@octanejs/vite-plugin": "0.1.51",
|
|
15
16
|
"octane": "0.1.51",
|
|
16
17
|
"pg": "8.23.0",
|
|
17
|
-
"@flowdular/sdk": "0.2.
|
|
18
|
+
"@flowdular/sdk": "0.2.3"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
20
21
|
"@octanejs/app-core": "0.0.47",
|