rcf-lite 0.21.0 → 0.22.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/CHANGELOG.md +16 -0
- package/blueprints/application-account-settings/CHANGELOG.md +12 -0
- package/blueprints/application-account-settings/README.md +114 -0
- package/blueprints/application-account-settings/blueprint.json +234 -0
- package/blueprints/application-account-settings/contributions/adrs/adr-2601-application-account-settings-capability-vocabulary.json +20 -0
- package/blueprints/application-account-settings/contributions/adrs/adr-2602-application-account-settings-security-surface-shape.json +20 -0
- package/blueprints/application-account-settings/contributions/adrs/adr-2603-application-account-settings-theme-persistence.json +20 -0
- package/blueprints/application-account-settings/contributions/adrs/adr-2604-application-account-settings-reauth-window.json +20 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-001.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-002.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-003.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-004.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-005.json +18 -0
- package/blueprints/application-account-settings/contributions/requirements/application-account-settings-req-006.json +18 -0
- package/blueprints/application-account-settings/contributions/tacs/tac-2601-application-account-settings-shell.json +41 -0
- package/blueprints/application-account-settings/contributions/tacs/tac-2602-application-account-settings-capability-discovery.json +28 -0
- package/blueprints/application-account-settings/contributions/tacs/tac-2603-application-account-settings-hosted-ui-bridge.json +35 -0
- package/blueprints/application-account-settings/contributions/tacs/tac-2604-application-account-settings-session-store.json +40 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25101.json +34 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25102.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25103.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25104.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25105.json +33 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25106.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25107.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25108.json +27 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25109.json +33 -0
- package/blueprints/application-account-settings/contributions/user-stories/application-account-settings-us-25110.json +27 -0
- package/blueprints/application-account-settings/docs/topics.md +48 -0
- package/blueprints/application-account-settings/guide/application-account-settings.md +30 -0
- package/blueprints/application-account-settings/probe-packs/application-account-settings.pack.mjs +246 -0
- package/blueprints/application-admin-console/docs/topics.md +7 -0
- package/blueprints/application-api-rest/docs/topics.md +8 -1
- package/blueprints/application-charts/docs/topics.md +7 -0
- package/blueprints/application-dashboard/docs/topics.md +7 -0
- package/blueprints/application-datatable/docs/topics.md +7 -0
- package/blueprints/application-empty-error-states/CHANGELOG.md +9 -0
- package/blueprints/application-empty-error-states/README.md +88 -0
- package/blueprints/application-empty-error-states/blueprint.json +119 -0
- package/blueprints/application-empty-error-states/contributions/adrs/adr-2301-application-empty-error-states-status-contract.json +25 -0
- package/blueprints/application-empty-error-states/contributions/adrs/adr-2302-application-empty-error-states-stack-trace-visibility.json +25 -0
- package/blueprints/application-empty-error-states/contributions/adrs/adr-2303-application-empty-error-states-offline-strategy.json +25 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-001.json +18 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-002.json +18 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-003.json +18 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-004.json +18 -0
- package/blueprints/application-empty-error-states/contributions/requirements/application-empty-error-states-req-005.json +18 -0
- package/blueprints/application-empty-error-states/contributions/tacs/tac-2301-application-empty-error-states-state-machine.json +46 -0
- package/blueprints/application-empty-error-states/contributions/tacs/tac-2302-application-empty-error-states-recovery-router.json +36 -0
- package/blueprints/application-empty-error-states/contributions/tacs/tac-2303-application-empty-error-states-offline-buffer.json +40 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22101.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22102.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22103.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22104.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22105.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22106.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22107.json +29 -0
- package/blueprints/application-empty-error-states/contributions/user-stories/application-empty-error-states-us-22108.json +29 -0
- package/blueprints/application-empty-error-states/docs/topics.md +53 -0
- package/blueprints/application-empty-error-states/guide/application-empty-error-states.md +50 -0
- package/blueprints/application-empty-error-states/probe-packs/application-empty-error-states.pack.mjs +284 -0
- package/blueprints/application-error-handling/docs/topics.md +7 -0
- package/blueprints/application-file-upload/CHANGELOG.md +9 -0
- package/blueprints/application-file-upload/README.md +85 -0
- package/blueprints/application-file-upload/blueprint.json +114 -0
- package/blueprints/application-file-upload/contributions/adrs/adr-2401-application-file-upload-transport.json +25 -0
- package/blueprints/application-file-upload/contributions/adrs/adr-2402-application-file-upload-accepted-set.json +25 -0
- package/blueprints/application-file-upload/contributions/adrs/adr-2403-application-file-upload-virus-scan.json +25 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-001.json +18 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-002.json +18 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-003.json +18 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-004.json +18 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-005.json +18 -0
- package/blueprints/application-file-upload/contributions/tacs/tac-2401-application-file-upload-input.json +46 -0
- package/blueprints/application-file-upload/contributions/tacs/tac-2402-application-file-upload-transport.json +47 -0
- package/blueprints/application-file-upload/contributions/tacs/tac-2403-application-file-upload-progress-announcer.json +46 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23101.json +28 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23102.json +28 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23103.json +29 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23104.json +28 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23105.json +29 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23106.json +28 -0
- package/blueprints/application-file-upload/contributions/user-stories/application-file-upload-us-23107.json +28 -0
- package/blueprints/application-file-upload/docs/topics.md +58 -0
- package/blueprints/application-file-upload/guide/application-file-upload.md +48 -0
- package/blueprints/application-file-upload/probe-packs/application-file-upload.pack.mjs +238 -0
- package/blueprints/application-forms-wizard/CHANGELOG.md +9 -0
- package/blueprints/application-forms-wizard/README.md +102 -0
- package/blueprints/application-forms-wizard/blueprint.json +120 -0
- package/blueprints/application-forms-wizard/contributions/adrs/adr-2501-application-forms-wizard-navigation.json +25 -0
- package/blueprints/application-forms-wizard/contributions/adrs/adr-2502-application-forms-wizard-save-and-return.json +25 -0
- package/blueprints/application-forms-wizard/contributions/adrs/adr-2503-application-forms-wizard-step-indicator.json +25 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-001.json +18 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-002.json +18 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-003.json +18 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-004.json +18 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-005.json +18 -0
- package/blueprints/application-forms-wizard/contributions/tacs/tac-2501-application-forms-wizard-task-list.json +46 -0
- package/blueprints/application-forms-wizard/contributions/tacs/tac-2502-application-forms-wizard-error-summary.json +40 -0
- package/blueprints/application-forms-wizard/contributions/tacs/tac-2503-application-forms-wizard-draft-store.json +40 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24101.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24102.json +29 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24103.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24104.json +29 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24105.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24106.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24107.json +28 -0
- package/blueprints/application-forms-wizard/contributions/user-stories/application-forms-wizard-us-24108.json +29 -0
- package/blueprints/application-forms-wizard/docs/topics.md +49 -0
- package/blueprints/application-forms-wizard/guide/application-forms-wizard.md +48 -0
- package/blueprints/application-forms-wizard/probe-packs/application-forms-wizard.pack.mjs +233 -0
- package/blueprints/application-notifications-in-app/docs/topics.md +7 -0
- package/blueprints/application-onboarding-tour/CHANGELOG.md +12 -0
- package/blueprints/application-onboarding-tour/README.md +77 -0
- package/blueprints/application-onboarding-tour/blueprint.json +164 -0
- package/blueprints/application-onboarding-tour/contributions/adrs/adr-2701-application-onboarding-tour-dismissal-policy.json +20 -0
- package/blueprints/application-onboarding-tour/contributions/adrs/adr-2702-application-onboarding-tour-completion-store-shape.json +20 -0
- package/blueprints/application-onboarding-tour/contributions/adrs/adr-2703-application-onboarding-tour-checklist-anchor.json +20 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-001.json +18 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-002.json +18 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-003.json +18 -0
- package/blueprints/application-onboarding-tour/contributions/requirements/application-onboarding-tour-req-004.json +18 -0
- package/blueprints/application-onboarding-tour/contributions/tacs/tac-2701-application-onboarding-tour-step-runner.json +41 -0
- package/blueprints/application-onboarding-tour/contributions/tacs/tac-2702-application-onboarding-tour-checklist-slot.json +35 -0
- package/blueprints/application-onboarding-tour/contributions/tacs/tac-2703-application-onboarding-tour-completion-store.json +34 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26101.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26102.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26103.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26104.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26105.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26106.json +27 -0
- package/blueprints/application-onboarding-tour/contributions/user-stories/application-onboarding-tour-us-26107.json +27 -0
- package/blueprints/application-onboarding-tour/docs/topics.md +48 -0
- package/blueprints/application-onboarding-tour/guide/application-onboarding-tour.md +59 -0
- package/blueprints/application-onboarding-tour/probe-packs/application-onboarding-tour.pack.mjs +231 -0
- package/blueprints/application-spa/docs/topics.md +8 -1
- package/blueprints/delivery-ci-workflows/docs/topics.md +8 -1
- package/blueprints/deploy-cloudflare-workers/docs/topics.md +8 -1
- package/blueprints/email-smtp-resend/docs/topics.md +8 -1
- package/blueprints/object-storage-s3/CHANGELOG.md +13 -0
- package/blueprints/object-storage-s3/README.md +108 -0
- package/blueprints/object-storage-s3/blueprint.json +72 -0
- package/blueprints/object-storage-s3/contributions/adrs/adr-2901-object-storage-s3-adapter.json +30 -0
- package/blueprints/object-storage-s3/contributions/adrs/adr-2902-object-storage-s3-presigned-ttl-floor.json +25 -0
- package/blueprints/object-storage-s3/contributions/adrs/adr-2903-object-storage-s3-multipart-threshold.json +25 -0
- package/blueprints/object-storage-s3/contributions/adrs/adr-2904-object-storage-s3-contract.json +25 -0
- package/blueprints/object-storage-s3/contributions/probes/event-secrecy.mjs +103 -0
- package/blueprints/object-storage-s3/contributions/probes/facade-round-trip.mjs +43 -0
- package/blueprints/object-storage-s3/contributions/probes/multipart-upload.mjs +84 -0
- package/blueprints/object-storage-s3/contributions/probes/presigned-url.mjs +101 -0
- package/blueprints/object-storage-s3/contributions/probes/probe-utils.mjs +85 -0
- package/blueprints/object-storage-s3/contributions/probes/put-get-round-trip.mjs +84 -0
- package/blueprints/object-storage-s3/contributions/probes/r2-real-account-smoke.mjs +64 -0
- package/blueprints/object-storage-s3/contributions/probes/run-event-secrecy.mjs +4 -0
- package/blueprints/object-storage-s3/contributions/probes/run-facade-round-trip.mjs +10 -0
- package/blueprints/object-storage-s3/contributions/probes/run-multipart-upload.mjs +4 -0
- package/blueprints/object-storage-s3/contributions/probes/run-presigned-url.mjs +4 -0
- package/blueprints/object-storage-s3/contributions/probes/run-put-get-round-trip.mjs +7 -0
- package/blueprints/object-storage-s3/contributions/probes/run-r2-real-account-smoke.mjs +4 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-001.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-002.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-003.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-004.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-005.json +18 -0
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-006.json +18 -0
- package/blueprints/object-storage-s3/contributions/tacs/tac-2901-object-storage-s3-facade.json +57 -0
- package/blueprints/object-storage-s3/contributions/tacs/tac-2902-object-storage-s3-multipart-uploader.json +36 -0
- package/blueprints/object-storage-s3/contributions/tacs/tac-2903-object-storage-s3-event-sink.json +36 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28101.json +34 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28102.json +43 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28103.json +25 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28104.json +34 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28105.json +25 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28106.json +34 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28107.json +34 -0
- package/blueprints/object-storage-s3/contributions/user-stories/object-storage-s3-us-28108.json +34 -0
- package/blueprints/object-storage-s3/docs/topics.md +62 -0
- package/blueprints/object-storage-s3/guide/object-storage-s3.md +207 -0
- package/blueprints/observability-essentials/docs/topics.md +8 -1
- package/blueprints/observability-logging/CHANGELOG.md +4 -0
- package/blueprints/observability-logging/README.md +3 -0
- package/blueprints/observability-logging/blueprint.json +3 -2
- package/blueprints/observability-logging/docs/topics.md +7 -0
- package/blueprints/observability-probe-endpoints/docs/topics.md +8 -1
- package/blueprints/persistence-data-d1/docs/topics.md +8 -1
- package/blueprints/persistence-data-postgres/CHANGELOG.md +12 -0
- package/blueprints/persistence-data-postgres/README.md +101 -0
- package/blueprints/persistence-data-postgres/blueprint.json +80 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2801-persistence-data-postgres-driver.json +30 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2802-persistence-data-postgres-migration-shape.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2803-persistence-data-postgres-runner-mode.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2804-persistence-data-postgres-recovery.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2805-persistence-data-postgres-connection-pool-posture.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/probes/facade-round-trip.mjs +56 -0
- package/blueprints/persistence-data-postgres/contributions/probes/migration-apply.mjs +75 -0
- package/blueprints/persistence-data-postgres/contributions/probes/pool-posture-smoke.mjs +56 -0
- package/blueprints/persistence-data-postgres/contributions/probes/prepared-statement-scan.mjs +186 -0
- package/blueprints/persistence-data-postgres/contributions/probes/probe-utils.mjs +76 -0
- package/blueprints/persistence-data-postgres/contributions/probes/recovery-restore-round-trip.mjs +173 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-facade-round-trip.mjs +10 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-migration-apply.mjs +10 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-pool-posture-smoke.mjs +9 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-prepared-statement-scan.mjs +10 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-recovery-restore-round-trip.mjs +9 -0
- package/blueprints/persistence-data-postgres/contributions/probes/run-transaction-atomicity.mjs +10 -0
- package/blueprints/persistence-data-postgres/contributions/probes/transaction-atomicity.mjs +79 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-001.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-002.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-003.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-004.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-005.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-006.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-007.json +18 -0
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2801-persistence-data-postgres-facade.json +58 -0
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2802-persistence-data-postgres-migration-runner.json +40 -0
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2803-persistence-data-postgres-transaction-helper.json +35 -0
- package/blueprints/persistence-data-postgres/contributions/tacs/tac-2804-persistence-data-postgres-recovery-runner.json +40 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27101.json +34 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27102.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27103.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27104.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27105.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27106.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27107.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27108.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27109.json +25 -0
- package/blueprints/persistence-data-postgres/contributions/user-stories/persistence-data-postgres-us-27110.json +25 -0
- package/blueprints/persistence-data-postgres/docs/topics.md +64 -0
- package/blueprints/persistence-data-postgres/guide/persistence-data-postgres.md +172 -0
- package/blueprints/persistence-data-sqlite/docs/topics.md +8 -1
- package/blueprints/security-auth-clerk/CHANGELOG.md +4 -0
- package/blueprints/security-auth-clerk/README.md +3 -0
- package/blueprints/security-auth-clerk/blueprint.json +147 -30
- package/blueprints/security-auth-clerk/docs/topics.md +8 -1
- package/blueprints/security-auth-keycloak/CHANGELOG.md +4 -0
- package/blueprints/security-auth-keycloak/README.md +3 -0
- package/blueprints/security-auth-keycloak/blueprint.json +182 -37
- package/blueprints/security-auth-keycloak/docs/topics.md +8 -1
- package/blueprints/security-auth-magic-link/CHANGELOG.md +4 -0
- package/blueprints/security-auth-magic-link/README.md +3 -0
- package/blueprints/security-auth-magic-link/blueprint.json +159 -33
- package/blueprints/security-auth-magic-link/docs/topics.md +8 -1
- package/blueprints/security-auth-oauth2/CHANGELOG.md +4 -0
- package/blueprints/security-auth-oauth2/README.md +3 -0
- package/blueprints/security-auth-oauth2/blueprint.json +158 -32
- package/blueprints/security-auth-oauth2/docs/topics.md +8 -1
- package/blueprints/security-secrets-management/CHANGELOG.md +11 -0
- package/blueprints/security-secrets-management/blueprint.json +2 -1
- package/blueprints/security-secrets-management/docs/topics.md +8 -1
- package/fixtures/canary-manifest.json +9 -9
- package/package.json +1 -1
- package/rcf/code-nodes/cn-134.json +13 -0
- package/rcf/code-nodes/cn-135.json +12 -0
- package/rcf/code-nodes/cn-136.json +13 -0
- package/rcf/code-nodes/cn-137.json +13 -0
- package/rcf/code-nodes/cn-138.json +12 -0
- package/rcf/code-nodes/cn-139.json +12 -0
- package/rcf/code-nodes/cn-140.json +13 -0
- package/rcf/code-nodes/cn-141.json +13 -0
- package/rcf/code-nodes/cn-142.json +12 -0
- package/rcf/code-nodes/cn-143.json +13 -0
- package/rcf/code-nodes/cn-144.json +13 -0
- package/rcf/code-nodes/cn-145.json +12 -0
- package/rcf/code-nodes/cn-146.json +12 -0
- package/rcf/code-nodes/cn-147.json +13 -0
- package/rcf/code-nodes/cn-148.json +13 -0
- package/rcf/code-nodes/cn-149.json +12 -0
- package/rcf/code-nodes/cn-150.json +13 -0
- package/rcf/code-nodes/cn-151.json +13 -0
- package/rcf/code-nodes/cn-152.json +12 -0
- package/rcf/code-nodes/cn-153.json +12 -0
- package/rcf/code-nodes/cn-154.json +13 -0
- package/rcf/code-nodes/cn-155.json +14 -0
- package/rcf/code-nodes/cn-156.json +13 -0
- package/rcf/code-nodes/cn-157.json +13 -0
- package/rcf/code-nodes/cn-158.json +12 -0
- package/rcf/code-nodes/cn-159.json +13 -0
- package/rcf/code-nodes/cn-160.json +12 -0
- package/rcf/code-nodes/cn-161.json +12 -0
- package/rcf/code-nodes/cn-162.json +13 -0
- package/rcf/code-nodes/cn-163.json +12 -0
- package/rcf/code-nodes/cn-164.json +13 -0
- package/rcf/code-nodes/cn-165.json +12 -0
- package/rcf/code-nodes/cn-166.json +12 -0
- package/rcf/code-nodes/cn-167.json +12 -0
- package/rcf/code-nodes/cn-168.json +12 -0
- package/rcf/code-nodes/cn-169.json +12 -0
- package/rcf/code-nodes/cn-170.json +12 -0
- package/rcf/code-nodes/cn-171.json +12 -0
- package/rcf/code-nodes/cn-172.json +12 -0
- package/rcf/code-nodes/cn-173.json +12 -0
- package/rcf/code-nodes/cn-174.json +12 -0
- package/rcf/code-nodes/cn-175.json +13 -0
- package/rcf/code-nodes/cn-176.json +12 -0
- package/rcf/code-nodes/cn-177.json +12 -0
- package/rcf/code-nodes/cn-178.json +12 -0
- package/rcf/code-nodes/cn-179.json +12 -0
- package/rcf/code-nodes/cn-180.json +13 -0
- package/rcf/code-nodes/cn-181.json +12 -0
- package/rcf/code-nodes/cn-182.json +13 -0
- package/rcf/code-nodes/cn-183.json +12 -0
- package/rcf/code-nodes/cn-184.json +13 -0
- package/rcf/code-nodes/cn-185.json +12 -0
- package/rcf/code-nodes/cn-186.json +12 -0
- package/rcf/code-nodes/cn-200.json +14 -0
- package/rcf/code-nodes/cn-201.json +13 -0
- package/rcf/code-nodes/cn-202.json +14 -0
- package/rcf/code-nodes/cn-203.json +14 -0
- package/rcf/code-nodes/cn-204.json +13 -0
- package/rcf/code-nodes/cn-205.json +14 -0
- package/rcf/fbs/fbs-043.json +23 -0
- package/rcf/fbs/fbs-044.json +23 -0
- package/rcf/fbs/fbs-045.json +23 -0
- package/rcf/fbs/fbs-046.json +24 -0
- package/rcf/fbs/fbs-047.json +24 -0
- package/rcf/fbs/fbs-060.json +22 -0
- package/rcf/fbs/fbs-061.json +20 -0
- package/rcf/requirements/req-024.json +69 -0
- package/rcf/requirements/req-025.json +59 -0
- package/rcf/requirements/req-026.json +154 -0
- package/rcf/requirements/req-027.json +33 -0
- package/rcf/requirements/req-028.json +13 -0
- package/rcf/requirements/req-040.json +13 -0
- package/rcf/requirements/req-041.json +125 -0
- package/rcf/test-suites/ts-053.json +70 -0
- package/rcf/test-suites/ts-054.json +70 -0
- package/rcf/test-suites/ts-055.json +77 -0
- package/rcf/test-suites/ts-056.json +78 -0
- package/rcf/test-suites/ts-057.json +78 -0
- package/rcf/test-suites/ts-070.json +62 -0
- package/rcf/test-suites/ts-071.json +62 -0
- package/rcf/user-stories/us-2401.json +62 -0
- package/rcf/user-stories/us-2501.json +58 -0
- package/rcf/user-stories/us-2601.json +51 -0
- package/rcf/user-stories/us-2701.json +55 -0
- package/rcf/user-stories/us-2801.json +55 -0
- package/rcf/user-stories/us-4001.json +69 -0
- package/rcf/user-stories/us-4101.json +69 -0
- package/releases/releases.yaml +11 -1
- package/src/blueprint/apply.js +10 -1
- package/src/blueprint/capabilities.js +41 -2
- package/src/cli/blueprint.js +8 -1
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# object-storage-s3 guide
|
|
2
|
+
|
|
3
|
+
## What this blueprint gets you
|
|
4
|
+
|
|
5
|
+
S3-shape object storage on any S3-compatible endpoint: Cloudflare R2 (the shipped first adapter target), AWS S3, MinIO (for local dev), Backblaze B2 in S3-compat mode, Wasabi, or self-hosted MinIO in production. The store facade is the sole reader of the S3 client (`@aws-sdk/client-s3` on Node targets or `aws4fetch` on Workers targets, elicited under ADR-2901). Consumer code calls named domain verbs on the facade and never touches the raw S3 client. Multipart-upload is invisible to consumer code: a payload above the elicited threshold (default 8 MiB per ADR-2903) switches transparently, with `AbortMultipartUpload` on failure so no orphan in-flight uploads remain. Presigned GET URLs come with a bounded TTL (floor 1 minute, default 15 minutes per ADR-2902). Four lifecycle events (`facadeReady`, `objectPut`, `objectDeleted`, `presignedIssued`) fire on the injected event sink with a metadata-only whitelist so consumer logging cannot leak object body bytes, user ids, or PII from the object.
|
|
6
|
+
|
|
7
|
+
## Apply this blueprint
|
|
8
|
+
|
|
9
|
+
`security-secrets-management` v1.0.1+ MUST be applied first per REQ-006 (Baz decision 6). The blueprint declares `requiresAppliedCapabilities: {capabilities: ["secretsProvider"], allowSkipFlag: "allow-no-secrets-yet", refusalMessageId: "object-storage-s3-no-secrets"}` and the T-5 capability mechanism (visual round spec 5.5.1) enforces the refusal at apply time. On a project that has not applied secrets-management:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
rcf define blueprint add object-storage-s3
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
exits 3 with `[object-storage-s3-no-secrets]` on stderr as the first-line tag; the message names the required capability (`secretsProvider`), the shipped predecessor (`security-secrets-management` v1.0.1+), and `--allow-no-secrets-yet` as the override for a scaffolding pass. The override applies the blueprint cleanly and records a `notes` line on `rcf/blueprints/object-storage-s3.applied.json` naming the missing predecessor so a later `rcf define validate` pass can flag the surface as not-yet-activated. Apply secrets-management first, then:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
rcf define blueprint add security-secrets-management
|
|
19
|
+
rcf define blueprint add object-storage-s3
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
On a project that already applied `object-storage-s3` and later needs a different wire-shape (a native-GCS or native-Azure sibling), `rcf define blueprint add object-storage-native-gcs` (once minted) surfaces a DELIBERATE conflict on the `objectStorageContract` global-ADR topic; resolve with one project-level ADR.
|
|
23
|
+
|
|
24
|
+
## Facade shape
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
import { createObjectStore } from './object-store.mjs';
|
|
28
|
+
import { secretsShim } from './secrets.mjs';
|
|
29
|
+
|
|
30
|
+
const credentials = await secretsShim.getSecret('objectStorageCredentials');
|
|
31
|
+
const store = createObjectStore({
|
|
32
|
+
endpointUrl: process.env.S3_ENDPOINT_URL, // https://<account-id>.r2.cloudflarestorage.com on R2
|
|
33
|
+
bucket: process.env.S3_BUCKET, // rcf-test on the fixture
|
|
34
|
+
credentialsRef: credentials, // { accessKeyId, secretAccessKey } via security-secrets-management
|
|
35
|
+
region: 'auto', // 'auto' for R2; 'eu-west-2' etc. for AWS S3
|
|
36
|
+
forcePathStyle: false, // true for MinIO; false for R2 and AWS with virtual-hosted style
|
|
37
|
+
onEvent: (record) => logger.log('object-storage', record),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
await store.ready();
|
|
41
|
+
|
|
42
|
+
// put a 1 KiB payload
|
|
43
|
+
await store.putObject('uploads/report.pdf', 'application/pdf', pdfBuffer);
|
|
44
|
+
|
|
45
|
+
// get and stream to a caller
|
|
46
|
+
const { body, contentType } = await store.getObject('uploads/report.pdf');
|
|
47
|
+
|
|
48
|
+
// presign a GET URL with a bounded TTL
|
|
49
|
+
const url = await store.presignGetUrl('uploads/report.pdf', 300); // 5 minutes
|
|
50
|
+
|
|
51
|
+
// delete
|
|
52
|
+
await store.deleteObject('uploads/report.pdf');
|
|
53
|
+
|
|
54
|
+
// list under a prefix
|
|
55
|
+
const { keys, isTruncated } = await store.listObjects('uploads/');
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The facade is the sole importer of `@aws-sdk/client-s3` in your source tree per REQ-001. A project-side call site that reaches into the SDK directly is refused at author-side review.
|
|
59
|
+
|
|
60
|
+
## Adapter choice per deploy target
|
|
61
|
+
|
|
62
|
+
ADR-2901 elicits the adapter per deploy target:
|
|
63
|
+
|
|
64
|
+
- **Node process** (server, container, non-Workers serverless): `@aws-sdk/client-s3` (AWS SDK v3, modular client-s3 package). Ships every op the v1.0.0 surface needs.
|
|
65
|
+
- **Cloudflare Workers**: `aws4fetch` (lightweight fetch-native S3 client). Sits within the Workers CPU-time budget where the AWS SDK's Node polyfills do not.
|
|
66
|
+
|
|
67
|
+
The facade's outward interface is unchanged across adapters; only the import at the top of the facade module changes. A future adapter (a GCS shim, an Azure Blob shim under a sibling blueprint) slots in at the same boundary.
|
|
68
|
+
|
|
69
|
+
## Presigned URL discipline
|
|
70
|
+
|
|
71
|
+
ADR-2902 sets the default TTL to 15 minutes and the floor to 1 minute. The facade refuses a presign below 60 seconds; the ceiling is elicited (no shipped default). Every `presignedIssued` event carries `{event, ts, key, ttl}` so downstream logging can flag long-lived URLs. The URL is signed at the client edge with the applied credentials; the browser or downstream caller fetches from the storage endpoint directly.
|
|
72
|
+
|
|
73
|
+
## Multipart upload
|
|
74
|
+
|
|
75
|
+
ADR-2903 sets the default multipart threshold to 8 MiB (matches AWS SDK convention). Below the threshold, `putObject` goes single-part; above, it delegates to the multipart uploader (TAC-2902):
|
|
76
|
+
|
|
77
|
+
1. `CreateMultipartUpload` returns an `UploadId`.
|
|
78
|
+
2. `UploadPart` per fixed-size chunk (default 8 MiB per part) with a stable `PartNumber` and captured `ETag`.
|
|
79
|
+
3. `CompleteMultipartUpload` with the ordered part list.
|
|
80
|
+
|
|
81
|
+
On any part-upload failure, `AbortMultipartUpload` runs before the error propagates so no orphan multipart upload remains on the bucket. `ListMultipartUploads(prefix=key)` after a successful completion returns zero uploads.
|
|
82
|
+
|
|
83
|
+
**R2 multipart re-upload gotcha** (per https://developers.cloudflare.com/r2/api/s3/api/): re-uploading to the same part number replaces the previous part with loss-on-fail semantics. If a re-upload fails, the original part is gone. The facade avoids the case in its shipped path (parts are single-attempt; abort-on-failure covers the mid-multipart error), but a consumer that layers its own retry on top of `putObject` should retry the whole put, not a partial multipart.
|
|
84
|
+
|
|
85
|
+
## Lifecycle events and PII discipline
|
|
86
|
+
|
|
87
|
+
The facade emits four events on the injected sink with a fixed metadata-only field discipline (TAC-2903):
|
|
88
|
+
|
|
89
|
+
| Event | Fields |
|
|
90
|
+
|---|---|
|
|
91
|
+
| `facadeReady` | `event`, `ts`, `endpointHost`, `bucketName` |
|
|
92
|
+
| `objectPut` | `event`, `ts`, `key`, `size`, `contentType` |
|
|
93
|
+
| `objectDeleted` | `event`, `ts`, `key` |
|
|
94
|
+
| `presignedIssued` | `event`, `ts`, `key`, `ttl` |
|
|
95
|
+
|
|
96
|
+
No record carries object body bytes, no body checksum, no user id field, no PII drawn from the object body. The `event-secrecy` probe (AC-28105-1) drives put/get/presign/delete against a PII fixture (key `users/1234/passport.jpg`, body containing `PII-FIXTURE-DO-NOT-LOG`) and asserts the whitelist compliance at ship time.
|
|
97
|
+
|
|
98
|
+
## R2 deviations from full S3
|
|
99
|
+
|
|
100
|
+
Cloudflare R2 is S3-compatible per https://developers.cloudflare.com/r2/api/s3/api/ but explicitly does not implement:
|
|
101
|
+
|
|
102
|
+
- **ACLs**: no per-object or per-bucket ACLs; use Cloudflare account roles and bucket-level API tokens.
|
|
103
|
+
- **Bucket policies**: no S3-style JSON bucket policies.
|
|
104
|
+
- **Object Lock**: no WORM or retention hold surface.
|
|
105
|
+
- **Versioning**: no object versioning; a put replaces the object.
|
|
106
|
+
- **Lifecycle policies**: R2 marks lifecycle configuration as "feature implementation is currently in progress"; do not depend on time-based expiration or class transitions on R2 at v1.0.0.
|
|
107
|
+
|
|
108
|
+
An operator relying on any of the four either picks a different endpoint (AWS S3 covers all four) or handles the equivalent semantics application-side.
|
|
109
|
+
|
|
110
|
+
## CI seam
|
|
111
|
+
|
|
112
|
+
The `object-storage-s3` facade needs an S3-compatible endpoint reachable from the CI runner. On GitHub Actions the standard shape is a `services:` block with MinIO as a service container. Per https://docs.github.com/en/actions/using-containerized-services/about-service-containers the runner exposes the service either at the label hostname (for container-hosted jobs) or at the mapped port (for host-runner jobs). The blueprint's applying project realises this block in its own `.github/workflows/pull-request-checks.yml`:
|
|
113
|
+
|
|
114
|
+
**Container-hosted job (hostname exposure):**
|
|
115
|
+
|
|
116
|
+
```yaml
|
|
117
|
+
jobs:
|
|
118
|
+
gate:
|
|
119
|
+
runs-on: ubuntu-latest
|
|
120
|
+
container: node:24
|
|
121
|
+
services:
|
|
122
|
+
minio:
|
|
123
|
+
image: minio/minio:latest
|
|
124
|
+
env:
|
|
125
|
+
MINIO_ROOT_USER: rcf-dev
|
|
126
|
+
MINIO_ROOT_PASSWORD: rcf-dev-only
|
|
127
|
+
ports:
|
|
128
|
+
- 9000:9000
|
|
129
|
+
- 9001:9001
|
|
130
|
+
options: >-
|
|
131
|
+
--entrypoint sh -c "minio server /data --console-address ':9001'"
|
|
132
|
+
--health-cmd "curl -f http://localhost:9000/minio/health/live"
|
|
133
|
+
--health-interval 3s --health-timeout 3s --health-retries 20
|
|
134
|
+
env:
|
|
135
|
+
S3_ENDPOINT_URL: http://minio:9000
|
|
136
|
+
S3_BUCKET: rcf-test
|
|
137
|
+
S3_ACCESS_KEY_ID: rcf-dev
|
|
138
|
+
S3_SECRET_ACCESS_KEY: rcf-dev-only
|
|
139
|
+
S3_FORCE_PATH_STYLE: 'true'
|
|
140
|
+
steps:
|
|
141
|
+
- uses: actions/checkout@v4
|
|
142
|
+
- run: pnpm install
|
|
143
|
+
- run: node packages/rcf-lite/test/fixtures/infra-s3-and-queue/src/create-bucket.mjs
|
|
144
|
+
- run: node blueprints/object-storage-s3/contributions/probes/run-facade-round-trip.mjs
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Host-runner job (mapped port exposure):**
|
|
148
|
+
|
|
149
|
+
```yaml
|
|
150
|
+
jobs:
|
|
151
|
+
gate:
|
|
152
|
+
runs-on: ubuntu-latest
|
|
153
|
+
services:
|
|
154
|
+
minio:
|
|
155
|
+
image: minio/minio:latest
|
|
156
|
+
env:
|
|
157
|
+
MINIO_ROOT_USER: rcf-dev
|
|
158
|
+
MINIO_ROOT_PASSWORD: rcf-dev-only
|
|
159
|
+
ports:
|
|
160
|
+
- 9000:9000
|
|
161
|
+
env:
|
|
162
|
+
S3_ENDPOINT_URL: http://localhost:9000
|
|
163
|
+
S3_BUCKET: rcf-test
|
|
164
|
+
S3_ACCESS_KEY_ID: rcf-dev
|
|
165
|
+
S3_SECRET_ACCESS_KEY: rcf-dev-only
|
|
166
|
+
S3_FORCE_PATH_STYLE: 'true'
|
|
167
|
+
steps:
|
|
168
|
+
- uses: actions/checkout@v4
|
|
169
|
+
- uses: actions/setup-node@v4
|
|
170
|
+
with: { node-version: '24' }
|
|
171
|
+
- run: pnpm install
|
|
172
|
+
- run: sleep 4 && node packages/rcf-lite/test/fixtures/infra-s3-and-queue/src/create-bucket.mjs
|
|
173
|
+
- run: node blueprints/object-storage-s3/contributions/probes/run-facade-round-trip.mjs
|
|
174
|
+
# ... plus the other four MinIO probes and the R2 smoke
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Alternate providers (GitLab CI, CircleCI, Buildkite) map through the same four-point contract per `blueprints/delivery-ci-workflows/assets/ci-provider-examples/notes.md`: job trigger, Node setup, entry-point invocation, artefact upload. The MinIO service container is the extension point.
|
|
178
|
+
|
|
179
|
+
## R2 real-account smoke
|
|
180
|
+
|
|
181
|
+
`node blueprints/object-storage-s3/contributions/probes/run-r2-real-account-smoke.mjs` behaves per spec section 3.5:
|
|
182
|
+
|
|
183
|
+
- Without `CI_HAS_CLOUDFLARE_ACCOUNT`: exits 0, writes a report with `verdict: pass, detail: "accountBound: skipped (no CI_HAS_CLOUDFLARE_ACCOUNT)", accountBoundSkipped: true`. Aggregate verdict pass.
|
|
184
|
+
- With `CI_HAS_CLOUDFLARE_ACCOUNT` set alongside `R2_ACCOUNT_ID`, `R2_BUCKET`, `S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY` on the runner env (or `.rcf/secrets/dev.env` locally): opens the facade against the R2 endpoint, puts a 1 KiB payload, gets it back byte-equal, deletes the temporary object on exit. Aggregate verdict pass.
|
|
185
|
+
|
|
186
|
+
The `accountBound` flag on the probe module surface flips the delivery-ci-workflows aggregate to pass on the skipped path per section 3.5.
|
|
187
|
+
|
|
188
|
+
## Elicited parameters
|
|
189
|
+
|
|
190
|
+
| Parameter | Default | Notes |
|
|
191
|
+
|---|---|---|
|
|
192
|
+
| endpointUrl | none | R2: `https://<account-id>.r2.cloudflarestorage.com`; AWS S3: `https://s3.<region>.amazonaws.com`; MinIO: `http://localhost:9000`. |
|
|
193
|
+
| bucket | none | The elicited bucket name. |
|
|
194
|
+
| credentialsRef | via `security-secrets-management` | `secretRef` opaque-string agreed with security-secrets-management. |
|
|
195
|
+
| adapter | `awsSdk` (Node) / `aws4fetch` (Workers) | ADR-2901. |
|
|
196
|
+
| defaultPresignTtlSeconds | 900 (15 minutes) | ADR-2902; floor 60 s enforced by facade. |
|
|
197
|
+
| multipartThresholdBytes | 8388608 (8 MiB) | ADR-2903. |
|
|
198
|
+
| forcePathStyle | `false` | `true` for MinIO. |
|
|
199
|
+
| region | `auto` | `auto` for R2; standard AWS region for AWS S3. |
|
|
200
|
+
| serverSideEncryption | none shipped | R2 is SSE-C only; AWS S3 supports `sseS3`; elicited per deploy target. |
|
|
201
|
+
|
|
202
|
+
## Standards trace
|
|
203
|
+
|
|
204
|
+
- Cloudflare R2 S3-compatibility surface: https://developers.cloudflare.com/r2/api/s3/api/ (supported ops, four deviations).
|
|
205
|
+
- Cloudflare R2 overview and presigned URLs: https://developers.cloudflare.com/r2/.
|
|
206
|
+
- MinIO S3 compatibility: https://docs.min.io/community/minio-object-store/administration/object-management/object-lifecycle-management.html.
|
|
207
|
+
- GitHub Actions service containers: https://docs.github.com/en/actions/using-containerized-services/about-service-containers.
|
|
@@ -43,7 +43,7 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
43
43
|
| persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
44
44
|
| delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
|
|
45
45
|
| observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
|
|
46
|
-
| security-secrets-management | 8101-8899 | 9xx | shipped v1.0.
|
|
46
|
+
| security-secrets-management | 8101-8899 | 9xx | shipped v1.0.1 | `secretsSource` |
|
|
47
47
|
| security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
|
|
48
48
|
| security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
|
|
49
49
|
| security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
|
|
@@ -55,6 +55,13 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
55
55
|
| application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
|
|
56
56
|
| application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
|
|
57
57
|
| application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
|
|
58
|
+
| application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
|
|
59
|
+
| application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
|
|
60
|
+
| application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
|
|
61
|
+
| application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
|
|
62
|
+
| application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
|
|
63
|
+
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
64
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
|
|
58
65
|
|
|
59
66
|
US 7101-7110 sit at the LOW end of the 7101-7899 band on purpose. A project-side story that mechanically derives from an observability-essentials REQs id into the number `7110` would collide against observability-essentials-US-7110 in this package; the band leaves headroom at the HIGH end (US 7181-7899) so a project's own stories anchored to observability-essentials REQs can allocate without conflict. The watchpost run4 lesson applies here too.
|
|
60
67
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# observability-logging CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 1.2.0 (visual round T-4, spec 2026-09-06 section 5.4.2, Baz Q2 default)
|
|
4
|
+
|
|
5
|
+
- Declares `capabilities: [auditLog, sessionInventory]` on `blueprint.json`. The `sessionInventory` addition ships the logging-as-session-inventory projection: a project may configure the logger session-emission channel as the source the account-settings sessions surface reads (device labels from the User-Agent header, last-active from the last event emitted per session, terminate as an operator write into the same channel). Additive per section 6 of `blueprint-authoring.md`. Consumed at apply time by the visual round T-4 `application-account-settings` blueprint. A project that does not run the logger as a session store leaves the surface capability supplied by the applied auth blueprint alone; the account-settings blueprint reads the union.
|
|
6
|
+
|
|
3
7
|
## 1.1.0 (visual round T-5, spec 2026-09-04 section 5.5.2, Baz Q2 default)
|
|
4
8
|
|
|
5
9
|
- Declares `capabilities: [auditLog]` on `blueprint.json`. No other change. The new field is additive per section 6 of `blueprint-authoring.md` (an additive optional field with no global-topic change is a minor bump). Keeps a single grammar for capability declaration: consumer blueprints read the union of declared `capabilities[]` on applied blueprints, never the `providesRoles[]` -> capability inference. This is the ratified rule (one grammar, no role-to-capability inference); the section 6a table previously noted `auditLog` as "implicit through the `logging` role" and now names `observability-logging` as the explicit shelf provider. Consumed at apply time by the visual round T-5 `application-admin-console` blueprint to gate the audit-log surface (probe pack check `AC-21105-1`).
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Structured single-line JSON emission for a rcf-lite project. General enterprise practice, no vendor lock-in. Ships the shelf-canonical `logging` global topic on `ADR-1601-observability-logging-line-shape` (transferred from `application-api-rest-ADR-304`, retained there as superseded history). Provides the `logging` role for the companion-suggestion mechanism. From 1.1.0, declares `capabilities: [auditLog]` on `blueprint.json` so the application-admin-console probe pack activates the audit-log surface check `AC-21105-1` when this blueprint is applied on the project (one grammar; consumer blueprints read declared capabilities, never a role-to-capability inference).
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
> Latest: **v1.2.0** (visual round T-4, 2026-09-06). `capabilities: [auditLog, sessionInventory]`. See [CHANGELOG.md](CHANGELOG.md).
|
|
7
|
+
|
|
5
8
|
## Apply
|
|
6
9
|
|
|
7
10
|
```
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"slug": "observability-logging",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"category": "observability",
|
|
5
5
|
"providesRoles": [
|
|
6
6
|
"logging"
|
|
7
7
|
],
|
|
8
8
|
"capabilities": [
|
|
9
|
-
"auditLog"
|
|
9
|
+
"auditLog",
|
|
10
|
+
"sessionInventory"
|
|
10
11
|
],
|
|
11
12
|
"contributions": [
|
|
12
13
|
{
|
|
@@ -22,5 +22,12 @@
|
|
|
22
22
|
| application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
|
|
23
23
|
| application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
|
|
24
24
|
| application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
|
|
25
|
+
| application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
|
|
26
|
+
| application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
|
|
27
|
+
| application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
|
|
28
|
+
| application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
|
|
29
|
+
| application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
|
|
30
|
+
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
31
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
|
|
25
32
|
|
|
26
33
|
The shelf-wide band registry lives in `packages/rcf-lite/docs/blueprint-authoring.md` section 5.
|
|
@@ -33,7 +33,7 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
33
33
|
| persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
34
34
|
| delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
|
|
35
35
|
| observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
|
|
36
|
-
| security-secrets-management | 8101-8899 | 9xx | shipped v1.0.
|
|
36
|
+
| security-secrets-management | 8101-8899 | 9xx | shipped v1.0.1 | `secretsSource` |
|
|
37
37
|
| security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
|
|
38
38
|
| security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
|
|
39
39
|
| security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
|
|
@@ -45,6 +45,13 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
45
45
|
| application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
|
|
46
46
|
| application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
|
|
47
47
|
| application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
|
|
48
|
+
| application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
|
|
49
|
+
| application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
|
|
50
|
+
| application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
|
|
51
|
+
| application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
|
|
52
|
+
| application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
|
|
53
|
+
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
54
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
|
|
48
55
|
|
|
49
56
|
US 14101-14108 sit at the LOW end of the 14101-14899 band on purpose. A project-side story that mechanically derives from an observability-probe-endpoints REQ id into the number `14108` would collide against observability-probe-endpoints-US-14108 in this package; the band leaves headroom at the HIGH end (US 14181-14899) so a project's own stories anchored to observability-probe-endpoints REQs can allocate without conflict. The watchpost run4 lesson applies here too. Band spacing between the previous HQ-lane row (persistence-data-d1, 13101-13899, 14xx) and this one (14101-14899, 15xx) reflects the four-digit widening pattern opened by security-auth-clerk at 10xx and continued through the round-2 HQ lane.
|
|
50
57
|
|
|
@@ -31,7 +31,7 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
31
31
|
| persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
32
32
|
| delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
|
|
33
33
|
| observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
|
|
34
|
-
| security-secrets-management | 8101-8899 | 9xx | shipped v1.0.
|
|
34
|
+
| security-secrets-management | 8101-8899 | 9xx | shipped v1.0.1 | `secretsSource` |
|
|
35
35
|
| security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
|
|
36
36
|
| security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
|
|
37
37
|
| security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
|
|
@@ -43,6 +43,13 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
43
43
|
| application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
|
|
44
44
|
| application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
|
|
45
45
|
| application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
|
|
46
|
+
| application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
|
|
47
|
+
| application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
|
|
48
|
+
| application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
|
|
49
|
+
| application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
|
|
50
|
+
| application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
|
|
51
|
+
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
52
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
|
|
46
53
|
|
|
47
54
|
US 13101-13107 sit at the LOW end of the 13101-13899 band on purpose. A project-side story that mechanically derives from a persistence-data-d1 REQ id into the number `13107` would collide against persistence-data-d1-US-13107 in this package; the band leaves headroom at the HIGH end (US 13181-13899) so a project's own stories anchored to persistence-data-d1 REQs can allocate without conflict. The watchpost run4 lesson applies here too.
|
|
48
55
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# persistence-data-postgres changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0 - 2026-09-06
|
|
4
|
+
|
|
5
|
+
Initial release. Contract for Postgres as the project's primary durable relational store on a server-tier deployment (Node process, container, non-Workers serverless), accessed through a store facade module that is the sole reader of the `pg` client. Landed via the infra round 5 spec (ratified 2026-09-06) as track T-1.
|
|
6
|
+
|
|
7
|
+
- 26 contributions: 7 REQs on facade / migrations / prepared statements / transactions / recovery / pool posture / advisory-lock helper; 10 USs at 27101-27110; 4 TACs (2801 facade, 2802 migration runner, 2803 transaction helper, 2804 recovery runner); 5 ADRs (2801 driver with scope global on `persistenceStore`, 2802 migration shape with scope global on `migrationDiscipline`, 2803 runner mode, 2804 recovery, 2805 connection-pool posture).
|
|
8
|
+
- Six Node-only probes under `contributions/probes/` proven against a live `postgres:17-alpine` container: `facade-round-trip`, `migration-apply`, `prepared-statement-scan`, `transaction-atomicity`, `recovery-restore-round-trip`, `pool-posture-smoke`. None account-bound; Postgres is local-first per Baz decision 8.
|
|
9
|
+
- Sample-app fixture at `packages/rcf-lite/test/fixtures/infra-postgres/` boots `postgres:17-alpine` via docker compose, applies three toy forward-only `.sql` migrations, exposes the facade over `pg`, and hosts `SIMULATE_MIGRATION_FAILURE` and `SIMULATE_CONSTRAINT_VIOLATION` switches for the negative-run probe paths.
|
|
10
|
+
- Declares `capabilities: ["relationalStore"]`, `suggestedCompanions: [{role: "logging"}, {role: "errorHandling"}]`, `providesRoles` absent, `requiresAppliedCapabilities` absent.
|
|
11
|
+
- Reserves the round-6 Hyperdrive v1.1.0 adapter slot at ADR-2801 by keeping the driver reference opaque at the facade boundary.
|
|
12
|
+
- Advisory-lock helper (REQ-007) ships in v1.0.0 as elicited with default `off` per the ratified Q1 answer on infra round 5 spec section 10.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# persistence-data-postgres
|
|
2
|
+
|
|
3
|
+
Postgres as the project's primary durable relational store on a server-tier deployment (Node process, container, non-Workers serverless), accessed through a store facade module that is the sole reader of the `pg` client. Numbered forward-only `.sql` migrations, prepared-statement discipline, transactional atomicity, and a two-path recovery model (scheduled `pg_dump` plus vendor point-in-time recovery). ORM-neutral: a project drops Kysely or Drizzle inside the facade without moving any AC.
|
|
4
|
+
|
|
5
|
+
## What this blueprint gives you
|
|
6
|
+
|
|
7
|
+
- **A store facade** (TAC-2801) that is the sole importer of `pg` in your source tree, opens a `pg.Pool` on boot, and exposes typed named domain verbs. Emits `facadeReady` on the first successful ready-check.
|
|
8
|
+
- **A migration runner** (TAC-2802) that applies numbered forward-only `.sql` files one file per transaction against a `schema_version` bookkeeping table.
|
|
9
|
+
- **A transaction helper** (TAC-2803) wrapping `BEGIN` and `COMMIT` around a callback with `ROLLBACK` on any error and a `transactionRolledBack` event carrying the failing statement's zero-based index.
|
|
10
|
+
- **A scheduled export runner** (TAC-2804) driving `pg_dump` via `child_process.execFile` and emitting `backupExported` on completion.
|
|
11
|
+
- **Six Node-only probes** proving every runtime observable against a real `postgres:17-alpine` container.
|
|
12
|
+
|
|
13
|
+
## The seven REQs
|
|
14
|
+
|
|
15
|
+
| REQ | What it commits |
|
|
16
|
+
|---|---|
|
|
17
|
+
| REQ-001 | Facade module is the sole reader of `pg`; opens on boot; emits `facadeReady`. |
|
|
18
|
+
| REQ-002 | Numbered forward-only `.sql` migrations applied one file one transaction; `schema_version` bookkeeping. |
|
|
19
|
+
| REQ-003 | Prepared-statement discipline: every `pg.query` first argument a static string literal with `$N` parameters. |
|
|
20
|
+
| REQ-004 | Transactional atomicity via a helper wrapping `BEGIN` and `COMMIT`; `ROLLBACK` on error with `transactionRolledBack` event. |
|
|
21
|
+
| REQ-005 | Two-path recovery: scheduled `pg_dump` PLUS vendor point-in-time recovery, both required, both elicited. |
|
|
22
|
+
| REQ-006 | Connection-pool posture per deploy target: long-lived on Node, request-scoped on container. |
|
|
23
|
+
| REQ-007 | Optional advisory-lock helper elicited default `off`; session or transaction level per the Postgres explicit-locking reference. |
|
|
24
|
+
|
|
25
|
+
## The four TACs
|
|
26
|
+
|
|
27
|
+
- **TAC-2801 facade**: the Postgres store facade module.
|
|
28
|
+
- **TAC-2802 migration runner**: applies `.sql` files one file one transaction; tracks `schema_version`.
|
|
29
|
+
- **TAC-2803 transaction helper**: `BEGIN` / `COMMIT` wrapper with rollback and statement-index event.
|
|
30
|
+
- **TAC-2804 recovery runner**: scheduled `pg_dump` runner with `backupExported` event.
|
|
31
|
+
|
|
32
|
+
## The five ADRs
|
|
33
|
+
|
|
34
|
+
- **ADR-2801 driver** (scope: global, topic `persistenceStore`): pg (node-postgres) as the shipped v1.0.0 driver; opaque driver reference at the facade boundary so the round-6 Hyperdrive v1.1.0 adapter slots in without a facade re-shape. Standards trace clause: node-postgres parameterised-queries contract at https://node-postgres.com/features/queries.
|
|
35
|
+
- **ADR-2802 migration shape** (scope: global, topic `migrationDiscipline`): numbered forward-only `.sql` files; one file one transaction; migration runner tool elicited.
|
|
36
|
+
- **ADR-2803 runner mode**: `atBoot` (long-lived Node default) or `ciStep` (Workers-adjacent default); elicited.
|
|
37
|
+
- **ADR-2804 recovery**: two-path recovery, both required, cadence elicited.
|
|
38
|
+
- **ADR-2805 pool posture**: long-lived on Node, request-scoped on container, delegated to Hyperdrive on Workers-adjacent (v1.1.0). See https://www.postgresql.org/docs/current/explicit-locking.html for the session-vs-transaction advisory-lock semantics REQ-007's optional helper uses.
|
|
39
|
+
|
|
40
|
+
## Elicited parameters
|
|
41
|
+
|
|
42
|
+
Connection URL (opaque, from `security-secrets-management` when applied; project-config file otherwise); migrations directory (default `./migrations/`); runner mode (`atBoot` or `ciStep`); scheduled export destination and cadence; PITR window and retention; ORM inside the facade (`none`, `kysely`, `drizzle`, or the project's own module); expose transaction helper (`always`, `neverOutsideFacade`); advisory-lock helper (`off`, `session`, `transaction`); pool posture (`longLivedNode`, `requestScopedContainer`, `hyperdriveManaged` reserved for v1.1.0); pool sizing overrides.
|
|
43
|
+
|
|
44
|
+
## Companions
|
|
45
|
+
|
|
46
|
+
- **logging**: every migration apply, every scheduled export completion, and every transaction rollback writes a request-scoped log line; a logging companion supplies the factory.
|
|
47
|
+
- **errorHandling**: a migration failure, a constraint violation, or a pool exhaustion constructs an internal error record; an error-handling companion supplies the record factory and the boundary.
|
|
48
|
+
|
|
49
|
+
## Composition and conflicts
|
|
50
|
+
|
|
51
|
+
Composes on `security-secrets-management` for the connection URL when applied. Conflicts by design on `persistenceStore` and `migrationDiscipline` with `persistence-data-sqlite` and `persistence-data-d1`; the operator resolves via one project-level ADR per topic.
|
|
52
|
+
|
|
53
|
+
## The six probes
|
|
54
|
+
|
|
55
|
+
Each probe is a Node module under `contributions/probes/` exporting the round-5 spec section 3.2 verdict envelope, with a matching `run-<probe-name>.mjs` shim that drives the probe against the sample-app fixture and writes the per-blueprint report at `.rcf/reports/blueprints/persistence-data-postgres/<probe-name>.json`.
|
|
56
|
+
|
|
57
|
+
| Probe | Anchor AC | What it proves |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| `facade-round-trip` | AC-27101-1 | Facade opens, `facadeReady` fires with database name, put and get round-trips |
|
|
60
|
+
| `migration-apply` | AC-27102-1 | Three `.sql` files apply one file one transaction; `migrationsApplied` fires; `schema_version` advances |
|
|
61
|
+
| `prepared-statement-scan` | AC-27103-1 | Source-tree scan asserts every `.query(...)` first argument is a static string |
|
|
62
|
+
| `transaction-atomicity` | AC-27104-1 | Constraint violation rolls back; `transactionRolledBack` fires with statementIndex 1; no row persists |
|
|
63
|
+
| `recovery-restore-round-trip` | AC-27105-1 | `pg_dump` artefact primes a fresh Postgres; row-count and checksum equality |
|
|
64
|
+
| `pool-posture-smoke` | AC-27106-1 | Two facades at pool size 5 handle twenty concurrent queries with no timeout |
|
|
65
|
+
|
|
66
|
+
None of the six probes carries `accountBound: true`; Postgres is local-first per infra round 5 spec Baz decision 8.
|
|
67
|
+
|
|
68
|
+
## How to run the probes locally
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
cd packages/rcf-lite/test/fixtures/infra-postgres
|
|
72
|
+
docker compose up -d postgres
|
|
73
|
+
sleep 3
|
|
74
|
+
node ../../../../blueprints/persistence-data-postgres/contributions/probes/run-facade-round-trip.mjs
|
|
75
|
+
node ../../../../blueprints/persistence-data-postgres/contributions/probes/run-migration-apply.mjs
|
|
76
|
+
node ../../../../blueprints/persistence-data-postgres/contributions/probes/run-prepared-statement-scan.mjs
|
|
77
|
+
node ../../../../blueprints/persistence-data-postgres/contributions/probes/run-transaction-atomicity.mjs
|
|
78
|
+
node ../../../../blueprints/persistence-data-postgres/contributions/probes/run-recovery-restore-round-trip.mjs
|
|
79
|
+
node ../../../../blueprints/persistence-data-postgres/contributions/probes/run-pool-posture-smoke.mjs
|
|
80
|
+
docker compose down -v
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Each shim exits 0 on aggregate pass and 1 otherwise; every report file carries `aggregateVerdict pass` on the canonical fixture state.
|
|
84
|
+
|
|
85
|
+
## Reserved round-6 Hyperdrive adapter slot
|
|
86
|
+
|
|
87
|
+
`persistence-data-postgres` v1.1.0 (round 6) adds a `driver: "hyperdrive"` option under ADR-2801, wrapping the same facade contract with the Cloudflare Hyperdrive connection pool and query cache per https://developers.cloudflare.com/hyperdrive/. The v1.0.0 facade holds the driver reference opaque at the facade boundary (`import pg from 'pg'` lives inside the facade; the round-6 minor swaps that import), so no outward AC moves.
|
|
88
|
+
|
|
89
|
+
## Known mechanism-reach gaps
|
|
90
|
+
|
|
91
|
+
- **Prepared-statement discipline (REQ-003)** is enforced by a build-time AST scan; a project author who bypasses the facade for a project-side raw `pg.query` call site outside the facade directory is not caught by this probe. Mitigation: the facade sole-reader AC on REQ-001 pins the discipline at author-side review; the prepared-statement-scan probe walks only the facade directory by design.
|
|
92
|
+
- **Advisory-lock semantics (REQ-007)** is elicited off by default per the ratified Q1 answer. When enabled, session-level locks survive rolled-back transactions per https://www.postgresql.org/docs/current/explicit-locking.html; use `transaction` for the common case and pick `session` only when cross-transaction locking is the intent.
|
|
93
|
+
- **Pool posture per deploy target (REQ-006)** ships defaults matching pg's own; the `pool-posture-smoke` probe drives twenty concurrent queries at pool size 5 and does not impose a sizing formula. Operators sizing for their workload override via the elicited pool-config fields.
|
|
94
|
+
|
|
95
|
+
## Standards trace
|
|
96
|
+
|
|
97
|
+
- node-postgres parameterised-queries contract: https://node-postgres.com/features/queries.
|
|
98
|
+
- Postgres advisory locks (for REQ-007's optional helper): https://www.postgresql.org/docs/current/explicit-locking.html.
|
|
99
|
+
- Postgres MVCC transaction semantics: implicit in the transaction-helper probe; ADR-2803's decision cites the Postgres transaction reference without a URL requirement (the vendor doc is stable).
|
|
100
|
+
- CI service container shape: https://docs.github.com/en/actions/using-containerized-services/about-service-containers.
|
|
101
|
+
- Cloudflare Hyperdrive (reserved v1.1.0 adapter slot): https://developers.cloudflare.com/hyperdrive/.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slug": "persistence-data-postgres",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"category": "persistence",
|
|
5
|
+
"capabilities": ["relationalStore"],
|
|
6
|
+
"suggestedCompanions": [
|
|
7
|
+
{
|
|
8
|
+
"role": "logging",
|
|
9
|
+
"reason": "Every migration apply, every scheduled export completion, and every transaction rollback writes a request-scoped log line; a logging companion supplies the factory the pipeline calls."
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"role": "errorHandling",
|
|
13
|
+
"reason": "A migration failure, a constraint violation, or a pool exhaustion constructs an internal error record; an error-handling companion supplies the record factory and the boundary."
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"contributions": [
|
|
17
|
+
{ "id": "persistence-data-postgres-REQ-001", "kind": "req", "path": "requirements/persistence-data-postgres-req-001.json" },
|
|
18
|
+
{ "id": "persistence-data-postgres-REQ-002", "kind": "req", "path": "requirements/persistence-data-postgres-req-002.json" },
|
|
19
|
+
{ "id": "persistence-data-postgres-REQ-003", "kind": "req", "path": "requirements/persistence-data-postgres-req-003.json" },
|
|
20
|
+
{ "id": "persistence-data-postgres-REQ-004", "kind": "req", "path": "requirements/persistence-data-postgres-req-004.json" },
|
|
21
|
+
{ "id": "persistence-data-postgres-REQ-005", "kind": "req", "path": "requirements/persistence-data-postgres-req-005.json" },
|
|
22
|
+
{ "id": "persistence-data-postgres-REQ-006", "kind": "req", "path": "requirements/persistence-data-postgres-req-006.json" },
|
|
23
|
+
{ "id": "persistence-data-postgres-REQ-007", "kind": "req", "path": "requirements/persistence-data-postgres-req-007.json" },
|
|
24
|
+
{ "id": "persistence-data-postgres-US-27101", "kind": "us", "path": "user-stories/persistence-data-postgres-us-27101.json" },
|
|
25
|
+
{ "id": "persistence-data-postgres-US-27102", "kind": "us", "path": "user-stories/persistence-data-postgres-us-27102.json" },
|
|
26
|
+
{ "id": "persistence-data-postgres-US-27103", "kind": "us", "path": "user-stories/persistence-data-postgres-us-27103.json" },
|
|
27
|
+
{ "id": "persistence-data-postgres-US-27104", "kind": "us", "path": "user-stories/persistence-data-postgres-us-27104.json" },
|
|
28
|
+
{ "id": "persistence-data-postgres-US-27105", "kind": "us", "path": "user-stories/persistence-data-postgres-us-27105.json" },
|
|
29
|
+
{ "id": "persistence-data-postgres-US-27106", "kind": "us", "path": "user-stories/persistence-data-postgres-us-27106.json" },
|
|
30
|
+
{ "id": "persistence-data-postgres-US-27107", "kind": "us", "path": "user-stories/persistence-data-postgres-us-27107.json" },
|
|
31
|
+
{ "id": "persistence-data-postgres-US-27108", "kind": "us", "path": "user-stories/persistence-data-postgres-us-27108.json" },
|
|
32
|
+
{ "id": "persistence-data-postgres-US-27109", "kind": "us", "path": "user-stories/persistence-data-postgres-us-27109.json" },
|
|
33
|
+
{ "id": "persistence-data-postgres-US-27110", "kind": "us", "path": "user-stories/persistence-data-postgres-us-27110.json" },
|
|
34
|
+
{ "id": "TAC-2801-persistence-data-postgres-facade", "kind": "tac", "path": "tacs/tac-2801-persistence-data-postgres-facade.json" },
|
|
35
|
+
{ "id": "TAC-2802-persistence-data-postgres-migration-runner", "kind": "tac", "path": "tacs/tac-2802-persistence-data-postgres-migration-runner.json" },
|
|
36
|
+
{ "id": "TAC-2803-persistence-data-postgres-transaction-helper", "kind": "tac", "path": "tacs/tac-2803-persistence-data-postgres-transaction-helper.json" },
|
|
37
|
+
{ "id": "TAC-2804-persistence-data-postgres-recovery-runner", "kind": "tac", "path": "tacs/tac-2804-persistence-data-postgres-recovery-runner.json" },
|
|
38
|
+
{
|
|
39
|
+
"id": "ADR-2801-persistence-data-postgres-driver",
|
|
40
|
+
"kind": "adr",
|
|
41
|
+
"path": "adrs/adr-2801-persistence-data-postgres-driver.json",
|
|
42
|
+
"scope": "global",
|
|
43
|
+
"topic": "persistenceStore",
|
|
44
|
+
"recommendedDefault": true,
|
|
45
|
+
"elicited": true,
|
|
46
|
+
"standardsTraceClause": "node-postgres parameterised-queries contract"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"id": "ADR-2802-persistence-data-postgres-migration-shape",
|
|
50
|
+
"kind": "adr",
|
|
51
|
+
"path": "adrs/adr-2802-persistence-data-postgres-migration-shape.json",
|
|
52
|
+
"scope": "global",
|
|
53
|
+
"topic": "migrationDiscipline",
|
|
54
|
+
"recommendedDefault": true,
|
|
55
|
+
"elicited": true,
|
|
56
|
+
"standardsTraceClause": "generic enterprise practice"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"id": "ADR-2803-persistence-data-postgres-runner-mode",
|
|
60
|
+
"kind": "adr",
|
|
61
|
+
"path": "adrs/adr-2803-persistence-data-postgres-runner-mode.json",
|
|
62
|
+
"elicited": true,
|
|
63
|
+
"standardsTraceClause": "generic enterprise practice"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "ADR-2804-persistence-data-postgres-recovery",
|
|
67
|
+
"kind": "adr",
|
|
68
|
+
"path": "adrs/adr-2804-persistence-data-postgres-recovery.json",
|
|
69
|
+
"elicited": true,
|
|
70
|
+
"standardsTraceClause": "generic enterprise practice"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"id": "ADR-2805-persistence-data-postgres-connection-pool-posture",
|
|
74
|
+
"kind": "adr",
|
|
75
|
+
"path": "adrs/adr-2805-persistence-data-postgres-connection-pool-posture.json",
|
|
76
|
+
"elicited": true,
|
|
77
|
+
"standardsTraceClause": "generic enterprise practice"
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adrId": "ADR-2801-persistence-data-postgres-driver",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "accepted",
|
|
7
|
+
"title": "The pg client (node-postgres) as the shipped v1.0.0 driver; a round-6 Hyperdrive adapter slots in at v1.1.0 without a facade re-shape",
|
|
8
|
+
"context": "A project deploying Postgres on a Node target has two mainstream driver choices: pg (node-postgres, the callback-and-pool oriented reference driver on npm) and postgres.js (a promise-first alternative with a compact API surface). Both speak the Postgres wire protocol; both support parameterised queries; both are actively maintained. The round-6 Cloudflare-line proposal reserves a Hyperdrive-in-front adapter that wraps pg with Cloudflare's connection-pool and query-cache surface. The v1.0.0 facade design has to hold the driver reference opaque at the facade boundary so the round-6 adapter slots in as an additive minor without a facade re-shape.",
|
|
9
|
+
"decision": "The shipped v1.0.0 driver is pg (node-postgres) with a long-lived pg.Pool held inside the facade module (or a request-scoped pool on request-scoped container targets per ADR-2805). Every pg.query call passes a static string literal as its first argument and supplies parameters as an array bound to $1, $2, ... $N per the node-postgres parameterised-queries contract at https://node-postgres.com/features/queries. The driver reference inside the facade is OPAQUE at this ADR: the facade imports pg and any consumer or adapter that wants to swap the driver (postgres.js, a Hyperdrive-wrapped pg via the round-6 v1.1.0 adapter, an ORM sitting inside the facade) replaces the import here without touching the outward interface. Alternative drivers are elicited at apply time under the adapter parameter; the v1.0.0 shipped default is pg with recommendedDefault true.",
|
|
10
|
+
"consequences": "The project inherits the pg driver's mature parameterised-query surface, its pool implementation with configurable size and idle-timeout, and its clean rejection propagation for constraint violations and connection errors. The Round-6 Hyperdrive adapter (Cloudflare's pg-driver-compatible connection-pool and query-cache surface per https://developers.cloudflare.com/hyperdrive/) slots in as a v1.1.0 minor bump that swaps the import at the facade boundary; no outward-interface change, no AC moves. Projects that want postgres.js instead pass adapter=postgresjs at apply time; the facade's outward interface is preserved. Projects that want an ORM (Kysely, Drizzle, Prisma) sitting inside the facade wire the ORM inside the facade against the same pg.Pool the shipped default holds; the outward interface is preserved. Standards trace clause: node-postgres parameterised-queries contract at https://node-postgres.com/features/queries.",
|
|
11
|
+
"alternativesConsidered": [
|
|
12
|
+
{
|
|
13
|
+
"name": "postgres.js as the shipped default",
|
|
14
|
+
"summary": "Ship postgres.js as the v1.0.0 default driver, elicit pg as the alternative.",
|
|
15
|
+
"reasonNotChosen": "postgres.js is a fine driver but has a smaller ecosystem and the round-6 Hyperdrive adapter targets pg specifically per Cloudflare's Hyperdrive docs. Shipping pg first keeps the round-6 slot clean; postgres.js remains available via the elicit."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "Bless one ORM (Kysely or Drizzle) as the shipped surface",
|
|
19
|
+
"summary": "Ship Kysely or Drizzle as the v1.0.0 default; the facade wraps the ORM, not pg.",
|
|
20
|
+
"reasonNotChosen": "ORMs sit above pg and are an operator choice on top of the driver, not a substitute for it. Blessing one ORM as default pushes the shelf into a maintenance stance on a tool it does not build; the facade contract is orm-neutral so a project may drop an ORM inside the facade without moving any AC."
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "Hyperdrive as the shipped v1.0.0 driver",
|
|
24
|
+
"summary": "Ship Hyperdrive-wrapped pg as the v1.0.0 default.",
|
|
25
|
+
"reasonNotChosen": "Hyperdrive is a Cloudflare-account-bound service and the round-5 spec ruling 5 (Baz decision 8) places Postgres as the local-first blueprint. Making Hyperdrive the default would force every project to bind to a Cloudflare account before applying the blueprint. Round 6 lands Hyperdrive as a v1.1.0 minor adapter behind an elicit, keeping local-first at v1.0.0."
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"createdAt": "2026-09-06T15:47:00.000Z",
|
|
29
|
+
"updatedAt": "2026-09-06T15:47:00.000Z"
|
|
30
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adrId": "ADR-2802-persistence-data-postgres-migration-shape",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "accepted",
|
|
7
|
+
"title": "Numbered forward-only .sql migration files; one file one transaction; migration runner tool elicited",
|
|
8
|
+
"context": "The Postgres ecosystem has multiple migration tools (node-pg-migrate, sqitch, flyway, prisma migrate, drizzle-kit, knex migrations). Each imposes a different filename convention, a different bookkeeping strategy, and a different transaction shape. Blessing one blocks projects that already carry another; blessing none diffuses the shape across the shelf.",
|
|
9
|
+
"decision": "The shipped discipline is numbered forward-only .sql migration files under an elicited migrations directory (default ./migrations/). Each filename begins with a monotonically increasing integer that is unique across the directory (001_..., 002_..., 003_...); the file body is engine-native SQL. The in-tree runner applies each file inside its own transaction (BEGIN, run the file body, COMMIT on success or ROLLBACK on error); the runner records applied filenames in a schema_version bookkeeping table it maintains inside the same database. There are no down migrations; a rollback is a new numbered file inverting the earlier change. Which runner tool the project reaches for is elicited on this ADR (bespoke Node runner shipped in the fixture, node-pg-migrate, sqitch, flyway); recommendedDefault is the bespoke Node runner because it holds the fewest opinions and reads the migrations directory directly.",
|
|
10
|
+
"consequences": "The project gets a portable migration shape any Postgres client can apply (a plain .sql file with a leading integer). One file one transaction bounds the rollback surface cleanly but forbids atomic schema changes spanning two files; projects combine multi-step changes into one file. Numbered forward-only means the deploy pipeline's rollback story is a new migration, not a down step; the deploy runbook names this. Refusing to bless a runner tool keeps the shelf out of a maintenance stance; the operator picks whichever tool their team already carries and points it at the same directory. Standards trace clause: generic enterprise practice.",
|
|
11
|
+
"alternativesConsidered": [
|
|
12
|
+
{
|
|
13
|
+
"name": "Bless node-pg-migrate as the shipped runner",
|
|
14
|
+
"summary": "Ship node-pg-migrate as the v1.0.0 default; the applying project inherits its filename convention, its bookkeeping table shape, and its up/down direction.",
|
|
15
|
+
"reasonNotChosen": "node-pg-migrate is a fine tool but its filename convention differs from sqitch and flyway; blessing it forces a project already on sqitch to migrate their catalogue. The discipline (numbered forward-only, one file one transaction) is what carries between tools; blessing the discipline and eliciting the tool is cheaper for the operator."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "Allow bidirectional migrations (up and down)",
|
|
19
|
+
"summary": "Ship the migration shape as pairs of .sql files (001_up.sql, 001_down.sql); the runner applies up in order and down in reverse.",
|
|
20
|
+
"reasonNotChosen": "Down migrations are a lie in production. Rolling back a shipped schema change with a down migration is safe only when the change did not add data-carrying columns or drop constraints in a way the down cannot invert. Forward-only migrations make the rollback path explicit (a new numbered file); the operator writes what actually inverts the change rather than trusting a mechanical down."
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"createdAt": "2026-09-06T15:47:00.000Z",
|
|
24
|
+
"updatedAt": "2026-09-06T15:47:00.000Z"
|
|
25
|
+
}
|