@cosmicdrift/kumiko-samples 0.362.0 → 0.363.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 (252) hide show
  1. package/package.json +1 -1
  2. package/packages/bundled-features/package.json +17 -6
  3. package/packages/bundled-features/src/admin-shell/changes.json +6 -0
  4. package/packages/bundled-features/src/admin-shell/feature.ts +8 -1
  5. package/packages/bundled-features/src/agent-tools/agent-manifest.ts +3 -4
  6. package/packages/bundled-features/src/agent-tools/filter-ops.ts +1 -3
  7. package/packages/bundled-features/src/agent-tools/tool-catalog.ts +1 -3
  8. package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +2 -1
  9. package/packages/bundled-features/src/auth-email-password/changes.json +14 -0
  10. package/packages/bundled-features/src/auth-email-password/email-templates.ts +12 -138
  11. package/packages/bundled-features/src/auth-email-password/feature.ts +30 -9
  12. package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +4 -5
  13. package/packages/bundled-features/src/auth-email-password/handlers/request-account-unlock.write.ts +2 -5
  14. package/packages/bundled-features/src/auth-email-password/handlers/request-email-verification.write.ts +2 -5
  15. package/packages/bundled-features/src/auth-email-password/handlers/request-password-reset.write.ts +2 -5
  16. package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +3 -4
  17. package/packages/bundled-features/src/auth-email-password/handlers/token-request-handler.ts +3 -12
  18. package/packages/bundled-features/src/auth-email-password/index.ts +2 -17
  19. package/packages/bundled-features/src/auth-email-password/magic-link-mail.ts +30 -22
  20. package/packages/bundled-features/src/auth-email-password/mail-notifications.ts +158 -0
  21. package/packages/bundled-features/src/auth-email-password/signup-activation.ts +2 -3
  22. package/packages/bundled-features/src/auth-foundation/types.ts +8 -18
  23. package/packages/bundled-features/src/auth-mfa/feature.ts +8 -10
  24. package/packages/bundled-features/src/auth-mfa/hmac-token-codec.ts +4 -4
  25. package/packages/bundled-features/src/auth-mfa/mfa-challenge-token.ts +3 -3
  26. package/packages/bundled-features/src/auth-mfa/mfa-preauth-setup-token.ts +3 -3
  27. package/packages/bundled-features/src/auth-mfa/mfa-setup-token.ts +8 -8
  28. package/packages/bundled-features/src/billing-foundation/changes.json +7 -0
  29. package/packages/bundled-features/src/billing-foundation/constants.ts +5 -4
  30. package/packages/bundled-features/src/billing-foundation/consumer-protection/confirmation-mail.ts +38 -44
  31. package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +3 -3
  32. package/packages/bundled-features/src/billing-foundation/consumer-protection/mail-notifications.ts +115 -0
  33. package/packages/bundled-features/src/billing-foundation/consumer-protection/register-consent.ts +2 -0
  34. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-mail.ts +30 -30
  35. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-notify.ts +2 -2
  36. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-pages.ts +1 -4
  37. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +2 -2
  38. package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +2 -2
  39. package/packages/bundled-features/src/billing-foundation/handlers/create-portal-session.write.ts +4 -9
  40. package/packages/bundled-features/src/billing-foundation/handlers/list-subscriptions.query.ts +1 -1
  41. package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +2 -2
  42. package/packages/bundled-features/src/billing-foundation/handlers/process-payment-event.write.ts +1 -1
  43. package/packages/bundled-features/src/billing-foundation/subscription-tier-sync.ts +3 -6
  44. package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +2 -1
  45. package/packages/bundled-features/src/cap-overview/web/cap-usage-cell.tsx +6 -4
  46. package/packages/bundled-features/src/channel-email/changes.json +19 -0
  47. package/packages/bundled-features/src/channel-email/email-channel.ts +122 -29
  48. package/packages/bundled-features/src/channel-email/feature.ts +6 -3
  49. package/packages/bundled-features/src/channel-email/index.ts +7 -1
  50. package/packages/bundled-features/src/channel-email/pii-guard.ts +13 -0
  51. package/packages/bundled-features/src/channel-email/smtp-transport.ts +15 -1
  52. package/packages/bundled-features/src/channel-email/types.ts +23 -0
  53. package/packages/bundled-features/src/channel-in-app/handlers/mark-read.write.ts +2 -2
  54. package/packages/bundled-features/src/config/handlers/set.write.ts +1 -5
  55. package/packages/bundled-features/src/custom-fields/db/queries/user-data-rights.ts +2 -2
  56. package/packages/bundled-features/src/custom-fields/lib/value-schema.ts +10 -11
  57. package/packages/bundled-features/src/custom-fields/wire-user-data-rights.ts +7 -6
  58. package/packages/bundled-features/src/data-retention/changes.json +6 -0
  59. package/packages/bundled-features/src/data-retention/index.ts +1 -0
  60. package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +8 -6
  61. package/packages/bundled-features/src/delivery/attachment-ref.ts +84 -0
  62. package/packages/bundled-features/src/delivery/changes.json +48 -0
  63. package/packages/bundled-features/src/delivery/channel-context.ts +129 -4
  64. package/packages/bundled-features/src/delivery/constants.ts +2 -0
  65. package/packages/bundled-features/src/delivery/delivery-service.ts +104 -26
  66. package/packages/bundled-features/src/delivery/feature.ts +1 -1
  67. package/packages/bundled-features/src/delivery/index.ts +17 -2
  68. package/packages/bundled-features/src/delivery/jobs.ts +48 -5
  69. package/packages/bundled-features/src/delivery/notify-factory.ts +14 -9
  70. package/packages/bundled-features/src/delivery/testing.ts +9 -1
  71. package/packages/bundled-features/src/delivery/types.ts +28 -18
  72. package/packages/bundled-features/src/delivery/unsubscribe.ts +5 -2
  73. package/packages/bundled-features/src/derivatives-sharp/render.ts +1 -22
  74. package/packages/bundled-features/src/document-ingest-foundation/pages.ts +6 -3
  75. package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +4 -4
  76. package/packages/bundled-features/src/file-foundation/index.ts +7 -0
  77. package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +86 -0
  78. package/packages/bundled-features/src/folders/web/folder-manager.tsx +5 -2
  79. package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +11 -11
  80. package/packages/bundled-features/src/form-draft/db/queries/draft-count.ts +2 -2
  81. package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +2 -2
  82. package/packages/bundled-features/src/form-draft/release-file-refs.ts +3 -2
  83. package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +1 -1
  84. package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +6 -6
  85. package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-accounts.query.ts +1 -1
  86. package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-messages.query.ts +1 -1
  87. package/packages/bundled-features/src/inbound-mail-foundation/handlers/scope-visibility.ts +2 -2
  88. package/packages/bundled-features/src/inbound-mail-foundation/oauth-state.ts +7 -7
  89. package/packages/bundled-features/src/inbound-mail-foundation/retention-sweep.ts +2 -6
  90. package/packages/bundled-features/src/inbound-mail-foundation/tenant-destroy-hook.ts +5 -13
  91. package/packages/bundled-features/src/inbound-mail-foundation/types.ts +4 -6
  92. package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +40 -25
  93. package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +4 -3
  94. package/packages/bundled-features/src/jobs/handlers/catalog.query.ts +1 -1
  95. package/packages/bundled-features/src/ledger/recurring.ts +1 -3
  96. package/packages/bundled-features/src/managed-pages/branding.ts +33 -9
  97. package/packages/bundled-features/src/managed-pages/changes.json +6 -0
  98. package/packages/bundled-features/src/managed-pages/feature.ts +1 -0
  99. package/packages/bundled-features/src/managed-pages/i18n.ts +1 -0
  100. package/packages/bundled-features/src/managed-pages/screens/branding-screen.ts +8 -0
  101. package/packages/bundled-features/src/page-render/branding.ts +3 -0
  102. package/packages/bundled-features/src/page-render/markdown.ts +1 -1
  103. package/packages/bundled-features/src/personal-access-tokens/feature.ts +2 -4
  104. package/packages/bundled-features/src/personal-access-tokens/handlers/list.query.ts +2 -1
  105. package/packages/bundled-features/src/personal-access-tokens/index.ts +1 -1
  106. package/packages/bundled-features/src/personal-access-tokens/revoke-for-user.ts +2 -1
  107. package/packages/bundled-features/src/renderer-foundation/README.md +11 -10
  108. package/packages/bundled-features/src/renderer-foundation/api.ts +14 -14
  109. package/packages/bundled-features/src/renderer-foundation/changes.json +39 -0
  110. package/packages/bundled-features/src/renderer-foundation/constants.ts +6 -8
  111. package/packages/bundled-features/src/renderer-foundation/feature.ts +7 -7
  112. package/packages/bundled-features/src/renderer-foundation/index.ts +13 -2
  113. package/packages/bundled-features/src/renderer-foundation/types.ts +132 -35
  114. package/packages/bundled-features/src/renderer-pdf/feature.ts +7 -1
  115. package/packages/bundled-features/src/sessions/db/queries/cleanup.ts +2 -2
  116. package/packages/bundled-features/src/sessions/feature.ts +2 -4
  117. package/packages/bundled-features/src/sessions/handlers/list.query.ts +2 -1
  118. package/packages/bundled-features/src/shared/attachment-file-name.ts +39 -0
  119. package/packages/bundled-features/src/shared/index.ts +6 -0
  120. package/packages/bundled-features/src/shared/is-tenant-db.ts +1 -1
  121. package/packages/bundled-features/src/shared/mail-template-body.ts +25 -0
  122. package/packages/bundled-features/src/shared/sharp-input-limits.ts +26 -0
  123. package/packages/bundled-features/src/shared/signup-handover.ts +4 -4
  124. package/packages/bundled-features/src/tags/handlers/assign-tag.write.ts +5 -1
  125. package/packages/bundled-features/src/tags/web/tag-chip.tsx +2 -1
  126. package/packages/bundled-features/src/template-resolver/README.md +63 -7
  127. package/packages/bundled-features/src/template-resolver/api.ts +83 -8
  128. package/packages/bundled-features/src/template-resolver/changes.json +118 -0
  129. package/packages/bundled-features/src/template-resolver/compile-document-body.ts +214 -0
  130. package/packages/bundled-features/src/template-resolver/constants.ts +39 -11
  131. package/packages/bundled-features/src/template-resolver/document-sanitizer.ts +335 -0
  132. package/packages/bundled-features/src/template-resolver/document-schema.ts +323 -0
  133. package/packages/bundled-features/src/template-resolver/feature.ts +56 -6
  134. package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +188 -0
  135. package/packages/bundled-features/src/template-resolver/handlers/collection-set.write.ts +30 -2
  136. package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +142 -0
  137. package/packages/bundled-features/src/template-resolver/handlers/diff-to-system.query.ts +72 -0
  138. package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +83 -0
  139. package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +3 -3
  140. package/packages/bundled-features/src/template-resolver/handlers/import-bundle-system.write.ts +42 -0
  141. package/packages/bundled-features/src/template-resolver/handlers/import-bundle.write.ts +22 -0
  142. package/packages/bundled-features/src/template-resolver/handlers/layout-source.query.ts +108 -0
  143. package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +5 -7
  144. package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +250 -0
  145. package/packages/bundled-features/src/template-resolver/handlers/preview.query.ts +25 -0
  146. package/packages/bundled-features/src/template-resolver/handlers/reset-to-system.write.ts +58 -0
  147. package/packages/bundled-features/src/template-resolver/handlers/resource-link-pdf.write.ts +34 -0
  148. package/packages/bundled-features/src/template-resolver/handlers/resource-remove.write.ts +50 -0
  149. package/packages/bundled-features/src/template-resolver/handlers/resource-shared.ts +24 -0
  150. package/packages/bundled-features/src/template-resolver/handlers/resource-upload.write.ts +135 -0
  151. package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +106 -0
  152. package/packages/bundled-features/src/template-resolver/handlers/set.write.ts +32 -3
  153. package/packages/bundled-features/src/template-resolver/handlers/shared.ts +7 -2
  154. package/packages/bundled-features/src/template-resolver/handlers/template-gates.ts +184 -0
  155. package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +183 -0
  156. package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +55 -0
  157. package/packages/bundled-features/src/template-resolver/handlers/toggle-status.write.ts +57 -10
  158. package/packages/bundled-features/src/template-resolver/handlers/upsert-system.write.ts +19 -71
  159. package/packages/bundled-features/src/template-resolver/handlers/upsert-tenant.write.ts +15 -76
  160. package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +17 -0
  161. package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +116 -0
  162. package/packages/bundled-features/src/template-resolver/index.ts +100 -0
  163. package/packages/bundled-features/src/template-resolver/layout-regions.ts +206 -0
  164. package/packages/bundled-features/src/template-resolver/linked-resources.ts +102 -0
  165. package/packages/bundled-features/src/template-resolver/preview-display-html.ts +36 -0
  166. package/packages/bundled-features/src/template-resolver/print-document.ts +58 -0
  167. package/packages/bundled-features/src/template-resolver/qualified-names.ts +30 -0
  168. package/packages/bundled-features/src/template-resolver/record-mapping.ts +26 -0
  169. package/packages/bundled-features/src/template-resolver/resource-image.ts +47 -0
  170. package/packages/bundled-features/src/template-resolver/seeding.ts +147 -17
  171. package/packages/bundled-features/src/template-resolver/store-template-resource.ts +416 -0
  172. package/packages/bundled-features/src/template-resolver/table.ts +14 -0
  173. package/packages/bundled-features/src/template-resolver/template-bundle.ts +79 -0
  174. package/packages/bundled-features/src/template-resolver/template-diff.ts +78 -0
  175. package/packages/bundled-features/src/template-resolver/template-meta.ts +129 -0
  176. package/packages/bundled-features/src/template-resolver/template-preview.ts +573 -0
  177. package/packages/bundled-features/src/template-resolver/template-resources.ts +74 -0
  178. package/packages/bundled-features/src/template-resolver/template-usage.ts +48 -0
  179. package/packages/bundled-features/src/template-resolver/template-validation.ts +229 -0
  180. package/packages/bundled-features/src/template-resolver/testing.ts +5 -5
  181. package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +9 -6
  182. package/packages/bundled-features/src/template-resolver/web/document-editor-extensions.ts +162 -0
  183. package/packages/bundled-features/src/template-resolver/web/document-editor.tsx +28 -0
  184. package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +850 -0
  185. package/packages/bundled-features/src/template-resolver/web/document-toolbar-blocks.ts +61 -0
  186. package/packages/bundled-features/src/template-resolver/web/editor-handle.ts +26 -0
  187. package/packages/bundled-features/src/template-resolver/web/i18n.ts +100 -0
  188. package/packages/bundled-features/src/template-resolver/web/index.ts +19 -0
  189. package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor-lazy.tsx +36 -0
  190. package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +169 -0
  191. package/packages/bundled-features/src/template-resolver/web/placeholder-text.ts +37 -0
  192. package/packages/bundled-features/src/template-resolver/web/use-stable-by-key.ts +14 -0
  193. package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +3 -2
  194. package/packages/bundled-features/src/tenant/seeding.ts +41 -7
  195. package/packages/bundled-features/src/tenant-lifecycle/boot-checks.ts +1 -1
  196. package/packages/bundled-features/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +2 -1
  197. package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +4 -4
  198. package/packages/bundled-features/src/user/handlers/detail.query.ts +3 -5
  199. package/packages/bundled-features/src/user/roles-input-schema.ts +2 -2
  200. package/packages/bundled-features/src/user-data-rights/changes.json +7 -0
  201. package/packages/bundled-features/src/user-data-rights/db/queries/forget-cleanup.ts +2 -2
  202. package/packages/bundled-features/src/user-data-rights/email-templates.ts +5 -149
  203. package/packages/bundled-features/src/user-data-rights/feature.ts +72 -35
  204. package/packages/bundled-features/src/user-data-rights/handlers/cancel-deletion.write.ts +2 -1
  205. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +5 -11
  206. package/packages/bundled-features/src/user-data-rights/lib/default-mailers.ts +134 -53
  207. package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +2 -2
  208. package/packages/bundled-features/src/user-data-rights/mail-notifications.ts +157 -0
  209. package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +1 -1
  210. package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +2 -1
  211. package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +2 -1
  212. package/packages/bundled-features/src/waitlist/changes.json +7 -0
  213. package/packages/bundled-features/src/waitlist/feature.ts +17 -0
  214. package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +4 -5
  215. package/packages/bundled-features/src/waitlist/mail.ts +69 -18
  216. package/packages/bundled-features/src/workflow-runner/event-trigger.ts +1 -2
  217. package/samples/apps/ui-walkthrough/package.json +2 -0
  218. package/samples/apps/ui-walkthrough/src/app/auth-constants.ts +9 -0
  219. package/samples/apps/ui-walkthrough/src/app/client.tsx +6 -0
  220. package/samples/apps/ui-walkthrough/src/app/seed-templates.ts +154 -0
  221. package/samples/apps/ui-walkthrough/src/app/server.ts +5 -1
  222. package/samples/apps/ui-walkthrough/src/app/shell.tsx +12 -1
  223. package/samples/apps/ui-walkthrough/src/app/template-seed-data.ts +354 -0
  224. package/samples/apps/ui-walkthrough/src/features/billing/feature.ts +68 -0
  225. package/samples/apps/ui-walkthrough/src/features/billing/i18n.ts +18 -0
  226. package/samples/apps/ui-walkthrough/src/features/billing/index.ts +2 -0
  227. package/samples/apps/ui-walkthrough/src/features/billing/web/index.ts +7 -0
  228. package/samples/apps/ui-walkthrough/src/run-config.ts +37 -1
  229. package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-features.ts +0 -2
  230. package/samples/apps/use-all-bundled/feature-manifest.json +115 -20
  231. package/samples/apps/use-all-bundled/kumiko/migrations/0045_template-resource-meta.rebuild.json +4 -0
  232. package/samples/apps/use-all-bundled/kumiko/migrations/0046_pdf-rendered.rebuild.json +4 -0
  233. package/samples/apps/use-all-bundled/package.json +2 -0
  234. package/samples/apps/use-all-bundled/playwright.config.ts +38 -3
  235. package/samples/apps/use-all-bundled/schema/generate.ts +13 -3
  236. package/samples/apps/use-all-bundled/schema/schema.generated.ts +3 -0
  237. package/samples/apps/use-all-bundled/scripts/check-coverage.ts +3 -0
  238. package/samples/apps/use-all-bundled/src/app/auth-constants.ts +3 -0
  239. package/samples/apps/use-all-bundled/src/app/client.tsx +4 -0
  240. package/samples/apps/use-all-bundled/src/app/seed-documents.ts +128 -0
  241. package/samples/apps/use-all-bundled/src/app/seed.ts +4 -0
  242. package/samples/apps/use-all-bundled/src/run-config.ts +11 -11
  243. package/samples/recipes/delivery-notifications/README.md +26 -25
  244. package/samples/recipes/delivery-notifications/package.json +2 -1
  245. package/samples/recipes/delivery-notifications/src/feature.ts +64 -58
  246. package/samples/recipes/seed-migration/README.md +1 -1
  247. package/packages/bundled-features/src/renderer-simple/changes.json +0 -27
  248. package/packages/bundled-features/src/renderer-simple/feature.ts +0 -66
  249. package/packages/bundled-features/src/renderer-simple/index.ts +0 -8
  250. package/packages/bundled-features/src/renderer-simple/mail-blocks.ts +0 -138
  251. package/packages/bundled-features/src/renderer-simple/resolve-variables.ts +0 -57
  252. package/packages/bundled-features/src/renderer-simple/simple-renderer.ts +0 -304
@@ -22,7 +22,6 @@ import {
22
22
  describeWorkflowStepError,
23
23
  getStep,
24
24
  SYSTEM_TENANT_ID,
25
- type TenantId,
26
25
  WORKFLOW_AGGREGATE_TYPE,
27
26
  WORKFLOW_RUN_FAILED_TYPE,
28
27
  WorkflowStepError,
@@ -71,7 +70,7 @@ export function assertEventTriggerStepsSupported(workflow: WorkflowDefinition):
71
70
  steps = buildPipelineSteps(workflow.pipelineDef, {
72
71
  type: "workflow-registration-probe",
73
72
  payload: {},
74
- user: createSystemUser(SYSTEM_TENANT_ID as TenantId),
73
+ user: createSystemUser(SYSTEM_TENANT_ID),
75
74
  });
76
75
  } catch (error) {
77
76
  throw new Error(
@@ -10,9 +10,11 @@
10
10
  "dependencies": {
11
11
  "@cosmicdrift/kumiko-bundled-features": "workspace:*",
12
12
  "@cosmicdrift/kumiko-dev-server": "workspace:*",
13
+ "@cosmicdrift/kumiko-document-designer": "workspace:*",
13
14
  "@cosmicdrift/kumiko-dispatcher-live": "workspace:*",
14
15
  "@cosmicdrift/kumiko-framework": "workspace:*",
15
16
  "@cosmicdrift/kumiko-headless": "workspace:*",
17
+ "@cosmicdrift/kumiko-renderer-mail-html": "workspace:*",
16
18
  "@cosmicdrift/kumiko-renderer-web": "workspace:*",
17
19
  "@cosmicdrift/kumiko-server-runtime": "workspace:*",
18
20
  "react": "^19.2.6",
@@ -18,3 +18,12 @@ export const ADMIN_PASSWORD = "kumiko-admin";
18
18
  // `as TenantId`-Cast lokal.
19
19
  export const DEV_TENANT_ID = "00000000-0000-4000-8000-000000000001";
20
20
  export const BETA_TENANT_ID = "00000000-0000-4000-8000-000000000002";
21
+
22
+ // Nordlicht Immobilien GmbH: the tenant the document-designer walkthrough runs
23
+ // in. Both users are new; the admin above stays untouched.
24
+ export const NORDLICHT_TENANT_ID = "00000000-0000-4000-8000-000000000003";
25
+ export const NORDLICHT_TENANT_NAME = "Nordlicht Immobilien GmbH";
26
+ export const TENANT_ADMIN_EMAIL = "a.berger@nordlicht-immobilien.de";
27
+ export const TENANT_ADMIN_PASSWORD = "nordlicht-berger";
28
+ export const PLATFORM_ADMIN_EMAIL = "plattform@kumiko.dev";
29
+ export const PLATFORM_ADMIN_PASSWORD = "kumiko-plattform";
@@ -2,8 +2,11 @@
2
2
  // übergibt Shell + clientFeatures an createKumikoApp.
3
3
 
4
4
  import { emailPasswordClient } from "@cosmicdrift/kumiko-bundled-features/auth-email-password/web";
5
+ import { textBlocksClient } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
6
+ import { documentDesignerClient } from "@cosmicdrift/kumiko-document-designer/web";
5
7
  import { localeDeClient } from "@cosmicdrift/kumiko-locale-de/web";
6
8
  import { createKumikoApp } from "@cosmicdrift/kumiko-renderer-web";
9
+ import { billingClient } from "../features/billing/web";
7
10
  import { rentalClient } from "../features/rental/web";
8
11
  import { tasksClient } from "../features/tasks/web";
9
12
  import { vehiclesClient } from "../features/vehicles/web";
@@ -17,5 +20,8 @@ createKumikoApp({
17
20
  tasksClient,
18
21
  rentalClient,
19
22
  vehiclesClient,
23
+ billingClient,
24
+ textBlocksClient(),
25
+ documentDesignerClient(),
20
26
  ],
21
27
  });
@@ -0,0 +1,154 @@
1
+ // Nordlicht Immobilien GmbH for the document-designer walkthrough: a tenant
2
+ // admin, a platform admin, branding and a realistic set of mail and PDF
3
+ // templates. Everything goes through the template write handlers (or the
4
+ // system-template seed), never straight into the tables.
5
+
6
+ import { seedAdmin } from "@cosmicdrift/kumiko-bundled-features/auth-email-password/seeding";
7
+ import { BRANDING_QN } from "@cosmicdrift/kumiko-bundled-features/managed-pages";
8
+ import {
9
+ TemplateResolverHandlers,
10
+ TemplateResolverQueries,
11
+ } from "@cosmicdrift/kumiko-bundled-features/template-resolver";
12
+ import type { SeedFn } from "@cosmicdrift/kumiko-dev-server";
13
+ import type { SessionUser, TenantId } from "@cosmicdrift/kumiko-framework/engine";
14
+ import { DEFAULT_MAIL_LAYOUT_MJML } from "@cosmicdrift/kumiko-renderer-mail-html";
15
+ import {
16
+ NORDLICHT_TENANT_ID,
17
+ NORDLICHT_TENANT_NAME,
18
+ PLATFORM_ADMIN_EMAIL,
19
+ PLATFORM_ADMIN_PASSWORD,
20
+ TENANT_ADMIN_EMAIL,
21
+ TENANT_ADMIN_PASSWORD,
22
+ } from "./auth-constants";
23
+ import {
24
+ INVOICE_CORRECTED_DRAFT,
25
+ INVOICE_ISSUED_DRAFT_VERSIONS,
26
+ PAYMENT_REMINDER_TEMPLATES,
27
+ type SeedTemplate,
28
+ SYSTEM_AUTH_MAILS,
29
+ SYSTEM_INVOICE_DOCUMENTS,
30
+ SYSTEM_INVOICE_ISSUED,
31
+ SYSTEM_PDF_LAYOUT,
32
+ SYSTEM_TENANCY_CERTIFICATE,
33
+ TENANT_MAIL_LAYOUT_VERSIONS,
34
+ TENANT_UTILITY_STATEMENT,
35
+ } from "./template-seed-data";
36
+
37
+ const NORDLICHT = NORDLICHT_TENANT_ID as TenantId;
38
+
39
+ const BRANDING = [
40
+ [BRANDING_QN.title, "Nordlicht Mieterportal"],
41
+ [BRANDING_QN.accentColor, "#205265"],
42
+ [BRANDING_QN.siteUrl, "https://nordlicht-immobilien.de"],
43
+ [BRANDING_QN.logoUrl, "https://nordlicht-immobilien.de/logo-nordlicht.png"],
44
+ ] as const;
45
+
46
+ export const seedTemplates: SeedFn = async (stack) => {
47
+ const membership = (roles: readonly string[]) => [
48
+ {
49
+ tenantId: NORDLICHT,
50
+ tenantKey: "nordlicht",
51
+ tenantName: NORDLICHT_TENANT_NAME,
52
+ roles,
53
+ },
54
+ ];
55
+ const tenantAdminAccount = await seedAdmin(stack.db, {
56
+ email: TENANT_ADMIN_EMAIL,
57
+ password: TENANT_ADMIN_PASSWORD,
58
+ displayName: "A. Berger",
59
+ emailVerified: true,
60
+ memberships: membership(["TenantAdmin"]),
61
+ });
62
+ const platformAdminAccount = await seedAdmin(stack.db, {
63
+ email: PLATFORM_ADMIN_EMAIL,
64
+ password: PLATFORM_ADMIN_PASSWORD,
65
+ displayName: "Plattform-Admin",
66
+ emailVerified: true,
67
+ globalRoles: ["SystemAdmin"],
68
+ memberships: membership(["TenantAdmin"]),
69
+ });
70
+ // The session re-derives roles from the membership row on every request, so
71
+ // the roles here only have to match what the account really has.
72
+ const tenantAdmin: SessionUser = {
73
+ id: tenantAdminAccount.id as SessionUser["id"],
74
+ tenantId: NORDLICHT,
75
+ roles: ["TenantAdmin"],
76
+ };
77
+ const platformAdmin: SessionUser = {
78
+ id: platformAdminAccount.id as SessionUser["id"],
79
+ tenantId: NORDLICHT,
80
+ roles: ["TenantAdmin", "SystemAdmin"],
81
+ };
82
+
83
+ const overview = await stack.http.queryOk<{ rows: { origin: string }[] }>(
84
+ TemplateResolverQueries.overview,
85
+ {},
86
+ tenantAdmin,
87
+ );
88
+ if (overview.rows.some((row) => row.origin === "tenant")) return;
89
+
90
+ const upsert = (
91
+ handler: string,
92
+ template: SeedTemplate,
93
+ user: SessionUser,
94
+ extra: Record<string, unknown> = {},
95
+ ) =>
96
+ stack.http.writeOk<{ id: string }>(
97
+ handler,
98
+ {
99
+ slug: template.slug,
100
+ kind: template.kind,
101
+ locale: template.locale,
102
+ contentFormat: "html",
103
+ content: template.content,
104
+ ...(template.title !== undefined && { title: template.title }),
105
+ ...(template.meta !== undefined && { meta: template.meta }),
106
+ ...(template.variableSchema !== undefined && { variableSchema: template.variableSchema }),
107
+ ...extra,
108
+ },
109
+ user,
110
+ );
111
+ const upsertSystem = (template: SeedTemplate) =>
112
+ upsert(TemplateResolverHandlers.upsertSystem, template, platformAdmin);
113
+ const upsertTenant = (template: SeedTemplate, status: "draft" | "active") =>
114
+ upsert(TemplateResolverHandlers.upsertTenant, template, tenantAdmin, { status });
115
+
116
+ await stack.http.writeOk(
117
+ TemplateResolverHandlers.upsertSystem,
118
+ {
119
+ slug: "default",
120
+ kind: "mail-layout",
121
+ locale: "en",
122
+ contentFormat: "mjml",
123
+ content: DEFAULT_MAIL_LAYOUT_MJML,
124
+ title: "Mail-Layout",
125
+ },
126
+ platformAdmin,
127
+ );
128
+ await upsertSystem(SYSTEM_PDF_LAYOUT);
129
+ for (const mail of SYSTEM_AUTH_MAILS) await upsertSystem(mail);
130
+ await upsertSystem(SYSTEM_INVOICE_ISSUED);
131
+ for (const document of SYSTEM_INVOICE_DOCUMENTS) await upsertSystem(document);
132
+ const certificate = await upsertSystem(SYSTEM_TENANCY_CERTIFICATE);
133
+ await stack.http.writeOk(
134
+ TemplateResolverHandlers.archiveSystem,
135
+ { id: certificate.id },
136
+ platformAdmin,
137
+ );
138
+
139
+ for (const [key, value] of BRANDING) {
140
+ await stack.http.writeOk("config:write:set", { key, value }, tenantAdmin);
141
+ }
142
+ // Each save is a new version of the same row; the second one makes the
143
+ // layout "customised" for the overview and the first leaves history to diff.
144
+ for (const content of TENANT_MAIL_LAYOUT_VERSIONS) {
145
+ await upsertTenant(
146
+ { slug: "default", kind: "mail-layout", locale: "en", title: "Mail-Layout", content },
147
+ "active",
148
+ );
149
+ }
150
+ for (const draft of INVOICE_ISSUED_DRAFT_VERSIONS) await upsertTenant(draft, "draft");
151
+ await upsertTenant(INVOICE_CORRECTED_DRAFT, "draft");
152
+ for (const reminder of PAYMENT_REMINDER_TEMPLATES) await upsertTenant(reminder, "active");
153
+ await upsertTenant(TENANT_UTILITY_STATEMENT, "active");
154
+ };
@@ -11,10 +11,12 @@
11
11
 
12
12
  import { runDevApp } from "@cosmicdrift/kumiko-dev-server";
13
13
  import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
14
+ import { createInMemoryFileProvider } from "@cosmicdrift/kumiko-framework/files";
14
15
  import { APP_FEATURES } from "../run-config";
15
16
  import { ADMIN_EMAIL, ADMIN_PASSWORD, BETA_TENANT_ID, DEV_TENANT_ID } from "./auth-constants";
16
17
  import { seedTasks } from "./seed";
17
18
  import { seedRental } from "./seed-rental";
19
+ import { seedTemplates } from "./seed-templates";
18
20
  import { seedVehicles } from "./seed-vehicles";
19
21
 
20
22
  // Zwei feste Tenants — Admin ist in beiden Mitglied damit der
@@ -25,10 +27,12 @@ import { seedVehicles } from "./seed-vehicles";
25
27
 
26
28
  await runDevApp({
27
29
  features: [...APP_FEATURES],
28
- seeds: [seedTasks, seedRental, seedVehicles],
30
+ seeds: [seedTasks, seedRental, seedVehicles, seedTemplates],
29
31
  // PORT env-var override für Playwright-e2e-Runs (config zeigt auf 4174);
30
32
  // sonst lokal-Default 4173.
31
33
  port: Number.parseInt(process.env["PORT"] ?? "4173", 10),
34
+ // Logo and attachment uploads of the mail editor need a file store.
35
+ files: { storageProvider: createInMemoryFileProvider() },
32
36
  clientEntry: "./src/app/client.tsx",
33
37
  htmlPath: "./public/index.html",
34
38
  watchDirs: ["./src", "../../../packages/*/src"],
@@ -5,6 +5,7 @@
5
5
  import {
6
6
  TenantMenuItems,
7
7
  UserMenu,
8
+ useSession,
8
9
  } from "@cosmicdrift/kumiko-bundled-features/auth-email-password/web";
9
10
  import {
10
11
  type AppSchema,
@@ -18,13 +19,19 @@ import {
18
19
  import { MoonStar, Sun } from "lucide-react";
19
20
  import type { ReactNode } from "react";
20
21
  import { AssistantAction } from "./assistant-action";
21
- import { BETA_TENANT_ID, DEV_TENANT_ID } from "./auth-constants";
22
+ import {
23
+ BETA_TENANT_ID,
24
+ DEV_TENANT_ID,
25
+ NORDLICHT_TENANT_ID,
26
+ NORDLICHT_TENANT_NAME,
27
+ } from "./auth-constants";
22
28
 
23
29
  const APP_NAME = "Kumiko Walkthrough";
24
30
 
25
31
  const tenantName = (tenantId: string): string => {
26
32
  if (tenantId === DEV_TENANT_ID) return "Dev Tenant";
27
33
  if (tenantId === BETA_TENANT_ID) return "Beta Tenant";
34
+ if (tenantId === NORDLICHT_TENANT_ID) return NORDLICHT_TENANT_NAME;
28
35
  return tenantId.slice(0, 8);
29
36
  };
30
37
 
@@ -41,10 +48,14 @@ export function AppShell({
41
48
  readonly schema: AppSchema;
42
49
  }): ReactNode {
43
50
  const t = useTranslation();
51
+ const session = useSession();
52
+ // Without the user the shell hides role-gated navs and KumikoScreen denies role-gated screens.
53
+ const user = session.user !== null ? { id: session.user.id, roles: session.roles } : undefined;
44
54
  return (
45
55
  <DefaultAppShell
46
56
  brand={<SidebarBrand name={APP_NAME} plan={t("tasks.shell.tagline")} />}
47
57
  schema={schema}
58
+ {...(user !== undefined && { user })}
48
59
  headerActions={
49
60
  <>
50
61
  <AssistantAction />
@@ -0,0 +1,354 @@
1
+ // Template content for the Nordlicht document-designer walkthrough. Pure data,
2
+ // no framework import: seed-templates.ts feeds it through the template write
3
+ // handlers, so every body here goes through the real sanitizer and placeholder
4
+ // validation.
5
+
6
+ export type SeedTemplate = {
7
+ readonly slug: string;
8
+ readonly kind: "mail" | "mail-layout" | "document-pdf" | "pdf-layout";
9
+ readonly locale: string;
10
+ readonly title?: string;
11
+ readonly content: string;
12
+ readonly meta?: Record<string, unknown>;
13
+ readonly variableSchema?: Record<string, unknown>;
14
+ };
15
+
16
+ // Document HTML marks a variable as an empty span; only link targets take {{name}}.
17
+ const v = (name: string): string => `<span data-variable="${name}"></span>`;
18
+
19
+ const AUTH_VARIABLE_SCHEMA = {
20
+ appName: { type: "text", required: true },
21
+ actionUrl: { type: "link", required: true },
22
+ validFor: { type: "text", required: true },
23
+ validUntil: { type: "text", required: true },
24
+ } as const;
25
+
26
+ const INVOICE_VARIABLE_SCHEMA = {
27
+ customerName: { type: "text", required: true },
28
+ invoiceNumber: { type: "text", required: true },
29
+ amount: { type: "money", required: true },
30
+ dueDate: { type: "date", required: true },
31
+ invoiceUrl: { type: "link", required: true },
32
+ } as const;
33
+
34
+ const DOCUMENT_LINES_SCHEMA = {
35
+ tenantName: { type: "text" },
36
+ customerName: { type: "text", required: true },
37
+ invoiceNumber: { type: "text", required: true },
38
+ invoiceDate: { type: "date", required: true },
39
+ total: { type: "money", required: true },
40
+ lines: {
41
+ type: "list",
42
+ required: true,
43
+ item: { description: { type: "text" }, amount: { type: "money" } },
44
+ },
45
+ } as const;
46
+
47
+ export const SYSTEM_PDF_LAYOUT: SeedTemplate = {
48
+ slug: "default",
49
+ kind: "pdf-layout",
50
+ locale: "en",
51
+ title: "Briefpapier",
52
+ content: [
53
+ `<div data-header><p><strong>${v("tenantName")}</strong></p></div>`,
54
+ "<div data-content></div>",
55
+ "<div data-signature></div>",
56
+ `<div data-footer><p>${v("tenantName")} · Seite ${v("page")} von ${v("pages")}</p></div>`,
57
+ ].join(""),
58
+ };
59
+
60
+ export const TENANT_MAIL_LAYOUT_VERSIONS: readonly string[] = [
61
+ [
62
+ `<div data-header><p><strong>${v("tenantName")}</strong></p></div>`,
63
+ "<div data-content></div>",
64
+ "<div data-signature><p>Mit freundlichen Grüßen</p></div>",
65
+ `<div data-footer><p>${v("tenantName")}</p></div>`,
66
+ ].join(""),
67
+ [
68
+ `<div data-header><p><strong>${v("tenantName")}</strong></p><p>Ihre Hausverwaltung in Kiel</p></div>`,
69
+ "<div data-content></div>",
70
+ `<div data-signature><p>Mit freundlichen Grüßen</p><p>${v("signature")}</p><p>${v("tenantName")}</p></div>`,
71
+ `<div data-footer><p>${v("imprint")}</p><p><a href="https://nordlicht-immobilien.de/datenschutz">Datenschutz</a> · <a href="{{unsubscribeUrl}}">Abmelden</a></p></div>`,
72
+ ].join(""),
73
+ ];
74
+
75
+ const LINES_TABLE = `<table><tbody><tr><th><p>Position</p></th><th><p>Betrag</p></th></tr><tr data-each="lines" data-repeat-header=""><td><p>${v("description")}</p></td><td><p>${v("amount")}</p></td></tr></tbody></table>`;
76
+
77
+ // The registry of the billing notifications declares the variables, so these
78
+ // templates carry no variableSchema of their own.
79
+ function invoiceIssuedBody(args: {
80
+ readonly intro: string;
81
+ readonly withDueDate: boolean;
82
+ }): string {
83
+ const due = args.withDueDate ? ` Bitte überweisen Sie den Betrag bis zum ${v("dueDate")}.` : "";
84
+ return [
85
+ "<h2>Ihre Rechnung ist da</h2>",
86
+ `<p>Guten Tag ${v("recipientName")},</p>`,
87
+ `<p>${args.intro} <strong>${v("invoiceNumber")}</strong> über <strong>${v("invoiceTotal")}</strong>.${due}</p>`,
88
+ '<a data-button href="{{invoiceUrl}}">Rechnung öffnen</a>',
89
+ LINES_TABLE,
90
+ "<hr>",
91
+ "<p>Mit freundlichen Grüßen</p>",
92
+ `<p>${v("tenantName")}</p>`,
93
+ ].join("");
94
+ }
95
+
96
+ const INVOICE_ISSUED_SLUG = "billing:notify:invoice-issued";
97
+ const INVOICE_CORRECTED_SLUG = "billing:notify:invoice-corrected";
98
+
99
+ const invoiceIssuedMeta = (subject: string) => ({
100
+ subject,
101
+ previewText: "Rechnung {{invoiceNumber}} über {{invoiceTotal}}, online abrufbar",
102
+ });
103
+
104
+ // The platform default has a due date; the tenant drafts below drop it, which
105
+ // is what blocks publishing in the walkthrough.
106
+ export const SYSTEM_INVOICE_ISSUED: SeedTemplate = {
107
+ slug: INVOICE_ISSUED_SLUG,
108
+ kind: "mail",
109
+ locale: "de",
110
+ title: "Rechnung versendet",
111
+ content: invoiceIssuedBody({ intro: "anbei senden wir Ihnen die Rechnung", withDueDate: true }),
112
+ meta: invoiceIssuedMeta("Rechnung {{invoiceNumber}} von {{tenantName}}"),
113
+ };
114
+
115
+ // Saved in order: each entry becomes the next version of the same draft.
116
+ export const INVOICE_ISSUED_DRAFT_VERSIONS: readonly SeedTemplate[] = [
117
+ {
118
+ slug: INVOICE_ISSUED_SLUG,
119
+ kind: "mail",
120
+ locale: "de",
121
+ title: "Rechnung versendet",
122
+ content: invoiceIssuedBody({
123
+ intro: "anbei senden wir Ihnen die Rechnung",
124
+ withDueDate: false,
125
+ }),
126
+ meta: invoiceIssuedMeta("Ihre Rechnung {{invoiceNumber}}"),
127
+ },
128
+ {
129
+ slug: INVOICE_ISSUED_SLUG,
130
+ kind: "mail",
131
+ locale: "de",
132
+ title: "Rechnung versendet",
133
+ content: invoiceIssuedBody({ intro: "anbei erhalten Sie die Rechnung", withDueDate: false }),
134
+ meta: invoiceIssuedMeta("Ihre Rechnung {{invoiceNumber}} von {{tenantName}}"),
135
+ },
136
+ ];
137
+
138
+ // Separate draft for the screenshot spec, so the mail-editor e2e can change
139
+ // "Rechnung versendet" without touching what the screenshots show.
140
+ export const INVOICE_CORRECTED_DRAFT: SeedTemplate = {
141
+ slug: INVOICE_CORRECTED_SLUG,
142
+ kind: "mail",
143
+ locale: "de",
144
+ title: "Korrigierte Rechnung",
145
+ content: invoiceIssuedBody({
146
+ intro: "anbei erhalten Sie die korrigierte Rechnung",
147
+ withDueDate: false,
148
+ }),
149
+ meta: invoiceIssuedMeta("Ihre Rechnung {{invoiceNumber}} von {{tenantName}}"),
150
+ };
151
+
152
+ export const PAYMENT_REMINDER_TEMPLATES: readonly SeedTemplate[] = [
153
+ {
154
+ slug: "billing:notify:payment-reminder",
155
+ kind: "mail",
156
+ locale: "de",
157
+ title: "Zahlungserinnerung",
158
+ content: [
159
+ `<p>Guten Tag ${v("customerName")},</p>`,
160
+ `<p>zu unserer Rechnung <strong>${v("invoiceNumber")}</strong> über <strong>${v("amount")}</strong> konnten wir bis heute keinen Zahlungseingang feststellen. Fällig war der Betrag am ${v("dueDate")}.</p>`,
161
+ `<p>Bitte überweisen Sie den offenen Betrag in den nächsten Tagen. Die Rechnung finden Sie hier: <a href="{{invoiceUrl}}">Rechnung öffnen</a></p>`,
162
+ "<p>Sollten Sie bereits gezahlt haben, betrachten Sie diese Nachricht bitte als gegenstandslos.</p>",
163
+ ].join(""),
164
+ meta: { subject: "Zahlungserinnerung zu Rechnung {{invoiceNumber}}" },
165
+ variableSchema: INVOICE_VARIABLE_SCHEMA,
166
+ },
167
+ {
168
+ slug: "billing:notify:payment-reminder",
169
+ kind: "mail",
170
+ locale: "en",
171
+ title: "Payment reminder",
172
+ content: [
173
+ `<p>Hello ${v("customerName")},</p>`,
174
+ `<p>we have not received a payment for invoice <strong>${v("invoiceNumber")}</strong> of <strong>${v("amount")}</strong>, which was due on ${v("dueDate")}.</p>`,
175
+ `<p>Please transfer the open amount in the next few days. You can find the invoice here: <a href="{{invoiceUrl}}">Open invoice</a></p>`,
176
+ "<p>If you have already paid, please disregard this message.</p>",
177
+ ].join(""),
178
+ meta: { subject: "Payment reminder for invoice {{invoiceNumber}}" },
179
+ variableSchema: INVOICE_VARIABLE_SCHEMA,
180
+ },
181
+ ];
182
+
183
+ function authMail(
184
+ notification: string,
185
+ locale: "de" | "en",
186
+ title: string,
187
+ subject: string,
188
+ paragraphs: readonly string[],
189
+ extraSchema: Record<string, unknown> = {},
190
+ ): SeedTemplate {
191
+ return {
192
+ slug: `auth-email-password:notify:${notification}`,
193
+ kind: "mail",
194
+ locale,
195
+ title,
196
+ content: paragraphs.join(""),
197
+ meta: { subject },
198
+ variableSchema: { ...AUTH_VARIABLE_SCHEMA, ...extraSchema },
199
+ };
200
+ }
201
+
202
+ export const SYSTEM_AUTH_MAILS: readonly SeedTemplate[] = [
203
+ authMail(
204
+ "password-reset",
205
+ "de",
206
+ "Passwort zurücksetzen",
207
+ "Passwort für {{appName}} zurücksetzen",
208
+ [
209
+ "<p>Hallo,</p>",
210
+ `<p>für Ihr Konto bei ${v("appName")} wurde ein neues Passwort angefordert. Über den folgenden Link können Sie es festlegen: <a href="{{actionUrl}}">Passwort zurücksetzen</a></p>`,
211
+ `<p>Der Link ist ${v("validFor")} gültig, bis ${v("validUntil")}. Haben Sie das nicht angefordert, können Sie diese Nachricht ignorieren.</p>`,
212
+ ],
213
+ ),
214
+ authMail("password-reset", "en", "Reset password", "Reset your {{appName}} password", [
215
+ "<p>Hello,</p>",
216
+ `<p>a new password was requested for your ${v("appName")} account. You can set it with this link: <a href="{{actionUrl}}">Reset password</a></p>`,
217
+ `<p>The link is valid for ${v("validFor")}, until ${v("validUntil")}. If you did not ask for this, you can ignore this message.</p>`,
218
+ ]),
219
+ authMail(
220
+ "invite",
221
+ "de",
222
+ "Einladung ins Team",
223
+ "Einladung zu {{appName}}",
224
+ [
225
+ "<p>Hallo,</p>",
226
+ `<p>Sie wurden zu ${v("appName")} eingeladen, mit der Rolle <strong>${v("role")}</strong>. Mit dem folgenden Link nehmen Sie die Einladung an: <a href="{{actionUrl}}">Einladung annehmen</a></p>`,
227
+ `<p>Die Einladung ist ${v("validFor")} gültig, bis ${v("validUntil")}.</p>`,
228
+ ],
229
+ { role: { type: "text", required: true } },
230
+ ),
231
+ authMail(
232
+ "invite",
233
+ "en",
234
+ "Team invitation",
235
+ "You are invited to {{appName}}",
236
+ [
237
+ "<p>Hello,</p>",
238
+ `<p>You have been invited to ${v("appName")} with the role <strong>${v("role")}</strong>. Accept the invitation with this link: <a href="{{actionUrl}}">Accept invitation</a></p>`,
239
+ `<p>The invitation is valid for ${v("validFor")}, until ${v("validUntil")}.</p>`,
240
+ ],
241
+ { role: { type: "text", required: true } },
242
+ ),
243
+ authMail(
244
+ "signup-activation",
245
+ "de",
246
+ "Registrierung bestätigen",
247
+ "Registrierung bei {{appName}} bestätigen",
248
+ [
249
+ "<p>Willkommen,</p>",
250
+ `<p>vielen Dank für Ihre Registrierung bei ${v("appName")}. Bitte bestätigen Sie Ihre E-Mail-Adresse: <a href="{{actionUrl}}">Registrierung bestätigen</a></p>`,
251
+ `<p>Der Link ist ${v("validFor")} gültig, bis ${v("validUntil")}.</p>`,
252
+ ],
253
+ ),
254
+ authMail(
255
+ "email-verification",
256
+ "de",
257
+ "E-Mail-Adresse bestätigen",
258
+ "E-Mail-Adresse für {{appName}} bestätigen",
259
+ [
260
+ "<p>Hallo,</p>",
261
+ `<p>bitte bestätigen Sie Ihre E-Mail-Adresse für ${v("appName")}: <a href="{{actionUrl}}">E-Mail-Adresse bestätigen</a></p>`,
262
+ `<p>Der Link ist ${v("validFor")} gültig, bis ${v("validUntil")}.</p>`,
263
+ ],
264
+ ),
265
+ authMail("email-verification", "en", "Confirm email address", "Confirm your {{appName}} email", [
266
+ "<p>Hello,</p>",
267
+ `<p>please confirm your email address for ${v("appName")}: <a href="{{actionUrl}}">Confirm email address</a></p>`,
268
+ `<p>The link is valid for ${v("validFor")}, until ${v("validUntil")}.</p>`,
269
+ ]),
270
+ authMail("account-unlock", "de", "Konto entsperren", "Ihr Konto bei {{appName}} entsperren", [
271
+ "<p>Hallo,</p>",
272
+ `<p>Ihr Konto bei ${v("appName")} wurde nach mehreren fehlgeschlagenen Anmeldungen gesperrt. Mit dem folgenden Link entsperren Sie es: <a href="{{actionUrl}}">Konto entsperren</a></p>`,
273
+ `<p>Der Link ist ${v("validFor")} gültig, bis ${v("validUntil")}.</p>`,
274
+ ]),
275
+ authMail("account-unlock", "en", "Unlock account", "Unlock your {{appName}} account", [
276
+ "<p>Hello,</p>",
277
+ `<p>your ${v("appName")} account was locked after several failed sign-ins. Unlock it with this link: <a href="{{actionUrl}}">Unlock account</a></p>`,
278
+ `<p>The link is valid for ${v("validFor")}, until ${v("validUntil")}.</p>`,
279
+ ]),
280
+ ];
281
+
282
+ const INVOICE_DOCUMENT_ROWS = `<table><tbody><tr><th><p>Leistung</p></th><th><p>Betrag</p></th></tr><tr data-each="lines" data-repeat-header=""><td><p>${v("description")}</p></td><td><p>${v("amount")}</p></td></tr></tbody></table>`;
283
+
284
+ export const SYSTEM_INVOICE_DOCUMENTS: readonly SeedTemplate[] = [
285
+ {
286
+ slug: "billing:invoice",
287
+ kind: "document-pdf",
288
+ locale: "de",
289
+ title: "Rechnung",
290
+ content: [
291
+ `<h1>Rechnung ${v("invoiceNumber")}</h1>`,
292
+ `<p>Rechnungsdatum: ${v("invoiceDate")}</p>`,
293
+ `<p>Guten Tag ${v("customerName")},</p>`,
294
+ "<p>für unsere Leistungen stellen wir Ihnen folgenden Betrag in Rechnung.</p>",
295
+ INVOICE_DOCUMENT_ROWS,
296
+ `<p><strong>Gesamtbetrag: ${v("total")}</strong></p>`,
297
+ "<p>Bitte überweisen Sie den Betrag innerhalb von 14 Tagen auf unser Konto.</p>",
298
+ ].join(""),
299
+ meta: { layoutSlug: "default", pageFormat: "A4", fileName: "Rechnung.pdf" },
300
+ variableSchema: DOCUMENT_LINES_SCHEMA,
301
+ },
302
+ {
303
+ slug: "billing:invoice",
304
+ kind: "document-pdf",
305
+ locale: "en",
306
+ title: "Invoice",
307
+ content: [
308
+ `<h1>Invoice ${v("invoiceNumber")}</h1>`,
309
+ `<p>Invoice date: ${v("invoiceDate")}</p>`,
310
+ `<p>Dear ${v("customerName")},</p>`,
311
+ "<p>we charge you the following amount for our services.</p>",
312
+ INVOICE_DOCUMENT_ROWS.replace("Leistung", "Service").replace("Betrag", "Amount"),
313
+ `<p><strong>Total: ${v("total")}</strong></p>`,
314
+ "<p>Please transfer the amount to our account within 14 days.</p>",
315
+ ].join(""),
316
+ meta: { layoutSlug: "default", pageFormat: "A4", fileName: "Invoice.pdf" },
317
+ variableSchema: DOCUMENT_LINES_SCHEMA,
318
+ },
319
+ ];
320
+
321
+ export const TENANT_UTILITY_STATEMENT: SeedTemplate = {
322
+ slug: "rental:utility-statement",
323
+ kind: "document-pdf",
324
+ locale: "de",
325
+ title: "Nebenkostenabrechnung",
326
+ content: [
327
+ `<h1>Nebenkostenabrechnung ${v("invoiceNumber")}</h1>`,
328
+ `<p>Abrechnungsdatum: ${v("invoiceDate")}</p>`,
329
+ `<p>Guten Tag ${v("customerName")},</p>`,
330
+ "<p>nachfolgend erhalten Sie die Abrechnung der Betriebskosten für den Abrechnungszeitraum.</p>",
331
+ INVOICE_DOCUMENT_ROWS,
332
+ `<p><strong>Ergebnis: ${v("total")}</strong></p>`,
333
+ "<p>Ein Guthaben überweisen wir Ihnen innerhalb von 30 Tagen, eine Nachzahlung ist zum Monatsende fällig.</p>",
334
+ ].join(""),
335
+ meta: { layoutSlug: "default", pageFormat: "A4", fileName: "Nebenkostenabrechnung.pdf" },
336
+ variableSchema: DOCUMENT_LINES_SCHEMA,
337
+ };
338
+
339
+ export const SYSTEM_TENANCY_CERTIFICATE: SeedTemplate = {
340
+ slug: "rental:tenancy-certificate",
341
+ kind: "document-pdf",
342
+ locale: "de",
343
+ title: "Mietbescheinigung",
344
+ content: [
345
+ "<h1>Mietbescheinigung</h1>",
346
+ `<p>Hiermit bestätigen wir, dass ${v("customerName")} bei uns Mieter ist und die Miete ordnungsgemäß zahlt.</p>`,
347
+ `<p>Ausgestellt am ${v("invoiceDate")}.</p>`,
348
+ ].join(""),
349
+ meta: { layoutSlug: "default", pageFormat: "A4", fileName: "Mietbescheinigung.pdf" },
350
+ variableSchema: {
351
+ customerName: { type: "text", required: true },
352
+ invoiceDate: { type: "date", required: true },
353
+ },
354
+ };