@cosmicdrift/kumiko-framework 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +159 -0
- package/package.json +91 -0
- package/src/__tests__/anonymous-access.integration.ts +325 -0
- package/src/__tests__/error-contract.integration.ts +435 -0
- package/src/__tests__/field-access.integration.ts +269 -0
- package/src/__tests__/full-stack.integration.ts +914 -0
- package/src/__tests__/ownership.integration.ts +449 -0
- package/src/__tests__/reference-data.integration.ts +198 -0
- package/src/__tests__/transition-guard.integration.ts +340 -0
- package/src/api/__tests__/api.test.ts +337 -0
- package/src/api/__tests__/auth-middleware-transport.test.ts +80 -0
- package/src/api/__tests__/auth-routes-cookie.test.ts +179 -0
- package/src/api/__tests__/batch.integration.ts +404 -0
- package/src/api/__tests__/body-limit.test.ts +88 -0
- package/src/api/__tests__/csrf-middleware.test.ts +97 -0
- package/src/api/__tests__/dispatcher-live.integration.ts +216 -0
- package/src/api/__tests__/metrics-endpoint.test.ts +126 -0
- package/src/api/__tests__/nested-write.integration.ts +213 -0
- package/src/api/__tests__/readiness.test.ts +76 -0
- package/src/api/__tests__/request-id-middleware.test.ts +72 -0
- package/src/api/__tests__/sse-broker.test.ts +58 -0
- package/src/api/__tests__/sse-route.test.ts +112 -0
- package/src/api/anonymous-cookie.ts +60 -0
- package/src/api/api-constants.ts +64 -0
- package/src/api/auth-middleware.ts +418 -0
- package/src/api/auth-routes.ts +982 -0
- package/src/api/csrf-middleware.ts +77 -0
- package/src/api/index.ts +31 -0
- package/src/api/jwt.ts +66 -0
- package/src/api/observability-middleware.ts +89 -0
- package/src/api/readiness.ts +132 -0
- package/src/api/request-context.ts +49 -0
- package/src/api/request-id-middleware.ts +50 -0
- package/src/api/route-registrars.ts +195 -0
- package/src/api/routes.ts +135 -0
- package/src/api/server.ts +640 -0
- package/src/api/sse-broker.ts +71 -0
- package/src/api/sse-route.ts +62 -0
- package/src/api/tokens.ts +16 -0
- package/src/db/__tests__/apply-entity-event-tenant.integration.ts +159 -0
- package/src/db/__tests__/compound-types.test.ts +114 -0
- package/src/db/__tests__/connection-options.test.ts +68 -0
- package/src/db/__tests__/cursor.test.ts +41 -0
- package/src/db/__tests__/db-helpers.test.ts +369 -0
- package/src/db/__tests__/dialect-instant.test.ts +50 -0
- package/src/db/__tests__/drizzle-helpers.integration.ts +186 -0
- package/src/db/__tests__/drizzle-table-types.test.ts +162 -0
- package/src/db/__tests__/encryption.test.ts +39 -0
- package/src/db/__tests__/event-store-executor-list.integration.ts +313 -0
- package/src/db/__tests__/event-store-executor.integration.ts +235 -0
- package/src/db/__tests__/implicit-projection-equivalence.integration.ts +304 -0
- package/src/db/__tests__/located-timestamp.test.ts +184 -0
- package/src/db/__tests__/money.test.ts +199 -0
- package/src/db/__tests__/multi-row-insert.integration.ts +76 -0
- package/src/db/__tests__/parse-auto-verb.test.ts +70 -0
- package/src/db/__tests__/required-not-null-migration-safety.integration.ts +105 -0
- package/src/db/__tests__/row-helpers.test.ts +59 -0
- package/src/db/__tests__/schema-migration.integration.ts +273 -0
- package/src/db/__tests__/table-builder-indexes.test.ts +153 -0
- package/src/db/__tests__/table-builder-required.test.ts +216 -0
- package/src/db/__tests__/tenant-db.integration.ts +606 -0
- package/src/db/__tests__/unique-violation-mapping.integration.ts +166 -0
- package/src/db/apply-entity-event.ts +188 -0
- package/src/db/assert-exists-in.ts +59 -0
- package/src/db/compound-types.ts +47 -0
- package/src/db/connection.ts +104 -0
- package/src/db/cursor.ts +83 -0
- package/src/db/dialect.ts +109 -0
- package/src/db/eagerload.ts +174 -0
- package/src/db/encryption.ts +39 -0
- package/src/db/event-store-executor.ts +906 -0
- package/src/db/index.ts +55 -0
- package/src/db/located-timestamp.ts +114 -0
- package/src/db/money.ts +120 -0
- package/src/db/pg-error.ts +46 -0
- package/src/db/reference-data.ts +77 -0
- package/src/db/row-helpers.ts +53 -0
- package/src/db/schema-inspection.ts +25 -0
- package/src/db/table-builder.ts +475 -0
- package/src/db/tenant-db.ts +434 -0
- package/src/engine/__tests__/auth-claims-registrar.test.ts +74 -0
- package/src/engine/__tests__/boot-validator-located-timestamps.test.ts +108 -0
- package/src/engine/__tests__/boot-validator.test.ts +1865 -0
- package/src/engine/__tests__/build-app-schema.test.ts +154 -0
- package/src/engine/__tests__/claim-keys.test.ts +274 -0
- package/src/engine/__tests__/config-helpers.test.ts +236 -0
- package/src/engine/__tests__/effective-features.test.ts +86 -0
- package/src/engine/__tests__/engine.test.ts +1461 -0
- package/src/engine/__tests__/entity-handlers.test.ts +274 -0
- package/src/engine/__tests__/event-helpers.test.ts +68 -0
- package/src/engine/__tests__/extends-registrar.test.ts +159 -0
- package/src/engine/__tests__/factories-long-text.test.ts +84 -0
- package/src/engine/__tests__/factories-time.test.ts +158 -0
- package/src/engine/__tests__/field-predicates.test.ts +48 -0
- package/src/engine/__tests__/hook-phases.test.ts +132 -0
- package/src/engine/__tests__/identifiers.test.ts +35 -0
- package/src/engine/__tests__/lifecycle-hooks.test.ts +237 -0
- package/src/engine/__tests__/nav.test.ts +267 -0
- package/src/engine/__tests__/ownership.test.ts +421 -0
- package/src/engine/__tests__/parse-ref-target.test.ts +43 -0
- package/src/engine/__tests__/projection-helpers.test.ts +62 -0
- package/src/engine/__tests__/projection.test.ts +191 -0
- package/src/engine/__tests__/qualified-name.test.ts +264 -0
- package/src/engine/__tests__/resolve-config-or-param.test.ts +315 -0
- package/src/engine/__tests__/run-in.test.ts +38 -0
- package/src/engine/__tests__/schema-builder.test.ts +380 -0
- package/src/engine/__tests__/screen.test.ts +408 -0
- package/src/engine/__tests__/state-machine.test.ts +148 -0
- package/src/engine/__tests__/system-user.test.ts +57 -0
- package/src/engine/__tests__/validation-hooks.test.ts +71 -0
- package/src/engine/access.ts +23 -0
- package/src/engine/boot-validator.ts +1528 -0
- package/src/engine/build-app-schema.ts +125 -0
- package/src/engine/config-helpers.ts +115 -0
- package/src/engine/constants.ts +85 -0
- package/src/engine/create-app.ts +98 -0
- package/src/engine/define-feature.ts +702 -0
- package/src/engine/define-handler.ts +78 -0
- package/src/engine/define-roles.ts +19 -0
- package/src/engine/effective-features.ts +87 -0
- package/src/engine/entity-handlers.ts +364 -0
- package/src/engine/event-helpers.ts +73 -0
- package/src/engine/factories.ts +328 -0
- package/src/engine/feature-ast/__tests__/canonical-form.test.ts +416 -0
- package/src/engine/feature-ast/__tests__/parse-happy-path.test.ts +197 -0
- package/src/engine/feature-ast/__tests__/parse-real-features.test.ts +128 -0
- package/src/engine/feature-ast/__tests__/parse.test.ts +888 -0
- package/src/engine/feature-ast/__tests__/patch.test.ts +360 -0
- package/src/engine/feature-ast/__tests__/patcher.test.ts +469 -0
- package/src/engine/feature-ast/__tests__/render-roundtrip.test.ts +287 -0
- package/src/engine/feature-ast/extractors.ts +2562 -0
- package/src/engine/feature-ast/index.ts +105 -0
- package/src/engine/feature-ast/parse.ts +369 -0
- package/src/engine/feature-ast/patch.ts +525 -0
- package/src/engine/feature-ast/patcher.ts +518 -0
- package/src/engine/feature-ast/patterns.ts +434 -0
- package/src/engine/feature-ast/render.ts +602 -0
- package/src/engine/feature-ast/source-location.ts +45 -0
- package/src/engine/field-access.ts +120 -0
- package/src/engine/index.ts +254 -0
- package/src/engine/ownership.ts +337 -0
- package/src/engine/parse-ref-target.ts +22 -0
- package/src/engine/pattern-library/__tests__/library.test.ts +351 -0
- package/src/engine/pattern-library/index.ts +24 -0
- package/src/engine/pattern-library/library.ts +1117 -0
- package/src/engine/pattern-library/types.ts +255 -0
- package/src/engine/projection-helpers.ts +85 -0
- package/src/engine/qualified-name.ts +122 -0
- package/src/engine/read-claim.ts +31 -0
- package/src/engine/registry.ts +1325 -0
- package/src/engine/resolve-config-or-param.ts +153 -0
- package/src/engine/run-in.ts +29 -0
- package/src/engine/schema-builder.ts +175 -0
- package/src/engine/screen-filter-ops.ts +51 -0
- package/src/engine/state-machine.ts +70 -0
- package/src/engine/system-user.ts +32 -0
- package/src/engine/types/config.ts +306 -0
- package/src/engine/types/event-type-map.ts +37 -0
- package/src/engine/types/feature.ts +574 -0
- package/src/engine/types/fields.ts +422 -0
- package/src/engine/types/handlers.ts +742 -0
- package/src/engine/types/hooks.ts +142 -0
- package/src/engine/types/http-route.ts +54 -0
- package/src/engine/types/identifiers.ts +47 -0
- package/src/engine/types/index.ts +208 -0
- package/src/engine/types/nav.ts +46 -0
- package/src/engine/types/projection.ts +132 -0
- package/src/engine/types/relations.ts +51 -0
- package/src/engine/types/screen.ts +452 -0
- package/src/engine/types/workspace.ts +42 -0
- package/src/engine/validation.ts +33 -0
- package/src/entrypoint/__tests__/entrypoint-job-wiring.integration.ts +173 -0
- package/src/entrypoint/__tests__/split-deploy.integration.ts +297 -0
- package/src/entrypoint/index.ts +442 -0
- package/src/errors/__tests__/classes.test.ts +371 -0
- package/src/errors/__tests__/write-failures.test.ts +109 -0
- package/src/errors/classes.ts +249 -0
- package/src/errors/i18n/de.yaml +83 -0
- package/src/errors/i18n/en.yaml +80 -0
- package/src/errors/index.ts +41 -0
- package/src/errors/kumiko-error.ts +67 -0
- package/src/errors/reasons.ts +36 -0
- package/src/errors/serialize.ts +136 -0
- package/src/errors/transition-details.ts +30 -0
- package/src/errors/write-error-info.ts +123 -0
- package/src/errors/zod-bridge.ts +49 -0
- package/src/event-store/__tests__/admin-api.integration.ts +361 -0
- package/src/event-store/__tests__/event-store.integration.ts +584 -0
- package/src/event-store/__tests__/get-stream-version-perf.integration.ts +83 -0
- package/src/event-store/__tests__/perf.integration.ts +255 -0
- package/src/event-store/__tests__/snapshot.integration.ts +267 -0
- package/src/event-store/__tests__/upcaster-dead-letter.integration.ts +204 -0
- package/src/event-store/__tests__/upcaster.integration.ts +460 -0
- package/src/event-store/admin-api.ts +257 -0
- package/src/event-store/archive.ts +106 -0
- package/src/event-store/errors.ts +35 -0
- package/src/event-store/event-store.ts +405 -0
- package/src/event-store/events-schema.ts +90 -0
- package/src/event-store/index.ts +50 -0
- package/src/event-store/snapshot.ts +210 -0
- package/src/event-store/upcaster-dead-letter.ts +119 -0
- package/src/event-store/upcaster.ts +147 -0
- package/src/files/__tests__/content-disposition.test.ts +123 -0
- package/src/files/__tests__/file-field-column.integration.ts +103 -0
- package/src/files/__tests__/file-field-pipeline.integration.ts +211 -0
- package/src/files/__tests__/file-handle.test.ts +122 -0
- package/src/files/__tests__/files.integration.ts +830 -0
- package/src/files/__tests__/storage-tracking.integration.ts +153 -0
- package/src/files/content-disposition.ts +55 -0
- package/src/files/file-handle.ts +63 -0
- package/src/files/file-ref-table.ts +22 -0
- package/src/files/file-routes.ts +353 -0
- package/src/files/in-memory-provider.ts +62 -0
- package/src/files/index.ts +29 -0
- package/src/files/local-provider.ts +35 -0
- package/src/files/storage-tracking.ts +60 -0
- package/src/files/types.ts +118 -0
- package/src/i18n/__tests__/i18n.test.ts +72 -0
- package/src/i18n/index.ts +29 -0
- package/src/jobs/__tests__/job-event-trigger.integration.ts +172 -0
- package/src/jobs/__tests__/job-multi-trigger.integration.ts +144 -0
- package/src/jobs/__tests__/jobs.integration.ts +566 -0
- package/src/jobs/index.ts +2 -0
- package/src/jobs/job-runner.ts +574 -0
- package/src/lifecycle/__tests__/create-test-lifecycle.ts +19 -0
- package/src/lifecycle/__tests__/lifecycle-server.integration.ts +108 -0
- package/src/lifecycle/__tests__/lifecycle.test.ts +212 -0
- package/src/lifecycle/__tests__/signal-handlers.test.ts +106 -0
- package/src/lifecycle/index.ts +13 -0
- package/src/lifecycle/lifecycle.ts +160 -0
- package/src/lifecycle/signal-handlers.ts +62 -0
- package/src/logging/__tests__/pino-trace-bridge.test.ts +50 -0
- package/src/logging/index.ts +3 -0
- package/src/logging/pino-logger.ts +64 -0
- package/src/logging/types.ts +7 -0
- package/src/migrations/__tests__/compare-snapshots.test.ts +150 -0
- package/src/migrations/__tests__/detect-drift.integration.ts +320 -0
- package/src/migrations/__tests__/detect-projections-to-rebuild.integration.ts +134 -0
- package/src/migrations/__tests__/rebuild-marker.test.ts +79 -0
- package/src/migrations/index.ts +28 -0
- package/src/migrations/projection-detection.ts +149 -0
- package/src/migrations/rebuild-marker.ts +64 -0
- package/src/migrations/schema-drift.ts +395 -0
- package/src/observability/__tests__/console-provider.test.ts +67 -0
- package/src/observability/__tests__/metric-validator.test.ts +87 -0
- package/src/observability/__tests__/noop-provider.test.ts +82 -0
- package/src/observability/__tests__/observability.integration.ts +559 -0
- package/src/observability/__tests__/prometheus-meter.test.ts +144 -0
- package/src/observability/__tests__/recording-meter.test.ts +101 -0
- package/src/observability/__tests__/recording-tracer.test.ts +110 -0
- package/src/observability/__tests__/sensitive-filter.test.ts +98 -0
- package/src/observability/console-provider.ts +130 -0
- package/src/observability/context.ts +26 -0
- package/src/observability/fallback.ts +34 -0
- package/src/observability/ids.ts +25 -0
- package/src/observability/index.ts +79 -0
- package/src/observability/metric-validator.ts +86 -0
- package/src/observability/metrics-handle.ts +56 -0
- package/src/observability/noop-provider.ts +146 -0
- package/src/observability/prometheus-meter.ts +284 -0
- package/src/observability/recording-meter.ts +156 -0
- package/src/observability/recording-tracer.ts +198 -0
- package/src/observability/redis-wrapper.ts +132 -0
- package/src/observability/sensitive-filter.ts +108 -0
- package/src/observability/standard-metrics.ts +213 -0
- package/src/observability/types/index.ts +29 -0
- package/src/observability/types/metric.ts +56 -0
- package/src/observability/types/provider.ts +32 -0
- package/src/observability/types/span.ts +64 -0
- package/src/pipeline/__tests__/archive-stream.integration.ts +220 -0
- package/src/pipeline/__tests__/auth-claims-resolver.test.ts +279 -0
- package/src/pipeline/__tests__/cascade-handler.integration.ts +419 -0
- package/src/pipeline/__tests__/cascade-handler.test.ts +52 -0
- package/src/pipeline/__tests__/causation-chain.integration.ts +206 -0
- package/src/pipeline/__tests__/ctx-bridge.integration.ts +234 -0
- package/src/pipeline/__tests__/dispatcher.test.ts +379 -0
- package/src/pipeline/__tests__/distributed-lock.integration.ts +67 -0
- package/src/pipeline/__tests__/domain-events-projections.integration.ts +323 -0
- package/src/pipeline/__tests__/event-dedup.integration.ts +153 -0
- package/src/pipeline/__tests__/event-define-event-strict.integration.ts +202 -0
- package/src/pipeline/__tests__/event-dispatcher-lifecycle.integration.ts +220 -0
- package/src/pipeline/__tests__/event-dispatcher-multi-instance.integration.ts +423 -0
- package/src/pipeline/__tests__/event-dispatcher-pg-listen.integration.ts +123 -0
- package/src/pipeline/__tests__/event-dispatcher-recovery.integration.ts +202 -0
- package/src/pipeline/__tests__/event-dispatcher-second-audit.integration.ts +290 -0
- package/src/pipeline/__tests__/event-dispatcher-strict.test.ts +65 -0
- package/src/pipeline/__tests__/event-dispatcher.integration.ts +287 -0
- package/src/pipeline/__tests__/event-retention.integration.ts +239 -0
- package/src/pipeline/__tests__/fetch-for-writing.integration.ts +281 -0
- package/src/pipeline/__tests__/lifecycle-pipeline.test.ts +430 -0
- package/src/pipeline/__tests__/load-aggregate-query.integration.ts +266 -0
- package/src/pipeline/__tests__/msp-error-mode.integration.ts +149 -0
- package/src/pipeline/__tests__/msp-multi-hop.integration.ts +228 -0
- package/src/pipeline/__tests__/msp-rebuild.integration.ts +368 -0
- package/src/pipeline/__tests__/multi-stream-projection.integration.ts +341 -0
- package/src/pipeline/__tests__/perf-rebuild.integration.ts +147 -0
- package/src/pipeline/__tests__/projection-rebuild.integration.ts +551 -0
- package/src/pipeline/__tests__/query-projection.integration.ts +201 -0
- package/src/pipeline/__tests__/redis-pipeline.integration.ts +306 -0
- package/src/pipeline/append-event-core.ts +117 -0
- package/src/pipeline/auth-claims-resolver.ts +103 -0
- package/src/pipeline/cascade-handler.ts +113 -0
- package/src/pipeline/dispatcher.ts +1585 -0
- package/src/pipeline/distributed-lock.ts +37 -0
- package/src/pipeline/entity-cache.ts +113 -0
- package/src/pipeline/event-consumer-state.ts +108 -0
- package/src/pipeline/event-dedup.ts +23 -0
- package/src/pipeline/event-dispatcher.ts +1016 -0
- package/src/pipeline/event-retention.ts +154 -0
- package/src/pipeline/idempotency.ts +76 -0
- package/src/pipeline/index.ts +66 -0
- package/src/pipeline/lifecycle-pipeline.ts +409 -0
- package/src/pipeline/msp-rebuild.ts +242 -0
- package/src/pipeline/multi-stream-apply-context.ts +115 -0
- package/src/pipeline/projection-rebuild.ts +334 -0
- package/src/pipeline/projection-state.ts +72 -0
- package/src/pipeline/projections-runner.ts +56 -0
- package/src/pipeline/redis-keys.ts +11 -0
- package/src/pipeline/system-hooks.ts +190 -0
- package/src/random/__tests__/generate.test.ts +149 -0
- package/src/random/generate.ts +141 -0
- package/src/random/index.ts +8 -0
- package/src/random/words.ts +392 -0
- package/src/rate-limit/__tests__/dispatcher-l3.integration.ts +111 -0
- package/src/rate-limit/__tests__/middleware.integration.ts +189 -0
- package/src/rate-limit/__tests__/resolver.integration.ts +189 -0
- package/src/rate-limit/bucket.ts +36 -0
- package/src/rate-limit/index.ts +14 -0
- package/src/rate-limit/middleware.ts +152 -0
- package/src/rate-limit/resolver.ts +267 -0
- package/src/redis/__tests__/redis-options.test.ts +54 -0
- package/src/redis/index.ts +74 -0
- package/src/search/__tests__/meilisearch-adapter.integration.ts +236 -0
- package/src/search/__tests__/search-adapter.test.ts +256 -0
- package/src/search/in-memory-adapter.ts +123 -0
- package/src/search/index.ts +12 -0
- package/src/search/meilisearch-adapter.ts +106 -0
- package/src/search/types.ts +39 -0
- package/src/secrets/__tests__/dek-cache.test.ts +213 -0
- package/src/secrets/__tests__/env-master-key-provider.test.ts +119 -0
- package/src/secrets/__tests__/envelope.test.ts +74 -0
- package/src/secrets/__tests__/leak-guard.test.ts +92 -0
- package/src/secrets/__tests__/rotation.test.ts +149 -0
- package/src/secrets/dek-cache.ts +116 -0
- package/src/secrets/env-master-key-provider.ts +162 -0
- package/src/secrets/envelope.ts +55 -0
- package/src/secrets/index.ts +19 -0
- package/src/secrets/leak-guard.ts +87 -0
- package/src/secrets/rotation.ts +34 -0
- package/src/secrets/types.ts +107 -0
- package/src/stack/db.ts +104 -0
- package/src/stack/event-collector.ts +23 -0
- package/src/stack/index.ts +32 -0
- package/src/stack/redis.ts +44 -0
- package/src/stack/request-helper.ts +168 -0
- package/src/stack/table-helpers.ts +104 -0
- package/src/stack/test-stack.ts +357 -0
- package/src/stack/test-users.ts +37 -0
- package/src/testing/__tests__/e2e-generator.test.ts +230 -0
- package/src/testing/__tests__/ensure-entity-table.integration.ts +54 -0
- package/src/testing/access-assertions.ts +15 -0
- package/src/testing/assertions.ts +35 -0
- package/src/testing/e2e-generator.ts +465 -0
- package/src/testing/expect-error.ts +25 -0
- package/src/testing/handler-context.ts +125 -0
- package/src/testing/http-cookies.ts +52 -0
- package/src/testing/index.ts +41 -0
- package/src/testing/late-bound.ts +39 -0
- package/src/testing/mutable-master-key-provider.ts +31 -0
- package/src/testing/observability-recorder.ts +54 -0
- package/src/testing/shared-entities.ts +49 -0
- package/src/testing/utils.ts +1 -0
- package/src/testing/wait-for.ts +31 -0
- package/src/time/__tests__/polyfill.test.ts +73 -0
- package/src/time/__tests__/tz-context.test.ts +121 -0
- package/src/time/index.ts +21 -0
- package/src/time/polyfill.ts +70 -0
- package/src/time/tz-context.ts +107 -0
- package/src/ui-types/app-schema.ts +57 -0
- package/src/ui-types/index.ts +65 -0
- package/src/utils/__tests__/assert.test.ts +17 -0
- package/src/utils/__tests__/env-parse.test.ts +54 -0
- package/src/utils/assert.ts +18 -0
- package/src/utils/env-parse.ts +16 -0
- package/src/utils/ids.ts +16 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/safe-json.ts +30 -0
- package/src/utils/serialization.ts +7 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
// --- Field Types ---
|
|
2
|
+
|
|
3
|
+
// OwnershipMap is declared in engine/ownership.ts — field-access maps to
|
|
4
|
+
// per-role ownership rules. A legacy `readonly string[]` form is still
|
|
5
|
+
// accepted at the type layer during migration: features that pass an
|
|
6
|
+
// array are auto-normalized to { [role]: "all" } at registry build.
|
|
7
|
+
// Long-term: string[] disappears.
|
|
8
|
+
import type { OwnershipMap } from "../ownership";
|
|
9
|
+
|
|
10
|
+
export type FieldAccess = {
|
|
11
|
+
readonly read?: OwnershipMap | readonly string[];
|
|
12
|
+
readonly write?: OwnershipMap | readonly string[];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// `sensitive: true` — the field's value is excluded from event payloads
|
|
16
|
+
// (create data, update changes/previous, delete/restore previous). The entity
|
|
17
|
+
// row still stores it; only the immutable event-log won't. Use for data that
|
|
18
|
+
// must never land in permanent history: password hashes, API tokens,
|
|
19
|
+
// unhashed PII, bank details, tax IDs. The trade-off: event-replay and
|
|
20
|
+
// custom projections cannot read sensitive field values. See
|
|
21
|
+
// docs/plans/architecture/projections.md.
|
|
22
|
+
|
|
23
|
+
export type TextFieldDef = {
|
|
24
|
+
readonly type: "text";
|
|
25
|
+
readonly maxLength?: number;
|
|
26
|
+
readonly required?: boolean;
|
|
27
|
+
readonly searchable?: boolean;
|
|
28
|
+
readonly sortable?: boolean;
|
|
29
|
+
/** Author erlaubt Screen-Filter auf diesem Feld (Tier 2.7c).
|
|
30
|
+
* Boot-Validator weist Filter mit `filterable !== true` zurück.
|
|
31
|
+
* Default: false — analog zu `sortable`, opt-in. */
|
|
32
|
+
readonly filterable?: boolean;
|
|
33
|
+
readonly encrypted?: boolean;
|
|
34
|
+
readonly sensitive?: boolean;
|
|
35
|
+
readonly format?: "email" | "url" | "phone";
|
|
36
|
+
readonly default?: string;
|
|
37
|
+
readonly access?: FieldAccess;
|
|
38
|
+
/** Mehrzeiliger Text — DefaultInput rendert dann ein <textarea> statt
|
|
39
|
+
* <input type="text">. `true` = Default 4 Zeilen, `{ rows: N }` =
|
|
40
|
+
* explizite Höhe. Search/sort/encrypt verhalten sich unverändert
|
|
41
|
+
* identisch zu single-line — nur die Render-Surface wechselt. */
|
|
42
|
+
readonly multiline?: boolean | { readonly rows?: number };
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Long-form text content — source-code, markdown, blog-posts, email-
|
|
47
|
+
* templates, anything that can be megabytes large. Bewusst MINIMALE
|
|
48
|
+
* Surface gegen `text`:
|
|
49
|
+
*
|
|
50
|
+
* - **Kein `sortable`**: ORDER BY auf 100 KB-Strings kostet I/O ohne
|
|
51
|
+
* sinnvolles UX-Outcome (lex-Sortierung von Code ist Nonsense).
|
|
52
|
+
* - **Kein `searchable`**: ILIKE/Substring-Suche auf langen Texten
|
|
53
|
+
* skaliert nicht. Wer wirklich Volltextsuche will, nimmt den
|
|
54
|
+
* SearchAdapter (Meilisearch) — der hat eine eigene Pipeline mit
|
|
55
|
+
* Tokenizer + Index, NICHT diesen field-flag.
|
|
56
|
+
* - **Kein `filterable`**: WHERE auf langen Strings same Story wie
|
|
57
|
+
* sortable.
|
|
58
|
+
* - **Kein `format`**: email/url/phone sind kurz definierte Inputs,
|
|
59
|
+
* longText ist per Definition unstrukturiert.
|
|
60
|
+
*
|
|
61
|
+
* Type-level enforcement statt convention: wer sortable/searchable
|
|
62
|
+
* braucht, nimmt `text` (mit den entsprechenden Skalierungs-Trade-offs).
|
|
63
|
+
* DB-mapping ist identisch zu text (Postgres `text` ist unbounded).
|
|
64
|
+
*/
|
|
65
|
+
export type LongTextFieldDef = {
|
|
66
|
+
readonly type: "longText";
|
|
67
|
+
/** Optionale soft-Cap. Default unbounded (= Postgres-text-limit, 1 GB).
|
|
68
|
+
* Nützlich für defensive Caps wie 1 MB damit ein verirrter Browser-
|
|
69
|
+
* Paste nicht die DB sprengt. */
|
|
70
|
+
readonly maxLength?: number;
|
|
71
|
+
readonly required?: boolean;
|
|
72
|
+
readonly encrypted?: boolean;
|
|
73
|
+
readonly sensitive?: boolean;
|
|
74
|
+
readonly default?: string;
|
|
75
|
+
readonly access?: FieldAccess;
|
|
76
|
+
readonly multiline?: boolean | { readonly rows?: number };
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export type BooleanFieldDef = {
|
|
80
|
+
readonly type: "boolean";
|
|
81
|
+
readonly required?: boolean;
|
|
82
|
+
readonly sortable?: boolean;
|
|
83
|
+
readonly filterable?: boolean;
|
|
84
|
+
readonly sensitive?: boolean;
|
|
85
|
+
readonly default?: boolean;
|
|
86
|
+
readonly access?: FieldAccess;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export type SelectFieldDef<TOptions extends readonly string[] = readonly string[]> = {
|
|
90
|
+
readonly type: "select";
|
|
91
|
+
readonly options: TOptions;
|
|
92
|
+
readonly required?: boolean;
|
|
93
|
+
readonly sortable?: boolean;
|
|
94
|
+
readonly filterable?: boolean;
|
|
95
|
+
readonly sensitive?: boolean;
|
|
96
|
+
readonly default?: TOptions[number];
|
|
97
|
+
readonly access?: FieldAccess;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// Mehrere Werte aus einer festen Options-Liste — UI rendert als
|
|
101
|
+
// Checkbox-/Multi-Select-Kontrolle. Storage: jsonb-Array<string>;
|
|
102
|
+
// jeder Eintrag muss in `options` enthalten sein.
|
|
103
|
+
//
|
|
104
|
+
// Wann statt `select`: wenn der User mehr als einen Wert gleichzeitig
|
|
105
|
+
// auswählen darf (Führerscheinklassen, Tags, Sprachen, Skills).
|
|
106
|
+
// Wann statt `embedded` mit Booleans: wenn die Option-Liste nicht
|
|
107
|
+
// hardcoded sein soll oder bei mehr als ~5 Optionen — sonst explodiert
|
|
108
|
+
// das embedded-Schema.
|
|
109
|
+
//
|
|
110
|
+
// Ordering: das Array bewahrt die Caller-Reihenfolge (jsonb-array, nicht
|
|
111
|
+
// set). Das Framework dedupliziert beim Schreiben nicht — Validator
|
|
112
|
+
// rejected Duplikate erst wenn Bedarf da ist.
|
|
113
|
+
export type MultiSelectFieldDef<TOptions extends readonly string[] = readonly string[]> = {
|
|
114
|
+
readonly type: "multiSelect";
|
|
115
|
+
readonly options: TOptions;
|
|
116
|
+
readonly required?: boolean;
|
|
117
|
+
readonly filterable?: boolean;
|
|
118
|
+
readonly sensitive?: boolean;
|
|
119
|
+
/** Default-Auswahl. Jeder Eintrag muss in `options` sein (Boot-Validator). */
|
|
120
|
+
readonly default?: readonly TOptions[number][];
|
|
121
|
+
readonly access?: FieldAccess;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export type NumberFieldDef = {
|
|
125
|
+
readonly type: "number";
|
|
126
|
+
readonly required?: boolean;
|
|
127
|
+
readonly sortable?: boolean;
|
|
128
|
+
readonly filterable?: boolean;
|
|
129
|
+
readonly sensitive?: boolean;
|
|
130
|
+
readonly default?: number;
|
|
131
|
+
readonly access?: FieldAccess;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export type MoneyFieldDef = {
|
|
135
|
+
readonly type: "money";
|
|
136
|
+
readonly required?: boolean;
|
|
137
|
+
readonly sortable?: boolean;
|
|
138
|
+
readonly filterable?: boolean;
|
|
139
|
+
readonly sensitive?: boolean;
|
|
140
|
+
readonly access?: FieldAccess;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// Reference-Field (Tier 2.7e-3) — FK-Style Verweis auf eine andere
|
|
144
|
+
// Entity. Gespeichert als UUID-Spalte (uuid type), Read-Side liefert
|
|
145
|
+
// optional die referenced Row mit (Tier 2.7e-4 eagerload).
|
|
146
|
+
//
|
|
147
|
+
// `entity` akzeptiert zwei Formen:
|
|
148
|
+
// - kurz ("customer") — same-feature reference, Default-Pfad.
|
|
149
|
+
// - qualifiziert ("users:user") — cross-feature, Format
|
|
150
|
+
// "<featureName>:<entityName>". Renderer baut die Lookup-Query-QN
|
|
151
|
+
// gegen das angegebene Feature (`users:query:user:list`).
|
|
152
|
+
//
|
|
153
|
+
// `labelField` (optional) — welches Feld der referenced Entity wird
|
|
154
|
+
// im Select-Dropdown als Label gezeigt. Default: "id". Best practice
|
|
155
|
+
// ist ein menschlich-lesbares Feld wie "name", "title", "email".
|
|
156
|
+
export type ReferenceFieldDef = {
|
|
157
|
+
readonly type: "reference";
|
|
158
|
+
readonly entity: string;
|
|
159
|
+
readonly required?: boolean;
|
|
160
|
+
readonly filterable?: boolean;
|
|
161
|
+
readonly sensitive?: boolean;
|
|
162
|
+
readonly access?: FieldAccess;
|
|
163
|
+
/** Welches Feld der referenced Entity als Display-Label im
|
|
164
|
+
* Select-Dropdown erscheint. Default: "id". Boot-Validator pinst
|
|
165
|
+
* dass das Feld auf der referenced Entity existiert. */
|
|
166
|
+
readonly labelField?: string;
|
|
167
|
+
/** Multi-Reference (Tier 2.7e-Multi): Wert ist ein Array von UUIDs
|
|
168
|
+
* statt single UUID. Storage als jsonb-Array<uuid>. UI rendert
|
|
169
|
+
* Multi-Select-Combobox mit Tag-Anzeige der gewählten Items. */
|
|
170
|
+
readonly multiple?: boolean;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// --- Currency ---
|
|
174
|
+
|
|
175
|
+
export const DEFAULT_CURRENCIES = [
|
|
176
|
+
"EUR",
|
|
177
|
+
"USD",
|
|
178
|
+
"GBP",
|
|
179
|
+
"CHF",
|
|
180
|
+
"JPY",
|
|
181
|
+
"SEK",
|
|
182
|
+
"NOK",
|
|
183
|
+
"DKK",
|
|
184
|
+
"PLN",
|
|
185
|
+
"CZK",
|
|
186
|
+
"CAD",
|
|
187
|
+
"AUD",
|
|
188
|
+
"NZD",
|
|
189
|
+
"CNY",
|
|
190
|
+
"INR",
|
|
191
|
+
] as const;
|
|
192
|
+
|
|
193
|
+
export type DefaultCurrency = (typeof DEFAULT_CURRENCIES)[number];
|
|
194
|
+
|
|
195
|
+
// --- Embedded Object ---
|
|
196
|
+
|
|
197
|
+
export type EmbeddedSubFieldDef = {
|
|
198
|
+
readonly type: "text" | "number" | "boolean" | "date";
|
|
199
|
+
readonly required?: boolean;
|
|
200
|
+
readonly searchable?: boolean;
|
|
201
|
+
readonly access?: FieldAccess;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
export type EmbeddedFieldDef = {
|
|
205
|
+
readonly type: "embedded";
|
|
206
|
+
readonly required?: boolean;
|
|
207
|
+
readonly sensitive?: boolean;
|
|
208
|
+
readonly schema: Readonly<Record<string, EmbeddedSubFieldDef>>;
|
|
209
|
+
readonly access?: FieldAccess;
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// Legacy "date" — JS-Date-Object, semantisch unklar (Wall-Clock vs Instant).
|
|
213
|
+
// Für neue Felder bevorzuge:
|
|
214
|
+
// - `timestamp` für UTC-Instant ("wann ist das passiert")
|
|
215
|
+
// - `locatedTimestamp(name)` Helper für Termine die an einem Ort
|
|
216
|
+
// stattfinden ("Pickup um 10:00 in Lissabon")
|
|
217
|
+
// - (kommt) `plainDate` für Kalender-Daten ohne Uhrzeit (z.B. Geburtstag)
|
|
218
|
+
// Siehe docs/plans/architecture/timezones.md
|
|
219
|
+
export type DateFieldDef = {
|
|
220
|
+
readonly type: "date";
|
|
221
|
+
readonly required?: boolean;
|
|
222
|
+
readonly sortable?: boolean;
|
|
223
|
+
readonly filterable?: boolean;
|
|
224
|
+
readonly sensitive?: boolean;
|
|
225
|
+
readonly access?: FieldAccess;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// UTC-Instant (Temporal.Instant). Für Ereignisse die zu einem bestimmten
|
|
229
|
+
// Augenblick passieren, ohne Location-Bezug: createdAt, loginAt, actualPickupAt.
|
|
230
|
+
// JSON-Form: ISO-UTC-String "2026-04-18T10:00:00Z" via .toJSON().
|
|
231
|
+
//
|
|
232
|
+
// Mit `locatedBy: "<name>Tz"` markiert: bildet ein Wall-Clock+TZ-Pair mit dem
|
|
233
|
+
// referenzierten tz-Feld. JSON-Form wird dann zwei Felder ({ at, tz }), DB
|
|
234
|
+
// speichert Wall-Clock+tz und konvertiert transparent (siehe DB-Wrapper,
|
|
235
|
+
// kommt in einer späteren Iteration).
|
|
236
|
+
//
|
|
237
|
+
// Verwendung über den `locatedTimestamp(name)` Helper, der das Pair atomar
|
|
238
|
+
// erzeugt und die Marker korrekt verdrahtet.
|
|
239
|
+
export type TimestampFieldDef = {
|
|
240
|
+
readonly type: "timestamp";
|
|
241
|
+
readonly required?: boolean;
|
|
242
|
+
readonly sortable?: boolean;
|
|
243
|
+
readonly filterable?: boolean;
|
|
244
|
+
readonly sensitive?: boolean;
|
|
245
|
+
readonly access?: FieldAccess;
|
|
246
|
+
/**
|
|
247
|
+
* Marker: dieses Timestamp-Feld ist Wall-Clock-Zeit an einem Ort.
|
|
248
|
+
* Wert ist der Name des begleitenden tz-Felds (IANA-Zone).
|
|
249
|
+
*
|
|
250
|
+
* Beispiel: `locatedTimestamp("pickup")` erzeugt
|
|
251
|
+
* { pickupAt: { type: "timestamp", locatedBy: "pickupTz" }, pickupTz: { type: "tz" } }
|
|
252
|
+
*/
|
|
253
|
+
readonly locatedBy?: string;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// IANA-Zonenname (z.B. "Europe/Berlin", "America/Los_Angeles").
|
|
257
|
+
// Wird via `Intl.supportedValuesOf("timeZone")` validiert (kommt im
|
|
258
|
+
// Zod-Validator-Schritt). Eigener Field-Typ damit Type-Safety + Storage
|
|
259
|
+
// (TEXT-Spalte) korrekt sind und der `locatedBy`-Marker eindeutig auflöst.
|
|
260
|
+
export type TzFieldDef = {
|
|
261
|
+
readonly type: "tz";
|
|
262
|
+
readonly required?: boolean;
|
|
263
|
+
readonly sensitive?: boolean;
|
|
264
|
+
readonly access?: FieldAccess;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// Wall-Clock-Termin an einem Ort als ATOMARES Konzept.
|
|
268
|
+
// EIN Feld in der Schema-Definition, ZWEI Spalten in der DB
|
|
269
|
+
// (`<name>_utc TIMESTAMPTZ` + `<name>_tz TEXT`), DREI Felder im API-Object
|
|
270
|
+
// ({ at, tz, utc }). Drizzle-Wrapper macht die Konvertierung transparent —
|
|
271
|
+
// Feature-Code sieht das 3-Felder-Object beim Read und schreibt
|
|
272
|
+
// { at, tz } beim Insert (utc wird berechnet).
|
|
273
|
+
//
|
|
274
|
+
// API-Form:
|
|
275
|
+
// Write: { at: "2026-04-15T10:00:00", tz: "Europe/Lisbon" }
|
|
276
|
+
// Read: { at: "2026-04-15T10:00:00", tz: "Europe/Lisbon", utc: "2026-04-15T09:00:00Z" }
|
|
277
|
+
//
|
|
278
|
+
// Default-Sicht für `at`: Wall-Clock am Ort (`tz`). Wer User-lokale Sicht
|
|
279
|
+
// will, projeziert `utc` separat per ctx.tz.fromInstantInZone(utc, userTz).
|
|
280
|
+
//
|
|
281
|
+
// Ersetzt das alte `locatedTimestamp(name)` Helper-Pattern (zwei separate
|
|
282
|
+
// Pair-Felder). Sauberer Single-Field-Typ + Auto-Convert-Logik.
|
|
283
|
+
//
|
|
284
|
+
// Siehe docs/plans/architecture/timezones.md.
|
|
285
|
+
export type LocatedTimestampFieldDef = {
|
|
286
|
+
readonly type: "locatedTimestamp";
|
|
287
|
+
readonly required?: boolean;
|
|
288
|
+
readonly sortable?: boolean;
|
|
289
|
+
readonly filterable?: boolean;
|
|
290
|
+
readonly sensitive?: boolean;
|
|
291
|
+
readonly access?: FieldAccess;
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
export type FileFieldDef = {
|
|
295
|
+
readonly type: "file";
|
|
296
|
+
readonly required?: boolean;
|
|
297
|
+
readonly maxSize?: string;
|
|
298
|
+
readonly accept?: readonly string[];
|
|
299
|
+
readonly access?: FieldAccess;
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
export type ImageFieldDef = {
|
|
303
|
+
readonly type: "image";
|
|
304
|
+
readonly required?: boolean;
|
|
305
|
+
readonly maxSize?: string;
|
|
306
|
+
readonly accept?: readonly string[];
|
|
307
|
+
readonly thumbnails?: boolean;
|
|
308
|
+
readonly access?: FieldAccess;
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
export type FilesFieldDef = {
|
|
312
|
+
readonly type: "files";
|
|
313
|
+
readonly maxSize?: string;
|
|
314
|
+
readonly accept?: readonly string[];
|
|
315
|
+
readonly maxCount?: number;
|
|
316
|
+
readonly access?: FieldAccess;
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
export type ImagesFieldDef = {
|
|
320
|
+
readonly type: "images";
|
|
321
|
+
readonly maxSize?: string;
|
|
322
|
+
readonly accept?: readonly string[];
|
|
323
|
+
readonly maxCount?: number;
|
|
324
|
+
readonly thumbnails?: boolean;
|
|
325
|
+
readonly access?: FieldAccess;
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
export type FieldDefinition =
|
|
329
|
+
| TextFieldDef
|
|
330
|
+
| LongTextFieldDef
|
|
331
|
+
| BooleanFieldDef
|
|
332
|
+
| SelectFieldDef
|
|
333
|
+
| MultiSelectFieldDef
|
|
334
|
+
| NumberFieldDef
|
|
335
|
+
| MoneyFieldDef
|
|
336
|
+
| ReferenceFieldDef
|
|
337
|
+
| EmbeddedFieldDef
|
|
338
|
+
| DateFieldDef
|
|
339
|
+
| TimestampFieldDef
|
|
340
|
+
| TzFieldDef
|
|
341
|
+
| LocatedTimestampFieldDef
|
|
342
|
+
| FileFieldDef
|
|
343
|
+
| ImageFieldDef
|
|
344
|
+
| FilesFieldDef
|
|
345
|
+
| ImagesFieldDef;
|
|
346
|
+
|
|
347
|
+
// Union of all field variants that represent uploaded files. They share
|
|
348
|
+
// `maxSize` and `accept`, which is what upload validation cares about.
|
|
349
|
+
export type AnyFileFieldDef = FileFieldDef | ImageFieldDef | FilesFieldDef | ImagesFieldDef;
|
|
350
|
+
|
|
351
|
+
export function isFileField(field: FieldDefinition | undefined): field is AnyFileFieldDef {
|
|
352
|
+
if (!field) return false;
|
|
353
|
+
return (
|
|
354
|
+
field.type === "file" ||
|
|
355
|
+
field.type === "image" ||
|
|
356
|
+
field.type === "files" ||
|
|
357
|
+
field.type === "images"
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// --- Entity ---
|
|
362
|
+
|
|
363
|
+
// --- State Transitions ---
|
|
364
|
+
|
|
365
|
+
export type TransitionMap = Readonly<Record<string, readonly string[]>>;
|
|
366
|
+
|
|
367
|
+
/** Composite-Index auf einer Entity. Spalten werden via field-Name
|
|
368
|
+
* referenziert (camelCase). buildDrizzleTable mapped sie auf snake_case-
|
|
369
|
+
* Spaltennamen und benennt den Index nach Convention:
|
|
370
|
+
*
|
|
371
|
+
* <table>_<col1>_<col2>_idx (non-unique)
|
|
372
|
+
* <table>_<col1>_<col2>_unique (unique)
|
|
373
|
+
*
|
|
374
|
+
* Eine `name`-Override ist erlaubt — Convention-Bruch in Bestandscode
|
|
375
|
+
* vermeidet Migration-Churn beim Refactor.
|
|
376
|
+
*
|
|
377
|
+
* Single-column indices über `tenantId` sind redundant (buildDrizzleTable
|
|
378
|
+
* legt die immer automatisch an); die Boot-Validation warnt. */
|
|
379
|
+
export type EntityIndexDef = {
|
|
380
|
+
readonly columns: readonly [string, ...string[]];
|
|
381
|
+
readonly unique?: boolean;
|
|
382
|
+
readonly name?: string;
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
export type FieldsMap = Readonly<Record<string, FieldDefinition>>;
|
|
386
|
+
|
|
387
|
+
export type EntityDefinition<F extends FieldsMap = FieldsMap> = {
|
|
388
|
+
readonly table?: string;
|
|
389
|
+
readonly fields: F;
|
|
390
|
+
readonly softDelete?: boolean;
|
|
391
|
+
readonly searchWeight?: number;
|
|
392
|
+
readonly defaultCurrency?: string;
|
|
393
|
+
/** Allowed state transitions per field. Boot validates against select options. */
|
|
394
|
+
readonly transitions?: Readonly<Record<string, TransitionMap>>;
|
|
395
|
+
/** Composite-Indices über mehrere Felder. Single-column FK-Indices und
|
|
396
|
+
* der tenant_id-Index werden weiterhin automatisch von buildDrizzleTable
|
|
397
|
+
* angelegt — diese Liste ist nur für Custom-Indices die der Author
|
|
398
|
+
* explizit deklariert (z.B. `{ unique: true, columns: ["key", "tenantId", "userId"] }`). */
|
|
399
|
+
readonly indexes?: readonly EntityIndexDef[];
|
|
400
|
+
/**
|
|
401
|
+
* PK-Typ der Entity.
|
|
402
|
+
* - `"serial"` (default): bigserial integer — schneller, kompakter, perfekt für klassische CRUD-Entities.
|
|
403
|
+
* - `"uuid"`: uuid mit `gen_random_uuid()` default — verpflichtend für Entities deren `id` als
|
|
404
|
+
* Foreign-Key-Wert in multi-tenant Kontexten reist (z.B. `tenant.id` IS der `tenantId`). Auch für
|
|
405
|
+
* ES-Aggregate (Phase 2+) notwendig, da Events per UUID aggregiert werden.
|
|
406
|
+
*/
|
|
407
|
+
readonly idType?: "serial" | "uuid";
|
|
408
|
+
/**
|
|
409
|
+
* Row-level ownership rules (H.2). read runs as WHERE-predicate on list/
|
|
410
|
+
* detail/queryProjection, scoping which rows the caller sees. write runs
|
|
411
|
+
* pre-save on create/update/delete, scoping which rows the caller may
|
|
412
|
+
* modify (Straddle-safe, multi-role atomic — see engine/ownership.ts).
|
|
413
|
+
*
|
|
414
|
+
* Keys are role names; rules use the `from()` helper or `{ where }`
|
|
415
|
+
* escape hatch. Entity-level ownership is AND-ed with tenant isolation —
|
|
416
|
+
* a user's tenant filter still applies first.
|
|
417
|
+
*/
|
|
418
|
+
readonly access?: {
|
|
419
|
+
readonly read?: OwnershipMap;
|
|
420
|
+
readonly write?: OwnershipMap;
|
|
421
|
+
};
|
|
422
|
+
};
|