@cosmicdrift/kumiko-samples 0.362.0 → 0.364.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/packages/bundled-features/package.json +23 -6
- package/packages/bundled-features/src/admin-shell/changes.json +6 -0
- package/packages/bundled-features/src/admin-shell/feature.ts +8 -1
- package/packages/bundled-features/src/agent-tools/agent-manifest.ts +3 -4
- package/packages/bundled-features/src/agent-tools/filter-ops.ts +1 -3
- package/packages/bundled-features/src/agent-tools/tool-catalog.ts +1 -3
- package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +2 -1
- package/packages/bundled-features/src/audit/changes.json +6 -0
- package/packages/bundled-features/src/audit/handlers/list.query.ts +10 -5
- package/packages/bundled-features/src/auth-email-password/bootstrap.ts +29 -8
- package/packages/bundled-features/src/auth-email-password/changes.json +51 -0
- package/packages/bundled-features/src/auth-email-password/email-rate-limits.ts +16 -0
- package/packages/bundled-features/src/auth-email-password/email-templates.ts +12 -138
- package/packages/bundled-features/src/auth-email-password/feature.ts +30 -9
- package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +6 -2
- package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +4 -5
- package/packages/bundled-features/src/auth-email-password/handlers/logout.write.ts +7 -2
- package/packages/bundled-features/src/auth-email-password/handlers/request-account-unlock.write.ts +2 -5
- package/packages/bundled-features/src/auth-email-password/handlers/request-email-verification.write.ts +2 -5
- package/packages/bundled-features/src/auth-email-password/handlers/request-password-reset.write.ts +2 -5
- package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +3 -4
- package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +2 -1
- package/packages/bundled-features/src/auth-email-password/handlers/token-request-handler.ts +5 -13
- package/packages/bundled-features/src/auth-email-password/index.ts +2 -17
- package/packages/bundled-features/src/auth-email-password/magic-link-mail.ts +30 -22
- package/packages/bundled-features/src/auth-email-password/mail-notifications.ts +158 -0
- package/packages/bundled-features/src/auth-email-password/signup-activation.ts +2 -3
- package/packages/bundled-features/src/auth-email-password/web/auth-gate.tsx +24 -5
- package/packages/bundled-features/src/auth-foundation/types.ts +8 -18
- package/packages/bundled-features/src/auth-mfa/feature.ts +8 -10
- package/packages/bundled-features/src/auth-mfa/hmac-token-codec.ts +4 -4
- package/packages/bundled-features/src/auth-mfa/mfa-challenge-token.ts +3 -3
- package/packages/bundled-features/src/auth-mfa/mfa-preauth-setup-token.ts +3 -3
- package/packages/bundled-features/src/auth-mfa/mfa-setup-token.ts +8 -8
- package/packages/bundled-features/src/billing-foundation/changes.json +43 -0
- package/packages/bundled-features/src/billing-foundation/constants.ts +5 -4
- package/packages/bundled-features/src/billing-foundation/consumer-protection/confirmation-mail.ts +90 -44
- package/packages/bundled-features/src/billing-foundation/consumer-protection/consent-gate.ts +22 -1
- package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +3 -3
- package/packages/bundled-features/src/billing-foundation/consumer-protection/mail-notifications.ts +118 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/register-consent.ts +2 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/register-termination.ts +11 -1
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-mail.ts +39 -33
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-notify.ts +2 -2
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-pages.ts +1 -4
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-receipt-limit.ts +41 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-record.ts +10 -1
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +36 -20
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-texts.ts +9 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/withdrawal-period.ts +35 -0
- package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +2 -2
- package/packages/bundled-features/src/billing-foundation/handlers/create-checkout-session.write.ts +11 -3
- package/packages/bundled-features/src/billing-foundation/handlers/create-portal-session.write.ts +4 -9
- package/packages/bundled-features/src/billing-foundation/handlers/list-subscriptions.query.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +12 -6
- package/packages/bundled-features/src/billing-foundation/handlers/process-payment-event.write.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/i18n.ts +3 -0
- package/packages/bundled-features/src/billing-foundation/subscription-tier-sync.ts +20 -11
- package/packages/bundled-features/src/billing-foundation/types.ts +7 -2
- package/packages/bundled-features/src/cap-counter/calendar-cap-usage-reservation.ts +2 -0
- package/packages/bundled-features/src/cap-counter/changes.json +6 -0
- package/packages/bundled-features/src/cap-counter/enforce-cap.ts +75 -5
- package/packages/bundled-features/src/cap-counter/index.ts +1 -0
- package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +3 -0
- package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +2 -1
- package/packages/bundled-features/src/cap-overview/web/cap-usage-cell.tsx +6 -4
- package/packages/bundled-features/src/channel-email/changes.json +19 -0
- package/packages/bundled-features/src/channel-email/email-channel.ts +135 -29
- package/packages/bundled-features/src/channel-email/feature.ts +6 -3
- package/packages/bundled-features/src/channel-email/index.ts +7 -1
- package/packages/bundled-features/src/channel-email/pii-guard.ts +13 -0
- package/packages/bundled-features/src/channel-email/smtp-transport.ts +15 -1
- package/packages/bundled-features/src/channel-email/types.ts +23 -0
- package/packages/bundled-features/src/channel-in-app/handlers/mark-read.write.ts +2 -2
- package/packages/bundled-features/src/config/changes.json +6 -0
- package/packages/bundled-features/src/config/handlers/set.write.ts +3 -7
- package/packages/bundled-features/src/config/resolver.ts +15 -12
- package/packages/bundled-features/src/config/write-helpers.ts +23 -0
- package/packages/bundled-features/src/crypto-shredding/changes.json +6 -0
- package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +48 -27
- package/packages/bundled-features/src/custom-fields/changes.json +6 -0
- package/packages/bundled-features/src/custom-fields/db/queries/user-data-rights.ts +2 -2
- package/packages/bundled-features/src/custom-fields/handlers/update-tenant-field.write.ts +0 -1
- package/packages/bundled-features/src/custom-fields/lib/value-schema.ts +10 -11
- package/packages/bundled-features/src/custom-fields/wire-user-data-rights.ts +7 -6
- package/packages/bundled-features/src/data-retention/changes.json +6 -0
- package/packages/bundled-features/src/data-retention/index.ts +1 -0
- package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +8 -6
- package/packages/bundled-features/src/delivery/attachment-ref.ts +105 -0
- package/packages/bundled-features/src/delivery/changes.json +66 -0
- package/packages/bundled-features/src/delivery/channel-context.ts +152 -4
- package/packages/bundled-features/src/delivery/constants.ts +2 -0
- package/packages/bundled-features/src/delivery/delivery-service.ts +104 -26
- package/packages/bundled-features/src/delivery/feature.ts +1 -1
- package/packages/bundled-features/src/delivery/index.ts +19 -2
- package/packages/bundled-features/src/delivery/jobs.ts +97 -17
- package/packages/bundled-features/src/delivery/notify-factory.ts +14 -9
- package/packages/bundled-features/src/delivery/testing.ts +9 -1
- package/packages/bundled-features/src/delivery/types.ts +34 -18
- package/packages/bundled-features/src/delivery/unsubscribe.ts +5 -2
- package/packages/bundled-features/src/derivatives-sharp/render.ts +1 -22
- package/packages/bundled-features/src/document-ingest-foundation/pages.ts +6 -3
- package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +4 -4
- package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +1 -1
- package/packages/bundled-features/src/file-foundation/changes.json +6 -0
- package/packages/bundled-features/src/file-foundation/index.ts +7 -0
- package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +89 -0
- package/packages/bundled-features/src/files-tenant-data/changes.json +6 -0
- package/packages/bundled-features/src/files-tenant-data/hooks.ts +4 -0
- package/packages/bundled-features/src/folders/web/folder-manager.tsx +5 -2
- package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +11 -11
- package/packages/bundled-features/src/form-draft/db/queries/draft-count.ts +2 -2
- package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +2 -2
- package/packages/bundled-features/src/form-draft/release-file-refs.ts +3 -2
- package/packages/bundled-features/src/inbound-mail-foundation/changes.json +6 -0
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +6 -6
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-accounts.query.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-messages.query.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/scope-visibility.ts +2 -2
- package/packages/bundled-features/src/inbound-mail-foundation/oauth-access-token.ts +13 -8
- package/packages/bundled-features/src/inbound-mail-foundation/oauth-state.ts +7 -7
- package/packages/bundled-features/src/inbound-mail-foundation/retention-sweep.ts +2 -6
- package/packages/bundled-features/src/inbound-mail-foundation/tenant-destroy-hook.ts +5 -13
- package/packages/bundled-features/src/inbound-mail-foundation/types.ts +4 -6
- package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +42 -25
- package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +4 -3
- package/packages/bundled-features/src/jobs/changes.json +19 -0
- package/packages/bundled-features/src/jobs/db/queries/stale-run-sweep.ts +12 -4
- package/packages/bundled-features/src/jobs/feature.ts +7 -4
- package/packages/bundled-features/src/jobs/handlers/catalog.query.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/list.query.ts +3 -1
- package/packages/bundled-features/src/jobs/handlers/stale-run-sweep.job.ts +5 -2
- package/packages/bundled-features/src/jobs/job-run-logger.ts +52 -17
- package/packages/bundled-features/src/jobs/tenant-job-run-table.ts +7 -2
- package/packages/bundled-features/src/ledger/changes.json +7 -0
- package/packages/bundled-features/src/ledger/entity.ts +3 -1
- package/packages/bundled-features/src/ledger/recurring.ts +1 -3
- package/packages/bundled-features/src/managed-pages/branding.ts +33 -9
- package/packages/bundled-features/src/managed-pages/changes.json +6 -0
- package/packages/bundled-features/src/managed-pages/feature.ts +1 -0
- package/packages/bundled-features/src/managed-pages/i18n.ts +1 -0
- package/packages/bundled-features/src/managed-pages/screens/branding-screen.ts +8 -0
- package/packages/bundled-features/src/page-render/branding.ts +3 -0
- package/packages/bundled-features/src/page-render/markdown.ts +1 -1
- package/packages/bundled-features/src/personal-access-tokens/feature.ts +2 -4
- package/packages/bundled-features/src/personal-access-tokens/handlers/list.query.ts +2 -1
- package/packages/bundled-features/src/personal-access-tokens/index.ts +1 -1
- package/packages/bundled-features/src/personal-access-tokens/revoke-for-user.ts +2 -1
- package/packages/bundled-features/src/renderer-foundation/README.md +11 -10
- package/packages/bundled-features/src/renderer-foundation/api.ts +14 -14
- package/packages/bundled-features/src/renderer-foundation/changes.json +39 -0
- package/packages/bundled-features/src/renderer-foundation/constants.ts +6 -8
- package/packages/bundled-features/src/renderer-foundation/feature.ts +7 -7
- package/packages/bundled-features/src/renderer-foundation/index.ts +13 -2
- package/packages/bundled-features/src/renderer-foundation/types.ts +134 -35
- package/packages/bundled-features/src/renderer-pdf/changes.json +12 -0
- package/packages/bundled-features/src/renderer-pdf/feature.ts +7 -1
- package/packages/bundled-features/src/renderer-pdf/render-table-pdf.ts +162 -82
- package/packages/bundled-features/src/secrets/changes.json +6 -0
- package/packages/bundled-features/src/secrets/feature.ts +4 -3
- package/packages/bundled-features/src/secrets/secrets-context.ts +23 -3
- package/packages/bundled-features/src/sessions/db/queries/cleanup.ts +2 -2
- package/packages/bundled-features/src/sessions/feature.ts +2 -4
- package/packages/bundled-features/src/sessions/handlers/list.query.ts +2 -1
- package/packages/bundled-features/src/shared/attachment-file-name.ts +39 -0
- package/packages/bundled-features/src/shared/changes.json +6 -0
- package/packages/bundled-features/src/shared/chunked-entity-migration.ts +4 -1
- package/packages/bundled-features/src/shared/index.ts +6 -0
- package/packages/bundled-features/src/shared/is-tenant-db.ts +1 -1
- package/packages/bundled-features/src/shared/mail-template-body.ts +42 -0
- package/packages/bundled-features/src/shared/sharp-input-limits.ts +26 -0
- package/packages/bundled-features/src/shared/signup-handover.ts +4 -4
- package/packages/bundled-features/src/subscription-stripe/changes.json +6 -0
- package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +19 -11
- package/packages/bundled-features/src/subscription-stripe/verify-webhook.ts +3 -1
- package/packages/bundled-features/src/tags/handlers/assign-tag.write.ts +5 -1
- package/packages/bundled-features/src/tags/web/tag-chip.tsx +2 -1
- package/packages/bundled-features/src/template-resolver/README.md +66 -8
- package/packages/bundled-features/src/template-resolver/api.ts +85 -9
- package/packages/bundled-features/src/template-resolver/changes.json +186 -0
- package/packages/bundled-features/src/template-resolver/compile-document-body.ts +278 -0
- package/packages/bundled-features/src/template-resolver/constants.ts +49 -11
- package/packages/bundled-features/src/template-resolver/document-sanitizer.ts +335 -0
- package/packages/bundled-features/src/template-resolver/document-schema.ts +345 -0
- package/packages/bundled-features/src/template-resolver/feature.ts +59 -6
- package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +188 -0
- package/packages/bundled-features/src/template-resolver/handlers/collection-set.write.ts +30 -2
- package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +160 -0
- package/packages/bundled-features/src/template-resolver/handlers/diff-to-system.query.ts +33 -0
- package/packages/bundled-features/src/template-resolver/handlers/discard-draft.write.ts +52 -0
- package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +138 -0
- package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +9 -6
- package/packages/bundled-features/src/template-resolver/handlers/import-bundle-system.write.ts +42 -0
- package/packages/bundled-features/src/template-resolver/handlers/import-bundle.write.ts +22 -0
- package/packages/bundled-features/src/template-resolver/handlers/layout-source.query.ts +151 -0
- package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +19 -18
- package/packages/bundled-features/src/template-resolver/handlers/override-diff.ts +49 -0
- package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +323 -0
- package/packages/bundled-features/src/template-resolver/handlers/preview.query.ts +25 -0
- package/packages/bundled-features/src/template-resolver/handlers/reset-to-system.write.ts +58 -0
- package/packages/bundled-features/src/template-resolver/handlers/resource-link-pdf.write.ts +34 -0
- package/packages/bundled-features/src/template-resolver/handlers/resource-remove.write.ts +50 -0
- package/packages/bundled-features/src/template-resolver/handlers/resource-shared.ts +24 -0
- package/packages/bundled-features/src/template-resolver/handlers/resource-upload.write.ts +135 -0
- package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +135 -0
- package/packages/bundled-features/src/template-resolver/handlers/set.write.ts +32 -3
- package/packages/bundled-features/src/template-resolver/handlers/shared.ts +7 -2
- package/packages/bundled-features/src/template-resolver/handlers/template-gates.ts +196 -0
- package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +233 -0
- package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +137 -0
- package/packages/bundled-features/src/template-resolver/handlers/toggle-status.write.ts +91 -17
- package/packages/bundled-features/src/template-resolver/handlers/upsert-system.write.ts +19 -71
- package/packages/bundled-features/src/template-resolver/handlers/upsert-tenant.write.ts +16 -77
- package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +31 -0
- package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +116 -0
- package/packages/bundled-features/src/template-resolver/index.ts +111 -0
- package/packages/bundled-features/src/template-resolver/layout-appearance.ts +40 -0
- package/packages/bundled-features/src/template-resolver/layout-regions.ts +206 -0
- package/packages/bundled-features/src/template-resolver/linked-resources.ts +102 -0
- package/packages/bundled-features/src/template-resolver/pdf-constants.ts +12 -0
- package/packages/bundled-features/src/template-resolver/preview-display-html.ts +36 -0
- package/packages/bundled-features/src/template-resolver/print-document.ts +58 -0
- package/packages/bundled-features/src/template-resolver/qualified-names.ts +34 -0
- package/packages/bundled-features/src/template-resolver/record-mapping.ts +26 -0
- package/packages/bundled-features/src/template-resolver/resource-image.ts +47 -0
- package/packages/bundled-features/src/template-resolver/seeding.ts +171 -20
- package/packages/bundled-features/src/template-resolver/store-template-resource.ts +416 -0
- package/packages/bundled-features/src/template-resolver/table.ts +27 -1
- package/packages/bundled-features/src/template-resolver/template-bundle.ts +79 -0
- package/packages/bundled-features/src/template-resolver/template-diff.ts +78 -0
- package/packages/bundled-features/src/template-resolver/template-draft.ts +106 -0
- package/packages/bundled-features/src/template-resolver/template-meta.ts +192 -0
- package/packages/bundled-features/src/template-resolver/template-preview.ts +676 -0
- package/packages/bundled-features/src/template-resolver/template-resources.ts +114 -0
- package/packages/bundled-features/src/template-resolver/template-usage.ts +68 -0
- package/packages/bundled-features/src/template-resolver/template-validation.ts +230 -0
- package/packages/bundled-features/src/template-resolver/testing.ts +5 -5
- package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +20 -13
- package/packages/bundled-features/src/template-resolver/web/document-editor-extensions.ts +215 -0
- package/packages/bundled-features/src/template-resolver/web/document-editor.tsx +37 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +1065 -0
- package/packages/bundled-features/src/template-resolver/web/document-toolbar-blocks.ts +72 -0
- package/packages/bundled-features/src/template-resolver/web/editor-handle.ts +26 -0
- package/packages/bundled-features/src/template-resolver/web/i18n.ts +121 -0
- package/packages/bundled-features/src/template-resolver/web/index.ts +26 -0
- package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor-lazy.tsx +36 -0
- package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +176 -0
- package/packages/bundled-features/src/template-resolver/web/placeholder-text.ts +37 -0
- package/packages/bundled-features/src/template-resolver/web/use-stable-by-key.ts +14 -0
- package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +3 -2
- package/packages/bundled-features/src/tenant/seeding.ts +41 -7
- package/packages/bundled-features/src/tenant-lifecycle/boot-checks.ts +1 -1
- package/packages/bundled-features/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +2 -1
- package/packages/bundled-features/src/tier-engine/changes.json +6 -0
- package/packages/bundled-features/src/tier-engine/feature.ts +11 -3
- package/packages/bundled-features/src/user/changes.json +6 -0
- package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +4 -4
- package/packages/bundled-features/src/user/handlers/detail.query.ts +3 -5
- package/packages/bundled-features/src/user/resolve-display-names.ts +8 -15
- package/packages/bundled-features/src/user/roles-input-schema.ts +2 -2
- package/packages/bundled-features/src/user/seeding.ts +19 -5
- package/packages/bundled-features/src/user-data-rights/changes.json +13 -0
- package/packages/bundled-features/src/user-data-rights/db/queries/forget-cleanup.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/email-templates.ts +5 -149
- package/packages/bundled-features/src/user-data-rights/feature.ts +72 -35
- package/packages/bundled-features/src/user-data-rights/handlers/cancel-deletion.write.ts +2 -1
- package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +5 -11
- package/packages/bundled-features/src/user-data-rights/lib/default-mailers.ts +134 -53
- package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/mail-notifications.ts +157 -0
- package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +2 -1
- package/packages/bundled-features/src/user-profile/changes.json +1 -1
- package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +2 -1
- package/packages/bundled-features/src/waitlist/changes.json +7 -0
- package/packages/bundled-features/src/waitlist/feature.ts +17 -0
- package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +4 -5
- package/packages/bundled-features/src/waitlist/mail.ts +69 -18
- package/packages/bundled-features/src/waitlist/options.ts +1 -1
- package/packages/bundled-features/src/workflow-runner/changes.json +6 -0
- package/packages/bundled-features/src/workflow-runner/event-trigger.ts +3 -3
- package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +7 -1
- package/samples/apps/ui-walkthrough/package.json +11 -0
- package/samples/apps/ui-walkthrough/playwright.config.ts +40 -7
- package/samples/apps/ui-walkthrough/src/app/auth-constants.ts +9 -0
- package/samples/apps/ui-walkthrough/src/app/client.tsx +6 -0
- package/samples/apps/ui-walkthrough/src/app/seed-templates.ts +239 -0
- package/samples/apps/ui-walkthrough/src/app/server.ts +5 -1
- package/samples/apps/ui-walkthrough/src/app/shell.tsx +12 -1
- package/samples/apps/ui-walkthrough/src/app/template-seed-data.ts +570 -0
- package/samples/apps/ui-walkthrough/src/features/billing/feature.ts +72 -0
- package/samples/apps/ui-walkthrough/src/features/billing/i18n.ts +18 -0
- package/samples/apps/ui-walkthrough/src/features/billing/index.ts +2 -0
- package/samples/apps/ui-walkthrough/src/features/billing/web/index.ts +7 -0
- package/samples/apps/ui-walkthrough/src/run-config.ts +41 -1
- package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-features.ts +0 -2
- package/samples/apps/use-all-bundled/feature-manifest.json +118 -21
- package/samples/apps/use-all-bundled/kumiko/migrations/0045_template-resource-meta.rebuild.json +4 -0
- package/samples/apps/use-all-bundled/kumiko/migrations/0046_pdf-rendered.rebuild.json +4 -0
- package/samples/apps/use-all-bundled/package.json +2 -0
- package/samples/apps/use-all-bundled/playwright.config.ts +38 -3
- package/samples/apps/use-all-bundled/schema/generate.ts +13 -3
- package/samples/apps/use-all-bundled/schema/schema.generated.ts +3 -0
- package/samples/apps/use-all-bundled/scripts/check-coverage.ts +3 -0
- package/samples/apps/use-all-bundled/src/app/auth-constants.ts +3 -0
- package/samples/apps/use-all-bundled/src/app/client.tsx +4 -0
- package/samples/apps/use-all-bundled/src/app/seed-documents.ts +128 -0
- package/samples/apps/use-all-bundled/src/app/seed.ts +4 -0
- package/samples/apps/use-all-bundled/src/run-config.ts +11 -11
- package/samples/recipes/delivery-notifications/README.md +26 -25
- package/samples/recipes/delivery-notifications/package.json +2 -1
- package/samples/recipes/delivery-notifications/src/feature.ts +64 -58
- package/samples/recipes/seed-migration/README.md +1 -1
- package/packages/bundled-features/src/renderer-simple/changes.json +0 -27
- package/packages/bundled-features/src/renderer-simple/feature.ts +0 -66
- package/packages/bundled-features/src/renderer-simple/index.ts +0 -8
- package/packages/bundled-features/src/renderer-simple/mail-blocks.ts +0 -138
- package/packages/bundled-features/src/renderer-simple/resolve-variables.ts +0 -57
- package/packages/bundled-features/src/renderer-simple/simple-renderer.ts +0 -304
|
@@ -0,0 +1,570 @@
|
|
|
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
|
+
// Resource key of the logo image the invoice mail embeds (uploaded by seed-templates.ts).
|
|
20
|
+
export const LOGO_RESOURCE_KEY = "logo-nordlicht.png";
|
|
21
|
+
|
|
22
|
+
const AUTH_VARIABLE_SCHEMA = {
|
|
23
|
+
appName: { type: "text", required: true },
|
|
24
|
+
actionUrl: { type: "link", required: true },
|
|
25
|
+
validFor: { type: "text", required: true },
|
|
26
|
+
validUntil: { type: "text", required: true },
|
|
27
|
+
} as const;
|
|
28
|
+
|
|
29
|
+
const INVOICE_VARIABLE_SCHEMA = {
|
|
30
|
+
customerName: { type: "text", required: true },
|
|
31
|
+
invoiceNumber: { type: "text", required: true },
|
|
32
|
+
amount: { type: "money", required: true },
|
|
33
|
+
dueDate: { type: "date", required: true },
|
|
34
|
+
invoiceUrl: { type: "link", required: true },
|
|
35
|
+
} as const;
|
|
36
|
+
|
|
37
|
+
const DOCUMENT_LINES_SCHEMA = {
|
|
38
|
+
tenantName: { type: "text" },
|
|
39
|
+
customerName: { type: "text", required: true },
|
|
40
|
+
invoiceNumber: { type: "text", required: true },
|
|
41
|
+
invoiceDate: { type: "date", required: true },
|
|
42
|
+
total: { type: "money", required: true },
|
|
43
|
+
lines: {
|
|
44
|
+
type: "list",
|
|
45
|
+
required: true,
|
|
46
|
+
item: { description: { type: "text" }, amount: { type: "money" } },
|
|
47
|
+
},
|
|
48
|
+
} as const;
|
|
49
|
+
|
|
50
|
+
// Same variable names the billing notifications declare; labels follow the template language.
|
|
51
|
+
type InvoiceDocumentLabels = {
|
|
52
|
+
readonly recipientAddress: string;
|
|
53
|
+
readonly invoiceNumber: string;
|
|
54
|
+
readonly invoiceDate: string;
|
|
55
|
+
readonly invoiceTotal: string;
|
|
56
|
+
readonly netTotal: string;
|
|
57
|
+
readonly vatAmount: string;
|
|
58
|
+
readonly dueDate: string;
|
|
59
|
+
readonly lines: string;
|
|
60
|
+
readonly position: string;
|
|
61
|
+
readonly description: string;
|
|
62
|
+
readonly period: string;
|
|
63
|
+
readonly net: string;
|
|
64
|
+
readonly paymentReference: string;
|
|
65
|
+
readonly iban: string;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
function invoiceDocumentSchema(labels: InvoiceDocumentLabels) {
|
|
69
|
+
return {
|
|
70
|
+
recipientAddress: {
|
|
71
|
+
type: "text",
|
|
72
|
+
required: true,
|
|
73
|
+
label: labels.recipientAddress,
|
|
74
|
+
example: "Familie Yilmaz, Lindenstraße 14, 24103 Kiel",
|
|
75
|
+
},
|
|
76
|
+
invoiceNumber: {
|
|
77
|
+
type: "text",
|
|
78
|
+
required: true,
|
|
79
|
+
label: labels.invoiceNumber,
|
|
80
|
+
example: "RE-2026-0142",
|
|
81
|
+
},
|
|
82
|
+
invoiceDate: { type: "date", required: true, label: labels.invoiceDate, example: "2026-10-01" },
|
|
83
|
+
dueDate: { type: "date", required: true, label: labels.dueDate, example: "2026-10-15" },
|
|
84
|
+
netTotal: {
|
|
85
|
+
type: "money",
|
|
86
|
+
label: labels.netTotal,
|
|
87
|
+
example: { amount: 107900, currency: "EUR" },
|
|
88
|
+
},
|
|
89
|
+
vatAmount: {
|
|
90
|
+
type: "money",
|
|
91
|
+
label: labels.vatAmount,
|
|
92
|
+
example: { amount: 20501, currency: "EUR" },
|
|
93
|
+
},
|
|
94
|
+
invoiceTotal: {
|
|
95
|
+
type: "money",
|
|
96
|
+
required: true,
|
|
97
|
+
label: labels.invoiceTotal,
|
|
98
|
+
example: { amount: 128401, currency: "EUR" },
|
|
99
|
+
},
|
|
100
|
+
lines: {
|
|
101
|
+
type: "list",
|
|
102
|
+
required: true,
|
|
103
|
+
label: labels.lines,
|
|
104
|
+
item: {
|
|
105
|
+
position: { type: "text", label: labels.position },
|
|
106
|
+
description: { type: "text", label: labels.description },
|
|
107
|
+
period: { type: "text", label: labels.period },
|
|
108
|
+
net: { type: "money", label: labels.net },
|
|
109
|
+
},
|
|
110
|
+
example: [
|
|
111
|
+
{
|
|
112
|
+
position: "1",
|
|
113
|
+
description: "Kaltmiete Lindenstraße 14, WE 3",
|
|
114
|
+
period: "Okt 2026",
|
|
115
|
+
net: { amount: 98000, currency: "EUR" },
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
position: "2",
|
|
119
|
+
description: "Stellplatz 7",
|
|
120
|
+
period: "Okt 2026",
|
|
121
|
+
net: { amount: 9900, currency: "EUR" },
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
paymentReference: {
|
|
126
|
+
type: "text",
|
|
127
|
+
label: labels.paymentReference,
|
|
128
|
+
example: "RE-2026-0142 / Yilmaz",
|
|
129
|
+
},
|
|
130
|
+
iban: { type: "text", label: labels.iban, example: "DE12 2105 0170 0012 3456 78" },
|
|
131
|
+
} as const;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const INVOICE_DOCUMENT_SCHEMA_DE = invoiceDocumentSchema({
|
|
135
|
+
recipientAddress: "Empfängeradresse",
|
|
136
|
+
invoiceNumber: "Rechnungsnummer",
|
|
137
|
+
invoiceDate: "Rechnungsdatum",
|
|
138
|
+
invoiceTotal: "Rechnungsbetrag",
|
|
139
|
+
netTotal: "Nettobetrag",
|
|
140
|
+
vatAmount: "Umsatzsteuer",
|
|
141
|
+
dueDate: "Fälligkeitsdatum",
|
|
142
|
+
lines: "Rechnungspositionen",
|
|
143
|
+
position: "Nr.",
|
|
144
|
+
description: "Bezeichnung",
|
|
145
|
+
period: "Zeitraum",
|
|
146
|
+
net: "Netto",
|
|
147
|
+
paymentReference: "Zahlungsreferenz",
|
|
148
|
+
iban: "IBAN",
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const INVOICE_DOCUMENT_SCHEMA_EN = invoiceDocumentSchema({
|
|
152
|
+
recipientAddress: "Recipient address",
|
|
153
|
+
invoiceNumber: "Invoice number",
|
|
154
|
+
invoiceDate: "Invoice date",
|
|
155
|
+
invoiceTotal: "Invoice total",
|
|
156
|
+
netTotal: "Net amount",
|
|
157
|
+
vatAmount: "VAT",
|
|
158
|
+
dueDate: "Due date",
|
|
159
|
+
lines: "Invoice lines",
|
|
160
|
+
position: "No.",
|
|
161
|
+
description: "Description",
|
|
162
|
+
period: "Period",
|
|
163
|
+
net: "Net",
|
|
164
|
+
paymentReference: "Payment reference",
|
|
165
|
+
iban: "IBAN",
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
export const SYSTEM_PDF_LAYOUT: SeedTemplate = {
|
|
169
|
+
slug: "default",
|
|
170
|
+
kind: "pdf-layout",
|
|
171
|
+
locale: "en",
|
|
172
|
+
title: "Briefpapier",
|
|
173
|
+
content: [
|
|
174
|
+
`<div data-header><table><tbody><tr><td><img data-resource="logo" alt="Nordlicht"></td><td><p data-align="right" data-size="small">Am Hafen 12 · 24103 Kiel</p></td></tr></tbody></table></div>`,
|
|
175
|
+
"<div data-content></div>",
|
|
176
|
+
"<div data-signature></div>",
|
|
177
|
+
`<div data-footer><p>Seite ${v("page")} von ${v("pages")}</p><p>${v("tenantName")} · HRB 18422 Kiel · IBAN DE12 2105 0170 0012 3456 78</p></div>`,
|
|
178
|
+
].join(""),
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export const TENANT_MAIL_LAYOUT_VERSIONS: readonly string[] = [
|
|
182
|
+
[
|
|
183
|
+
`<div data-header><p><strong>${v("tenantName")}</strong></p></div>`,
|
|
184
|
+
"<div data-content></div>",
|
|
185
|
+
"<div data-signature><p>Mit freundlichen Grüßen</p></div>",
|
|
186
|
+
`<div data-footer><p>${v("tenantName")}</p></div>`,
|
|
187
|
+
].join(""),
|
|
188
|
+
[
|
|
189
|
+
'<div data-header><img data-resource="logo" alt="Nordlicht"></div>',
|
|
190
|
+
"<div data-content></div>",
|
|
191
|
+
`<div data-signature><p>Mit freundlichen Grüßen</p><p>${v("signature")}</p><p>${v("tenantName")}</p></div>`,
|
|
192
|
+
`<div data-footer><p>${v("imprint")}</p><p><a href="https://nordlicht-immobilien.de/datenschutz">Datenschutz</a> · <a href="{{unsubscribeUrl}}">Abmeldelink</a></p></div>`,
|
|
193
|
+
].join(""),
|
|
194
|
+
];
|
|
195
|
+
|
|
196
|
+
const LINES_TABLE = `<table><tbody><tr><th><p>Position</p></th><th><p data-align="right">Betrag</p></th></tr><tr data-each="lines" data-repeat-header=""><td><p>${v("description")}</p></td><td><p data-align="right">${v("amount")}</p></td></tr><tr><td><p><strong>Gesamt</strong></p></td><td><p data-align="right">${v("invoiceTotal")}</p></td></tr></tbody></table>`;
|
|
197
|
+
|
|
198
|
+
// The registry of the billing notifications declares the variables, so these
|
|
199
|
+
// templates carry no variableSchema of their own.
|
|
200
|
+
function invoiceIssuedBody(args: {
|
|
201
|
+
readonly intro: string;
|
|
202
|
+
readonly withDueDate: boolean;
|
|
203
|
+
}): string {
|
|
204
|
+
const due = args.withDueDate ? ` Bitte überweisen Sie den Betrag bis zum ${v("dueDate")}.` : "";
|
|
205
|
+
return [
|
|
206
|
+
`<h2>Ihre Rechnung ${v("invoiceNumber")}</h2>`,
|
|
207
|
+
`<p>Guten Tag ${v("recipientName")},</p>`,
|
|
208
|
+
`<p>${args.intro} ${v("invoiceNumber")} über ${v("invoiceTotal")}.${due} Die Rechnung finden Sie als PDF im Anhang und jederzeit online.</p>`,
|
|
209
|
+
'<a data-button href="{{invoiceUrl}}">Rechnung online ansehen</a>',
|
|
210
|
+
LINES_TABLE,
|
|
211
|
+
"<hr>",
|
|
212
|
+
"<p>Bei Fragen zur Rechnung antworten Sie einfach auf diese E-Mail.</p>",
|
|
213
|
+
`<p>${v("signature")}</p>`,
|
|
214
|
+
].join("");
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const INVOICE_ISSUED_SLUG = "billing:notify:invoice-issued";
|
|
218
|
+
const INVOICE_CORRECTED_SLUG = "billing:notify:invoice-corrected";
|
|
219
|
+
|
|
220
|
+
const invoiceIssuedMeta = (subject: string) => ({
|
|
221
|
+
subject,
|
|
222
|
+
previewText: "Rechnung {{invoiceNumber}} über {{invoiceTotal}}, online abrufbar",
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const tenantInvoiceMeta = (subject: string) => ({
|
|
226
|
+
...invoiceIssuedMeta(subject),
|
|
227
|
+
senderName: "Nordlicht Immobilien GmbH",
|
|
228
|
+
replyTo: "buchhaltung@nordlicht-immobilien.de",
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// The platform default has a due date; the tenant drafts below drop it, which
|
|
232
|
+
// is what blocks publishing in the walkthrough.
|
|
233
|
+
export const SYSTEM_INVOICE_ISSUED: SeedTemplate = {
|
|
234
|
+
slug: INVOICE_ISSUED_SLUG,
|
|
235
|
+
kind: "mail",
|
|
236
|
+
locale: "de",
|
|
237
|
+
title: "Rechnung versendet",
|
|
238
|
+
content: invoiceIssuedBody({ intro: "anbei senden wir Ihnen die Rechnung", withDueDate: true }),
|
|
239
|
+
meta: invoiceIssuedMeta("Rechnung {{invoiceNumber}} von {{tenantName}}"),
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// Saved in order: each entry becomes the next version of the same draft.
|
|
243
|
+
export const INVOICE_ISSUED_DRAFT_VERSIONS: readonly SeedTemplate[] = [
|
|
244
|
+
{
|
|
245
|
+
slug: INVOICE_ISSUED_SLUG,
|
|
246
|
+
kind: "mail",
|
|
247
|
+
locale: "de",
|
|
248
|
+
title: "Rechnung versendet",
|
|
249
|
+
content: invoiceIssuedBody({
|
|
250
|
+
intro: "anbei senden wir Ihnen die Rechnung",
|
|
251
|
+
withDueDate: false,
|
|
252
|
+
}),
|
|
253
|
+
meta: tenantInvoiceMeta("Ihre Rechnung {{invoiceNumber}}"),
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
slug: INVOICE_ISSUED_SLUG,
|
|
257
|
+
kind: "mail",
|
|
258
|
+
locale: "de",
|
|
259
|
+
title: "Rechnung versendet",
|
|
260
|
+
content: invoiceIssuedBody({ intro: "anbei erhalten Sie die Rechnung", withDueDate: false }),
|
|
261
|
+
meta: tenantInvoiceMeta("Ihre Rechnung {{invoiceNumber}} von {{tenantName}}"),
|
|
262
|
+
},
|
|
263
|
+
];
|
|
264
|
+
|
|
265
|
+
// Separate draft for the screenshot spec, so the mail-editor e2e can change
|
|
266
|
+
// "Rechnung versendet" without touching what the screenshots show.
|
|
267
|
+
export const INVOICE_CORRECTED_DRAFT: SeedTemplate = {
|
|
268
|
+
slug: INVOICE_CORRECTED_SLUG,
|
|
269
|
+
kind: "mail",
|
|
270
|
+
locale: "de",
|
|
271
|
+
title: "Korrigierte Rechnung",
|
|
272
|
+
content: invoiceIssuedBody({
|
|
273
|
+
intro: "anbei erhalten Sie die korrigierte Rechnung",
|
|
274
|
+
withDueDate: false,
|
|
275
|
+
}),
|
|
276
|
+
meta: invoiceIssuedMeta("Ihre Rechnung {{invoiceNumber}} von {{tenantName}}"),
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
export const PAYMENT_REMINDER_TEMPLATES: readonly SeedTemplate[] = [
|
|
280
|
+
{
|
|
281
|
+
slug: "billing:notify:payment-reminder",
|
|
282
|
+
kind: "mail",
|
|
283
|
+
locale: "de",
|
|
284
|
+
title: "Zahlungserinnerung",
|
|
285
|
+
content: [
|
|
286
|
+
`<p>Guten Tag ${v("customerName")},</p>`,
|
|
287
|
+
`<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>`,
|
|
288
|
+
`<p>Bitte überweisen Sie den offenen Betrag in den nächsten Tagen. Die Rechnung finden Sie hier: <a href="{{invoiceUrl}}">Rechnung öffnen</a></p>`,
|
|
289
|
+
"<p>Sollten Sie bereits gezahlt haben, betrachten Sie diese Nachricht bitte als gegenstandslos.</p>",
|
|
290
|
+
].join(""),
|
|
291
|
+
meta: { subject: "Zahlungserinnerung zu Rechnung {{invoiceNumber}}" },
|
|
292
|
+
variableSchema: INVOICE_VARIABLE_SCHEMA,
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
slug: "billing:notify:payment-reminder",
|
|
296
|
+
kind: "mail",
|
|
297
|
+
locale: "en",
|
|
298
|
+
title: "Payment reminder",
|
|
299
|
+
content: [
|
|
300
|
+
`<p>Hello ${v("customerName")},</p>`,
|
|
301
|
+
`<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>`,
|
|
302
|
+
`<p>Please transfer the open amount in the next few days. You can find the invoice here: <a href="{{invoiceUrl}}">Open invoice</a></p>`,
|
|
303
|
+
"<p>If you have already paid, please disregard this message.</p>",
|
|
304
|
+
].join(""),
|
|
305
|
+
meta: { subject: "Payment reminder for invoice {{invoiceNumber}}" },
|
|
306
|
+
variableSchema: INVOICE_VARIABLE_SCHEMA,
|
|
307
|
+
},
|
|
308
|
+
];
|
|
309
|
+
|
|
310
|
+
function authMail(
|
|
311
|
+
notification: string,
|
|
312
|
+
locale: "de" | "en",
|
|
313
|
+
title: string,
|
|
314
|
+
subject: string,
|
|
315
|
+
paragraphs: readonly string[],
|
|
316
|
+
extraSchema: Record<string, unknown> = {},
|
|
317
|
+
): SeedTemplate {
|
|
318
|
+
return {
|
|
319
|
+
slug: `auth-email-password:notify:${notification}`,
|
|
320
|
+
kind: "mail",
|
|
321
|
+
locale,
|
|
322
|
+
title,
|
|
323
|
+
content: paragraphs.join(""),
|
|
324
|
+
meta: { subject },
|
|
325
|
+
variableSchema: { ...AUTH_VARIABLE_SCHEMA, ...extraSchema },
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export const SYSTEM_AUTH_MAILS: readonly SeedTemplate[] = [
|
|
330
|
+
authMail(
|
|
331
|
+
"password-reset",
|
|
332
|
+
"de",
|
|
333
|
+
"Passwort zurücksetzen",
|
|
334
|
+
"Passwort für {{appName}} zurücksetzen",
|
|
335
|
+
[
|
|
336
|
+
"<p>Hallo,</p>",
|
|
337
|
+
`<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>`,
|
|
338
|
+
`<p>Der Link ist ${v("validFor")} gültig, bis ${v("validUntil")}. Haben Sie das nicht angefordert, können Sie diese Nachricht ignorieren.</p>`,
|
|
339
|
+
],
|
|
340
|
+
),
|
|
341
|
+
authMail("password-reset", "en", "Reset password", "Reset your {{appName}} password", [
|
|
342
|
+
"<p>Hello,</p>",
|
|
343
|
+
`<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>`,
|
|
344
|
+
`<p>The link is valid for ${v("validFor")}, until ${v("validUntil")}. If you did not ask for this, you can ignore this message.</p>`,
|
|
345
|
+
]),
|
|
346
|
+
authMail(
|
|
347
|
+
"invite",
|
|
348
|
+
"de",
|
|
349
|
+
"Einladung ins Team",
|
|
350
|
+
"Einladung zu {{appName}}",
|
|
351
|
+
[
|
|
352
|
+
"<p>Hallo,</p>",
|
|
353
|
+
`<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>`,
|
|
354
|
+
`<p>Die Einladung ist ${v("validFor")} gültig, bis ${v("validUntil")}.</p>`,
|
|
355
|
+
],
|
|
356
|
+
{ role: { type: "text", required: true } },
|
|
357
|
+
),
|
|
358
|
+
authMail(
|
|
359
|
+
"invite",
|
|
360
|
+
"en",
|
|
361
|
+
"Team invitation",
|
|
362
|
+
"You are invited to {{appName}}",
|
|
363
|
+
[
|
|
364
|
+
"<p>Hello,</p>",
|
|
365
|
+
`<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>`,
|
|
366
|
+
`<p>The invitation is valid for ${v("validFor")}, until ${v("validUntil")}.</p>`,
|
|
367
|
+
],
|
|
368
|
+
{ role: { type: "text", required: true } },
|
|
369
|
+
),
|
|
370
|
+
authMail(
|
|
371
|
+
"signup-activation",
|
|
372
|
+
"de",
|
|
373
|
+
"Registrierung bestätigen",
|
|
374
|
+
"Registrierung bei {{appName}} bestätigen",
|
|
375
|
+
[
|
|
376
|
+
"<p>Willkommen,</p>",
|
|
377
|
+
`<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>`,
|
|
378
|
+
`<p>Der Link ist ${v("validFor")} gültig, bis ${v("validUntil")}.</p>`,
|
|
379
|
+
],
|
|
380
|
+
),
|
|
381
|
+
authMail(
|
|
382
|
+
"email-verification",
|
|
383
|
+
"de",
|
|
384
|
+
"E-Mail-Adresse bestätigen",
|
|
385
|
+
"E-Mail-Adresse für {{appName}} bestätigen",
|
|
386
|
+
[
|
|
387
|
+
"<p>Hallo,</p>",
|
|
388
|
+
`<p>bitte bestätigen Sie Ihre E-Mail-Adresse für ${v("appName")}: <a href="{{actionUrl}}">E-Mail-Adresse bestätigen</a></p>`,
|
|
389
|
+
`<p>Der Link ist ${v("validFor")} gültig, bis ${v("validUntil")}.</p>`,
|
|
390
|
+
],
|
|
391
|
+
),
|
|
392
|
+
authMail("email-verification", "en", "Confirm email address", "Confirm your {{appName}} email", [
|
|
393
|
+
"<p>Hello,</p>",
|
|
394
|
+
`<p>please confirm your email address for ${v("appName")}: <a href="{{actionUrl}}">Confirm email address</a></p>`,
|
|
395
|
+
`<p>The link is valid for ${v("validFor")}, until ${v("validUntil")}.</p>`,
|
|
396
|
+
]),
|
|
397
|
+
authMail("account-unlock", "de", "Konto entsperren", "Ihr Konto bei {{appName}} entsperren", [
|
|
398
|
+
"<p>Hallo,</p>",
|
|
399
|
+
`<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>`,
|
|
400
|
+
`<p>Der Link ist ${v("validFor")} gültig, bis ${v("validUntil")}.</p>`,
|
|
401
|
+
]),
|
|
402
|
+
authMail("account-unlock", "en", "Unlock account", "Unlock your {{appName}} account", [
|
|
403
|
+
"<p>Hello,</p>",
|
|
404
|
+
`<p>your ${v("appName")} account was locked after several failed sign-ins. Unlock it with this link: <a href="{{actionUrl}}">Unlock account</a></p>`,
|
|
405
|
+
`<p>The link is valid for ${v("validFor")}, until ${v("validUntil")}.</p>`,
|
|
406
|
+
]),
|
|
407
|
+
];
|
|
408
|
+
|
|
409
|
+
const UTILITY_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>`;
|
|
410
|
+
|
|
411
|
+
const right = (inner: string): string => `<p data-align="right">${inner}</p>`;
|
|
412
|
+
|
|
413
|
+
function invoiceRows(labels: {
|
|
414
|
+
readonly service: string;
|
|
415
|
+
readonly period: string;
|
|
416
|
+
readonly net: string;
|
|
417
|
+
}): string {
|
|
418
|
+
return [
|
|
419
|
+
"<table><tbody>",
|
|
420
|
+
`<tr><th><p>#</p></th><th><p>${labels.service}</p></th><th><p>${labels.period}</p></th><th><p data-align="right">${labels.net}</p></th></tr>`,
|
|
421
|
+
`<tr data-each="lines" data-repeat-header=""><td><p>${v("position")}</p></td><td><p>${v("description")}</p></td><td><p>${v("period")}</p></td><td><p data-align="right">${v("net")}</p></td></tr>`,
|
|
422
|
+
"</tbody></table>",
|
|
423
|
+
].join("");
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export const SYSTEM_INVOICE_DOCUMENTS: readonly SeedTemplate[] = [
|
|
427
|
+
{
|
|
428
|
+
slug: "billing:invoice",
|
|
429
|
+
kind: "document-pdf",
|
|
430
|
+
locale: "de",
|
|
431
|
+
title: "Rechnung",
|
|
432
|
+
content: [
|
|
433
|
+
`<p data-size="small"><u>Nordlicht Immobilien GmbH · Am Hafen 12 · 24103 Kiel</u></p>`,
|
|
434
|
+
`<p>${v("recipientAddress")}</p>`,
|
|
435
|
+
right(`Rechnungsnummer: ${v("invoiceNumber")}`),
|
|
436
|
+
right(`Rechnungsdatum: ${v("invoiceDate")}`),
|
|
437
|
+
right(`Fällig am: ${v("dueDate")}`),
|
|
438
|
+
`<h1>Rechnung ${v("invoiceNumber")}</h1>`,
|
|
439
|
+
"<p>Sehr geehrte Damen und Herren,</p>",
|
|
440
|
+
"<p>wir stellen Ihnen die folgenden Leistungen in Rechnung:</p>",
|
|
441
|
+
invoiceRows({ service: "Leistung", period: "Zeitraum", net: "Netto" }),
|
|
442
|
+
right(`Nettobetrag ${v("netTotal")}`),
|
|
443
|
+
right(`Umsatzsteuer 19 % ${v("vatAmount")}`),
|
|
444
|
+
right(`<strong>Rechnungsbetrag ${v("invoiceTotal")}</strong>`),
|
|
445
|
+
`<p>Bitte überweisen Sie den Rechnungsbetrag bis zum ${v("dueDate")} unter Angabe der Referenz ${v("paymentReference")} auf ${v("iban")}.</p>`,
|
|
446
|
+
"<div data-page-break></div>",
|
|
447
|
+
"<p>Zahlungsbedingungen und Hinweise auf Seite 2 …</p>",
|
|
448
|
+
].join(""),
|
|
449
|
+
meta: {
|
|
450
|
+
layoutSlug: "default",
|
|
451
|
+
pageFormat: "A4",
|
|
452
|
+
fileName: "rechnung-{{invoiceNumber}}.pdf",
|
|
453
|
+
metadata: { title: "Rechnung {{invoiceNumber}}" },
|
|
454
|
+
},
|
|
455
|
+
variableSchema: INVOICE_DOCUMENT_SCHEMA_DE,
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
slug: "billing:invoice",
|
|
459
|
+
kind: "document-pdf",
|
|
460
|
+
locale: "en",
|
|
461
|
+
title: "Invoice",
|
|
462
|
+
content: [
|
|
463
|
+
`<p data-size="small"><u>Nordlicht Immobilien GmbH · Am Hafen 12 · 24103 Kiel</u></p>`,
|
|
464
|
+
`<p>${v("recipientAddress")}</p>`,
|
|
465
|
+
right(`Invoice number: ${v("invoiceNumber")}`),
|
|
466
|
+
right(`Invoice date: ${v("invoiceDate")}`),
|
|
467
|
+
right(`Due on: ${v("dueDate")}`),
|
|
468
|
+
`<h1>Invoice ${v("invoiceNumber")}</h1>`,
|
|
469
|
+
"<p>Dear Sir or Madam,</p>",
|
|
470
|
+
"<p>we charge you the following services:</p>",
|
|
471
|
+
invoiceRows({ service: "Service", period: "Period", net: "Net" }),
|
|
472
|
+
right(`Net amount ${v("netTotal")}`),
|
|
473
|
+
right(`VAT 19 % ${v("vatAmount")}`),
|
|
474
|
+
right(`<strong>Total ${v("invoiceTotal")}</strong>`),
|
|
475
|
+
`<p>Please transfer the amount by ${v("dueDate")} quoting the reference ${v("paymentReference")} to ${v("iban")}.</p>`,
|
|
476
|
+
"<div data-page-break></div>",
|
|
477
|
+
"<p>Terms of payment and notes on page 2 …</p>",
|
|
478
|
+
].join(""),
|
|
479
|
+
meta: {
|
|
480
|
+
layoutSlug: "default",
|
|
481
|
+
pageFormat: "A4",
|
|
482
|
+
fileName: "invoice-{{invoiceNumber}}.pdf",
|
|
483
|
+
metadata: { title: "Invoice {{invoiceNumber}}" },
|
|
484
|
+
},
|
|
485
|
+
variableSchema: INVOICE_DOCUMENT_SCHEMA_EN,
|
|
486
|
+
},
|
|
487
|
+
];
|
|
488
|
+
|
|
489
|
+
export const TENANT_UTILITY_STATEMENT: SeedTemplate = {
|
|
490
|
+
slug: "rental:utility-statement",
|
|
491
|
+
kind: "document-pdf",
|
|
492
|
+
locale: "de",
|
|
493
|
+
title: "Nebenkostenabrechnung",
|
|
494
|
+
content: [
|
|
495
|
+
`<h1>Nebenkostenabrechnung ${v("invoiceNumber")}</h1>`,
|
|
496
|
+
`<p>Abrechnungsdatum: ${v("invoiceDate")}</p>`,
|
|
497
|
+
`<p>Guten Tag ${v("customerName")},</p>`,
|
|
498
|
+
"<p>nachfolgend erhalten Sie die Abrechnung der Betriebskosten für den Abrechnungszeitraum.</p>",
|
|
499
|
+
UTILITY_ROWS,
|
|
500
|
+
`<p><strong>Ergebnis: ${v("total")}</strong></p>`,
|
|
501
|
+
"<p>Ein Guthaben überweisen wir Ihnen innerhalb von 30 Tagen, eine Nachzahlung ist zum Monatsende fällig.</p>",
|
|
502
|
+
].join(""),
|
|
503
|
+
meta: { layoutSlug: "default", pageFormat: "A4", fileName: "Nebenkostenabrechnung.pdf" },
|
|
504
|
+
variableSchema: DOCUMENT_LINES_SCHEMA,
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
export const SYSTEM_TENANCY_CERTIFICATE: SeedTemplate = {
|
|
508
|
+
slug: "rental:tenancy-certificate",
|
|
509
|
+
kind: "document-pdf",
|
|
510
|
+
locale: "de",
|
|
511
|
+
title: "Mietbescheinigung",
|
|
512
|
+
content: [
|
|
513
|
+
"<h1>Mietbescheinigung</h1>",
|
|
514
|
+
`<p>Hiermit bestätigen wir, dass ${v("customerName")} bei uns Mieter ist und die Miete ordnungsgemäß zahlt.</p>`,
|
|
515
|
+
`<p>Ausgestellt am ${v("invoiceDate")}.</p>`,
|
|
516
|
+
].join(""),
|
|
517
|
+
meta: { layoutSlug: "default", pageFormat: "A4", fileName: "Mietbescheinigung.pdf" },
|
|
518
|
+
variableSchema: {
|
|
519
|
+
customerName: { type: "text", required: true },
|
|
520
|
+
invoiceDate: { type: "date", required: true },
|
|
521
|
+
},
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
// Two other tenants customise the invoice for the "Anpassungen der Mandanten" drawer: one
|
|
525
|
+
// published copy with a second save, one draft.
|
|
526
|
+
export type TenantInvoiceOverride = {
|
|
527
|
+
readonly tenantId: string;
|
|
528
|
+
readonly tenantKey: string;
|
|
529
|
+
readonly tenantName: string;
|
|
530
|
+
readonly adminEmail: string;
|
|
531
|
+
readonly adminName: string;
|
|
532
|
+
readonly status: "active" | "draft";
|
|
533
|
+
readonly versions: readonly SeedTemplate[];
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
const SYSTEM_INVOICE_DE = SYSTEM_INVOICE_DOCUMENTS[0] as SeedTemplate;
|
|
537
|
+
const INVOICE_INTRO = "<p>wir stellen Ihnen die folgenden Leistungen in Rechnung:</p>";
|
|
538
|
+
|
|
539
|
+
function invoiceWithIntro(sentence: string): SeedTemplate {
|
|
540
|
+
return {
|
|
541
|
+
...SYSTEM_INVOICE_DE,
|
|
542
|
+
content: SYSTEM_INVOICE_DE.content.replace(INVOICE_INTRO, `<p>${sentence}</p>`),
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
export const TENANT_INVOICE_OVERRIDES: readonly TenantInvoiceOverride[] = [
|
|
547
|
+
{
|
|
548
|
+
tenantId: "00000000-0000-4000-8000-000000000004",
|
|
549
|
+
tenantKey: "kuestenwohnen",
|
|
550
|
+
tenantName: "Küstenwohnen Kiel GmbH",
|
|
551
|
+
adminEmail: "verwaltung@kuestenwohnen-kiel.de",
|
|
552
|
+
adminName: "M. Petersen",
|
|
553
|
+
status: "active",
|
|
554
|
+
versions: [
|
|
555
|
+
invoiceWithIntro("für den genannten Zeitraum stellen wir Ihnen Folgendes in Rechnung:"),
|
|
556
|
+
invoiceWithIntro(
|
|
557
|
+
"für den genannten Zeitraum stellen wir Ihnen Folgendes in Rechnung. Die Nebenkosten rechnen wir jährlich ab.",
|
|
558
|
+
),
|
|
559
|
+
],
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
tenantId: "00000000-0000-4000-8000-000000000005",
|
|
563
|
+
tenantKey: "hansa-wohnbau",
|
|
564
|
+
tenantName: "Hansa Wohnbau eG",
|
|
565
|
+
adminEmail: "rechnungswesen@hansa-wohnbau.de",
|
|
566
|
+
adminName: "K. Lorenzen",
|
|
567
|
+
status: "draft",
|
|
568
|
+
versions: [invoiceWithIntro("nachfolgend die Abrechnung für Ihre Wohnung:")],
|
|
569
|
+
},
|
|
570
|
+
];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { defineFeature, templateVariable } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
+
import { toKeyFirst } from "../translations";
|
|
3
|
+
import { billingTranslations } from "./i18n";
|
|
4
|
+
|
|
5
|
+
// Both mails are sent by the host app's billing run, not by an event trigger in
|
|
6
|
+
// this sample; they exist so the template overview has real senders to show.
|
|
7
|
+
const INVOICE_ISSUED_VARIABLES = {
|
|
8
|
+
recipientName: templateVariable.text({
|
|
9
|
+
label: "Empfängername",
|
|
10
|
+
required: true,
|
|
11
|
+
example: "Familie Yilmaz",
|
|
12
|
+
}),
|
|
13
|
+
recipientEmail: templateVariable.text({
|
|
14
|
+
label: "Empfänger-Adresse",
|
|
15
|
+
example: "yilmaz.familie@example.org",
|
|
16
|
+
}),
|
|
17
|
+
invoiceNumber: templateVariable.text({
|
|
18
|
+
label: "Rechnungsnummer",
|
|
19
|
+
required: true,
|
|
20
|
+
example: "RE-2026-0142",
|
|
21
|
+
}),
|
|
22
|
+
invoiceTotal: templateVariable.money({
|
|
23
|
+
label: "Rechnungsbetrag",
|
|
24
|
+
required: true,
|
|
25
|
+
example: { amount: 128450, currency: "EUR" },
|
|
26
|
+
}),
|
|
27
|
+
dueDate: templateVariable.date({
|
|
28
|
+
label: "Fälligkeitsdatum",
|
|
29
|
+
required: true,
|
|
30
|
+
example: "2026-10-30",
|
|
31
|
+
}),
|
|
32
|
+
invoiceUrl: templateVariable.link({
|
|
33
|
+
label: "Link zur Rechnung",
|
|
34
|
+
required: true,
|
|
35
|
+
example: "https://nordlicht-immobilien.de/rechnungen/RE-2026-0142",
|
|
36
|
+
}),
|
|
37
|
+
lines: templateVariable.list(
|
|
38
|
+
{
|
|
39
|
+
description: templateVariable.text({ label: "Bezeichnung" }),
|
|
40
|
+
amount: templateVariable.money({ label: "Betrag" }),
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: "Rechnungspositionen",
|
|
44
|
+
required: true,
|
|
45
|
+
example: [
|
|
46
|
+
{ description: "Kaltmiete Oktober 2026, Lindenstraße 14 WE 3", amount: 98000 },
|
|
47
|
+
{ description: "Betriebskostenvorauszahlung Oktober 2026", amount: 24500 },
|
|
48
|
+
{ description: "Stellplatz 7, Oktober 2026", amount: 5950 },
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
),
|
|
52
|
+
paymentReference: templateVariable.text({
|
|
53
|
+
label: "Zahlungsreferenz",
|
|
54
|
+
example: "RE-2026-0142 / Yilmaz",
|
|
55
|
+
}),
|
|
56
|
+
} as const;
|
|
57
|
+
|
|
58
|
+
const PAYMENT_REMINDER_VARIABLES = {
|
|
59
|
+
customerName: templateVariable.text({ required: true }),
|
|
60
|
+
invoiceNumber: templateVariable.text({ required: true }),
|
|
61
|
+
amount: templateVariable.money({ required: true }),
|
|
62
|
+
dueDate: templateVariable.date({ required: true }),
|
|
63
|
+
invoiceUrl: templateVariable.link({ required: true }),
|
|
64
|
+
} as const;
|
|
65
|
+
|
|
66
|
+
export const billingFeature = defineFeature("billing", (r) => {
|
|
67
|
+
r.translations({ keys: toKeyFirst(billingTranslations) });
|
|
68
|
+
|
|
69
|
+
r.notification("invoice-issued", { variables: INVOICE_ISSUED_VARIABLES });
|
|
70
|
+
r.notification("invoice-corrected", { variables: INVOICE_ISSUED_VARIABLES });
|
|
71
|
+
r.notification("payment-reminder", { variables: PAYMENT_REMINDER_VARIABLES });
|
|
72
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
|
|
2
|
+
|
|
3
|
+
// The keys follow the document-designer's "used by" lookup:
|
|
4
|
+
// `<feature>:feature.label` and `<feature>:notify.<notification>.label`.
|
|
5
|
+
export const billingTranslations: TranslationsByLocale = {
|
|
6
|
+
de: {
|
|
7
|
+
"billing:feature.label": "Rechnungen",
|
|
8
|
+
"billing:notify.invoice-issued.label": "Rechnung gestellt",
|
|
9
|
+
"billing:notify.invoice-corrected.label": "Rechnung korrigiert",
|
|
10
|
+
"billing:notify.payment-reminder.label": "Mahnlauf",
|
|
11
|
+
},
|
|
12
|
+
en: {
|
|
13
|
+
"billing:feature.label": "Invoices",
|
|
14
|
+
"billing:notify.invoice-issued.label": "Invoice issued",
|
|
15
|
+
"billing:notify.invoice-corrected.label": "Invoice corrected",
|
|
16
|
+
"billing:notify.payment-reminder.label": "Dunning run",
|
|
17
|
+
},
|
|
18
|
+
};
|