@cosmicdrift/kumiko-samples 0.388.0 → 0.390.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.
Files changed (385) hide show
  1. package/package.json +1 -1
  2. package/packages/bundled-features/package.json +25 -13
  3. package/packages/bundled-features/src/agent-tools/changes.json +6 -0
  4. package/packages/bundled-features/src/agent-tools/index.ts +1 -1
  5. package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +42 -26
  6. package/packages/bundled-features/src/audit/feature.ts +2 -1
  7. package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +1 -1
  8. package/packages/bundled-features/src/auth-email-password/bootstrap.ts +13 -1
  9. package/packages/bundled-features/src/auth-email-password/changes.json +18 -0
  10. package/packages/bundled-features/src/auth-email-password/feature.ts +2 -2
  11. package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +7 -7
  12. package/packages/bundled-features/src/auth-email-password/handlers/confirm-account-unlock.write.ts +3 -3
  13. package/packages/bundled-features/src/auth-email-password/handlers/confirm-token-flow.ts +5 -5
  14. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +9 -7
  15. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +11 -7
  16. package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +4 -4
  17. package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +2 -2
  18. package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +9 -7
  19. package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +23 -16
  20. package/packages/bundled-features/src/auth-email-password/handlers/request-account-unlock.write.ts +1 -0
  21. package/packages/bundled-features/src/auth-email-password/handlers/request-email-verification.write.ts +1 -0
  22. package/packages/bundled-features/src/auth-email-password/handlers/request-password-reset.write.ts +1 -0
  23. package/packages/bundled-features/src/auth-email-password/handlers/reset-password.write.ts +3 -2
  24. package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +12 -12
  25. package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +16 -8
  26. package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +4 -2
  27. package/packages/bundled-features/src/auth-email-password/handlers/token-request-handler.ts +10 -2
  28. package/packages/bundled-features/src/auth-email-password/handlers/verify-email.write.ts +3 -2
  29. package/packages/bundled-features/src/auth-email-password/magic-link-mail.ts +16 -3
  30. package/packages/bundled-features/src/auth-email-password/seeding.ts +14 -9
  31. package/packages/bundled-features/src/auth-email-password/signup-activation.ts +2 -0
  32. package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +8 -2
  33. package/packages/bundled-features/src/auth-email-password/web/auth-redirect.ts +23 -21
  34. package/packages/bundled-features/src/auth-email-password/web/default-auth-pages-gate.tsx +6 -3
  35. package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +11 -1
  36. package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -0
  37. package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +16 -5
  38. package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +7 -1
  39. package/packages/bundled-features/src/auth-email-password/web/return-path.ts +35 -0
  40. package/packages/bundled-features/src/auth-email-password/web/session.tsx +6 -1
  41. package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +11 -3
  42. package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +12 -2
  43. package/packages/bundled-features/src/auth-foundation/feature.ts +13 -4
  44. package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
  45. package/packages/bundled-features/src/auth-mfa/config.ts +3 -7
  46. package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +5 -5
  47. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +24 -14
  48. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +9 -3
  49. package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +6 -1
  50. package/packages/bundled-features/src/auth-mfa/handlers/enable-start.write.ts +3 -1
  51. package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +14 -9
  52. package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -4
  53. package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +25 -14
  54. package/packages/bundled-features/src/auth-mfa/mfa-code-verifier.ts +10 -4
  55. package/packages/bundled-features/src/auth-mfa/mfa-status-checker.ts +17 -8
  56. package/packages/bundled-features/src/auth-mfa/verify-factor.ts +1 -1
  57. package/packages/bundled-features/src/billing-foundation/billing-info-query.ts +2 -2
  58. package/packages/bundled-features/src/billing-foundation/changes.json +6 -0
  59. package/packages/bundled-features/src/billing-foundation/consumer-protection/consent-gate.ts +1 -1
  60. package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +5 -5
  61. package/packages/bundled-features/src/billing-foundation/consumer-protection/register-consent.ts +10 -7
  62. package/packages/bundled-features/src/billing-foundation/consumer-protection/register-termination.ts +15 -12
  63. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-open-cancels.ts +22 -0
  64. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-provider-lock.ts +4 -0
  65. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-receipt-limit.ts +4 -4
  66. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-record.ts +17 -58
  67. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +10 -8
  68. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +18 -15
  69. package/packages/bundled-features/src/billing-foundation/events.ts +1 -1
  70. package/packages/bundled-features/src/billing-foundation/feature.ts +8 -3
  71. package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +1 -1
  72. package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +5 -5
  73. package/packages/bundled-features/src/billing-foundation/handlers/process-payment-event.write.ts +3 -3
  74. package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +2 -2
  75. package/packages/bundled-features/src/billing-foundation/projection.ts +1 -1
  76. package/packages/bundled-features/src/billing-foundation/types.ts +1 -1
  77. package/packages/bundled-features/src/cap-counter/aggregate-id.ts +1 -1
  78. package/packages/bundled-features/src/cap-counter/book-cap-usage.ts +5 -4
  79. package/packages/bundled-features/src/cap-counter/cap-reservation.ts +21 -8
  80. package/packages/bundled-features/src/cap-counter/changes.json +12 -0
  81. package/packages/bundled-features/src/cap-counter/constants.ts +1 -1
  82. package/packages/bundled-features/src/cap-counter/feature.ts +3 -2
  83. package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +1 -1
  84. package/packages/bundled-features/src/cap-counter/reservation-chain.ts +1 -1
  85. package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +4 -4
  86. package/packages/bundled-features/src/cap-overview/feature.ts +1 -0
  87. package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -1
  88. package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
  89. package/packages/bundled-features/src/compliance-profiles/seeding.ts +12 -7
  90. package/packages/bundled-features/src/config/changes.json +6 -0
  91. package/packages/bundled-features/src/config/feature.ts +6 -6
  92. package/packages/bundled-features/src/config/handlers/cascade.query.ts +1 -1
  93. package/packages/bundled-features/src/config/handlers/readiness.query.ts +1 -1
  94. package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +23 -13
  95. package/packages/bundled-features/src/config/handlers/reset.write.ts +3 -3
  96. package/packages/bundled-features/src/config/handlers/selected-extensions.query.ts +1 -1
  97. package/packages/bundled-features/src/config/handlers/set.write.ts +22 -5
  98. package/packages/bundled-features/src/config/handlers/values.query.ts +1 -1
  99. package/packages/bundled-features/src/crypto-shredding/changes.json +12 -0
  100. package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +9 -9
  101. package/packages/bundled-features/src/crypto-shredding/resolve-file-bytes-deleter.ts +3 -3
  102. package/packages/bundled-features/src/custom-fields/changes.json +6 -0
  103. package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +1 -1
  104. package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +1 -1
  105. package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +1 -1
  106. package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +1 -1
  107. package/packages/bundled-features/src/custom-fields/index.ts +4 -0
  108. package/packages/bundled-features/src/custom-fields/lib/parse-serialized-field.ts +1 -1
  109. package/packages/bundled-features/src/data-retention/feature.ts +1 -1
  110. package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +12 -2
  111. package/packages/bundled-features/src/delivery/attempt-log.ts +1 -1
  112. package/packages/bundled-features/src/delivery/changes.json +12 -0
  113. package/packages/bundled-features/src/delivery/delivery-service.ts +6 -5
  114. package/packages/bundled-features/src/delivery/feature.ts +3 -2
  115. package/packages/bundled-features/src/delivery/index.ts +5 -0
  116. package/packages/bundled-features/src/delivery/jobs.ts +11 -11
  117. package/packages/bundled-features/src/delivery/system-channel-context.ts +33 -0
  118. package/packages/bundled-features/src/delivery/testing.ts +1 -1
  119. package/packages/bundled-features/src/document-ingest-foundation/append-missing-extract-event.ts +84 -0
  120. package/packages/bundled-features/src/document-ingest-foundation/changes.json +6 -0
  121. package/packages/bundled-features/src/document-ingest-foundation/events.ts +16 -1
  122. package/packages/bundled-features/src/document-ingest-foundation/index.ts +11 -0
  123. package/packages/bundled-features/src/feature-toggles/feature.ts +1 -0
  124. package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +1 -1
  125. package/packages/bundled-features/src/feature-toggles/handlers/set.write.ts +1 -1
  126. package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
  127. package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
  128. package/packages/bundled-features/src/file-derivatives/handlers/public-variant-by-file-ref.query.ts +5 -1
  129. package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +7 -5
  130. package/packages/bundled-features/src/file-foundation/feature.ts +1 -1
  131. package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +7 -5
  132. package/packages/bundled-features/src/file-provider-s3/feature.ts +4 -1
  133. package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +8 -8
  134. package/packages/bundled-features/src/form-draft/feature.ts +1 -1
  135. package/packages/bundled-features/src/form-draft/handlers/cleanup.job.ts +22 -12
  136. package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +3 -3
  137. package/packages/bundled-features/src/form-draft/handlers/get.query.ts +1 -1
  138. package/packages/bundled-features/src/foundation-shared/config-helpers.ts +1 -1
  139. package/packages/bundled-features/src/host-routing/changes.json +6 -0
  140. package/packages/bundled-features/src/host-routing/validate-options.ts +5 -0
  141. package/packages/bundled-features/src/inbound-mail-foundation/events.ts +1 -1
  142. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +2 -1
  143. package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +2 -2
  144. package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +1 -1
  145. package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +1 -1
  146. package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +10 -10
  147. package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +1 -1
  148. package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +1 -1
  149. package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +1 -1
  150. package/packages/bundled-features/src/inbound-provider-imap/feature.ts +4 -1
  151. package/packages/bundled-features/src/jobs/changes.json +6 -0
  152. package/packages/bundled-features/src/jobs/events.ts +1 -1
  153. package/packages/bundled-features/src/jobs/feature.ts +1 -0
  154. package/packages/bundled-features/src/jobs/handlers/consumer.write.ts +7 -4
  155. package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
  156. package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +11 -5
  157. package/packages/bundled-features/src/jobs/handlers/retention-cleanup.job.ts +1 -1
  158. package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
  159. package/packages/bundled-features/src/jobs/handlers/stale-run-sweep.job.ts +1 -1
  160. package/packages/bundled-features/src/jobs/handlers/trigger.write.ts +2 -2
  161. package/packages/bundled-features/src/jobs/job-run-logger.ts +139 -90
  162. package/packages/bundled-features/src/ledger/web/index.ts +1 -1
  163. package/packages/bundled-features/src/legal-pages/README.md +1 -1
  164. package/packages/bundled-features/src/legal-pages/lib/boot-check.ts +12 -8
  165. package/packages/bundled-features/src/legal-pages/seed.ts +5 -2
  166. package/packages/bundled-features/src/mail-foundation/feature.ts +2 -2
  167. package/packages/bundled-features/src/mail-transport-smtp/changes.json +12 -0
  168. package/packages/bundled-features/src/mail-transport-smtp/config-keys.ts +1 -1
  169. package/packages/bundled-features/src/mail-transport-smtp/feature.ts +13 -12
  170. package/packages/bundled-features/src/managed-pages/changes.json +6 -0
  171. package/packages/bundled-features/src/managed-pages/constants.ts +1 -0
  172. package/packages/bundled-features/src/managed-pages/feature.ts +3 -1
  173. package/packages/bundled-features/src/managed-pages/index.ts +1 -0
  174. package/packages/bundled-features/src/managed-pages/seeding.ts +13 -8
  175. package/packages/bundled-features/src/notes-history/handlers/add-note.write.ts +2 -2
  176. package/packages/bundled-features/src/personal-access-tokens/feature.ts +2 -1
  177. package/packages/bundled-features/src/personal-access-tokens/handlers/create.write.ts +2 -2
  178. package/packages/bundled-features/src/personal-access-tokens/handlers/revoke.write.ts +1 -1
  179. package/packages/bundled-features/src/rate-limiting/handlers/status.query.ts +2 -2
  180. package/packages/bundled-features/src/readiness/handlers/status.query.ts +4 -1
  181. package/packages/bundled-features/src/renderer-foundation/api.ts +3 -3
  182. package/packages/bundled-features/src/secrets/announce-secret-change.ts +4 -4
  183. package/packages/bundled-features/src/secrets/changes.json +6 -0
  184. package/packages/bundled-features/src/secrets/feature.ts +9 -9
  185. package/packages/bundled-features/src/secrets/handlers/delete.write.ts +4 -3
  186. package/packages/bundled-features/src/secrets/handlers/rotate.job.ts +13 -8
  187. package/packages/bundled-features/src/secrets/handlers/set.write.ts +4 -3
  188. package/packages/bundled-features/src/secrets/secrets-context.ts +16 -6
  189. package/packages/bundled-features/src/secrets/write-gate.ts +10 -3
  190. package/packages/bundled-features/src/seo/feature.ts +1 -1
  191. package/packages/bundled-features/src/sessions/changes.json +19 -0
  192. package/packages/bundled-features/src/sessions/feature.ts +2 -1
  193. package/packages/bundled-features/src/sessions/handlers/cleanup.job.ts +2 -2
  194. package/packages/bundled-features/src/sessions/handlers/detail.query.ts +5 -2
  195. package/packages/bundled-features/src/sessions/handlers/list.query.ts +5 -2
  196. package/packages/bundled-features/src/sessions/handlers/mine.query.ts +5 -2
  197. package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +3 -3
  198. package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +1 -1
  199. package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
  200. package/packages/bundled-features/src/sessions/index.ts +1 -1
  201. package/packages/bundled-features/src/sessions/screens.ts +8 -4
  202. package/packages/bundled-features/src/sessions/session-callbacks.ts +1 -9
  203. package/packages/bundled-features/src/sessions/session-revoked-event.ts +1 -1
  204. package/packages/bundled-features/src/sessions/web/session-device-cell.tsx +10 -12
  205. package/packages/bundled-features/src/sessions/web/user-agent.ts +12 -0
  206. package/packages/bundled-features/src/shared/index.ts +15 -0
  207. package/packages/bundled-features/src/shared/purge-files-reaching-subject.ts +36 -4
  208. package/packages/bundled-features/src/shared/require-for-tenant.ts +7 -5
  209. package/packages/bundled-features/src/shared/run-in-sub-transaction.ts +5 -5
  210. package/packages/bundled-features/src/shared/stream-tenant-backfill.ts +201 -0
  211. package/packages/bundled-features/src/shared/stream-tenant-derived-state.ts +107 -0
  212. package/packages/bundled-features/src/step-dispatcher/changes.json +6 -0
  213. package/packages/bundled-features/src/step-dispatcher/deliver-dispatch-request.ts +17 -3
  214. package/packages/bundled-features/src/step-dispatcher/feature.ts +1 -1
  215. package/packages/bundled-features/src/step-dispatcher/mail-runner.ts +2 -1
  216. package/packages/bundled-features/src/subscription-dodo/plugin-methods.ts +1 -1
  217. package/packages/bundled-features/src/subscription-dodo/runtime.ts +7 -7
  218. package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +5 -3
  219. package/packages/bundled-features/src/subscription-stripe/runtime.ts +7 -7
  220. package/packages/bundled-features/src/tags/feature.ts +1 -0
  221. package/packages/bundled-features/src/template-resolver/api.ts +3 -3
  222. package/packages/bundled-features/src/template-resolver/changes.json +54 -0
  223. package/packages/bundled-features/src/template-resolver/document-ops.ts +20 -1
  224. package/packages/bundled-features/src/template-resolver/feature.ts +2 -2
  225. package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +5 -4
  226. package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +2 -2
  227. package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +1 -1
  228. package/packages/bundled-features/src/template-resolver/handlers/layout-source.query.ts +36 -11
  229. package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +32 -7
  230. package/packages/bundled-features/src/template-resolver/handlers/patch-draft.write.ts +1 -1
  231. package/packages/bundled-features/src/template-resolver/handlers/send-test-shared.ts +1 -1
  232. package/packages/bundled-features/src/template-resolver/handlers/send-test-status.query.ts +22 -19
  233. package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +2 -2
  234. package/packages/bundled-features/src/template-resolver/handlers/tenant-override-selection.ts +6 -2
  235. package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +4 -2
  236. package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +1 -1
  237. package/packages/bundled-features/src/template-resolver/seeding.ts +22 -5
  238. package/packages/bundled-features/src/template-resolver/store-template-resource.ts +68 -19
  239. package/packages/bundled-features/src/template-resolver/template-resources.ts +4 -4
  240. package/packages/bundled-features/src/template-resolver/testing.ts +2 -2
  241. package/packages/bundled-features/src/template-resolver/web/document-insert-fields.tsx +222 -0
  242. package/packages/bundled-features/src/template-resolver/web/document-insert-model.ts +164 -0
  243. package/packages/bundled-features/src/template-resolver/web/document-insert-panel.tsx +115 -0
  244. package/packages/bundled-features/src/template-resolver/web/document-tiptap-bubble.tsx +177 -0
  245. package/packages/bundled-features/src/template-resolver/web/document-tiptap-content.tsx +38 -0
  246. package/packages/bundled-features/src/template-resolver/web/document-tiptap-context.ts +119 -0
  247. package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +51 -1098
  248. package/packages/bundled-features/src/template-resolver/web/document-tiptap-helpers.ts +161 -0
  249. package/packages/bundled-features/src/template-resolver/web/document-tiptap-layout.tsx +83 -0
  250. package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar-groups.tsx +153 -0
  251. package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar.tsx +182 -0
  252. package/packages/bundled-features/src/template-resolver/web/editor-handle.ts +18 -0
  253. package/packages/bundled-features/src/template-resolver/web/i18n.ts +6 -0
  254. package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +19 -6
  255. package/packages/bundled-features/src/template-resolver/web/qualified-names.ts +1 -0
  256. package/packages/bundled-features/src/template-resolver/web/use-document-tiptap-model.ts +138 -0
  257. package/packages/bundled-features/src/tenant/changes.json +19 -0
  258. package/packages/bundled-features/src/tenant/feature.ts +1 -0
  259. package/packages/bundled-features/src/tenant/handlers/cancel-invitation.write.ts +1 -1
  260. package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
  261. package/packages/bundled-features/src/tenant/handlers/remove-member.write.ts +2 -2
  262. package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +3 -3
  263. package/packages/bundled-features/src/tenant/handlers/update-member-roles.write.ts +1 -1
  264. package/packages/bundled-features/src/tenant/index.ts +5 -0
  265. package/packages/bundled-features/src/tenant/invited-membership.ts +6 -1
  266. package/packages/bundled-features/src/tenant/schema/tenant.ts +4 -1
  267. package/packages/bundled-features/src/tenant/seeding.ts +65 -62
  268. package/packages/bundled-features/src/tenant/stream-tenant-backfill.ts +115 -0
  269. package/packages/bundled-features/src/tenant/testing.ts +77 -0
  270. package/packages/bundled-features/src/tenant-handover/events.ts +1 -1
  271. package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
  272. package/packages/bundled-features/src/tenant-lifecycle/changes.json +6 -0
  273. package/packages/bundled-features/src/tenant-lifecycle/feature.ts +5 -5
  274. package/packages/bundled-features/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +22 -10
  275. package/packages/bundled-features/src/tenant-lifecycle/handlers/request-destruction.write.ts +22 -11
  276. package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +23 -12
  277. package/packages/bundled-features/src/tenant-lifecycle/stages.ts +42 -4
  278. package/packages/bundled-features/src/tenant-lifecycle/testing.ts +9 -8
  279. package/packages/bundled-features/src/tier-engine/entity.ts +1 -1
  280. package/packages/bundled-features/src/tier-engine/feature.ts +8 -3
  281. package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +3 -3
  282. package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +7 -1
  283. package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +3 -3
  284. package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +71 -97
  285. package/packages/bundled-features/src/user/feature.ts +1 -0
  286. package/packages/bundled-features/src/user/handlers/find-for-auth.query.ts +2 -2
  287. package/packages/bundled-features/src/user/handlers/update-roles.ts +2 -2
  288. package/packages/bundled-features/src/user/index.ts +2 -0
  289. package/packages/bundled-features/src/user/invited-global-roles.ts +6 -1
  290. package/packages/bundled-features/src/user/principal-status.ts +1 -1
  291. package/packages/bundled-features/src/user/seeding.ts +24 -6
  292. package/packages/bundled-features/src/user/testing.ts +22 -0
  293. package/packages/bundled-features/src/user-data-rights/COMPLIANCE.md +1 -1
  294. package/packages/bundled-features/src/user-data-rights/README.md +1 -1
  295. package/packages/bundled-features/src/user-data-rights/audit-download.ts +12 -2
  296. package/packages/bundled-features/src/user-data-rights/changes.json +36 -0
  297. package/packages/bundled-features/src/user-data-rights/feature.ts +30 -24
  298. package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +1 -1
  299. package/packages/bundled-features/src/user-data-rights/handlers/deletion-grace-period.ts +1 -1
  300. package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +2 -2
  301. package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +2 -2
  302. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +1 -1
  303. package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +4 -4
  304. package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +12 -6
  305. package/packages/bundled-features/src/user-data-rights/index.ts +8 -1
  306. package/packages/bundled-features/src/user-data-rights/lib/mail-transport-resolver.ts +1 -1
  307. package/packages/bundled-features/src/user-data-rights/lib/storage-provider-resolver.ts +1 -1
  308. package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +6 -1
  309. package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +8 -2
  310. package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +14 -3
  311. package/packages/bundled-features/src/user-data-rights/run-user-export.ts +11 -1
  312. package/packages/bundled-features/src/user-data-rights/web/constants.ts +16 -0
  313. package/packages/bundled-features/src/user-data-rights/web/index.ts +6 -0
  314. package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +8 -6
  315. package/packages/bundled-features/src/waitlist/changes.json +18 -0
  316. package/packages/bundled-features/src/waitlist/feature.ts +1 -0
  317. package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +1 -1
  318. package/packages/bundled-features/src/waitlist/handlers/invite.write.ts +2 -2
  319. package/packages/bundled-features/src/waitlist/handlers/reject.write.ts +1 -1
  320. package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +34 -10
  321. package/packages/bundled-features/src/waitlist/import.ts +23 -3
  322. package/packages/bundled-features/src/waitlist/legacy-migrate.ts +8 -2
  323. package/packages/bundled-features/src/waitlist/link-on-signup.ts +7 -1
  324. package/packages/bundled-features/src/waitlist/options.ts +2 -1
  325. package/packages/bundled-features/src/workflow-runner/changes.json +6 -0
  326. package/packages/bundled-features/src/workflow-runner/db/queries/due-runs.ts +1 -1
  327. package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -3
  328. package/packages/bundled-features/src/workflow-runner/event-trigger.ts +2 -1
  329. package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
  330. package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +8 -8
  331. package/packages/bundled-features/src/workflow-runner/runner.ts +6 -4
  332. package/samples/apps/cap-billing-demo/src/feature.ts +19 -5
  333. package/samples/apps/config-demo/src/app/server.ts +1 -1
  334. package/samples/apps/styleguide/src/app/client.tsx +2 -0
  335. package/samples/apps/styleguide/src/app/seed.ts +6 -4
  336. package/samples/apps/styleguide/src/app/server.ts +6 -3
  337. package/samples/apps/styleguide/src/features/widgets/feature.ts +15 -4
  338. package/samples/apps/styleguide/src/features/workboard/feature.ts +185 -0
  339. package/samples/apps/styleguide/src/features/workboard/i18n.ts +27 -0
  340. package/samples/apps/styleguide/src/features/workboard/seed.ts +121 -0
  341. package/samples/apps/styleguide/src/features/workboard/web.ts +13 -0
  342. package/samples/apps/ui-walkthrough/src/features/rental/i18n.ts +2 -0
  343. package/samples/apps/ui-walkthrough/src/features/rental/screens.ts +9 -0
  344. package/samples/apps/use-all-bundled/bin/main.ts +2 -0
  345. package/samples/apps/use-all-bundled/feature-manifest.json +17 -1
  346. package/samples/apps/use-all-bundled/kumiko/schema.ts +2 -0
  347. package/samples/apps/use-all-bundled/kumiko.config.ts +2 -0
  348. package/samples/apps/use-all-bundled/package.json +2 -1
  349. package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +2 -0
  350. package/samples/apps/use-all-bundled/src/app/notes-feature.ts +2 -0
  351. package/samples/apps/use-all-bundled/src/app/seed.ts +12 -2
  352. package/samples/apps/use-all-bundled/src/bundled-lists.ts +15 -0
  353. package/samples/apps/user-data-rights-demo/README.md +1 -1
  354. package/samples/apps/user-data-rights-demo/src/feature.ts +3 -2
  355. package/samples/recipes/api-worker-split/README.md +2 -1
  356. package/samples/recipes/api-worker-split/src/feature.ts +2 -1
  357. package/samples/recipes/cross-feature-events/README.md +5 -5
  358. package/samples/recipes/cross-feature-events/package.json +1 -1
  359. package/samples/recipes/cross-feature-events/src/feature.ts +4 -4
  360. package/samples/recipes/event-sourcing/README.md +5 -5
  361. package/samples/recipes/event-sourcing/package.json +1 -1
  362. package/samples/recipes/event-sourcing/src/feature.ts +15 -15
  363. package/samples/recipes/files-post-processing/README.md +1 -1
  364. package/samples/recipes/files-post-processing/package.json +1 -1
  365. package/samples/recipes/files-post-processing/src/feature.ts +6 -4
  366. package/samples/recipes/golden-path/src/feature.ts +2 -1
  367. package/samples/recipes/lane-routing/package.json +1 -1
  368. package/samples/recipes/legal-pages/README.md +2 -2
  369. package/samples/recipes/lifecycle-hooks/README.md +4 -0
  370. package/samples/recipes/lifecycle-hooks/src/feature.ts +26 -1
  371. package/samples/recipes/list-table-options/README.md +50 -0
  372. package/samples/recipes/list-table-options/package.json +11 -0
  373. package/samples/recipes/list-table-options/src/feature.ts +221 -0
  374. package/samples/recipes/managed-config/README.md +3 -3
  375. package/samples/recipes/pdf-audit-export/src/feature.ts +2 -1
  376. package/samples/recipes/search/README.md +1 -1
  377. package/samples/recipes/search/src/feature.ts +3 -3
  378. package/samples/recipes/secrets-demo/README.md +1 -1
  379. package/samples/recipes/secrets-demo/src/feature.ts +5 -2
  380. package/samples/recipes/state-machine/src/events.ts +4 -3
  381. package/samples/recipes/state-machine/src/reducer.ts +1 -1
  382. package/samples/recipes/tenant-isolation/README.md +1 -0
  383. package/samples/recipes/tenant-isolation/src/feature.ts +36 -0
  384. package/samples/recipes/workflow-engine/src/resume-loop.ts +4 -4
  385. package/samples/recipes/workflow-engine/src/workflow-runner.ts +2 -2
@@ -23,7 +23,7 @@
23
23
  // existing resume-due-runs job picks the row up on its next
24
24
  // cron tick — the resume path remains unchanged.
25
25
 
26
- import { selectMany, updateMany } from "@cosmicdrift/kumiko-framework/db";
26
+ import { selectMany, sql, updateMany } from "@cosmicdrift/kumiko-framework/db";
27
27
  import type {
28
28
  FeatureRegistrar,
29
29
  MultiStreamApplyFn,
@@ -32,7 +32,6 @@ import type {
32
32
  } from "@cosmicdrift/kumiko-framework/engine";
33
33
  import { evaluateEventMatch } from "@cosmicdrift/kumiko-framework/engine";
34
34
  import { createFallbackLogger } from "@cosmicdrift/kumiko-framework/logging";
35
- import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
36
35
  import type { TriggerEventRef } from "./runner.ts";
37
36
  import { workflowRunPendingTable } from "./tables.ts";
38
37
 
@@ -92,7 +91,9 @@ const wakeupApply: MultiStreamApplyFn = async (event, tx) => {
92
91
  aggregateId: event.aggregateId,
93
92
  version: event.version,
94
93
  } satisfies TriggerEventRef,
95
- wakeAt: getTemporal().Now.instant().toString(),
94
+ // DB clock, like the due comparison in due-runs.ts: an app-clock stamp ahead of the
95
+ // database clock would leave the row not-yet-due for the next resume tick.
96
+ wakeAt: sql`now()`,
96
97
  },
97
98
  { tenantId: row.tenantId, runId: row.runId, stepIndex: row.stepIndex },
98
99
  );
@@ -144,7 +144,8 @@ export function registerEventTrigger(r: FeatureRegistrar, workflow: WorkflowDefi
144
144
  version: event.version,
145
145
  },
146
146
  ...(idempotencyKey && { idempotencyKey }),
147
- handlerCtx: ctx,
147
+ // The MSP context is still flat; the runner reads the namespaced shape.
148
+ handlerCtx: { events: { unsafeAppend: ctx.unsafeAppendEvent } },
148
149
  });
149
150
  } catch (error) {
150
151
  // Failures outside the step loop (run-started append) have no step yet, so 0.
@@ -76,7 +76,7 @@ export function createWorkflowRunnerFeature() {
76
76
 
77
77
  for (const row of dueRows) {
78
78
  try {
79
- await ctx.write("workflow-runner:write:resume-run", {
79
+ await ctx.dispatch.write("workflow-runner:write:resume-run", {
80
80
  runId: row.runId,
81
81
  stepIndex: row.stepIndex,
82
82
  });
@@ -84,7 +84,7 @@ export function createWorkflowRunnerFeature() {
84
84
  // skip: one row's dispatch failing (infra hiccup, not a business
85
85
  // outcome — resume-run itself never throws for expected cases)
86
86
  // must not stop the rest of this tenant's due rows from resuming.
87
- ctx.log.warn(
87
+ ctx.obs.log.warn(
88
88
  `[workflow-runner:resume-due-runs] runId=${row.runId} stepIndex=${row.stepIndex} dispatch failed: ${String(error)}`,
89
89
  );
90
90
  }
@@ -7,7 +7,7 @@
7
7
  // 1. Fingerprint check FIRST — before claiming, before any pipeline
8
8
  // work. A changed workflow definition fails loud (WORKFLOW_RUN_FAILED,
9
9
  // reason "workflow_definition_changed"), never a silent skip.
10
- // 2. Claim via a savepoint-scoped WORKFLOW_RESUMED append (ctx.tryAppendEvent,
10
+ // 2. Claim via a savepoint-scoped WORKFLOW_RESUMED append (ctx.events.tryAppend,
11
11
  // not unsafeAppendEvent — a losing VersionConflict must not poison this
12
12
  // handler's own transaction). A losing claim means another worker beat
13
13
  // us to this row; silent no-op.
@@ -78,7 +78,7 @@ async function appendRunFailed(
78
78
  runId: string,
79
79
  failedPayload: WorkflowRunFailedPayload,
80
80
  ): Promise<void> {
81
- await ctx.unsafeAppendEvent({
81
+ await ctx.events.unsafeAppend({
82
82
  aggregateId: runId,
83
83
  aggregateType: WORKFLOW_AGGREGATE_TYPE,
84
84
  type: WORKFLOW_RUN_FAILED_TYPE,
@@ -176,7 +176,7 @@ function readResumedPayload(payload: unknown): {
176
176
  // mistake attempt 1's WORKFLOW_RESUMED for attempt 2's and skip the second
177
177
  // retry entirely.
178
178
  function isRunAlreadySettled(
179
- runEvents: Awaited<ReturnType<HandlerContext["loadAggregate"]>>,
179
+ runEvents: Awaited<ReturnType<HandlerContext["events"]["load"]>>,
180
180
  stepIndex: number,
181
181
  expectedRetryAttempt: number | undefined,
182
182
  ): boolean {
@@ -192,7 +192,7 @@ function isRunAlreadySettled(
192
192
  });
193
193
  }
194
194
 
195
- type LoadedEvents = Awaited<ReturnType<HandlerContext["loadAggregate"]>>;
195
+ type LoadedEvents = Awaited<ReturnType<HandlerContext["events"]["load"]>>;
196
196
 
197
197
  function isRecord(value: unknown): value is Record<string, unknown> {
198
198
  return typeof value === "object" && value !== null;
@@ -229,7 +229,7 @@ function readTriggerSource(startedPayload: unknown): TriggerSource | null {
229
229
  }
230
230
 
231
231
  async function loadReferencedEvent(ctx: HandlerContext, ref: TriggerEventRef) {
232
- const events = await ctx.loadAggregate(ref.aggregateId);
232
+ const events = await ctx.events.load(ref.aggregateId, { atVersion: ref.version });
233
233
  return events.find((e) => e.id === ref.eventId);
234
234
  }
235
235
 
@@ -385,7 +385,7 @@ async function runResumedPipeline(ctx: HandlerContext, input: ResumedPipelineInp
385
385
  workflowName,
386
386
  stepIndex: steps.length,
387
387
  };
388
- await ctx.unsafeAppendEvent({
388
+ await ctx.events.unsafeAppend({
389
389
  aggregateId: runId,
390
390
  aggregateType: WORKFLOW_AGGREGATE_TYPE,
391
391
  type: WORKFLOW_RUN_COMPLETED_TYPE,
@@ -448,7 +448,7 @@ export const resumeRunHandler: WriteHandlerDef = {
448
448
  }
449
449
 
450
450
  const { workflowName } = pending;
451
- const runEvents = await ctx.loadAggregate(runId);
451
+ const runEvents = await ctx.events.load(runId);
452
452
 
453
453
  // Before the workflow resolution: a racing tick on an already-settled run
454
454
  // must not append run-failed after run-completed when the definition has
@@ -469,7 +469,7 @@ export const resumeRunHandler: WriteHandlerDef = {
469
469
  }
470
470
  const workflow = resolved.workflow;
471
471
 
472
- const claim = await ctx.tryAppendEvent({
472
+ const claim = await ctx.events.tryAppend({
473
473
  aggregateId: runId,
474
474
  aggregateType: WORKFLOW_AGGREGATE_TYPE,
475
475
  type: WORKFLOW_RESUMED_TYPE,
@@ -75,7 +75,9 @@ export type WorkflowRunFailedPayload = {
75
75
  readonly reason?: string;
76
76
  };
77
77
 
78
- export type WorkflowRunContext = Pick<HandlerContext, "unsafeAppendEvent">;
78
+ export type WorkflowRunContext = {
79
+ readonly events: Pick<HandlerContext["events"], "unsafeAppend">;
80
+ };
79
81
 
80
82
  export class WorkflowSuspensionUnsupportedError extends Error {
81
83
  constructor(
@@ -116,7 +118,7 @@ export async function startAndRunWorkflow(args: {
116
118
  ...(args.idempotencyKey && { idempotencyKey: args.idempotencyKey }),
117
119
  };
118
120
 
119
- await args.handlerCtx.unsafeAppendEvent({
121
+ await args.handlerCtx.events.unsafeAppend({
120
122
  aggregateId: args.runId,
121
123
  aggregateType: WORKFLOW_AGGREGATE_TYPE,
122
124
  type: WORKFLOW_RUN_STARTED_TYPE,
@@ -127,7 +129,7 @@ export async function startAndRunWorkflow(args: {
127
129
 
128
130
  // @cast-boundary msp-to-handler-ctx — event-trigger hands over the narrower
129
131
  // MultiStreamApplyContext (no query/write/writeAs). The step vocabulary this
130
- // runner drives (wait, compute, return) only ever calls unsafeAppendEvent.
132
+ // runner drives (wait, compute, return) only ever calls events.unsafeAppend.
131
133
  const stepCtx = args.handlerCtx as unknown as HandlerContext;
132
134
  const outcome = await runStepList(
133
135
  steps,
@@ -158,7 +160,7 @@ export async function startAndRunWorkflow(args: {
158
160
  stepIndex: steps.length,
159
161
  };
160
162
 
161
- await args.handlerCtx.unsafeAppendEvent({
163
+ await args.handlerCtx.events.unsafeAppend({
162
164
  aggregateId: args.runId,
163
165
  aggregateType: WORKFLOW_AGGREGATE_TYPE,
164
166
  type: WORKFLOW_RUN_COMPLETED_TYPE,
@@ -40,18 +40,32 @@ import type { EmailMessage } from "@cosmicdrift/kumiko-bundled-features/channel-
40
40
  import {
41
41
  createMailFoundationFeature,
42
42
  createTransportForTenant,
43
+ type MailTransportContext,
43
44
  } from "@cosmicdrift/kumiko-bundled-features/mail-foundation";
44
45
  import {
45
46
  access,
46
47
  createTenantConfig,
47
48
  defineFeature,
48
- type HandlerContext,
49
+ type ReservationContext,
49
50
  type WriteHandlerDef,
50
51
  } from "@cosmicdrift/kumiko-framework/engine";
51
52
  import { z } from "zod";
52
53
  import { DEMO_TIER_MAP, TIER_NAMES, type TierName } from "./tier-map";
53
54
 
54
55
  const FEATURE_NAME = "newsletter";
56
+
57
+ // The transport factory takes a narrow context (it also runs in the worker), so the handler's
58
+ // secrets live under services and are handed over explicitly.
59
+ function mailContextOf(
60
+ ctx: Pick<ReservationContext, "config" | "registry" | "services" | "user">,
61
+ ): MailTransportContext {
62
+ return {
63
+ config: ctx.config,
64
+ registry: ctx.registry,
65
+ secrets: ctx.services.secrets,
66
+ auditUserId: ctx.user.id,
67
+ };
68
+ }
55
69
  const NEWSLETTER_CAP = "newsletters-per-month";
56
70
 
57
71
  // =============================================================================
@@ -71,7 +85,7 @@ const innerSendHandler: WriteHandlerDef = {
71
85
  handler: async (event, ctx) => {
72
86
  const payload = event.payload as z.infer<typeof sendSchema>;
73
87
  const transport = await createTransportForTenant(
74
- ctx,
88
+ mailContextOf(ctx),
75
89
  event.user.tenantId,
76
90
  "newsletter:write:send",
77
91
  );
@@ -108,7 +122,7 @@ function isValidTierName(value: string): value is TierName {
108
122
  return (TIER_NAMES as readonly string[]).includes(value);
109
123
  }
110
124
 
111
- async function resolveTier(ctx: HandlerContext): Promise<TierName> {
125
+ async function resolveTier(ctx: ReservationContext): Promise<TierName> {
112
126
  const tenantId = ctx.user?.tenantId;
113
127
  if (tenantId) {
114
128
  const sub = await getSubscriptionForTenant(ctx, tenantId);
@@ -131,10 +145,10 @@ async function resolveTier(ctx: HandlerContext): Promise<TierName> {
131
145
 
132
146
  /** Notifier-Factory: bauen einen SoftHitNotifier der die Warnung über
133
147
  * dieselbe mail-foundation an den Tenant-Admin schickt. */
134
- function buildSoftHitNotifier(ctx: HandlerContext): SoftHitNotifier {
148
+ function buildSoftHitNotifier(ctx: ReservationContext): SoftHitNotifier {
135
149
  return async (info) => {
136
150
  const transport = await createTransportForTenant(
137
- ctx,
151
+ mailContextOf(ctx),
138
152
  info.tenantId,
139
153
  "newsletter:soft-hit-notifier",
140
154
  );
@@ -26,6 +26,6 @@ await runDevApp({
26
26
  watchDirs: ["./src", "../../../packages/*/src"],
27
27
  extraContext: ({ registry }) => ({
28
28
  configResolver: resolver,
29
- _configAccessorFactory: createConfigAccessorFactory(registry, resolver),
29
+ configAccessorFactory: createConfigAccessorFactory(registry, resolver),
30
30
  }),
31
31
  });
@@ -7,6 +7,7 @@ import { styleguideClient } from "../features/demo/web";
7
7
  import { examplesClient } from "../features/examples/web";
8
8
  import { galleryClient } from "../features/gallery/web";
9
9
  import { widgetsClient } from "../features/widgets/web";
10
+ import { workboardClient } from "../features/workboard/web";
10
11
  import { AppShell } from "./shell";
11
12
 
12
13
  // createKumikoApp fetches the schema itself from the authenticated
@@ -24,5 +25,6 @@ createKumikoApp({
24
25
  widgetsClient,
25
26
  examplesClient,
26
27
  contentClient(),
28
+ workboardClient,
27
29
  ],
28
30
  });
@@ -1,5 +1,5 @@
1
1
  import type { SeedFn } from "@cosmicdrift/kumiko-dev-server";
2
- import { createTenantDb } from "@cosmicdrift/kumiko-framework/db";
2
+ import { buildEntityTable, createTenantDb, fetchOne } from "@cosmicdrift/kumiko-framework/db";
3
3
  import { createEntityExecutor } from "@cosmicdrift/kumiko-framework/engine";
4
4
  import { TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
5
5
 
@@ -8,9 +8,6 @@ import { demoEntity } from "../features/demo/feature";
8
8
  // Gibt der List-View echte Rows mit Status-/Flag-Vielfalt. price (money)
9
9
  // bleibt leer — der Money-Input zeigt sich im Edit-Screen, im Seed lassen wir
10
10
  // ihn weg um nicht von der money-Payload-Form abzuhängen.
11
- // ponytail: kein Idempotenz-Check — die Screenshot-DB ist ephemer (frisch pro
12
- // Boot). Beim `bun run dev` gegen die persistente Dev-DB dupliziert ein
13
- // Neustart die Rows; das ist hier nur eine Demo, daher egal.
14
11
  const STATUSES = ["draft", "review", "published", "archived"] as const;
15
12
 
16
13
  // Fixed across boots (unlike the framework-minted ids for every other seed
@@ -19,7 +16,12 @@ const STATUSES = ["draft", "review", "published", "archived"] as const;
19
16
  // otherwise change every run.
20
17
  export const FIRST_STYLEGUIDE_ITEM_ID = "00000000-0000-4000-8000-0000000000f1";
21
18
 
19
+ const demoItemTable = buildEntityTable("item", demoEntity);
20
+
22
21
  export const seedStyleguideItems: SeedFn = async (stack) => {
22
+ // The first row has a fixed id, so its presence means a persistent dev DB was seeded already.
23
+ if (await fetchOne(stack.db, demoItemTable, { id: FIRST_STYLEGUIDE_ITEM_ID })) return;
24
+
23
25
  // Bypass the write-handler HTTP path for the first row — its schema has
24
26
  // no `id` field (buildInsertSchema only exposes entity fields), so an
25
27
  // explicit id would be silently stripped before reaching the executor.
@@ -20,6 +20,8 @@ import { examplesFeature } from "../features/examples/feature";
20
20
  import { galleryFeature } from "../features/gallery/feature";
21
21
  import { aiTextDemoFeature } from "../features/widgets/ai-text-demo";
22
22
  import { widgetsFeature } from "../features/widgets/feature";
23
+ import { workboardFeature } from "../features/workboard/feature";
24
+ import { seedWorkboardTasks } from "../features/workboard/seed";
23
25
  import { seedStyleguideItems } from "./seed";
24
26
 
25
27
  const configResolver = createConfigResolver();
@@ -35,17 +37,18 @@ await runDevApp({
35
37
  contentFeature,
36
38
  aiTextDemoFeature,
37
39
  aiSettingsFeature,
40
+ workboardFeature,
38
41
  ],
39
- // Aktiviert die Upload-Routes (/api/files) + ctx.files für den Avatar-
42
+ // Aktiviert die Upload-Routes (/api/files) + ctx.services.files für den Avatar-
40
43
  // Stresstest. In-Memory reicht für die Demo (nicht-persistent).
41
44
  files: { storageProvider: createInMemoryFileProvider() },
42
45
  port: Number.parseInt(process.env["PORT"] ?? "4180", 10),
43
46
  clientEntry: "./src/app/client.tsx",
44
47
  htmlPath: "./public/index.html",
45
48
  watchDirs: ["./src", "../../../packages/*/src"],
46
- seeds: [seedStyleguideItems, seedAiConnections],
49
+ seeds: [seedStyleguideItems, seedAiConnections, seedWorkboardTasks],
47
50
  extraContext: ({ registry }) => ({
48
51
  configResolver,
49
- _configAccessorFactory: createConfigAccessorFactory(registry, configResolver),
52
+ configAccessorFactory: createConfigAccessorFactory(registry, configResolver),
50
53
  }),
51
54
  });
@@ -28,13 +28,21 @@ const loanMonthMs = (monthIndex: number): number => Date.UTC(2020, monthIndex, 1
28
28
  // screenshots stay stable.
29
29
  const growth = (1 + LOAN_MONTHLY_RATE) ** LOAN_MONTHS;
30
30
  const annuityMinor = (LOAN_PRINCIPAL_MINOR * LOAN_MONTHLY_RATE * growth) / (growth - 1);
31
+ // Month index -> extra repayment, which shortens the term below LOAN_MONTHS.
32
+ const EXTRA_REPAYMENTS_MINOR: ReadonlyMap<number, number> = new Map([
33
+ [84, 3_000_000],
34
+ [150, 2_000_000],
35
+ ]);
31
36
  let balanceMinor: number = LOAN_PRINCIPAL_MINOR;
32
37
  let interestPaidMinor = 0;
38
+ let payoffMonth: number | undefined;
33
39
  const LOAN_REMAINING_POINTS = [{ atMs: loanMonthMs(0), value: LOAN_PRINCIPAL_MINOR }];
34
40
  const LOAN_INTEREST_POINTS = [{ atMs: loanMonthMs(0), value: 0 }];
35
41
  for (let i = 1; i <= LOAN_MONTHS; i++) {
36
42
  const interest = balanceMinor * LOAN_MONTHLY_RATE;
37
- balanceMinor = Math.max(0, balanceMinor - (annuityMinor - interest));
43
+ const extraRepayment = EXTRA_REPAYMENTS_MINOR.get(i) ?? 0;
44
+ balanceMinor = Math.max(0, balanceMinor - (annuityMinor - interest) - extraRepayment);
45
+ if (balanceMinor === 0) payoffMonth ??= i;
38
46
  interestPaidMinor += interest;
39
47
  LOAN_REMAINING_POINTS.push({ atMs: loanMonthMs(i), value: Math.round(balanceMinor) });
40
48
  LOAN_INTEREST_POINTS.push({ atMs: loanMonthMs(i), value: Math.round(interestPaidMinor) });
@@ -44,10 +52,13 @@ const LOAN_SERIES = [
44
52
  { key: "interest", label: "widgets:dashboard:loan-interest", points: LOAN_INTEREST_POINTS },
45
53
  ];
46
54
  const LOAN_MARKERS = [
47
- { atMs: loanMonthMs(84), label: { i18nKey: "widgets:dashboard:marker-extra-1" }, kind: "extra" },
48
- { atMs: loanMonthMs(150), label: { i18nKey: "widgets:dashboard:marker-extra-2" }, kind: "extra" },
55
+ ...[...EXTRA_REPAYMENTS_MINOR.keys()].map((monthIndex, i) => ({
56
+ atMs: loanMonthMs(monthIndex),
57
+ label: { i18nKey: `widgets:dashboard:marker-extra-${i + 1}` },
58
+ kind: "extra",
59
+ })),
49
60
  {
50
- atMs: loanMonthMs(LOAN_MONTHS),
61
+ atMs: loanMonthMs(payoffMonth ?? LOAN_MONTHS),
51
62
  label: { i18nKey: "widgets:dashboard:marker-payoff" },
52
63
  kind: "payoff",
53
64
  },
@@ -0,0 +1,185 @@
1
+ import {
2
+ createDateField,
3
+ createEntity,
4
+ createNumberField,
5
+ createSelectField,
6
+ createTextField,
7
+ defineFeature,
8
+ } from "@cosmicdrift/kumiko-framework/engine";
9
+
10
+ import { WORKBOARD_I18N } from "./i18n";
11
+
12
+ export const taskEntity = createEntity({
13
+ table: "read_workboard_tasks",
14
+ fields: {
15
+ title: createTextField({
16
+ personal: false,
17
+ reason: "is_business_data",
18
+ required: true,
19
+ searchable: true,
20
+ sortable: true,
21
+ }),
22
+ status: createSelectField({
23
+ options: ["open", "inProgress", "blocked", "done"] as const,
24
+ default: "open",
25
+ sortable: true,
26
+ filterable: true,
27
+ }),
28
+ priority: createSelectField({
29
+ options: ["low", "medium", "high"] as const,
30
+ default: "medium",
31
+ sortable: true,
32
+ filterable: true,
33
+ }),
34
+ dueDate: createDateField({ sortable: true }),
35
+ assignee: createTextField({ personal: false, reason: "is_business_data", sortable: true }),
36
+ estimateHours: createNumberField({ sortable: true, filterable: true }),
37
+ },
38
+ });
39
+
40
+ const open = {
41
+ access: {
42
+ openToAll: {
43
+ reason: "demo app: any signed-in user manages every task; there is no per-user ownership",
44
+ },
45
+ },
46
+ } as const;
47
+
48
+ // All of this round's list options on one screen: remembered state, one reset
49
+ // button, the column picker (estimateHours starts hidden) and the density choice.
50
+ export const workboardFeature = defineFeature("workboard", (r) => {
51
+ r.translations({ keys: WORKBOARD_I18N });
52
+ r.crud("task", taskEntity, { write: open, read: open });
53
+
54
+ r.screen({
55
+ id: "task-list",
56
+ type: "entityList",
57
+ entity: "task",
58
+ columns: [
59
+ "title",
60
+ "status",
61
+ "priority",
62
+ { field: "dueDate", hideOnNarrow: true },
63
+ { field: "assignee", hideOnNarrow: true },
64
+ { field: "estimateHours", hidden: true, hideOnNarrow: true },
65
+ ],
66
+ pagination: "pages",
67
+ pageSize: 25,
68
+ defaultSort: { field: "dueDate", dir: "asc" },
69
+ searchable: true,
70
+ facets: { status: { display: "chips" }, priority: {} },
71
+ table: {
72
+ rememberState: true,
73
+ resetAll: true,
74
+ columnPicker: true,
75
+ density: { default: "comfortable", userChoice: true },
76
+ export: { xlsx: true },
77
+ },
78
+ rowActions: [
79
+ { kind: "navigate", id: "edit", label: "Edit", screen: "task-edit", rowClick: true },
80
+ ],
81
+ });
82
+
83
+ // The same tasks as a spreadsheet-like board: fixed column widths, a pinned title,
84
+ // keyboard navigation between rows, row checkboxes with a bulk delete.
85
+ r.screen({
86
+ id: "task-board",
87
+ type: "entityList",
88
+ entity: "task",
89
+ columns: [
90
+ { field: "title", pinned: "left", width: 260, minWidth: 140 },
91
+ { field: "status", width: 180, minWidth: 100 },
92
+ { field: "priority", width: 180, minWidth: 100 },
93
+ { field: "dueDate", width: 180, minWidth: 100, hideOnNarrow: true },
94
+ { field: "assignee", width: 220, minWidth: 100, hideOnNarrow: true },
95
+ { field: "estimateHours", width: 180, minWidth: 100, hideOnNarrow: true },
96
+ ],
97
+ pagination: "pages",
98
+ pageSize: 25,
99
+ defaultSort: { field: "dueDate", dir: "asc" },
100
+ searchable: true,
101
+ table: {
102
+ rememberState: true,
103
+ columnPicker: true,
104
+ pinning: true,
105
+ resizing: true,
106
+ keyboardNavigation: true,
107
+ density: { default: "comfortable", userChoice: true },
108
+ },
109
+ rowActions: [
110
+ { kind: "navigate", id: "edit", label: "Edit", screen: "task-edit", rowClick: true },
111
+ {
112
+ kind: "writeHandler",
113
+ id: "delete",
114
+ label: "Delete",
115
+ handler: "workboard:write:task:delete",
116
+ style: "danger",
117
+ visible: { field: "status", ne: "done" },
118
+ },
119
+ ],
120
+ bulkActions: [{ id: "delete", rowAction: "delete" }],
121
+ });
122
+
123
+ // The same tasks grouped by status on the server: each header carries the
124
+ // group's count and estimate sum, a footer row the sum over all filtered tasks.
125
+ r.screen({
126
+ id: "task-estimates",
127
+ type: "entityList",
128
+ entity: "task",
129
+ columns: ["title", "status", "priority", "assignee", "estimateHours"],
130
+ pagination: "pages",
131
+ pageSize: 3,
132
+ defaultSort: { field: "title", dir: "asc" },
133
+ searchable: true,
134
+ facets: { estimateHours: { display: "range" } },
135
+ table: {
136
+ grouping: { field: "status", collapsedWhen: "done", userChoice: true, fields: ["priority"] },
137
+ totals: [{ field: "estimateHours", kind: "sum" }],
138
+ },
139
+ rowActions: [
140
+ { kind: "navigate", id: "edit", label: "Edit", screen: "task-edit", rowClick: true },
141
+ ],
142
+ });
143
+
144
+ r.screen({
145
+ id: "task-edit",
146
+ type: "entityEdit",
147
+ entity: "task",
148
+ dormant: true,
149
+ listScreenId: "task-list",
150
+ layout: {
151
+ sections: [
152
+ {
153
+ columns: 2,
154
+ fields: ["title", "assignee", "status", "priority", "dueDate", "estimateHours"],
155
+ },
156
+ ],
157
+ },
158
+ });
159
+
160
+ r.nav({ id: "workboard", label: "workboard:nav.workboard", icon: "list", order: 40 });
161
+ r.nav({
162
+ id: "task-list",
163
+ label: "workboard:nav.tasks",
164
+ parent: "workboard:nav:workboard",
165
+ screen: "workboard:screen:task-list",
166
+ icon: "table",
167
+ order: 10,
168
+ });
169
+ r.nav({
170
+ id: "task-board",
171
+ label: "workboard:nav.board",
172
+ parent: "workboard:nav:workboard",
173
+ screen: "workboard:screen:task-board",
174
+ icon: "table",
175
+ order: 20,
176
+ });
177
+ r.nav({
178
+ id: "task-estimates",
179
+ label: "workboard:nav.estimates",
180
+ parent: "workboard:nav:workboard",
181
+ screen: "workboard:screen:task-estimates",
182
+ icon: "table",
183
+ order: 30,
184
+ });
185
+ });
@@ -0,0 +1,27 @@
1
+ import type { LocalizedString } from "../shared-i18n";
2
+
3
+ export const WORKBOARD_I18N: Readonly<Record<string, LocalizedString>> = {
4
+ "workboard:nav.workboard": { de: "Aufgaben", en: "Workboard" },
5
+ "workboard:nav.tasks": { de: "Alle Aufgaben", en: "All tasks" },
6
+ "workboard:nav.board": { de: "Aufgaben-Board", en: "Task board" },
7
+ "workboard:nav.estimates": { de: "Aufwand je Status", en: "Estimates by status" },
8
+ "screen:task-board.title": { de: "Aufgaben-Board", en: "Task board" },
9
+ "screen:task-estimates.title": { de: "Aufwand je Status", en: "Estimates by status" },
10
+ "screen:task-list.title": { de: "Aufgaben", en: "Tasks" },
11
+ "screen:task-edit.title": { de: "Aufgabe bearbeiten", en: "Edit task" },
12
+ "screen:task-edit.create.title": { de: "Aufgabe anlegen", en: "Create task" },
13
+ "screen:task-edit.edit.title": { de: "Aufgabe bearbeiten", en: "Edit task" },
14
+ "workboard:entity:task:field:title": { de: "Titel", en: "Title" },
15
+ "workboard:entity:task:field:status": { de: "Status", en: "Status" },
16
+ "workboard:entity:task:field:status:option:open": { de: "Offen", en: "Open" },
17
+ "workboard:entity:task:field:status:option:inProgress": { de: "In Arbeit", en: "In progress" },
18
+ "workboard:entity:task:field:status:option:blocked": { de: "Blockiert", en: "Blocked" },
19
+ "workboard:entity:task:field:status:option:done": { de: "Erledigt", en: "Done" },
20
+ "workboard:entity:task:field:priority": { de: "Priorität", en: "Priority" },
21
+ "workboard:entity:task:field:priority:option:low": { de: "Niedrig", en: "Low" },
22
+ "workboard:entity:task:field:priority:option:medium": { de: "Mittel", en: "Medium" },
23
+ "workboard:entity:task:field:priority:option:high": { de: "Hoch", en: "High" },
24
+ "workboard:entity:task:field:dueDate": { de: "Fällig am", en: "Due date" },
25
+ "workboard:entity:task:field:assignee": { de: "Zuständig", en: "Assignee" },
26
+ "workboard:entity:task:field:estimateHours": { de: "Aufwand (Std.)", en: "Estimate (h)" },
27
+ };