@flowdular/sdk 0.2.4 → 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.
- package/.ai/agents/sandbox/business-manager.md +5 -1
- package/.ai/blueprints/author-spec/README.md +1 -1
- package/.ai/blueprints/author-spec/spec-requirements.yaml +44 -0
- package/.ai/blueprints/author-spec/steps.yaml +5 -5
- package/.ai/blueprints/author-spec/templates/module.yaml +99 -3
- package/.ai/blueprints/edit-module/gates.yaml +4 -0
- package/.ai/blueprints/edit-module/required-files.yaml +9 -0
- package/.ai/blueprints/new-module/gates.yaml +4 -0
- package/.ai/blueprints/new-module/spec-requirements.yaml +2 -2
- package/.ai/blueprints/release/gates.yaml +4 -0
- package/.ai/platform-capabilities.md +128 -0
- package/.ai/policies/capabilities.yaml +100 -0
- package/.ai/policies/path-ownership.yaml +5 -2
- package/.ai/policies/task-budgets.yaml +5 -3
- package/.ai/references/catalog/module.json +4 -4
- package/.ai/references/catalog/package.json +2 -2
- package/.ai/references/catalog/spec/module.yaml +5 -3
- package/.ai/references/catalog/src/platform.ts +2 -0
- package/.ai/references/catalog/src/services/catalog-service.ts +89 -1
- package/.ai/references/catalog/src/services/data-classes.ts +47 -0
- package/.ai/references/catalog/src/services/database-repository.ts +98 -1
- package/.ai/references/catalog/src/services/repository.ts +22 -1
- package/.ai/references/catalog/tests/data-classes.test.ts +157 -0
- package/.ai/references/catalog.provenance.json +12 -10
- package/.ai/skills/README.md +10 -0
- package/.ai/skills/agent-tool-design/SKILL.md +1 -2
- package/.ai/skills/auth-security-review/SKILL.md +1 -1
- package/.ai/skills/business-agent-design/SKILL.md +0 -1
- package/.ai/skills/deploy-operate/SKILL.md +114 -0
- package/.ai/skills/module-new/SKILL.md +29 -3
- package/.ai/skills/module-update/SKILL.md +9 -3
- package/.ai/skills/perf-audit/SKILL.md +0 -1
- package/.ai/skills/release-eject-pr/SKILL.md +0 -1
- package/.ai/skills/spec-interview/SKILL.md +120 -0
- package/.ai/skills/test-hardening/SKILL.md +1 -0
- package/.ai/skills/ux-design/SKILL.md +34 -3
- package/.ai/skills/variables/SKILL.md +0 -2
- package/.ai/skills/workflow-development/SKILL.md +0 -1
- package/AGENTS.md +4 -0
- package/docs/agent-contract.md +2 -2
- package/docs/design-system.md +185 -31
- package/modules/access/migrations/0001_access_core.down.sql +1 -0
- package/modules/access/migrations/0001_access_core.up.sql +28 -0
- package/modules/access/migrations/README.md +3 -0
- package/modules/access/module.json +33 -0
- package/modules/access/package.json +43 -0
- package/modules/access/spec/module.yaml +225 -0
- package/modules/access/src/acl/permissions.ts +6 -0
- package/modules/access/src/api/endpoints.ts +244 -0
- package/modules/access/src/client/ActivityView.tsrx +245 -0
- package/modules/access/src/client/AttestationsView.tsrx +176 -0
- package/modules/access/src/client/ReviewView.tsrx +586 -0
- package/modules/access/src/client/api.ts +132 -0
- package/modules/access/src/client/contribution.tsrx +41 -0
- package/modules/access/src/client/index.ts +41 -0
- package/modules/access/src/client/navigation.ts +57 -0
- package/modules/access/src/client/presentation.ts +69 -0
- package/modules/access/src/client/state.ts +72 -0
- package/modules/access/src/domain/types.ts +189 -0
- package/modules/access/src/index.ts +38 -0
- package/modules/access/src/platform.ts +60 -0
- package/modules/access/src/server/index.ts +42 -0
- package/modules/access/src/server/runtime.ts +105 -0
- package/modules/access/src/services/access-service.ts +298 -0
- package/modules/access/src/services/audit-window.ts +78 -0
- package/modules/access/src/services/auth-directory.ts +72 -0
- package/modules/access/src/services/changes.ts +91 -0
- package/modules/access/src/services/data-classes.ts +28 -0
- package/modules/access/src/services/database-repository.ts +185 -0
- package/modules/access/src/services/directory.ts +102 -0
- package/modules/access/src/services/index.ts +33 -0
- package/modules/access/src/services/list-exports.ts +150 -0
- package/modules/access/src/services/migration.ts +54 -0
- package/modules/access/src/services/repository.ts +30 -0
- package/modules/access/src/services/review.ts +178 -0
- package/modules/access/translations/en.json +155 -0
- package/modules/access/translations/pl.json +155 -0
- package/modules/agents/migrations/0022_credential_rotation_inventory.down.sql +2 -0
- package/modules/agents/migrations/0022_credential_rotation_inventory.up.sql +7 -0
- package/modules/agents/migrations/0023_agents_retention_indexes.down.sql +2 -0
- package/modules/agents/migrations/0023_agents_retention_indexes.up.sql +9 -0
- package/modules/agents/migrations/0024_agent_meter_refusals.down.sql +3 -0
- package/modules/agents/migrations/0024_agent_meter_refusals.up.sql +22 -0
- package/modules/agents/migrations/0025_agent_list_indexes.down.sql +3 -0
- package/modules/agents/migrations/0025_agent_list_indexes.up.sql +11 -0
- package/modules/agents/module.json +30 -4
- package/modules/agents/package.json +2 -1
- package/modules/agents/spec/module.yaml +63 -5
- package/modules/agents/src/api/endpoints.ts +291 -33
- package/modules/agents/src/cli/commands.json +11 -0
- package/modules/agents/src/cli/index.ts +45 -0
- package/modules/agents/src/client/AgentDashboardWidget.tsrx +19 -11
- package/modules/agents/src/client/AgentDefinitionList.tsrx +53 -10
- package/modules/agents/src/client/AgentPlaygroundView.tsrx +4 -4
- package/modules/agents/src/client/AgentProceduresView.tsrx +2 -2
- package/modules/agents/src/client/AgentRunsView.tsrx +143 -40
- package/modules/agents/src/client/AgentsView.tsrx +109 -33
- package/modules/agents/src/client/api.ts +99 -21
- package/modules/agents/src/client/state.ts +97 -0
- package/modules/agents/src/domain/types.ts +44 -4
- package/modules/agents/src/platform.ts +42 -0
- package/modules/agents/src/server/action-execution.ts +201 -106
- package/modules/agents/src/server/runtime.ts +32 -0
- package/modules/agents/src/services/agent-service.ts +158 -30
- package/modules/agents/src/services/credential-rotation.ts +185 -0
- package/modules/agents/src/services/credential-vault.ts +71 -46
- package/modules/agents/src/services/data-classes.ts +176 -0
- package/modules/agents/src/services/database-repository.ts +393 -101
- package/modules/agents/src/services/metering.ts +111 -0
- package/modules/agents/src/services/migration.ts +109 -0
- package/modules/agents/src/services/module-agent-preflight.ts +17 -9
- package/modules/agents/src/services/notifications.ts +98 -0
- package/modules/agents/src/services/provider-repository.ts +9 -18
- package/modules/agents/src/services/provider-service.ts +1 -9
- package/modules/agents/src/services/reports.ts +107 -0
- package/modules/agents/src/services/repository.ts +86 -6
- package/modules/agents/src/services/usage-service.ts +2 -0
- package/modules/agents/src/services/worker.ts +114 -4
- package/modules/agents/src/settings.ts +14 -3
- package/modules/agents/translations/en.json +14 -4
- package/modules/agents/translations/pl.json +14 -4
- package/modules/approvals/migrations/0001_approvals_core.down.sql +3 -0
- package/modules/approvals/migrations/0001_approvals_core.up.sql +78 -0
- package/modules/approvals/migrations/0002_approvals_expiry_routing_role.down.sql +2 -0
- package/modules/approvals/migrations/0002_approvals_expiry_routing_role.up.sql +19 -0
- package/modules/approvals/migrations/0003_approvals_retention_indexes.down.sql +6 -0
- package/modules/approvals/migrations/0003_approvals_retention_indexes.up.sql +14 -0
- package/modules/approvals/migrations/0004_approvals_inbox_keyset_indexes.down.sql +5 -0
- package/modules/approvals/migrations/0004_approvals_inbox_keyset_indexes.up.sql +12 -0
- package/modules/approvals/migrations/README.md +3 -0
- package/modules/approvals/module.json +34 -0
- package/modules/approvals/package.json +43 -0
- package/modules/approvals/spec/module.yaml +318 -0
- package/modules/approvals/src/acl/permissions.ts +7 -0
- package/modules/approvals/src/api/endpoints.ts +457 -0
- package/modules/approvals/src/client/ApprovalRequestDrawer.tsrx +138 -0
- package/modules/approvals/src/client/ApprovalsView.tsrx +562 -0
- package/modules/approvals/src/client/PendingCountWidget.tsrx +52 -0
- package/modules/approvals/src/client/api.ts +203 -0
- package/modules/approvals/src/client/approvals.css +51 -0
- package/modules/approvals/src/client/contribution.tsrx +44 -0
- package/modules/approvals/src/client/index.ts +26 -0
- package/modules/approvals/src/client/navigation.ts +39 -0
- package/modules/approvals/src/client/pending-count.ts +26 -0
- package/modules/approvals/src/client/presentation.ts +52 -0
- package/modules/approvals/src/client/state.ts +141 -0
- package/modules/approvals/src/domain/capability.ts +95 -0
- package/modules/approvals/src/domain/types.ts +154 -0
- package/modules/approvals/src/index.ts +52 -0
- package/modules/approvals/src/platform.ts +128 -0
- package/modules/approvals/src/server/index.ts +42 -0
- package/modules/approvals/src/server/runtime.ts +181 -0
- package/modules/approvals/src/services/approvals-service.ts +557 -0
- package/modules/approvals/src/services/callbacks.ts +75 -0
- package/modules/approvals/src/services/data-classes.ts +167 -0
- package/modules/approvals/src/services/database-repository.ts +724 -0
- package/modules/approvals/src/services/eligibility.ts +121 -0
- package/modules/approvals/src/services/expiry-runner.ts +81 -0
- package/modules/approvals/src/services/index.ts +31 -0
- package/modules/approvals/src/services/migration.ts +222 -0
- package/modules/approvals/src/services/notifications.ts +95 -0
- package/modules/approvals/src/services/repository.ts +161 -0
- package/modules/approvals/src/services/service-error.ts +70 -0
- package/modules/approvals/src/settings.ts +102 -0
- package/modules/approvals/translations/en.json +104 -0
- package/modules/approvals/translations/pl.json +104 -0
- package/modules/audit/migrations/0001_audit_core.down.sql +8 -0
- package/modules/audit/migrations/0001_audit_core.up.sql +107 -0
- package/modules/audit/migrations/0002_audit_sweep_routing_role.down.sql +2 -0
- package/modules/audit/migrations/0002_audit_sweep_routing_role.up.sql +21 -0
- package/modules/audit/migrations/0003_audit_export_request.down.sql +12 -0
- package/modules/audit/migrations/0003_audit_export_request.up.sql +40 -0
- package/modules/audit/migrations/0004_audit_hold_seal_erasure.down.sql +17 -0
- package/modules/audit/migrations/0004_audit_hold_seal_erasure.up.sql +192 -0
- package/modules/audit/migrations/0005_audit_event_format.down.sql +17 -0
- package/modules/audit/migrations/0005_audit_event_format.up.sql +60 -0
- package/modules/audit/migrations/0006_audit_own_class_walks.down.sql +3 -0
- package/modules/audit/migrations/0006_audit_own_class_walks.up.sql +14 -0
- package/modules/audit/migrations/README.md +3 -0
- package/modules/audit/module.json +32 -0
- package/modules/audit/package.json +49 -0
- package/modules/audit/spec/module.yaml +809 -0
- package/modules/audit/src/acl/permissions.ts +7 -0
- package/modules/audit/src/api/endpoints.ts +315 -0
- package/modules/audit/src/cli/commands.json +95 -0
- package/modules/audit/src/cli/index.ts +658 -0
- package/modules/audit/src/client/DataClassesView.tsrx +420 -0
- package/modules/audit/src/client/ExportsView.tsrx +256 -0
- package/modules/audit/src/client/HoldsView.tsrx +604 -0
- package/modules/audit/src/client/SweepsView.tsrx +251 -0
- package/modules/audit/src/client/api.ts +185 -0
- package/modules/audit/src/client/contribution.tsrx +52 -0
- package/modules/audit/src/client/index.ts +23 -0
- package/modules/audit/src/client/navigation.ts +74 -0
- package/modules/audit/src/client/presentation.ts +105 -0
- package/modules/audit/src/client/state.ts +86 -0
- package/modules/audit/src/domain/data-classes.ts +16 -0
- package/modules/audit/src/domain/types.ts +339 -0
- package/modules/audit/src/index.ts +76 -0
- package/modules/audit/src/platform.ts +44 -0
- package/modules/audit/src/server/index.ts +177 -0
- package/modules/audit/src/server/runtime.ts +303 -0
- package/modules/audit/src/services/anchor-key.ts +143 -0
- package/modules/audit/src/services/anchor-rotation.ts +147 -0
- package/modules/audit/src/services/audit-runners.ts +278 -0
- package/modules/audit/src/services/backup-guard.ts +95 -0
- package/modules/audit/src/services/database-repository.ts +1946 -0
- package/modules/audit/src/services/declared-classes.ts +64 -0
- package/modules/audit/src/services/erasure-port.ts +126 -0
- package/modules/audit/src/services/erasure-service.ts +770 -0
- package/modules/audit/src/services/export-directory.ts +106 -0
- package/modules/audit/src/services/export-service.ts +714 -0
- package/modules/audit/src/services/hold-service.ts +295 -0
- package/modules/audit/src/services/index.ts +17 -0
- package/modules/audit/src/services/migration.ts +658 -0
- package/modules/audit/src/services/own-classes.ts +318 -0
- package/modules/audit/src/services/platform-version.ts +23 -0
- package/modules/audit/src/services/repository.ts +495 -0
- package/modules/audit/src/services/retention-service.ts +191 -0
- package/modules/audit/src/services/seal-service.ts +769 -0
- package/modules/audit/src/services/service-error.ts +61 -0
- package/modules/audit/src/services/subject-keys.ts +90 -0
- package/modules/audit/src/services/sweep-service.ts +298 -0
- package/modules/audit/src/services/zip.ts +217 -0
- package/modules/audit/src/settings.ts +69 -0
- package/modules/audit/translations/en.json +210 -0
- package/modules/audit/translations/pl.json +210 -0
- package/modules/auth/README.md +77 -29
- package/modules/auth/migrations/0016_external_identities.up.sql +16 -0
- package/modules/auth/migrations/0017_mfa_key_id.up.sql +8 -0
- package/modules/auth/migrations/0018_retire_bundled_module_scopes.up.sql +29 -0
- package/modules/auth/migrations/0019_notifications_member_scopes.up.sql +44 -0
- package/modules/auth/migrations/0020_identity_providers.up.sql +61 -0
- package/modules/auth/migrations/0021_membership_status.up.sql +19 -0
- package/modules/auth/migrations/0022_auth_provider_scopes.up.sql +45 -0
- package/modules/auth/migrations/0023_enterprise_module_scopes.down.sql +19 -0
- package/modules/auth/migrations/0023_enterprise_module_scopes.up.sql +71 -0
- package/modules/auth/migrations/0024_approvals_member_scopes.down.sql +22 -0
- package/modules/auth/migrations/0024_approvals_member_scopes.up.sql +48 -0
- package/modules/auth/migrations/0025_audit_holds_owner_scope.down.sql +21 -0
- package/modules/auth/migrations/0025_audit_holds_owner_scope.up.sql +47 -0
- package/modules/auth/migrations/0026_auth_export_keyset_indexes.down.sql +6 -0
- package/modules/auth/migrations/0026_auth_export_keyset_indexes.up.sql +15 -0
- package/modules/auth/migrations/0027_workflow_automation_profile_scopes.down.sql +34 -0
- package/modules/auth/migrations/0027_workflow_automation_profile_scopes.up.sql +72 -0
- package/modules/auth/migrations/0028_auth_member_search_prefix_indexes.down.sql +6 -0
- package/modules/auth/migrations/0028_auth_member_search_prefix_indexes.up.sql +21 -0
- package/modules/auth/migrations/0029_reports_exports_access_scopes.down.sql +22 -0
- package/modules/auth/migrations/0029_reports_exports_access_scopes.up.sql +56 -0
- package/modules/auth/migrations/0030_auth_membership_keyset_index.down.sql +4 -0
- package/modules/auth/migrations/0030_auth_membership_keyset_index.up.sql +10 -0
- package/modules/auth/migrations/0031_membership_scope_backfills_under_rls.down.sql +4 -0
- package/modules/auth/migrations/0031_membership_scope_backfills_under_rls.up.sql +31 -0
- package/modules/auth/migrations/0032_audit_actor_service.down.sql +9 -0
- package/modules/auth/migrations/0032_audit_actor_service.up.sql +10 -0
- package/modules/auth/migrations/0033_auth_account_keyset_indexes.down.sql +5 -0
- package/modules/auth/migrations/0033_auth_account_keyset_indexes.up.sql +23 -0
- package/modules/auth/module.json +3 -3
- package/modules/auth/package.json +2 -1
- package/modules/auth/spec/module.yaml +372 -3
- package/modules/auth/src/acl/scopes.ts +50 -6
- package/modules/auth/src/cli/commands.json +11 -0
- package/modules/auth/src/cli/greenfield.ts +2 -2
- package/modules/auth/src/cli/index.ts +14 -0
- package/modules/auth/src/cli/secrets.ts +114 -0
- package/modules/auth/src/client/AuthenticationCore.tsrx +61 -8
- package/modules/auth/src/client/api.ts +72 -6
- package/modules/auth/src/client/contribution.tsrx +23 -0
- package/modules/auth/src/client/index.ts +6 -0
- package/modules/auth/src/client/providers/IdentityProviderForm.tsrx +191 -0
- package/modules/auth/src/client/providers/IdentityProvidersView.tsrx +358 -0
- package/modules/auth/src/client/providers/api.ts +128 -0
- package/modules/auth/src/client/providers/provider-columns.tsrx +60 -0
- package/modules/auth/src/client/providers/state.ts +35 -0
- package/modules/auth/src/client/security/SecurityView.tsrx +9 -1
- package/modules/auth/src/client/state.ts +15 -1
- package/modules/auth/src/domain/types.ts +55 -0
- package/modules/auth/src/index.ts +11 -1
- package/modules/auth/src/middleware/authentication.ts +4 -0
- package/modules/auth/src/server/endpoints.ts +467 -171
- package/modules/auth/src/server/http.ts +3 -2
- package/modules/auth/src/server/index.ts +22 -1
- package/modules/auth/src/server/membership-endpoints.ts +62 -0
- package/modules/auth/src/server/mfa-enforcement.ts +156 -0
- package/modules/auth/src/server/oidc.ts +389 -0
- package/modules/auth/src/server/provider-endpoints.ts +246 -0
- package/modules/auth/src/server/provider-host.ts +77 -0
- package/modules/auth/src/server/runtime.ts +231 -55
- package/modules/auth/src/services/auth-service-error.ts +7 -2
- package/modules/auth/src/services/auth-service.ts +948 -51
- package/modules/auth/src/services/data-classes.ts +236 -0
- package/modules/auth/src/services/database-repository.ts +853 -71
- package/modules/auth/src/services/identity-provider-service.ts +571 -0
- package/modules/auth/src/services/mail-delivery.ts +16 -16
- package/modules/auth/src/services/mail-message.ts +54 -0
- package/modules/auth/src/services/mail-port.ts +24 -0
- package/modules/auth/src/services/mail-smtp.ts +85 -0
- package/modules/auth/src/services/mfa-rotation.ts +144 -0
- package/modules/auth/src/services/migration.ts +810 -0
- package/modules/auth/src/services/password.ts +14 -0
- package/modules/auth/src/services/provider-secret-rotation.ts +169 -0
- package/modules/auth/src/services/provider-secrets.ts +136 -0
- package/modules/auth/src/services/repository.ts +321 -5
- package/modules/auth/src/services/session-sweep-runner.ts +73 -0
- package/modules/auth/src/services/settings-store.ts +10 -83
- package/modules/auth/src/services/totp.ts +88 -62
- package/modules/auth/src/services/validation.ts +194 -7
- package/modules/auth/src/settings.ts +18 -0
- package/modules/auth/translations/en.json +84 -1
- package/modules/auth/translations/pl.json +84 -1
- package/modules/automations/migrations/0005_secret_rotation_inventory.down.sql +1 -0
- package/modules/automations/migrations/0005_secret_rotation_inventory.up.sql +6 -0
- package/modules/automations/migrations/0006_automations_list_sort_indexes.down.sql +4 -0
- package/modules/automations/migrations/0006_automations_list_sort_indexes.up.sql +11 -0
- package/modules/automations/module.json +24 -6
- package/modules/automations/package.json +4 -1
- package/modules/automations/spec/module.yaml +81 -7
- package/modules/automations/src/api/endpoints.ts +202 -28
- package/modules/automations/src/cli/commands.json +17 -0
- package/modules/automations/src/cli/index.ts +114 -0
- package/modules/automations/src/client/AutomationScheduleForm.tsrx +77 -19
- package/modules/automations/src/client/AutomationSchedulesView.tsrx +144 -40
- package/modules/automations/src/client/AutomationTriggersView.tsrx +131 -32
- package/modules/automations/src/client/api.ts +62 -19
- package/modules/automations/src/client/presentation.ts +20 -2
- package/modules/automations/src/client/state.ts +84 -0
- package/modules/automations/src/domain/cadence.ts +99 -3
- package/modules/automations/src/domain/cron.ts +366 -0
- package/modules/automations/src/domain/time-zone.ts +61 -0
- package/modules/automations/src/platform.ts +38 -4
- package/modules/automations/src/server/index.ts +11 -0
- package/modules/automations/src/server/runtime.ts +46 -22
- package/modules/{automations-workflows-integration/src/server/adapter.ts → automations/src/server/workflow-target.ts} +13 -14
- package/modules/{automations-workflows-integration/src/server/tools.ts → automations/src/server/workflow-tools.ts} +0 -0
- package/modules/automations/src/services/data-classes.ts +62 -0
- package/modules/automations/src/services/database-repository.ts +152 -38
- package/modules/automations/src/services/migration.ts +119 -9
- package/modules/automations/src/services/repository.ts +52 -1
- package/modules/automations/src/services/schedule-runner.ts +84 -0
- package/modules/automations/src/services/schedule-service.ts +152 -26
- package/modules/automations/src/services/secret-rotation.ts +176 -0
- package/modules/automations/src/services/secret-vault.ts +68 -41
- package/modules/automations/src/services/trigger-service.ts +13 -10
- package/modules/automations/translations/en.json +15 -2
- package/modules/automations/translations/pl.json +15 -2
- package/modules/connectors/migrations/0001_connectors_core.down.sql +3 -0
- package/modules/connectors/migrations/0001_connectors_core.up.sql +72 -0
- package/modules/connectors/migrations/0002_connectors_call_keys.down.sql +3 -0
- package/modules/connectors/migrations/0002_connectors_call_keys.up.sql +18 -0
- package/modules/connectors/migrations/README.md +3 -0
- package/modules/connectors/module.json +28 -0
- package/modules/{automations-workflows-integration → connectors}/package.json +27 -26
- package/modules/connectors/spec/module.yaml +447 -0
- package/modules/connectors/src/acl/permissions.ts +6 -0
- package/modules/connectors/src/agent/tools.ts +180 -0
- package/modules/connectors/src/api/endpoints.ts +572 -0
- package/modules/connectors/src/client/ConnectorCallsView.tsrx +358 -0
- package/modules/connectors/src/client/ConnectorForm.tsrx +424 -0
- package/modules/connectors/src/client/ConnectorsView.tsrx +711 -0
- package/modules/connectors/src/client/api.ts +281 -0
- package/modules/connectors/src/client/consent.ts +48 -0
- package/modules/connectors/src/client/contribution.tsrx +37 -0
- package/modules/connectors/src/client/index.ts +22 -0
- package/modules/connectors/src/client/navigation.ts +42 -0
- package/modules/connectors/src/client/presentation.ts +38 -0
- package/modules/connectors/src/client/state.ts +175 -0
- package/modules/connectors/src/domain/calls.ts +70 -0
- package/modules/connectors/src/domain/definitions.ts +190 -0
- package/modules/connectors/src/domain/http-json.ts +68 -0
- package/modules/connectors/src/domain/types.ts +185 -0
- package/modules/connectors/src/index.ts +64 -0
- package/modules/connectors/src/platform.ts +56 -0
- package/modules/connectors/src/server/index.ts +66 -0
- package/modules/connectors/src/server/runtime.ts +163 -0
- package/modules/connectors/src/services/call-service.ts +903 -0
- package/modules/connectors/src/services/connectors-service.ts +653 -0
- package/modules/connectors/src/services/credential-vault.ts +188 -0
- package/modules/connectors/src/services/data-classes.ts +158 -0
- package/modules/connectors/src/services/database-repository.ts +897 -0
- package/modules/connectors/src/services/egress.ts +261 -0
- package/modules/connectors/src/services/index.ts +19 -0
- package/modules/connectors/src/services/migration.ts +166 -0
- package/modules/connectors/src/services/repository.ts +175 -0
- package/modules/connectors/src/services/service-error.ts +46 -0
- package/modules/connectors/src/settings.ts +69 -0
- package/modules/connectors/translations/en.json +191 -0
- package/modules/connectors/translations/pl.json +191 -0
- package/modules/directory/migrations/0001_directory_core.down.sql +5 -0
- package/modules/directory/migrations/0001_directory_core.up.sql +111 -0
- package/modules/directory/migrations/README.md +3 -0
- package/modules/directory/module.json +27 -0
- package/modules/directory/package.json +46 -0
- package/modules/directory/spec/module.yaml +351 -0
- package/modules/directory/src/acl/permissions.ts +7 -0
- package/modules/directory/src/api/endpoints.ts +478 -0
- package/modules/directory/src/api/scim-endpoints.ts +516 -0
- package/modules/directory/src/client/GroupMappingsView.tsrx +430 -0
- package/modules/directory/src/client/ProvisioningLogView.tsrx +248 -0
- package/modules/directory/src/client/ScimTokensView.tsrx +587 -0
- package/modules/directory/src/client/api.ts +222 -0
- package/modules/directory/src/client/contribution.tsrx +46 -0
- package/modules/directory/src/client/index.ts +22 -0
- package/modules/directory/src/client/navigation.ts +57 -0
- package/modules/directory/src/client/presentation.ts +143 -0
- package/modules/directory/src/client/state.ts +173 -0
- package/modules/directory/src/domain/scim.ts +346 -0
- package/modules/directory/src/domain/types.ts +166 -0
- package/modules/directory/src/index.ts +44 -0
- package/modules/directory/src/platform.ts +43 -0
- package/modules/directory/src/server/index.ts +17 -0
- package/modules/directory/src/server/runtime.ts +124 -0
- package/modules/directory/src/services/auth-port.ts +127 -0
- package/modules/directory/src/services/data-classes.ts +41 -0
- package/modules/directory/src/services/database-repository.ts +1067 -0
- package/modules/directory/src/services/directory-service.ts +311 -0
- package/modules/directory/src/services/index.ts +43 -0
- package/modules/directory/src/services/migration.ts +146 -0
- package/modules/directory/src/services/provisioning-service.ts +1420 -0
- package/modules/directory/src/services/rate-limiter.ts +103 -0
- package/modules/directory/src/services/repository.ts +208 -0
- package/modules/directory/src/services/service-error.ts +42 -0
- package/modules/directory/src/services/token-service.ts +215 -0
- package/modules/directory/src/settings.ts +86 -0
- package/modules/directory/translations/en.json +185 -0
- package/modules/directory/translations/pl.json +185 -0
- package/modules/documents/migrations/0001_documents_core.down.sql +1 -0
- package/modules/documents/migrations/0001_documents_core.up.sql +35 -0
- package/modules/documents/migrations/0002_documents_files_page.down.sql +1 -0
- package/modules/documents/migrations/0002_documents_files_page.up.sql +6 -0
- package/modules/documents/migrations/README.md +3 -0
- package/modules/documents/module.json +28 -0
- package/modules/documents/package.json +49 -0
- package/modules/documents/spec/module.yaml +247 -0
- package/modules/documents/src/acl/permissions.ts +6 -0
- package/modules/documents/src/api/endpoints.ts +401 -0
- package/modules/documents/src/client/DocumentUploader.tsrx +148 -0
- package/modules/documents/src/client/DocumentsView.tsrx +540 -0
- package/modules/documents/src/client/api.ts +209 -0
- package/modules/documents/src/client/contribution.tsrx +29 -0
- package/modules/documents/src/client/download.ts +70 -0
- package/modules/documents/src/client/index.ts +22 -0
- package/modules/documents/src/client/navigation.ts +25 -0
- package/modules/documents/src/client/presentation.ts +110 -0
- package/modules/documents/src/client/state.ts +117 -0
- package/modules/documents/src/domain/attachments.ts +84 -0
- package/modules/documents/src/domain/types.ts +80 -0
- package/modules/documents/src/index.ts +46 -0
- package/modules/documents/src/platform.ts +61 -0
- package/modules/documents/src/server/index.ts +30 -0
- package/modules/documents/src/server/runtime.ts +107 -0
- package/modules/documents/src/services/attachments.ts +39 -0
- package/modules/documents/src/services/data-classes.ts +25 -0
- package/modules/documents/src/services/database-repository.ts +259 -0
- package/modules/documents/src/services/documents-service.ts +586 -0
- package/modules/documents/src/services/index.ts +18 -0
- package/modules/documents/src/services/migration.ts +82 -0
- package/modules/documents/src/services/repository.ts +48 -0
- package/modules/documents/src/settings.ts +107 -0
- package/modules/documents/translations/en.json +111 -0
- package/modules/documents/translations/pl.json +111 -0
- package/modules/exports/migrations/0001_exports_core.down.sql +2 -0
- package/modules/exports/migrations/0001_exports_core.up.sql +28 -0
- package/modules/exports/migrations/0002_exports_job_routing_role.down.sql +4 -0
- package/modules/exports/migrations/0002_exports_job_routing_role.up.sql +21 -0
- package/modules/exports/migrations/README.md +3 -0
- package/modules/exports/module.json +28 -0
- package/modules/exports/package.json +44 -0
- package/modules/exports/spec/module.yaml +229 -0
- package/modules/exports/src/acl/permissions.ts +6 -0
- package/modules/exports/src/api/endpoints.ts +211 -0
- package/modules/exports/src/client/ExportsView.tsrx +327 -0
- package/modules/exports/src/client/api.ts +133 -0
- package/modules/exports/src/client/contribution.tsrx +31 -0
- package/modules/exports/src/client/index.ts +20 -0
- package/modules/exports/src/client/navigation.ts +25 -0
- package/modules/exports/src/client/presentation.ts +53 -0
- package/modules/exports/src/client/state.ts +56 -0
- package/modules/exports/src/domain/lists.ts +29 -0
- package/modules/exports/src/domain/types.ts +120 -0
- package/modules/exports/src/index.ts +41 -0
- package/modules/exports/src/platform.ts +80 -0
- package/modules/exports/src/server/index.ts +51 -0
- package/modules/exports/src/server/runtime.ts +160 -0
- package/modules/exports/src/services/data-classes.ts +56 -0
- package/modules/exports/src/services/database-repository.ts +405 -0
- package/modules/exports/src/services/export-runner.ts +123 -0
- package/modules/exports/src/services/export-service.ts +356 -0
- package/modules/exports/src/services/index.ts +6 -0
- package/modules/exports/src/services/list-registry.ts +105 -0
- package/modules/exports/src/services/migration.ts +89 -0
- package/modules/exports/src/services/repository.ts +97 -0
- package/modules/exports/src/settings.ts +70 -0
- package/modules/exports/translations/en.json +69 -0
- package/modules/exports/translations/pl.json +69 -0
- package/modules/import/migrations/0001_import_core.down.sql +6 -0
- package/modules/import/migrations/0001_import_core.up.sql +61 -0
- package/modules/import/migrations/0002_import_job_routing_role.down.sql +4 -0
- package/modules/import/migrations/0002_import_job_routing_role.up.sql +20 -0
- package/modules/import/migrations/0003_import_jobs_export_index.down.sql +1 -0
- package/modules/import/migrations/0003_import_jobs_export_index.up.sql +7 -0
- package/modules/import/migrations/0004_import_jobs_traceparent.down.sql +1 -0
- package/modules/import/migrations/0004_import_jobs_traceparent.up.sql +7 -0
- package/modules/import/migrations/README.md +3 -0
- package/modules/import/module.json +37 -0
- package/modules/import/package.json +50 -0
- package/modules/import/spec/module.yaml +335 -0
- package/modules/import/src/acl/permissions.ts +6 -0
- package/modules/import/src/api/endpoints.ts +400 -0
- package/modules/import/src/client/ImportJobDrawer.tsrx +229 -0
- package/modules/import/src/client/ImportsView.tsrx +455 -0
- package/modules/import/src/client/NewImportForm.tsrx +274 -0
- package/modules/import/src/client/api.ts +243 -0
- package/modules/import/src/client/contribution.tsrx +29 -0
- package/modules/import/src/client/index.ts +23 -0
- package/modules/import/src/client/navigation.ts +25 -0
- package/modules/import/src/client/presentation.ts +59 -0
- package/modules/import/src/client/state.ts +43 -0
- package/modules/import/src/domain/csv.ts +258 -0
- package/modules/import/src/domain/ports.ts +157 -0
- package/modules/import/src/domain/types.ts +179 -0
- package/modules/import/src/index.ts +58 -0
- package/modules/import/src/platform.ts +60 -0
- package/modules/import/src/server/index.ts +49 -0
- package/modules/import/src/server/runtime.ts +158 -0
- package/modules/import/src/services/csv-source.ts +121 -0
- package/modules/import/src/services/data-classes.ts +63 -0
- package/modules/import/src/services/database-repository.ts +780 -0
- package/modules/import/src/services/import-runner.ts +127 -0
- package/modules/import/src/services/import-service.ts +872 -0
- package/modules/import/src/services/index.ts +6 -0
- package/modules/import/src/services/migration.ts +156 -0
- package/modules/import/src/services/port-registry.ts +158 -0
- package/modules/import/src/services/repository.ts +147 -0
- package/modules/import/src/settings.ts +70 -0
- package/modules/import/translations/en.json +175 -0
- package/modules/import/translations/pl.json +175 -0
- package/modules/metering/migrations/0001_metering_core.down.sql +6 -0
- package/modules/metering/migrations/0001_metering_core.up.sql +119 -0
- package/modules/metering/migrations/0002_metering_bucket_export.down.sql +3 -0
- package/modules/metering/migrations/0002_metering_bucket_export.up.sql +5 -0
- package/modules/metering/migrations/README.md +3 -0
- package/modules/metering/module.json +46 -0
- package/modules/metering/package.json +50 -0
- package/modules/metering/spec/module.yaml +269 -0
- package/modules/metering/src/acl/permissions.ts +5 -0
- package/modules/metering/src/api/endpoints.ts +104 -0
- package/modules/metering/src/cli/commands.json +28 -0
- package/modules/metering/src/cli/index.ts +246 -0
- package/modules/metering/src/client/LimitsView.tsrx +170 -0
- package/modules/metering/src/client/UsageSummaryWidget.tsrx +63 -0
- package/modules/metering/src/client/UsageView.tsrx +205 -0
- package/modules/metering/src/client/api.ts +91 -0
- package/modules/metering/src/client/contribution.tsrx +42 -0
- package/modules/metering/src/client/index.ts +26 -0
- package/modules/metering/src/client/navigation.ts +54 -0
- package/modules/metering/src/client/presentation.ts +63 -0
- package/modules/metering/src/client/state.ts +31 -0
- package/modules/metering/src/domain/meters.ts +100 -0
- package/modules/metering/src/domain/types.ts +71 -0
- package/modules/metering/src/index.ts +51 -0
- package/modules/metering/src/platform.ts +84 -0
- package/modules/metering/src/server/index.ts +40 -0
- package/modules/metering/src/server/runtime.ts +165 -0
- package/modules/metering/src/services/data-classes.ts +34 -0
- package/modules/metering/src/services/database-repository.ts +574 -0
- package/modules/metering/src/services/index.ts +9 -0
- package/modules/metering/src/services/meter-registry.ts +145 -0
- package/modules/metering/src/services/metering-service.ts +441 -0
- package/modules/metering/src/services/migration.ts +183 -0
- package/modules/metering/src/services/notifications.ts +75 -0
- package/modules/metering/src/services/reports.ts +105 -0
- package/modules/metering/src/services/repository.ts +132 -0
- package/modules/metering/src/services/service-error.ts +46 -0
- package/modules/metering/src/settings.ts +47 -0
- package/modules/metering/translations/en.json +68 -0
- package/modules/metering/translations/pl.json +68 -0
- package/modules/notifications/migrations/0001_notifications_core.down.sql +1 -0
- package/modules/notifications/migrations/0001_notifications_core.up.sql +26 -0
- package/modules/notifications/migrations/0002_notifications_preferences.down.sql +1 -0
- package/modules/notifications/migrations/0002_notifications_preferences.up.sql +17 -0
- package/modules/notifications/migrations/0003_notifications_webhook_subscriptions.down.sql +1 -0
- package/modules/notifications/migrations/0003_notifications_webhook_subscriptions.up.sql +30 -0
- package/modules/notifications/migrations/0004_notifications_deliveries.down.sql +1 -0
- package/modules/notifications/migrations/0004_notifications_deliveries.up.sql +35 -0
- package/modules/notifications/migrations/0005_notifications_delivery_routing_role.down.sql +2 -0
- package/modules/notifications/migrations/0005_notifications_delivery_routing_role.up.sql +17 -0
- package/modules/notifications/migrations/0006_notifications_delivery_title.down.sql +1 -0
- package/modules/notifications/migrations/0006_notifications_delivery_title.up.sql +11 -0
- package/modules/notifications/migrations/0007_notifications_secret_rotation_inventory.down.sql +2 -0
- package/modules/notifications/migrations/0007_notifications_secret_rotation_inventory.up.sql +19 -0
- package/modules/notifications/migrations/0008_notifications_delivery_claim.down.sql +8 -0
- package/modules/notifications/migrations/0008_notifications_delivery_claim.up.sql +19 -0
- package/modules/notifications/migrations/0009_notifications_kind_approvals.down.sql +16 -0
- package/modules/notifications/migrations/0009_notifications_kind_approvals.up.sql +18 -0
- package/modules/notifications/migrations/0010_notifications_kind_meter_threshold.down.sql +16 -0
- package/modules/notifications/migrations/0010_notifications_kind_meter_threshold.up.sql +18 -0
- package/modules/notifications/migrations/0011_notifications_retention_keyset.down.sql +5 -0
- package/modules/notifications/migrations/0011_notifications_retention_keyset.up.sql +15 -0
- package/modules/notifications/migrations/0012_notifications_email_channel.down.sql +12 -0
- package/modules/notifications/migrations/0012_notifications_email_channel.up.sql +38 -0
- package/modules/notifications/migrations/0013_notifications_list_pages.down.sql +5 -0
- package/modules/notifications/migrations/0013_notifications_list_pages.up.sql +13 -0
- package/modules/notifications/migrations/README.md +3 -0
- package/modules/notifications/module.json +32 -0
- package/modules/notifications/package.json +49 -0
- package/modules/notifications/spec/module.yaml +718 -0
- package/modules/notifications/src/acl/permissions.ts +11 -0
- package/modules/notifications/src/api/endpoints.ts +814 -0
- package/modules/notifications/src/cli/commands.json +17 -0
- package/modules/notifications/src/cli/index.ts +126 -0
- package/modules/notifications/src/client/DeliveriesView.tsrx +483 -0
- package/modules/notifications/src/client/FactList.tsrx +24 -0
- package/modules/notifications/src/client/NotificationPreferencesView.tsrx +240 -0
- package/modules/notifications/src/client/NotificationsInboxView.tsrx +592 -0
- package/modules/notifications/src/client/UnreadCountWidget.tsrx +62 -0
- package/modules/notifications/src/client/WebhookForm.tsrx +297 -0
- package/modules/notifications/src/client/WebhooksView.tsrx +637 -0
- package/modules/notifications/src/client/api.ts +382 -0
- package/modules/notifications/src/client/contribution.tsrx +83 -0
- package/modules/notifications/src/client/inbox.ts +41 -0
- package/modules/notifications/src/client/index.ts +29 -0
- package/modules/notifications/src/client/navigation.ts +92 -0
- package/modules/notifications/src/client/notifications.css +70 -0
- package/modules/notifications/src/client/presentation.ts +81 -0
- package/modules/notifications/src/client/state.ts +246 -0
- package/modules/notifications/src/client/unread-count.ts +26 -0
- package/modules/notifications/src/domain/locale.ts +47 -0
- package/modules/notifications/src/domain/publish.ts +46 -0
- package/modules/notifications/src/domain/types.ts +186 -0
- package/modules/notifications/src/index.ts +62 -0
- package/modules/notifications/src/platform.ts +85 -0
- package/modules/notifications/src/server/index.ts +82 -0
- package/modules/notifications/src/server/runtime.ts +251 -0
- package/modules/notifications/src/services/data-classes.ts +139 -0
- package/modules/notifications/src/services/database-repository.ts +1334 -0
- package/modules/notifications/src/services/delivery-payload.ts +93 -0
- package/modules/notifications/src/services/delivery-runner.ts +170 -0
- package/modules/notifications/src/services/delivery-service.ts +811 -0
- package/modules/notifications/src/services/egress.ts +239 -0
- package/modules/notifications/src/services/email-channel.ts +93 -0
- package/modules/notifications/src/services/index.ts +23 -0
- package/modules/notifications/src/services/migration.ts +572 -0
- package/modules/notifications/src/services/notifications-service.ts +297 -0
- package/modules/notifications/src/services/paging.ts +60 -0
- package/modules/notifications/src/services/publish-service.ts +133 -0
- package/modules/notifications/src/services/repository.ts +342 -0
- package/modules/notifications/src/services/secret-rotation.ts +177 -0
- package/modules/notifications/src/services/secret-vault.ts +168 -0
- package/modules/notifications/src/services/service-error.ts +67 -0
- package/modules/notifications/src/services/signature.ts +81 -0
- package/modules/notifications/src/services/webhook-service.ts +307 -0
- package/modules/notifications/src/settings.ts +130 -0
- package/modules/notifications/translations/en.json +255 -0
- package/modules/notifications/translations/pl.json +255 -0
- package/modules/profile/module.json +3 -3
- package/modules/profile/package.json +1 -1
- package/modules/profile/spec/module.yaml +3 -3
- package/modules/profile/src/services/database-repository.ts +3 -13
- package/modules/reports/module.json +28 -0
- package/modules/reports/package.json +42 -0
- package/modules/reports/spec/module.yaml +231 -0
- package/modules/reports/src/acl/permissions.ts +5 -0
- package/modules/reports/src/api/endpoints.ts +72 -0
- package/modules/reports/src/client/ReportsSummaryWidget.tsrx +52 -0
- package/modules/reports/src/client/ReportsView.tsrx +246 -0
- package/modules/reports/src/client/api.ts +65 -0
- package/modules/reports/src/client/contribution.tsrx +36 -0
- package/modules/reports/src/client/index.ts +18 -0
- package/modules/reports/src/client/navigation.ts +39 -0
- package/modules/reports/src/client/presentation.ts +123 -0
- package/modules/reports/src/client/state.ts +28 -0
- package/modules/reports/src/domain/providers.ts +115 -0
- package/modules/reports/src/domain/types.ts +44 -0
- package/modules/reports/src/index.ts +47 -0
- package/modules/reports/src/platform.ts +37 -0
- package/modules/reports/src/server/index.ts +21 -0
- package/modules/reports/src/server/runtime.ts +40 -0
- package/modules/reports/src/services/index.ts +17 -0
- package/modules/reports/src/services/provider-registry.ts +144 -0
- package/modules/reports/src/services/range.ts +65 -0
- package/modules/reports/src/services/reports-service.ts +316 -0
- package/modules/reports/src/services/service-error.ts +26 -0
- package/modules/reports/src/settings.ts +49 -0
- package/modules/reports/translations/en.json +35 -0
- package/modules/reports/translations/pl.json +35 -0
- package/modules/sandbox/module.json +4 -4
- package/modules/sandbox/package.json +1 -1
- package/modules/sandbox/spec/module.yaml +3 -3
- package/modules/sandbox/src/services/database-repository.ts +14 -23
- package/modules/sandbox/src/services/directory.ts +16 -0
- package/modules/sandbox/src/services/sandbox-service.ts +13 -11
- package/modules/search/migrations/0001_search_core.down.sql +1 -0
- package/modules/search/migrations/0001_search_core.up.sql +22 -0
- package/modules/search/migrations/0002_search_recent_export.down.sql +3 -0
- package/modules/search/migrations/0002_search_recent_export.up.sql +5 -0
- package/modules/search/migrations/README.md +3 -0
- package/modules/search/module.json +28 -0
- package/modules/search/package.json +43 -0
- package/modules/search/spec/module.yaml +177 -0
- package/modules/search/src/acl/permissions.ts +5 -0
- package/modules/search/src/api/endpoints.ts +221 -0
- package/modules/search/src/client/SearchView.tsrx +346 -0
- package/modules/search/src/client/api.ts +157 -0
- package/modules/search/src/client/contribution.tsrx +31 -0
- package/modules/search/src/client/index.ts +17 -0
- package/modules/search/src/client/navigation.ts +97 -0
- package/modules/search/src/client/search.css +56 -0
- package/modules/search/src/client/state.ts +113 -0
- package/modules/search/src/domain/data-classes.ts +73 -0
- package/modules/search/src/domain/providers.ts +88 -0
- package/modules/search/src/domain/types.ts +56 -0
- package/modules/search/src/index.ts +46 -0
- package/modules/search/src/platform.ts +42 -0
- package/modules/search/src/server/index.ts +25 -0
- package/modules/search/src/server/runtime.ts +123 -0
- package/modules/search/src/services/database-repository.ts +163 -0
- package/modules/search/src/services/index.ts +21 -0
- package/modules/search/src/services/migration.ts +65 -0
- package/modules/search/src/services/provider-registry.ts +137 -0
- package/modules/search/src/services/repository.ts +43 -0
- package/modules/search/src/services/search-service.ts +442 -0
- package/modules/search/src/services/service-error.ts +35 -0
- package/modules/search/src/settings.ts +68 -0
- package/modules/search/translations/en.json +45 -0
- package/modules/search/translations/pl.json +45 -0
- package/modules/system/module.json +2 -2
- package/modules/system/package.json +1 -1
- package/modules/system/spec/module.yaml +30 -3
- package/modules/system/src/client/FlagsPanel.tsrx +127 -0
- package/modules/system/src/client/ModuleSettingRow.tsrx +17 -7
- package/modules/system/src/client/ModuleSettingsSection.tsrx +10 -71
- package/modules/system/src/client/ModulesView.tsrx +91 -65
- package/modules/system/src/client/flags.ts +35 -0
- package/modules/system/src/client/index.ts +8 -0
- package/modules/system/src/client/navigation.ts +8 -0
- package/modules/system/src/client/settings-state.ts +159 -0
- package/modules/system/src/client/state.ts +2 -0
- package/modules/system/src/domain/time-zone.ts +105 -0
- package/modules/system/src/index.ts +12 -0
- package/modules/system/src/platform.ts +5 -1
- package/modules/system/src/server/endpoints.ts +72 -21
- package/modules/system/src/settings.ts +28 -0
- package/modules/system/translations/en.json +17 -0
- package/modules/system/translations/pl.json +17 -0
- package/modules/users/module.json +30 -4
- package/modules/users/package.json +4 -1
- package/modules/users/spec/module.yaml +290 -7
- package/modules/users/src/api/endpoints.ts +228 -15
- package/modules/users/src/client/InviteMemberForm.tsrx +2 -2
- package/modules/users/src/client/MemberDrawer.tsrx +142 -26
- package/modules/users/src/client/UserAccountForm.tsrx +2 -2
- package/modules/users/src/client/UsersView.tsrx +432 -71
- package/modules/users/src/client/api.ts +106 -12
- package/modules/users/src/client/contribution.tsrx +5 -0
- package/modules/users/src/client/member-columns.tsrx +22 -9
- package/modules/users/src/client/state.ts +172 -7
- package/modules/users/src/domain/lists.ts +9 -0
- package/modules/users/src/index.ts +11 -0
- package/modules/users/src/platform.ts +50 -1
- package/modules/users/src/services/member-export.ts +51 -0
- package/modules/users/src/services/member-import.ts +249 -0
- package/modules/users/src/services/member-search.ts +145 -0
- package/modules/users/src/services/users-service.ts +117 -4
- package/modules/users/translations/en.json +57 -8
- package/modules/users/translations/pl.json +57 -8
- package/modules/workflows/migrations/0004_payload_rotation_inventory.up.sql +17 -0
- package/modules/workflows/migrations/0005_workflows_human_approval.up.sql +28 -0
- package/modules/workflows/migrations/0006_workflows_retention_indexes.up.sql +11 -0
- package/modules/workflows/migrations/0007_workflows_erasure_subject_indexes.up.sql +17 -0
- package/modules/workflows/migrations/0008_workflows_subject_account.up.sql +24 -0
- package/modules/workflows/migrations/0009_workflows_definition_list_indexes.up.sql +9 -0
- package/modules/workflows/module.json +34 -6
- package/modules/workflows/package.json +2 -1
- package/modules/workflows/spec/module.yaml +26 -9
- package/modules/workflows/src/api/endpoints.ts +131 -25
- package/modules/workflows/src/cli/commands.json +17 -0
- package/modules/workflows/src/cli/index.ts +114 -0
- package/modules/workflows/src/client/WorkflowExecutionHistory.tsrx +36 -27
- package/modules/workflows/src/client/WorkflowInspector.tsrx +116 -0
- package/modules/workflows/src/client/WorkflowNodePalette.tsrx +1 -0
- package/modules/workflows/src/client/WorkflowsView.tsrx +236 -99
- package/modules/workflows/src/client/api.ts +54 -34
- package/modules/workflows/src/client/canvas-model.ts +12 -0
- package/modules/workflows/src/client/state.ts +95 -0
- package/modules/workflows/src/domain/events.ts +25 -11
- package/modules/workflows/src/domain/graph.ts +135 -1
- package/modules/workflows/src/domain/types.ts +91 -4
- package/modules/workflows/src/platform.ts +12 -0
- package/modules/workflows/src/server/runtime.ts +78 -5
- package/modules/workflows/src/services/approvals.ts +62 -0
- package/modules/workflows/src/services/cursors.ts +37 -0
- package/modules/workflows/src/services/data-classes.ts +232 -0
- package/modules/workflows/src/services/database-repository.ts +660 -171
- package/modules/workflows/src/services/migration.ts +240 -0
- package/modules/workflows/src/services/notifications.ts +98 -0
- package/modules/workflows/src/services/payload-codec.ts +51 -28
- package/modules/workflows/src/services/payload-rotation.ts +171 -0
- package/modules/workflows/src/services/repository.ts +123 -8
- package/modules/workflows/src/services/simulation.ts +7 -0
- package/modules/workflows/src/services/worker.ts +446 -25
- package/modules/workflows/src/services/workflows-service.ts +264 -103
- package/modules/workflows/translations/en.json +12 -4
- package/modules/workflows/translations/pl.json +12 -4
- package/modules.json +48 -4
- package/package.json +64 -6
- package/packages/client/package.json +1 -0
- package/packages/client/src/ApplicationShell.tsrx +43 -0
- package/packages/client/src/contributions.ts +55 -0
- package/packages/client/src/i18n/locales/en.json +5 -0
- package/packages/client/src/i18n/locales/pl.json +5 -0
- package/packages/client/src/index.ts +13 -1
- package/packages/client/src/routing.ts +22 -0
- package/packages/client/src/shell/CommandPalette.tsrx +223 -11
- package/packages/client/src/shell/command-search.ts +126 -0
- package/packages/client/src/shell/command.ts +30 -0
- package/packages/client/src/shell/navigation.ts +12 -0
- package/packages/client/src/shell/palette-keys.ts +27 -0
- package/packages/client/src/shell/shell.css +7 -0
- package/packages/contracts/schemas/module-spec.schema.json +287 -1
- package/packages/contracts/schemas/module.schema.json +25 -0
- package/packages/contracts/src/index.ts +144 -1
- package/packages/database/src/backup.ts +179 -0
- package/packages/database/src/decoders.ts +25 -0
- package/packages/database/src/index.ts +17 -0
- package/packages/database/src/record-history.ts +5 -14
- package/packages/harness/src/index.ts +2 -0
- package/packages/harness/src/runtime.ts +218 -1
- package/packages/harness/src/tool-adapters.ts +19 -1
- package/packages/kernel/src/acl.ts +179 -0
- package/packages/kernel/src/capability-registry.ts +69 -2
- package/packages/kernel/src/data-class-registry.ts +354 -0
- package/packages/kernel/src/index.ts +65 -4
- package/packages/kernel/src/keyring.ts +208 -0
- package/packages/kernel/src/module-compatibility.ts +35 -4
- package/packages/kernel/src/module-registry.ts +49 -2
- package/packages/kernel/src/module-settings.ts +189 -27
- package/packages/server/package.json +2 -1
- package/packages/server/src/composition.ts +38 -0
- package/packages/server/src/endpoint.ts +104 -47
- package/packages/server/src/export/csv.ts +34 -0
- package/packages/server/src/export/definition.ts +346 -0
- package/packages/server/src/export/index.ts +61 -0
- package/packages/server/src/export/run.ts +116 -0
- package/packages/server/src/index.ts +155 -0
- package/packages/server/src/jobs/index.ts +93 -0
- package/packages/server/src/jobs/runner.ts +486 -0
- package/packages/server/src/log.ts +291 -0
- package/packages/server/src/mail/config.ts +184 -0
- package/packages/server/src/mail/contracts.ts +251 -0
- package/packages/server/src/mail/index.ts +31 -0
- package/packages/server/src/mail/port.ts +101 -0
- package/packages/server/src/mail/smtp.ts +191 -0
- package/packages/server/src/mail/template.ts +105 -0
- package/packages/server/src/metrics.ts +447 -0
- package/packages/server/src/pagination.ts +246 -0
- package/packages/server/src/trace/context.ts +103 -0
- package/packages/server/src/trace/egress.ts +66 -0
- package/packages/server/src/trace/error-sink.ts +296 -0
- package/packages/server/src/trace/exporter.ts +295 -0
- package/packages/server/src/trace/index.ts +60 -0
- package/packages/server/src/trace/job-sink.ts +172 -0
- package/packages/server/src/trace/tracer.ts +338 -0
- package/packages/server/src/web.ts +5 -1
- package/packages/storage/package.json +40 -0
- package/packages/storage/src/config.ts +189 -0
- package/packages/storage/src/content-type.ts +124 -0
- package/packages/storage/src/contracts.ts +112 -0
- package/packages/storage/src/envelope.ts +189 -0
- package/packages/storage/src/index.ts +43 -0
- package/packages/storage/src/local.ts +75 -0
- package/packages/storage/src/port.ts +251 -0
- package/packages/storage/src/read-token.ts +130 -0
- package/packages/storage/src/s3.ts +144 -0
- package/packages/storage/src/scanner.ts +22 -0
- package/packages/storage/src/sigv4.ts +104 -0
- package/packages/storage/src/store.ts +13 -0
- package/packages/ui/package.json +1 -0
- package/packages/ui/src/components/Button.tsrx +3 -0
- package/packages/ui/src/components/ConfirmDialog.tsrx +13 -2
- package/packages/ui/src/components/DateField.tsrx +92 -0
- package/packages/ui/src/components/DatePicker.tsrx +525 -0
- package/packages/ui/src/components/DateRangeField.tsrx +93 -0
- package/packages/ui/src/components/Drawer.tsrx +10 -1
- package/packages/ui/src/components/FileUpload.tsrx +158 -0
- package/packages/ui/src/components/Pagination.tsrx +130 -0
- package/packages/ui/src/components/Select.tsrx +78 -0
- package/packages/ui/src/components/Table.tsrx +498 -81
- package/packages/ui/src/components/Tabs.tsrx +53 -0
- package/packages/ui/src/components/ToastHost.tsrx +48 -0
- package/packages/ui/src/components/calendar.ts +243 -0
- package/packages/ui/src/components/date-field.ts +62 -0
- package/packages/ui/src/components/file-upload.ts +49 -0
- package/packages/ui/src/components/focus-trap.ts +62 -0
- package/packages/ui/src/components/pagination.ts +68 -0
- package/packages/ui/src/components/table-sorting.ts +49 -0
- package/packages/ui/src/components/tabs.ts +61 -0
- package/packages/ui/src/components/toast-store.ts +116 -0
- package/packages/ui/src/icons/Icon.tsrx +5 -0
- package/packages/ui/src/index.ts +45 -0
- package/packages/ui/src/styles/components.css +598 -0
- package/modules/automations-workflows-integration/module.json +0 -27
- package/modules/automations-workflows-integration/spec/module.yaml +0 -93
- package/modules/automations-workflows-integration/src/index.ts +0 -14
- package/modules/automations-workflows-integration/src/platform.ts +0 -24
- package/modules/automations-workflows-integration/src/server/index.ts +0 -11
- package/modules/automations-workflows-integration/translations/en.json +0 -21
- package/modules/automations-workflows-integration/translations/pl.json +0 -21
- package/modules/workflows/src/services/cursor-codec.ts +0 -62
|
@@ -12,7 +12,11 @@ handoff:
|
|
|
12
12
|
- ux-designer
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
You own specification decisions and locale terminology, never implementation. Use only the Task skill selected under Session. Consult reference/packages/contracts/schemas/module-spec.schema.json and reference/example-module/spec/module.yaml when writing the spec.
|
|
15
|
+
You own specification decisions and locale terminology, never implementation. Use only the Task skill selected under Session. Consult reference/platform-capabilities.md, reference/packages/contracts/schemas/module-spec.schema.json and reference/example-module/spec/module.yaml when writing the spec.
|
|
16
|
+
|
|
17
|
+
Write schemaVersion 2: entities with typed fields and states, screens, actions, widgets, settings, agentTools, plus outOfScope and decisions. Fill decisions for every choice, including the platform defaults you proposed. The capability card is closed: anything it lists as missing goes to outOfScope with the business decision, never into a scenario. v1 specs stay valid.
|
|
18
|
+
|
|
19
|
+
When a decision is missing, end the reply with exactly one fenced block tagged questions holding {"questions":[{"id":"Q-1","question":"...","options":["..."],"recommended":"...","allowFreeText":true}]} and nothing after it. The operator answers in a form and the replies arrive next turn as a Decisions section.
|
|
16
20
|
|
|
17
21
|
For an edit, compare against base/modules/<dir>/spec/module.yaml and make the smallest delta covering the brief. Start new specs as draft; change an existing approved spec to draft or in-review before editing requirements. Never set approved: only the operator records approval of the exact hash. Later edits invalidate it.
|
|
18
22
|
|
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
|
|
3
3
|
Turn an agreed business request into `modules/<dir>/spec/module.yaml`. In the sandbox this is the first turn of a `new-module` session, taken by `business-manager`; at the repository root it is `spec-author` following `.ai/agents/spec-author.md`. The blueprint creates or revises the specification only. It never creates implementation files and never sets `status: approved`; approval belongs to a human owner (the sandbox approve button, or an edit in the pull request).
|
|
4
4
|
|
|
5
|
-
The result
|
|
5
|
+
The result is a `schemaVersion: 2` document that validates against `packages/contracts/schemas/module-spec.schema.json` (`pnpm flowdular spec validate --all --json`, including the cross checks between actions, permissions, entities and fields) and is decision complete: permissions with one read and one manage id per entity, entities with typed fields and tenant uniqueness, screens and actions, invariants for tenancy and uniqueness, data ownership, acceptance scenarios that include a denial and a tenant isolation case, `outOfScope` for everything `.ai/platform-capabilities.md` lists as missing, and `decisions` recording every choice and who made it. The procedure is the `spec-interview` skill: propose a platform default per decision and ask only what cannot be inferred, through the questions protocol described in `.ai/agents/sandbox/business-manager.md`. Unknown business decisions stay explicit questions, never guesses. `templates/module.yaml` is a starting point with the keys the schema knows. Version 1 specs stay valid for existing modules.
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
schemaVersion: 1
|
|
2
2
|
# Keys below exist in packages/contracts/schemas/module-spec.schema.json.
|
|
3
|
+
# A new specification is authored at specSchemaVersion 2: it carries the domain
|
|
4
|
+
# model, so the implementing agent reads the spec instead of the repository.
|
|
5
|
+
# An existing version 1 specification stays valid and is not rewritten.
|
|
6
|
+
specSchemaVersion: 2
|
|
3
7
|
status:
|
|
4
8
|
initial: draft
|
|
5
9
|
allowed:
|
|
@@ -22,14 +26,54 @@ requiredKeys:
|
|
|
22
26
|
- permissions
|
|
23
27
|
- dataOwnership
|
|
24
28
|
- acceptanceScenarios
|
|
29
|
+
- decisions
|
|
30
|
+
- outOfScope
|
|
31
|
+
byCapability:
|
|
32
|
+
database:
|
|
33
|
+
entities: at least one, with every persisted field typed and one field unique inside the tenant
|
|
34
|
+
client:
|
|
35
|
+
screens: at least one list screen whose columns and filters are field ids of its entity
|
|
36
|
+
api:
|
|
37
|
+
actions: one per mutation, each naming a permission the spec declares
|
|
25
38
|
identifiers:
|
|
26
39
|
id: ^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)+$
|
|
27
40
|
permissions: <module>.<entity>.read and <module>.<entity>.manage
|
|
28
41
|
acceptanceScenarios: ^[A-Z][A-Z0-9-]+$
|
|
42
|
+
entities: ^[a-z][a-z0-9-]*$
|
|
43
|
+
fields: ^[a-z][a-zA-Z0-9]*$
|
|
44
|
+
screens, actions, widgets: ^[a-z][a-z0-9-]*$
|
|
45
|
+
settings: ^[a-z][a-zA-Z0-9]*$
|
|
46
|
+
agentTools: <module>.<entity>.<verb>, the dotted tool identity the registry uses
|
|
47
|
+
decisions: ^[A-Z][A-Z0-9-]+$
|
|
48
|
+
entities:
|
|
49
|
+
fieldTypes:
|
|
50
|
+
- string
|
|
51
|
+
- text
|
|
52
|
+
- integer
|
|
53
|
+
- decimal
|
|
54
|
+
- boolean
|
|
55
|
+
- date
|
|
56
|
+
- datetime
|
|
57
|
+
- enum
|
|
58
|
+
- reference
|
|
59
|
+
- json
|
|
60
|
+
rules:
|
|
61
|
+
- an enum field declares values; a reference field names an entity of this
|
|
62
|
+
spec or <moduleId>.<entityId> of a declared dependency
|
|
63
|
+
- 'the first entity drives the scaffold: fields become the domain type, the
|
|
64
|
+
0001 migration columns, the repository mapping and the create input'
|
|
65
|
+
- states.field names the enum field that declares exactly states.values
|
|
66
|
+
- no field is called id, tenantId or createdAt; every tenant table owns them
|
|
67
|
+
- no field is a PostgreSQL reserved word such as order, user, group or end
|
|
29
68
|
acceptanceScenarios:
|
|
30
69
|
minimum: 3
|
|
31
70
|
mustInclude:
|
|
32
71
|
- denial
|
|
33
72
|
- tenant isolation
|
|
73
|
+
decisions:
|
|
74
|
+
policy: every answered question is recorded, decidedBy user when the operator
|
|
75
|
+
answered and default when a platform default was applied instead
|
|
76
|
+
outOfScope:
|
|
77
|
+
policy: what the business excluded, and what the platform does not provide yet
|
|
34
78
|
openQuestions:
|
|
35
79
|
policy: stay in the handoff message; never guessed into the file
|
|
@@ -2,17 +2,17 @@ schemaVersion: 1
|
|
|
2
2
|
steps:
|
|
3
3
|
- id: collect
|
|
4
4
|
role: business-manager
|
|
5
|
-
action: Validate the brief against input.schema.json (module id, outcome, actors); list the
|
|
6
|
-
inputs: [brief]
|
|
7
|
-
outputs: [open questions]
|
|
5
|
+
action: Validate the brief against input.schema.json (module id, outcome, actors); walk the spec-interview decision checklist against .ai/platform-capabilities.md, propose a platform default for every decision and list the ones that cannot be inferred.
|
|
6
|
+
inputs: [brief, platform-capabilities.md]
|
|
7
|
+
outputs: [proposed decisions, open questions]
|
|
8
8
|
- id: ask
|
|
9
9
|
role: business-manager
|
|
10
|
-
action:
|
|
10
|
+
action: Ask every unresolved decision through the questions protocol (one fenced questions block in the sandbox, the question tool in Claude Code) instead of guessing; each answer becomes a decisions[] entry.
|
|
11
11
|
inputs: [open questions]
|
|
12
12
|
outputs: [answers]
|
|
13
13
|
- id: draft
|
|
14
14
|
role: business-manager
|
|
15
|
-
action: Write spec/module.yaml from templates/module.yaml with status draft; permissions, invariants, dataOwnership, acceptanceScenarios complete.
|
|
15
|
+
action: Write spec/module.yaml (schemaVersion 2) from templates/module.yaml with status draft; permissions, invariants, dataOwnership, acceptanceScenarios, entities with typed fields, screens, actions, outOfScope and decisions complete.
|
|
16
16
|
inputs: [answers]
|
|
17
17
|
outputs: [spec/module.yaml]
|
|
18
18
|
gates: [spec-schema]
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# Replace every {placeholder}. Keys are the ones module-spec.schema.json knows;
|
|
2
2
|
# nothing else is accepted. Keep status: draft; a human approves.
|
|
3
|
-
schemaVersion
|
|
3
|
+
# schemaVersion 2 adds the domain model below, so an implementing agent never
|
|
4
|
+
# has to scan the repository. Every version 2 section is optional: delete the
|
|
5
|
+
# ones the module does not need, keep the ones it does.
|
|
6
|
+
schemaVersion: 2
|
|
4
7
|
id: '{moduleId}'
|
|
5
8
|
specVersion: 0.1.0
|
|
6
9
|
status: draft
|
|
@@ -14,9 +17,9 @@ capabilities:
|
|
|
14
17
|
- translations
|
|
15
18
|
dependencies:
|
|
16
19
|
- id: system.core
|
|
17
|
-
range: ^0.
|
|
20
|
+
range: ^0.5.0
|
|
18
21
|
- id: auth.core
|
|
19
|
-
range: ^0.
|
|
22
|
+
range: ^0.11.0
|
|
20
23
|
tenancy: required
|
|
21
24
|
locales:
|
|
22
25
|
- en
|
|
@@ -30,6 +33,99 @@ permissions:
|
|
|
30
33
|
description: Create and update {entities} in the active tenant.
|
|
31
34
|
dataOwnership:
|
|
32
35
|
- '{moduleId} owns {entity} identity and lifecycle status.'
|
|
36
|
+
# The first entity drives the scaffold: its fields become the domain type, the
|
|
37
|
+
# 0001 migration columns, the repository mapping and the create input.
|
|
38
|
+
entities:
|
|
39
|
+
- id: '{entities}'
|
|
40
|
+
name: '{Entity}'
|
|
41
|
+
description: '{what one record is}'
|
|
42
|
+
fields:
|
|
43
|
+
# type: string | text | integer | decimal | boolean | date | datetime |
|
|
44
|
+
# enum | reference | json
|
|
45
|
+
- id: '{code}'
|
|
46
|
+
type: string
|
|
47
|
+
required: true
|
|
48
|
+
unique: tenant
|
|
49
|
+
maxLength: 64
|
|
50
|
+
description: '{business identifier}'
|
|
51
|
+
- id: '{title}'
|
|
52
|
+
type: string
|
|
53
|
+
required: true
|
|
54
|
+
maxLength: 160
|
|
55
|
+
- id: status
|
|
56
|
+
type: enum
|
|
57
|
+
required: true
|
|
58
|
+
values:
|
|
59
|
+
- active
|
|
60
|
+
- archived
|
|
61
|
+
# reference: '<entityId>' in this spec, or '<moduleId>.<entityId>'
|
|
62
|
+
- id: '{ownerId}'
|
|
63
|
+
type: reference
|
|
64
|
+
reference: auth.core.users
|
|
65
|
+
states:
|
|
66
|
+
field: status
|
|
67
|
+
values:
|
|
68
|
+
- active
|
|
69
|
+
- archived
|
|
70
|
+
transitions:
|
|
71
|
+
- from: active
|
|
72
|
+
to: archived
|
|
73
|
+
permission: '{module}.{entities}.manage'
|
|
74
|
+
screens:
|
|
75
|
+
- id: '{entities}'
|
|
76
|
+
kind: list
|
|
77
|
+
entity: '{entities}'
|
|
78
|
+
title: '{Entities}'
|
|
79
|
+
columns:
|
|
80
|
+
- '{code}'
|
|
81
|
+
- '{title}'
|
|
82
|
+
- status
|
|
83
|
+
filters:
|
|
84
|
+
- status
|
|
85
|
+
navigationGroup: Operations
|
|
86
|
+
actions:
|
|
87
|
+
- id: 'create-{entity}'
|
|
88
|
+
entity: '{entities}'
|
|
89
|
+
permission: '{module}.{entities}.manage'
|
|
90
|
+
kind: create
|
|
91
|
+
risk: workspace-write
|
|
92
|
+
idempotent: false
|
|
93
|
+
description: Create a {entity} in the active tenant.
|
|
94
|
+
- id: 'archive-{entity}'
|
|
95
|
+
entity: '{entities}'
|
|
96
|
+
permission: '{module}.{entities}.manage'
|
|
97
|
+
kind: update
|
|
98
|
+
risk: workspace-write
|
|
99
|
+
idempotent: true
|
|
100
|
+
description: Archive a {entity} without deleting its history.
|
|
101
|
+
widgets:
|
|
102
|
+
- id: '{entities}-total'
|
|
103
|
+
slot: dashboard.metrics
|
|
104
|
+
entity: '{entities}'
|
|
105
|
+
description: Number of active {entities} in the active tenant.
|
|
106
|
+
settings:
|
|
107
|
+
- key: '{settingKey}'
|
|
108
|
+
type: integer
|
|
109
|
+
scope: tenant
|
|
110
|
+
default: 30
|
|
111
|
+
description: '{what the number controls}'
|
|
112
|
+
agentTools:
|
|
113
|
+
- id: '{module}.{entity}.list'
|
|
114
|
+
permission: '{module}.{entities}.read'
|
|
115
|
+
description: List {entities} of the active tenant.
|
|
116
|
+
risk: read
|
|
117
|
+
outOfScope:
|
|
118
|
+
- '{what the platform does not provide yet, for example file attachments}'
|
|
119
|
+
- '{what the business excluded, for example e-mail notifications}'
|
|
120
|
+
decisions:
|
|
121
|
+
- id: '{MODULE}-STATUS'
|
|
122
|
+
question: '{the question that was open}'
|
|
123
|
+
answer: '{the answer that was given}'
|
|
124
|
+
decidedBy: user
|
|
125
|
+
- id: '{MODULE}-RETENTION'
|
|
126
|
+
question: '{a question nobody answered}'
|
|
127
|
+
answer: '{the platform default that was applied instead}'
|
|
128
|
+
decidedBy: default
|
|
33
129
|
acceptanceScenarios:
|
|
34
130
|
- id: '{MODULE}-LIST'
|
|
35
131
|
given: Tenant-scoped {entities} exist.
|
|
@@ -28,3 +28,7 @@ gates:
|
|
|
28
28
|
command: pnpm format:check
|
|
29
29
|
sandbox: prettier --check . (cwd module)
|
|
30
30
|
required: true
|
|
31
|
+
- id: auto-review
|
|
32
|
+
command: run the auto-review skill as a separate read-only phase over the finished change
|
|
33
|
+
sandbox: inspectAutoReview(paths, module) in packages/sandbox/src/server/auto-review.ts; the record must match the current module contents, and eject refuses a missing or stale review (GATES in packages/sandbox/src/server/delivery/plan.ts)
|
|
34
|
+
required: true
|
|
@@ -44,9 +44,18 @@ byChange:
|
|
|
44
44
|
- 'src/client/XView.tsrx'
|
|
45
45
|
- 'src/client/contribution.tsrx'
|
|
46
46
|
- 'src/client/index.ts'
|
|
47
|
+
- 'translations/*.json'
|
|
48
|
+
- 'tests/module.test.ts'
|
|
47
49
|
widget:
|
|
48
50
|
- 'src/client/*.tsrx'
|
|
49
51
|
- 'src/client/contribution.tsrx'
|
|
52
|
+
- 'translations/*.json'
|
|
53
|
+
- 'tests/module.test.ts'
|
|
54
|
+
translations:
|
|
55
|
+
- 'translations/*.json'
|
|
56
|
+
- 'src/client/contribution.tsrx'
|
|
57
|
+
- 'spec/module.yaml'
|
|
58
|
+
- 'module.json'
|
|
50
59
|
permission:
|
|
51
60
|
- 'spec/module.yaml'
|
|
52
61
|
- 'src/acl/permissions.ts'
|
|
@@ -28,3 +28,7 @@ gates:
|
|
|
28
28
|
command: pnpm format:check
|
|
29
29
|
sandbox: prettier --check . (cwd module)
|
|
30
30
|
required: true
|
|
31
|
+
- id: auto-review
|
|
32
|
+
command: run the auto-review skill as a separate read-only phase over the finished change
|
|
33
|
+
sandbox: inspectAutoReview(paths, module) in packages/sandbox/src/server/auto-review.ts; the record must match the current module contents, and eject refuses a missing or stale review (GATES in packages/sandbox/src/server/delivery/plan.ts)
|
|
34
|
+
required: true
|
|
@@ -5,6 +5,10 @@ gates:
|
|
|
5
5
|
command: eject stream runs spec-schema and module-schema once, then dependencies, typecheck, tests, format per draft module
|
|
6
6
|
required: true
|
|
7
7
|
appliesTo: sandbox-eject
|
|
8
|
+
- id: auto-review
|
|
9
|
+
command: run the auto-review skill as a separate read-only phase over the finished change
|
|
10
|
+
sandbox: every draft module needs a passing auto-review record that matches its current contents; GATES in packages/sandbox/src/server/delivery/plan.ts lists it with the deterministic gates and eject stops on a missing or stale record
|
|
11
|
+
required: true
|
|
8
12
|
- id: verify
|
|
9
13
|
command: pnpm verify
|
|
10
14
|
required: true
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Platform capability card
|
|
2
|
+
|
|
3
|
+
What a Flowdular module can be built from, and what the platform does not provide yet. This card is closed: if a capability is not listed under "What a module gets", the platform does not have it, and a specification must place the request under `outOfScope` with the business decision instead of promising it.
|
|
4
|
+
|
|
5
|
+
Read this file before writing or implementing a spec. It replaces scanning `modules/` and `packages/` for the common case. When a task needs a detail this card does not carry, read the one file named here, not the tree.
|
|
6
|
+
|
|
7
|
+
## What a module gets
|
|
8
|
+
|
|
9
|
+
**Tenant identity.** Every request carries a principal resolved by `modules/auth`. `principalFromContext(octane)!.tenantId` is the only tenant authority; a tenant id from a body, query or header is a defect. Row-level security binds the same id inside the transaction.
|
|
10
|
+
|
|
11
|
+
**Authorization.** `defineEndpoint` (`packages/server/src/endpoint.ts`) takes `id`, `path`, `methods`, `handler` and `access`. `access` is either `{ kind: 'public' }` or `{ kind: 'permission', permission }` with `resolveIdentity: endpointIdentityFromContext`. A protected endpoint answers 401 `UNAUTHENTICATED` without an identity and 403 `FORBIDDEN` without the permission. Permission ids match `^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)+$` and are declared in the spec `permissions`, in `src/acl/permissions.ts` and on the endpoint. CSRF and input bounds are not endpoint options: mutations call `sessionMutationDenial(octane, auth)` first (`modules/auth/src/server/session-security.ts`) and parse the body through `readJsonObject`, `requiredString`, `optionalString`, `requiredInteger` (`packages/server/src/http.ts`, 415 without JSON, 413 over 16 KB).
|
|
12
|
+
|
|
13
|
+
**Record policies.** A permission answers who may act on a kind of record; a policy answers whether this record allows it. `definePolicy` (`packages/kernel/src/acl.ts`) declares `{ id, permission, evaluate }`, where `evaluate({ principal, permission, record, action })` returns `{ allowed: true }` or `{ allowed: false, reason, requiresApproval? }`; `requiresApproval.requirement` carries `roleKey`, `scope`, `decisions` and `expiresInDays`, and nothing more: resolving a role to people, collecting their decisions and keeping the receipt belong to `approvals.core`, described below. Policies are registered into a `createPolicyRegistry()` while the module composes, at most 256, one registration per id, and the registry is sealed before requests run. An endpoint calls `authorizeRecord(registry, principal, permission, record, action?)`, which checks the permission scope first and then the policies of that permission in registration order, answering the first denial. A permission with no policy is allowed by the scope alone, and a policy that throws denies. The platform does not hand a module a shared registry yet, so a module that wants record conditions today owns its registry inside its own composition.
|
|
14
|
+
|
|
15
|
+
**List pagination.** A list endpoint pages with `readPageQuery`, `encodeCursor`, `decodeCursor`, `pageResponse` and `keysetWhere` (`packages/server/src/pagination.ts`). `readPageQuery(url, { maxLimit, defaultLimit })` answers `{ limit, cursor }`, defaults to 50, refuses a limit outside 1 to the endpoint bound with 400 `INVALID_INPUT` and a malformed cursor with 400 `CURSOR_INVALID`; the platform ceiling is 200 rows. A cursor is the keyset of the last row of the page, HMAC signed with a 32 byte secret the module owns, bounded to 1 KB, and `decodeCursor` refuses anything this server did not sign with the same `CURSOR_INVALID`. The body shape is `{ items, page: { nextCursor, limit, total? } }`, `nextCursor` is null on the last page, and `total` is only for a count that is cheap. `keysetWhere(['created_at', 'id'], values, { direction, parameterOffset })` builds the row-order predicate with bound parameters; offset paging over a tenant's rows is not a platform capability. New list endpoints use these; the list endpoints written before them still carry their own paging until their module retrofits it.
|
|
16
|
+
|
|
17
|
+
**List export.** A list endpoint that already pages with the keyset helpers becomes a CSV export by declaring one: `defineListExport({ id, label, permission, columns, page })` (`packages/server/src/export/`), where `id` is the owning module id plus the list key (`users.core.members`), `permission` is the one the list endpoint itself requires, `columns` is 1 to 64 `{ key, header, value(row) }` entries and `page(principal, cursor, limit)` is the paging the endpoint already implements. The declaration is type erased at definition time, so no row object leaves the module that produced it. A module registers its declarations while it composes, through the public capability `exports.lists.v1` (`context.capabilities.get<ExportLists>(EXPORT_LISTS_CAPABILITY)?.register(moduleId, […])`, `modules/exports`); the id must sit inside the registering module's namespace and the catalogue is sealed before the first request. `exports.core` owns the rest: `POST /api/exports/start` behind `exports.lists.manage` plus the list's own permission checked on the live principal, `GET /api/exports/jobs` and `/api/exports/jobs/:id` paged behind `exports.lists.read`, `GET /api/exports/lists` behind the same permission for the catalogue of registered lists (id, label, registering module and whether the asking principal holds that list's permission, never the permission id), which is what the Exports screen's start control offers to a reader holding `exports.lists.manage`, and `POST /api/exports/jobs/read-url` for a signed storage route minted per request, which re-checks the exported list's permission on the live principal so the file is never easier to read than the list. A poll loop on the job runner walks the pages under the requester's snapshot and writes RFC 4180 with a UTF-8 byte order mark to the storage port under `exports.core`. Neither bound truncates: over `maxRows` (default 100000) or `maxBytes` (default 50 MB, both platform settings, and the storage object ceiling of 25 MB applies underneath) the job fails with `EXPORT_ROWS_EXCEEDED` or `EXPORT_BYTES_EXCEEDED` and writes no file. A list that answers a next cursor answers at least one row with it and never the cursor it was given. Cells are written as the declaration answered them and are never rewritten, so a value beginning with `=`, `+`, `-` or `@` reaches the file as data and this module neither prefixes nor quotes it against a spreadsheet reading it as a formula; a module whose column can carry such a value neutralises it in its own `value(row)`. Jobs are held 30 days by the data class `exports.core.jobs`, whose sweep deletes the file with the row.
|
|
18
|
+
|
|
19
|
+
**PostgreSQL with forced row-level security.** A module receives a `DatabaseProvider` as `context.databases` and acquires a lease per purpose (`runtime`, `migration`, `background`, `preview`, `test`); it never sees a DSN or a pool. Every statement runs inside `database.transaction(fn, { tenantId, access })` with `access: 'read' | 'write'`; a runtime lease without a `tenantId` throws `TENANT_CONTEXT_REQUIRED`. The adapter sets `coreloom.tenant_id` transaction-locally, and each tenant table must `ENABLE` and `FORCE ROW LEVEL SECURITY` with a `USING` and `WITH CHECK` policy against it. Migrations are numbered, immutable once applied, mirrored byte for byte in `databaseMigrations`, and recorded in the `_coreloom_migrations_v2` ledger by checksum. The runtime role holds neither `SUPERUSER` nor `BYPASSRLS`. (`packages/database/src/{contracts,postgresql,migrations,provider}.ts`.)
|
|
20
|
+
|
|
21
|
+
**Background work.** A module that polls its own routing table runs one loop per job through `createJobRunner` (`packages/server/src/jobs/`), taking `{ name, intervalMs, claim, perform, heartbeat?, heartbeatEveryMs?, staleAfterMs, backoff?, batchLimit?, logger, now?, onEvent? }`. The runner owns the loop and nothing else: the timer and its `unref`, the guard that keeps two passes from overlapping, at most `batchLimit` claims per pass, per-item isolation so one failing item never stops the pass, a renewal timer that calls `heartbeat` while `perform` runs and aborts its `AbortSignal` with the stable code `CLAIM_LOST` when the fence answers false, exponential `backoff` after a pass that raised and a reset by one that did not, and `start`, `tick`, `stop`, `quiesce` and `dispose`. It opens no database handle: the table, the routing read, the claim statement with its stale window, the renewal statement and every outcome recorded stay the module's own, `claim` answering null ends the pass, and a stage that observes the abort stops without settling anything. `onEvent` is a trace hook that costs nothing when nobody listens. A composition wires it as `start`, `stop: () => runner.quiesce()` and `dispose: () => runner.dispose()`; `import.core` is the first adopter and `packages/server/src/jobs/index.ts` carries the recipe for the rest.
|
|
22
|
+
|
|
23
|
+
**Module settings.** `defineModuleSettings` (`packages/kernel/src/module-settings.ts`) declares `{ moduleId, settings }`. A setting has `type: 'string' | 'number' | 'boolean'`, `defaultValue`, `visibility: 'private' | 'shared'`, `client: boolean`, and optionally `kind: 'flag'`, `scope: 'platform' | 'tenant'`, `secret`, `labelKey`, `descriptionKey`, `label`, `description`, `enum` (string type only), `min`, `max`, `pattern`, `multiline`. Keys match `^[a-z][a-zA-Z0-9]*$`. The allowed-values field is `enum`, not `values`. A `secret` setting can be neither `client: true` nor `visibility: 'shared'`. Values are read live with `context.settings.get(tenantId, moduleId, key)` and edited in Administration, Modules behind `system.settings.read` and `system.settings.manage` (`GET /api/settings`, `POST /api/settings/update`, `modules/system/src/server/endpoints.ts`). A read needs the tenant primed first (`await context.settings.prime(tenantId)`): the authenticated request path and the platform composition prime, a background path primes itself, and `set` is awaited.
|
|
24
|
+
|
|
25
|
+
**Feature flags.** A flag is a module setting declared `kind: 'flag'`: a non-secret `boolean` with a `defaultValue`, a `label`, a `description` and `scope: 'tenant'`, which is the default and the only scope a flag may take; `defineModuleSettings` refuses anything else, a platform-scoped flag included. There is no flag store, no flag endpoint and no flag registry. A module reads one on the request path with the ordinary settings read, `context.settings.get<boolean>(tenantId, moduleId, key)`: a lookup of the declaration, a lookup of the cached per `(tenant, module)` value set under a key the read builds, the touch that keeps that entry at the head of the cache, the property read and one `typeof` check. No query of its own, and nothing beyond what any setting already costs: a declared `pattern` is compiled once with the declaration, never per read. There is deliberately no `context.flags`; the read is the settings read, and the module id is the one the module already knows. An override is per workspace behind `system.settings.manage` on the Flags tab of Administration, Modules, which groups every declared flag by its owning module and links the audit trail. Every change appends one `settings.flag.changed` auth audit event with the module, the key, the previous and next values and the actor (`settings.updated` stays the event for every other setting). No percentage rollout and no targeting: a flag is on or off for a workspace.
|
|
26
|
+
|
|
27
|
+
**Navigation groups.** A navigation contribution picks exactly one group (`NavigationGroup`, `packages/client/src/contributions.ts`):
|
|
28
|
+
|
|
29
|
+
<!-- capabilities:navigation-groups -->
|
|
30
|
+
|
|
31
|
+
`Workspace`, `Operations`, `Agents`, `Automations`, `Administration`, `Development`
|
|
32
|
+
|
|
33
|
+
<!-- /capabilities:navigation-groups -->
|
|
34
|
+
|
|
35
|
+
**Workspace slots.** A widget contribution targets exactly one slot (`WORKSPACE_SLOTS`, same file):
|
|
36
|
+
|
|
37
|
+
<!-- capabilities:workspace-slots -->
|
|
38
|
+
|
|
39
|
+
`dashboard.metrics`, `dashboard.main`, `dashboard.aside`, `topbar.actions`
|
|
40
|
+
|
|
41
|
+
<!-- /capabilities:workspace-slots -->
|
|
42
|
+
|
|
43
|
+
**Account menu.** A view reached from the avatar menu rather than the sidebar, for anything owned by the person instead of the workspace: `accountMenu` entries carry `id`, `viewId`, `label`, `description`, `glyph`, `scope`, `order`.
|
|
44
|
+
|
|
45
|
+
**Agent tools registry.** A module registers tools during `createServerComposition` with `context.agentTools.register(tools)`. A tool is built by `defineApiAgentTool` (wraps one `endpointId`) or `defineCliAgentTool` (wraps one CLI `capability`) from `packages/harness/src/tool-adapters.ts` and declares `id`, `description`, `requiredPermissions`, `inputSchema`, `outputSchema`, `contractVersion`, `risk: 'read' | 'workspace-write' | 'external' | 'destructive'`, `idempotency`, `idempotencyProtection: 'target-ledger'`, `cancellation`, `timeoutMs`. A CLI capability with risk `external` or `destructive` cannot become an unattended agent tool.
|
|
46
|
+
|
|
47
|
+
**Business agents.** `defineAgent` (`modules/agents/src/server/define-agent.ts`) declares `moduleId`, `key`, `definitionRevision`, `name`, `description`, `instructions`, `allowedTools` (at most 32, exact ids, no wildcards) and `limits` (`maxSteps` 1 to 32, `timeoutMs`, `temperature`, `maxOutputTokens`). Registered with `context.agentDefinitions.register(...)`. The definition owns behaviour and the maximum tool ceiling; provider, model, credentials, active state and the reduced enabled tools are tenant binding data.
|
|
48
|
+
|
|
49
|
+
**Workflows.** `workflows.core` owns typed DAGs with exactly nine node kinds (`modules/workflows/src/domain/types.ts`): `input`, `agent`, `agent-decision`, `gate`, `validator`, `action`, `merge`, `output` and `human-approval`, which opens an approvals.core request with the run as subject, parks the run in `waiting-approval` and resumes on approval or fails it with `WORKFLOW_APPROVAL_REJECTED`, `WORKFLOW_APPROVAL_EXPIRED` or `WORKFLOW_APPROVAL_CANCELLED`; publishing such a node needs approvals.core present and the named role defined in the workspace. A module starts a run through the public `WORKFLOW_EXECUTION_CAPABILITY`; workflow trigger sources are `manual`, `module`, `schedule` and `webhook`.
|
|
50
|
+
|
|
51
|
+
**Automations triggers.** Two mechanisms in `automations.core`. A schedule uses a cadence string in one of two forms (`modules/automations/src/domain/cadence.ts`): `every:N`, where `N` is whole minutes from 1 to 10080 and the unit is implicit, or `cron:<minute> <hour> <day of month> <month> <day of week>`, five fields with no seconds, at most 100 characters, each field `*`, a number, a three letter month or weekday name, a list, a range, or any of those with a step (`*/15`, `9-17/4`); both day fields restricted means either matches. A cron slot is a wall clock time in the workspace zone from the shared `system.core.timeZone` setting, stored in UTC; a wall time a daylight saving change removes is skipped and one that occurs twice fires at the first of the two. An expression the module cannot honour is refused at save with `INVALID_CADENCE`. Missed slots are skipped, never replayed. An inbound webhook posts to `POST /api/automations/triggers/:id/fire`, authenticated by an HMAC signature in `x-flowdular-signature` with `x-flowdular-timestamp` inside a 5 minute window and a 16 KB body cap, answering `202 { accepted, runId }`. Targets are pluggable through `automations.targets.v1`; the shipped kinds are `agent` and `workflow`.
|
|
52
|
+
|
|
53
|
+
**CLI extensions.** A module contributes `pnpm flowdular <namespace> <action>` through `src/cli/commands.json` plus `defineCliExtension` (`packages/cli-protocol/src/index.ts`), declared in `module.json` under `cli`. The first path segment must equal the module id's first segment and may not be a reserved group (`help`, `doctor`, `capability`, `spec`, `blueprint`, `module`, `migration`, `setup`). Each command carries a `CapabilityDescriptor` with `id`, `version`, `summary`, `risk: 'read' | 'workspace-write' | 'process' | 'external' | 'destructive'`, `requiresApprovedSpec`, `supportsDryRun`, optional `localOnly` and `confirmation`. The runner refuses `external` always and non-local `destructive` always, gates `localOnly` to `development` and `test`, and treats every write command as a dry run without `--apply`.
|
|
54
|
+
|
|
55
|
+
**Translations.** The shipped locales are `en` and `pl`. A module keeps a flat bundle per locale in `translations/<locale>.json`, imports them in `src/client/contribution.tsrx` and returns `translations: { en, pl }`. Keys resolve fully qualified as `<first module segment>.<key>` through `t()`. `flowdular module validate` reports `TRANSLATION_FILE_MISSING`, `TRANSLATION_PARSE_ERROR`, `TRANSLATION_KEYS_MISMATCH` and `TRANSLATION_KEY_MISSING`.
|
|
56
|
+
|
|
57
|
+
**Web surfaces.** A module may own public, server-rendered website pages separate from the authenticated shell (`packages/server/src/web.ts`). `defineWebSurface` declares `{ id, pages }` with at most 128 pages; a page has `id`, `path`, `entry`, optional `layout`, a `load` function and `access`, which is one of `{ kind: 'public' }`, `{ kind: 'authenticated' }` or `{ kind: 'permission', permission }`. The operator, not the module, mounts a surface at a tenant-scoped path; `setup`, `health`, `ready`, `assets`, `app`, `api`, `auth`, `sign-in`, `sign-up`, `forgot-password`, `reset-password` and `accept-invitation` are reserved.
|
|
58
|
+
|
|
59
|
+
**Public capabilities registry.** Cross-module access goes through `context.capabilities.register(id, value)` in the owning module and `context.capabilities.get<T>(id)` in the consumer (`packages/kernel/src/capability-registry.ts`). The owning module lists the id under `provides` in `module.json`; the consumer lists it under `requires` (`{ "id", "optional": true }` when it handles a null `get`). The composition gives each module a registry view that accepts only its declared ids, the kernel orders required providers first and refuses a missing provider, and the installer resolves a required capability to a release that provides it. A type import from the provider's package still needs the module and package dependency (`"range": "^0.11.0"`). A module never opens another module's database or imports its `src/` path.
|
|
60
|
+
|
|
61
|
+
**Notifications.** `notifications.core` (optional, enabled by default) owns a per-member in-app inbox with preferences, per-tenant outbound webhook subscriptions signed with the inbound automations scheme, and e-mail delivery of inbox items, all three sharing one delivery ledger with bounded retry and a dead letter. A module publishes through the public capability `notifications.publish.v1` obtained lazily with `context.capabilities.get` and tolerates its absence; the input is `{ tenantId, kind, sourceModule, sourceRef, title, body?, recipients }` with the kinds `agent-run-completed`, `agent-run-failed`, `workflow-run-completed`, `workflow-run-failed`, `webhook-dead-letter` (`modules/notifications/src/domain/publish.ts`). A new kind is a `notifications.core` spec edit, not a publisher's decision. A publisher never chooses a channel: the member does, with the per-kind switch that decides whether an item exists at all and the `emailDelivery` switch (off by default) that also mails the items they receive, through the platform mail port and the address `auth.core` holds. `ToastHost` and `toasts` remain the in-screen confirmation for what the reader just did.
|
|
62
|
+
|
|
63
|
+
**Mail.** A module sends through `context.mail` (`packages/server/src/mail/`) and never selects a transport, a relay or a provider SDK. `send({ to, subject, text, html?, locale?, headers? })` takes at most 16 recipients, a 200 character single-line subject, 64 KB of text, 256 KB of HTML and 16 extra headers whose names the envelope does not own; CR and LF are refused everywhere a header could be opened, so header injection is the port's problem and not each sender's. It rejects with a `MailError` carrying `MAIL_NOT_CONFIGURED` (no transport composed), `MAIL_MESSAGE_REJECTED` (a bound) or `MAIL_DELIVERY_FAILED` (the relay, whose words never travel with it); `mail.configured` is the flag a feature gates on instead of provoking a refusal. `renderMailTemplate({ subject, text, html? }, values)` fills `{{ name }}` holes in one pass and escapes every value for the HTML part. The deployment picks the adapter with `FD_MAIL_TRANSPORT`: `none` (refuses), `development` (an in-memory outbox of the last 100 messages, refused in production) or `smtp` (`FD_MAIL_SMTP_URL`, `FD_MAIL_FROM`; the retired `FD_AUTH_MAIL_*` names still work with a deprecation line). `auth.core` sends invitations, resets and confirmations through it, `notifications.core` mails inbox items; a module that wants to reach a person publishes a notification rather than composing mail of its own.
|
|
64
|
+
|
|
65
|
+
**Object storage.** A module writes files through `context.storage` (`packages/storage/src/index.ts`) and never sees an adapter, a bucket or a path. `put`, `get`, `delete`, `stat` and `readUrl` take `{ tenantId, moduleId, objectId }`; the key is `<tenantId>/<moduleId>/<objectId>` and the tenant id comes from the principal, never from the request, because no row-level security reaches an object store. Development and test use a local directory, a deployment uses an S3-compatible bucket (`FD_STORAGE_ADAPTER=local|s3`, `local` refused in production). Every object is encrypted with AES-256-GCM under `FD_STORAGE_ENCRYPTION_KEY` before it is written, with the key id and the metadata authenticated alongside it. An object is at most 25 MB (`FD_STORAGE_MAX_OBJECT_BYTES`) and must be one of PDF, PNG, JPEG, GIF, WebP, plain text, CSV, `.docx`, `.xlsx`, `.pptx`, `application/msword` or `application/vnd.ms-excel`, verified against the bytes; archives and executables are refused. A malware scanner is a deployment seam, so the stored verdict is `clean`, `infected` (refused) or `unscanned` (the default). `readUrl` returns `/api/storage/objects/<token>`, a signed platform route that expires in at most an hour and streams the decrypted body as an attachment, never a presigned URL to the ciphertext. Upload, metadata and the attachment table belong to `documents.core`, described next; a module never puts bytes of its own through `context.storage` when a document fits.
|
|
66
|
+
|
|
67
|
+
**Connectors.** `connectors.core` (optional) is the governed way out to an external system. A module ships a connector definition through the public capability `connectors.definitions.v1` (`modules/connectors/src/domain/definitions.ts`): `register({ key, moduleId, label, authKinds, operations: [{ key, label, method, path, inputSchema, outputSchema }], defaultAllowedHosts, allowedPorts? })` (ports default to 443 only), and the platform ships `http-json`. An owner creates an instance behind `connectors.instances.manage` with a base URL, sealed credentials under `FD_CONNECTORS_SECRET_KEY`, a host allowlist and two consent flags, `allowWorkflows` and `allowAgents`, both off. A call goes through `connectors.calls.v1`: `call({ tenantId, instanceId, operation, input, caller: 'test' | 'workflow' | 'agent', callerRef? })`, which enforces status, consent for that caller kind, the egress policy (https, no private addresses, no redirects, timeout and size caps) and logs the call without any body; `consented(tenantId, instanceId, caller)` answers admission alone. The agent tool `connectors.call` is declared `workspace-write` with the harness consent gate `connectors.instance-consent` (`AgentToolConsent` in `packages/harness/src/runtime.ts`), carries the full action contract (`idempotency: 'required'` backed by a per-call key ledger) so workflows may use it, has no HTTP route of its own, and dials only the addresses the egress policy verified, so the ceiling is raised per instance by the owner's consent, never by a declaration.
|
|
68
|
+
|
|
69
|
+
**Approvals.** `approvals.core` (optional) turns a policy's `requiresApproval` into a request people decide. A module opens one through the public capability `approvals.requests.v1` (`modules/approvals/src/domain/capability.ts`): `open({ tenantId, subjectModule, subjectRef, permission, action, title, summary?, requesterAccountId, requirement, onResolved? })`, plus `get`, `list` and `cancel`. Eligible deciders are resolved at open from the requirement's role key and scope (both, when both are named; the requester never decides), re-read at decision time, and a request needs `decisions` approvals before `expiresInDays` runs out. Open is idempotent per subject while a request is pending, and a requirement that resolves to nobody, to too few or to more than 200 deciders is refused with a stable code. Decisions are an append-only ledger behind `approvals.requests.read`, `approvals.requests.decide` and `approvals.requests.manage`; deciders and requesters are notified through the kinds `approval-requested` and `approval-decided`. The subject module learns the outcome from `onResolved`, which runs once per terminal state after the deciding transaction commits, or by reading the request back.
|
|
70
|
+
|
|
71
|
+
**Documents.** `documents.core` (optional) owns file attachments of any record. A screen uploads through `POST /api/documents/upload` with the raw body and the headers `x-document-filename`, `x-document-owner-module`, `x-document-record-ref` and `x-document-description`, lists with `GET /api/documents?ownerModule=&recordRef=`, opens through `POST /api/documents/read-url` (a short-lived storage URL) and deletes through `POST /api/documents/delete`, all behind `documents.files.read` or `documents.files.manage` with CSRF first. A module reads its own records' attachments through the public capability `documents.attachments.v1` (`modules/documents/src/domain/attachments.ts`): `list(tenantId, ownerModule, recordRef)`, `open(tenantId, ownerModule, recordRef, id)` answering `{ contentType, bytes, filename, body }` or null for anything not readable (unknown, another pair, deleted, infected) and `delete(tenantId, ownerModule, recordRef, id)`; the reference pair is a scope, the caller's permission on its own record is the authorization, and the storage key never leaves documents.core. Checksums, scan verdicts and the object limits come from the storage port.
|
|
72
|
+
|
|
73
|
+
**Directory and SCIM.** `directory.core` (optional) gives a workspace a SCIM 2.0 endpoint at `/api/scim/v2/:workspace` (Users and Groups) authenticated by a workspace SCIM token an owner creates through `POST /api/directory/tokens`, group mappings paged through `GET /api/directory/groups` with the role keys from `GET /api/directory/groups/context`, and a provisioning ledger at `GET /api/directory/provisioning-events`. Deprovisioning disables the membership through users.core; no password ever crosses SCIM. A module does not talk to SCIM; it reads memberships through users.core as before.
|
|
74
|
+
|
|
75
|
+
**Metering.** `metering.core` (optional) counts what a workspace consumes. A module declares meters at composition through the public capability `metering.meters.v1` (`modules/metering/src/domain/meters.ts`): `declare(moduleId, [{ key, label, unit, kind }])`, and at run time `record({ tenantId, meter, amount, at?, sourceRef? })`, idempotent per source reference and written by metering.core in its own tenant transaction, and `check({ tenantId, meter, amount })` answering `allowed`, `warning` or `refused` against the operator's monthly limit; a refusal carries the stable code `METER_LIMIT_EXCEEDED` and the caller records it in its own trail. Usage screens are behind `metering.usage.read`; limits are set only by the operator with `pnpm flowdular metering limits set`.
|
|
76
|
+
|
|
77
|
+
**Import.** `import.core` (optional) brings CSV rows into a module's records through a port the module registers at composition with the public capability `import.ports.v1` (`modules/import/src/domain/ports.ts`, re-exported from `@flowdular/module-import`): `register(moduleId, [{ key, label, permission, fields: [{ id, label, required, type }], naturalKey, validate({ tenantId, principal, rows }), write({ tenantId, principal, rows, mode }) }])`. Rows arrive as `{ row, values }` with unmapped columns absent; `validate` returns refusals only, `write` answers one outcome per row (`created`, `updated`, `skipped`, `failed`) under the mode `create-only`, `update-existing` or `skip-existing`, in batches of at most `batchSize` inside the port's own tenant transaction, and a row it says nothing about is failed with `PORT_SILENT`. The CSV is a document stored through `documents.core`; jobs, per-row outcomes and saved mappings live behind `import.jobs.read` and `import.jobs.manage`, the target's own manage permission is checked on the live principal at start and continue, and the poll loop parses and writes a job in bounded batches. `users.core.members` is the first target.
|
|
78
|
+
|
|
79
|
+
**Search.** `search.core` (optional) merges record hits from providers each module registers at composition through the public capability `search.providers.v1` (`modules/search/src/domain/providers.ts`): `register(moduleId, [{ key, label, permission, search({ tenantId, principal, query, limit, cursor?, signal? }) }])`, where `search` runs over the owner's own tables inside the owner's own tenant transaction and answers `{ hits: [{ ref, title, snippet, viewId, route, score }], nextCursor }`. `GET /api/search?q=` behind `search.records.read` fans out with a per-provider time budget, drops the providers whose permission the principal lacks, names the ones that timed out, answers a signed `page.nextCursor` a client sends back to page further, keeps the query in the member's recall only when the request carries `remember=1` (a deliberate submit, never a debounced prefix), and the command palette shows hits below navigation through the `commandSearch` client contribution (`@flowdular/client`), whose optional `onOpen(hit)` the shell calls on the contribution that answered with the opened hit, once, without awaiting it and with a throw or a rejection isolated, so search.core keeps that hit's query in recall while the record is already opening. search.core holds no index; a provider owns its index or its bounded scan.
|
|
80
|
+
|
|
81
|
+
**Reports.** `reports.core` (optional) composes one workspace report out of the rollups other modules already hold. A module registers a provider at composition through the public capability `reports.v1` (`modules/reports/src/domain/providers.ts`): `register(moduleId, [{ key, label, permission, read({ tenantId, principal, range: { from, to }, signal? }) }])`, where `read` runs over the owner's own rollup inside the owner's own tenant transaction and answers `{ tiles: [{ key, label, value, unit?, delta? }], series?: [{ key, label, points: [{ at, value }] }] }`. The registry is bounded to 64 providers per deployment and an answer to 16 tiles, 8 series and 400 points, and it is sealed when reports.core starts. `GET /api/reports?from=&to=` behind `reports.workspace.read` (owners; the scope is not a member scope) resolves the range as two inclusive UTC days, defaulting to the last 30 days and bounded to 400, refuses a reversed or malformed one with `INVALID_RANGE` before any call, drops the providers whose permission the principal lacks without naming them, fans out in parallel under a per-provider time budget (the platform setting `reports.core.providerTimeoutMs`, 3000 ms by default) and names the ones that failed, timed out or answered past a bound in `unavailable`. The Reports screen in Administration renders tiles with `Kpi` and series with `Chart`, and the `reports-summary` widget on `dashboard.metrics` shows the three largest tiles. reports.core owns no table and declares an empty data class list; the shipped providers are `metering.usage` (this month per meter, the monthly limit carried as the unit's context) and `agents.runs` (runs and tokens per day over the range).
|
|
82
|
+
|
|
83
|
+
**Access review.** `access.core` (optional) answers who holds what in one workspace and what changed, reading auth.core live and storing only the attestation that someone reviewed it. `GET /api/access/review` behind `access.review.read` (owners; neither scope is a member scope) lists memberships with their account and workspace status, their role and the scopes held beyond that role, the usable API tokens by label, prefix and scopes, and the identity providers with their joining rules, with exact counts beside listings capped at 500 members, 100 roles, 200 tokens and 50 providers. `GET /api/access/diff?from=&to=` and `GET /api/access/activity?from=&to=` read the platform audit trail over two inclusive UTC calendar dates, at most 366 days apart, refusing a reversed or malformed range with `RANGE_REVERSED`, `RANGE_TOO_LONG` or `INVALID_INPUT` before any read; the diff answers the changes that move access (membership, role, scope, token, provider) and the activity report adds the administrative ones (settings, flags, password and MFA resets, workspace changes). Both walk at most 8 pages of 100 events per request and answer a signed cursor for the rest, so a client pages rather than a request scanning a whole trail. `POST /api/access/attest` behind `access.review.manage` (CSRF first) appends one row to the append-only `access_attestations` ledger with the period, the note and the counts the server recomputed itself, never counts from the body, and `GET /api/access/attestations` pages it newest first; the data class `access.core.attestations` is kept, exportable and not erasable, and both lists are registered with `exports.lists.v1` when exports.core is present. The screens are Review, Access activity and Attestations in Administration. Not covered: which member is bound to which identity provider (auth.core exposes no read of that), and holds and erasures, which live in audit.core's own trail.
|
|
84
|
+
|
|
85
|
+
**Audit, retention, holds and erasure.** `audit.core` (optional, enabled by default) reads the data class registry below for the Data classes screen (`GET /api/audit/data-classes`, `POST /api/audit/data-classes/set-retention` behind `audit.retention.manage`), runs the one retention sweep on the platform loop with tenant-scoped periods and a backup guard (`FD_AUDIT_BACKUP_MANIFEST`), and exports a workspace on request: `pnpm flowdular audit export --workspace --output [--apply]` records the request and the running platform writes the archive into `FD_AUDIT_EXPORT_DIRECTORY`. Its own trail is hash chained and serialized per workspace; `audit seal --workspace --output [--apply]` closes a segment into JSON Lines with an anchor signed under `FD_AUDIT_ANCHOR_KEY`, `audit verify --workspace --input` checks a workspace's segments and chain, and a sealed event is swept only once its segment file exists. Legal holds (`audit.holds.manage`, owners, for listing as well as placing and lifting; `audit holds list|place|lift` for the operator) cover an account, a workspace, a class or a date range; a held class is skipped by the sweep and refused by erasure with `HOLD_ACTIVE`. Erasure is `pnpm flowdular audit erase --workspace --account --output [--apply --confirm erase-subject] [--destroy-key]`, performed by the platform loop within a day of the request: it walks every declared data class, calls the class's optional `erase({ tenantId, subject: { accountId }, limit })` (answering `{ removed, redacted?, truncated? }`) and `count?({ tenantId, subject })`, names a class without `erase` as not erasable, and writes a JSON certificate marked complete or partial; audit events themselves are excluded from erasure and sealed per subject so `--destroy-key` makes their subject fields unreadable. A module contributes its data class declaration and, when it holds personal data, `erase` and `count` on that declaration.
|
|
86
|
+
|
|
87
|
+
**Data classes.** A module that owns rows declares them while it composes with `context.dataClasses.declare('<module id>', classes)` (`packages/kernel/src/data-class-registry.ts`). A declaration carries `key` (`^[a-z][a-z0-9-]*$`, the class id is `<module id>.<key>`), `label`, `defaultRetentionDays` (1 to 36500 or null for kept until a person deletes; zero is refused), `exportable`, `excludedReason` when it is not, and four optional operations the owner runs on its own tables under its own tenant transaction: `sweep({ tenantId, cutoff, limit })` answering `{ removed }`, `export({ tenantId, sink })` writing rows through `sink.write(row)` and answering `{ rows, from, to }`, `erase({ tenantId, subject: { accountId }, limit })` answering `{ removed, redacted?, truncated? }` and `count({ tenantId, subject })` answering a number or null. `removed` is rows the erasure took out and `redacted` is rows it kept but stripped of the subject, for a class whose row cannot go, such as an append-only ledger; both are non-negative integers, the erasure loop counts them together as the batch's progress, so a class that only redacts is asked again until it is done, and the certificate carries both. A module that owns no class declares an empty list, so a workspace sees it holds none. At most 64 classes per module, one declaration per module, and the platform seals the registry after every composition ran: a later `declare` throws. `list()` answers the whole catalogue from any module's view. audit.core reads it for the retention screens, the one retention sweep and the per-workspace export, and never opens another module's database; a class without a sweep is never swept and one without an export is named in the export manifest as excluded.
|
|
88
|
+
|
|
89
|
+
**Health and readiness.** `GET /api/health` is static and public. `GET /api/ready` checks the database provider and answers 503 with `retry-after: 1` when it is unavailable (`platform/src/server/health.ts`).
|
|
90
|
+
|
|
91
|
+
**Metrics.** Every request served through `defineEndpoint` is counted and timed in process by `serverMetrics()` (`packages/server/src/metrics.ts`), bounded to 2000 label sets per series family. Exposing them is opt-in and the operator's decision, never the module's: `platform/src/server/metrics.ts` composes `GET /api/metrics` (Prometheus text exposition 0.0.4) only when `FD_METRICS=true`, and answers 401 without `Authorization: Bearer <token>` when `FD_METRICS_TOKEN` is set. Labels carry the endpoint id, the method and the status class, never a request path, tenant or session. A module owns counters and histograms of its own through `context.metrics`, the binder the generated composition already bound to its module id (`createModuleMetrics('<module id>')` builds the same one outside a composition): `counter(name, labels?)` adds one to `flowdular_module_<module id>_<name>_total` and `histogram(name, value, labels?)` observes into `flowdular_module_<module id>_<name>` with the request duration buckets (seconds, 0.005 to 10). The module id is lower-cased and every character outside `a-z0-9_` becomes `_`, so `agents.core` reads `flowdular_module_agents_core_`. A metric name matches `^[a-z][a-z0-9_]{0,63}$`, a call carries at most 8 labels whose names match the same shape, a label value is cut at 128 characters, a family holds at most 2000 label sets and a process opens at most 256 module families per kind; every refusal is counted in `flowdular_metrics_dropped_samples_total` and never raises into the module's work. Module series are exposed on the same `/api/metrics` behind the same token (`docs/operations.md`, Metrics). There is still no gauge.
|
|
92
|
+
|
|
93
|
+
**Tracing.** Every request served through `defineEndpoint` carries a W3C trace context: the caller's `traceparent` when it sent a usable one, a new root otherwise, returned in the response `traceparent` header, present on the handler as `context.trace` and ambient for everything the handler awaits. The logger writes `traceId` and `spanId` on every line inside that scope, so a log search and a trace search answer with the same ids. A module reads the ambient trace with `currentTrace()`, captures it as a header value with `currentTraceParent()` to store on a row it enqueues, and resumes it by handing that value back as `traceparent` when it starts its own span; a row without one is a new root. `resumeJobTrace(tracer, traceparent, name, work)` is that resumption in one call: it opens the span from the stored header, keeps the trace ambient across every await inside `work`, ends the span on the outcome and rethrows what `work` threw, so a background stage and the request that enqueued it share one trace id (`import.core` performs every claimed job through it). `context.tracer` is the tracer of the process (`serverTracer()` outside a composition), and `startSpan(name, { parent?, traceparent?, kind?, attributes?, startedAt? })` answers a span with `setAttribute` and an idempotent `end(status?, message?, endedAt?)`; without a parent or a header it nests under the ambient trace. Spans land in one bounded in-process ring (`TRACE_LIMITS`): 4096 spans, oldest evicted and counted, at most 16 attributes per span and 256 characters per name, key and string value. `createJobTraceSink()` turns a job runner's `onEvent` stream into one span per pass plus one per performed, failed or lost item; a failed item has no duration in the event, so its span is recorded at the instant the runner reported it and the pass span bounds it. Every platform job runner installs it, so a module that passes an `onEvent` of its own is the one case that records no pass spans. The harness takes an optional `tracer` and wraps every provider call and every tool call, including a denial, with the failure code as the span message; `agents.core` hands it the tracer of the process, so an agent run is spans without a module asking for them. Export is the operator's decision and never runs on a request path: `FD_TRACE_EXPORTER=otlp` with `FD_TRACE_OTLP_URL` posts OTLP/HTTP JSON in batches of 512 spans or every 5 seconds, retries a batch at most 3 times and then drops it, and refuses a non-https collector in production. `FD_TRACE_SAMPLE` (0 to 1, default 1) decides a root on its trace id; an unsampled trace still propagates its header. A logged error is also reported through `FD_ERROR_SINK=webhook` with `FD_ERROR_SINK_URL` and an optional `FD_ERROR_SINK_TOKEN` bearer credential: identities only (name, message, endpoint, module, request id, trace id), never a stack, log fields or a credential, bounded to 64 queued reports, 32 per request and 8 KiB per body (`docs/configuration.md` and `docs/operations.md`, Observability).
|
|
94
|
+
|
|
95
|
+
## Shared UI
|
|
96
|
+
|
|
97
|
+
Every value exported from `packages/ui/src/index.ts`:
|
|
98
|
+
|
|
99
|
+
<!-- capabilities:ui-exports -->
|
|
100
|
+
|
|
101
|
+
`BrandMark`, `MARK_VIEWBOX`, `MARK_WARP`, `MARK_WEFT`, `Icon`, `ICON_PATHS`, `Button`, `FormField`, `Select`, `DateField`, `DateRangeField`, `dateRangeReversed`, `formatDateValue`, `DatePicker`, `DATE_PRESET_IDS`, `datePresetRange`, `FileUpload`, `fileRefusal`, `SearchField`, `CheckGrid`, `Drawer`, `ScopeSummary`, `summarizeScopes`, `SettingRow`, `Tag`, `Table`, `TableCard`, `Pagination`, `pageRange`, `keysetPage`, `Kpi`, `Chart`, `PageHeader`, `EmptyState`, `Alert`, `Avatar`, `Switch`, `ConfirmDialog`, `focusableElements`, `trapFocus`, `Filters`, `Tabs`, `ToastHost`, `createToastStore`, `toasts`, `VariableTextarea`, `VariableInput`, `VariableSelect`, `initials`
|
|
102
|
+
|
|
103
|
+
<!-- /capabilities:ui-exports -->
|
|
104
|
+
|
|
105
|
+
`ICON_PATHS`, `MARK_*`, `DATE_PRESET_IDS`, `summarizeScopes`, `initials`, `pageRange`, `keysetPage`, `formatDateValue`, `dateRangeReversed`, `datePresetRange`, `fileRefusal`, `createToastStore` and `toasts` are constants and helpers, not components. There is no other shared component: a screen that needs one builds it module-locally on tokens and flags it as a promotion candidate.
|
|
106
|
+
|
|
107
|
+
`Drawer` and `ConfirmDialog` trap Tab inside the open panel and return focus to whatever opened it; `trapFocus(root)` is that trap for a module-owned modal (install on open, call the returned release on close) and `focusableElements(root)` lists its Tab stops. `Table` takes `mode="server"` for a list the module already sorted, narrowed and paged in SQL, and a `reason` on a `TableAction` that is read as the refused action's accessible description. `Table` also takes `selection` (`TableSelection`: controlled `selectedKeys`, `onSelectionChange`, `label`, `rowLabel`, `selectable`) for a leading checkbox column whose header toggles the rows on screen, `bulkActions` (`TableBulkAction`, `onSelect(keys)`, same `reason` pattern) in a bar above the table while something is selected, and `selectionSummary(count)` for the polite announcement.
|
|
108
|
+
|
|
109
|
+
Every visual class is defined once in `packages/ui/src/styles/components.css` and prefixed `ui-` (about 180 names in `ui-block__element--modifier` form; `.num` for tabular figures is the only exception). Tokens live in `tokens.css`. A module composes `ui-*` classes and never restyles one. The writable and component-owned subsets are listed in `.ai/skills/ux-design/SKILL.md`.
|
|
110
|
+
|
|
111
|
+
## What does not exist yet
|
|
112
|
+
|
|
113
|
+
None of the following is available. A specification that needs one records it under `outOfScope` with the business decision that covers the gap, and never writes an acceptance scenario, screen, action or agent tool that depends on it.
|
|
114
|
+
|
|
115
|
+
- E-mail templates as a platform feature. `context.mail` sends a message a module composed itself, with `renderMailTemplate` for the substitution and the escaping; there is no template registry, no per-tenant editing, no layout and no attachment.
|
|
116
|
+
- Outbound HTTP calls from a module of its own. Outbound delivery is `notifications.core`'s signed webhook and a `connectors.core` instance the owner configured and consented to; `risk: 'external'` is refused by the CLI runner and by the harness, so a spec must not declare an `external` action and a module that needs an external system registers a connector definition instead.
|
|
117
|
+
- Multi-row server actions. `Table` selects rows and offers `bulkActions` with the selected keys; the endpoint that acts on many keys at once, its permission and its audit are still the module's own.
|
|
118
|
+
- PDF generation.
|
|
119
|
+
- A tracing or metrics backend of our own. The span API, the trace context, the module-owned counters and histograms and the OTLP exporter exist and are described above; the collector, the dashboards and the alerts are the operator's, and there is no gauge, no span event, no baggage header and no OTLP logs or metrics exporter. Error reporting is one bounded webhook, not an incident tool.
|
|
120
|
+
- An event bus. Modules integrate through the public capabilities registry, synchronously.
|
|
121
|
+
- SAML and LDAP. Authentication is password plus the configured OIDC providers; provisioning is SCIM through `directory.core`.
|
|
122
|
+
- Server-side sorting and filtering written for a module. The screen half exists: `Table` in `mode="server"` reports every sort and page change and renders the rows as they arrive, `pagination.totalRows` is optional there and `pagination.hasMore` carries a keyset page. The `ORDER BY`, the `WHERE` and the count behind them are still the module's own SQL.
|
|
123
|
+
|
|
124
|
+
## The rule
|
|
125
|
+
|
|
126
|
+
A specification states what the platform can deliver and nothing else. For every request that lands on the list above, the spec carries one `outOfScope` entry naming the gap and the business decision made instead ("attachments deferred; the invoice number is typed by hand"), and the matching `decisions[]` entry records who decided. Promising a missing capability in an acceptance scenario is a spec defect, and an implementation that finds one reports it back rather than inventing a substitute.
|
|
127
|
+
|
|
128
|
+
`node scripts/platform-capabilities.mjs --check` (also run by `pnpm verify`) fails when the component, navigation group or slot lists above drift from the code.
|