@neohm/nestend 3.3.9 → 3.3.10

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 (158) hide show
  1. package/README.md +165 -64
  2. package/dist/admin/admin.module.d.ts.map +1 -1
  3. package/dist/admin/admin.module.js.map +1 -1
  4. package/dist/admin/controllers/admin.api.key.controller.js +1 -1
  5. package/dist/admin/controllers/admin.api.key.controller.js.map +1 -1
  6. package/dist/admin/controllers/admin.email.template.controller.d.ts +24 -0
  7. package/dist/admin/controllers/admin.email.template.controller.d.ts.map +1 -0
  8. package/dist/admin/controllers/admin.email.template.controller.js +106 -0
  9. package/dist/admin/controllers/admin.email.template.controller.js.map +1 -0
  10. package/dist/admin/controllers/admin.pdf.template.controller.d.ts +24 -0
  11. package/dist/admin/controllers/admin.pdf.template.controller.d.ts.map +1 -0
  12. package/dist/admin/controllers/admin.pdf.template.controller.js +106 -0
  13. package/dist/admin/controllers/admin.pdf.template.controller.js.map +1 -0
  14. package/dist/admin/controllers/admin.scheduled.task.controller.d.ts.map +1 -1
  15. package/dist/admin/controllers/admin.scheduled.task.controller.js +1 -1
  16. package/dist/admin/controllers/admin.scheduled.task.controller.js.map +1 -1
  17. package/dist/admin/controllers/admin.scope.controller.d.ts.map +1 -1
  18. package/dist/admin/controllers/admin.scope.controller.js +1 -1
  19. package/dist/admin/controllers/admin.scope.controller.js.map +1 -1
  20. package/dist/admin/controllers/admin.system.user.controller.d.ts.map +1 -1
  21. package/dist/admin/controllers/admin.system.user.controller.js +1 -1
  22. package/dist/admin/controllers/admin.system.user.controller.js.map +1 -1
  23. package/dist/admin/controllers/admin.tenant.controller.d.ts.map +1 -1
  24. package/dist/admin/controllers/admin.tenant.controller.js +1 -1
  25. package/dist/admin/controllers/admin.tenant.controller.js.map +1 -1
  26. package/dist/admin/controllers/admin.tenant.user.controller.d.ts.map +1 -1
  27. package/dist/admin/controllers/admin.tenant.user.controller.js +1 -1
  28. package/dist/admin/controllers/admin.tenant.user.controller.js.map +1 -1
  29. package/dist/admin/controllers/admin.user.controller.d.ts.map +1 -1
  30. package/dist/admin/controllers/admin.user.controller.js +1 -1
  31. package/dist/admin/controllers/admin.user.controller.js.map +1 -1
  32. package/dist/admin/controllers/system.role.controller.d.ts.map +1 -1
  33. package/dist/admin/controllers/system.role.controller.js +1 -1
  34. package/dist/admin/controllers/system.role.controller.js.map +1 -1
  35. package/dist/admin/dtos/add.email.template.dto.d.ts +9 -0
  36. package/dist/admin/dtos/add.email.template.dto.d.ts.map +1 -0
  37. package/dist/admin/dtos/add.email.template.dto.js +68 -0
  38. package/dist/admin/dtos/add.email.template.dto.js.map +1 -0
  39. package/dist/admin/dtos/add.pdf.template.dto.d.ts +8 -0
  40. package/dist/admin/dtos/add.pdf.template.dto.d.ts.map +1 -0
  41. package/dist/admin/dtos/add.pdf.template.dto.js +58 -0
  42. package/dist/admin/dtos/add.pdf.template.dto.js.map +1 -0
  43. package/dist/admin/dtos/add.tenant.dto.d.ts +1 -0
  44. package/dist/admin/dtos/add.tenant.dto.d.ts.map +1 -1
  45. package/dist/admin/dtos/add.tenant.dto.js +7 -0
  46. package/dist/admin/dtos/add.tenant.dto.js.map +1 -1
  47. package/dist/admin/dtos/email.template.list.dto.d.ts +4 -0
  48. package/dist/admin/dtos/email.template.list.dto.d.ts.map +1 -0
  49. package/dist/admin/dtos/email.template.list.dto.js +8 -0
  50. package/dist/admin/dtos/email.template.list.dto.js.map +1 -0
  51. package/dist/admin/dtos/pdf.template.list.dto.d.ts +4 -0
  52. package/dist/admin/dtos/pdf.template.list.dto.d.ts.map +1 -0
  53. package/dist/admin/dtos/pdf.template.list.dto.js +8 -0
  54. package/dist/admin/dtos/pdf.template.list.dto.js.map +1 -0
  55. package/dist/admin/es6.classes.d.ts +12 -4
  56. package/dist/admin/es6.classes.d.ts.map +1 -1
  57. package/dist/admin/es6.classes.js +22 -1
  58. package/dist/admin/es6.classes.js.map +1 -1
  59. package/dist/admin/libraries/email.template.data.processor.d.ts +13 -0
  60. package/dist/admin/libraries/email.template.data.processor.d.ts.map +1 -0
  61. package/dist/admin/libraries/email.template.data.processor.js +51 -0
  62. package/dist/admin/libraries/email.template.data.processor.js.map +1 -0
  63. package/dist/admin/libraries/email.template.list.processor.d.ts +15 -0
  64. package/dist/admin/libraries/email.template.list.processor.d.ts.map +1 -0
  65. package/dist/admin/libraries/email.template.list.processor.js +31 -0
  66. package/dist/admin/libraries/email.template.list.processor.js.map +1 -0
  67. package/dist/admin/libraries/pdf.template.data.processor.d.ts +13 -0
  68. package/dist/admin/libraries/pdf.template.data.processor.d.ts.map +1 -0
  69. package/dist/admin/libraries/pdf.template.data.processor.js +48 -0
  70. package/dist/admin/libraries/pdf.template.data.processor.js.map +1 -0
  71. package/dist/admin/libraries/pdf.template.list.processor.d.ts +15 -0
  72. package/dist/admin/libraries/pdf.template.list.processor.d.ts.map +1 -0
  73. package/dist/admin/libraries/pdf.template.list.processor.js +30 -0
  74. package/dist/admin/libraries/pdf.template.list.processor.js.map +1 -0
  75. package/dist/admin/libraries/tenant.data.processor.d.ts.map +1 -1
  76. package/dist/admin/libraries/tenant.data.processor.js +1 -0
  77. package/dist/admin/libraries/tenant.data.processor.js.map +1 -1
  78. package/dist/admin/services/template.service.d.ts +7 -0
  79. package/dist/admin/services/template.service.d.ts.map +1 -0
  80. package/dist/admin/services/template.service.js +34 -0
  81. package/dist/admin/services/template.service.js.map +1 -0
  82. package/dist/constants/entity.constants.d.ts +1 -0
  83. package/dist/constants/entity.constants.d.ts.map +1 -1
  84. package/dist/constants/entity.constants.js +1 -0
  85. package/dist/constants/entity.constants.js.map +1 -1
  86. package/dist/constants/entity.maps.d.ts +2 -0
  87. package/dist/constants/entity.maps.d.ts.map +1 -1
  88. package/dist/constants/entity.maps.js +2 -0
  89. package/dist/constants/entity.maps.js.map +1 -1
  90. package/dist/document/document.module.d.ts.map +1 -1
  91. package/dist/document/document.module.js +3 -1
  92. package/dist/document/document.module.js.map +1 -1
  93. package/dist/document/dtos/pdf.document.options.dto.d.ts +17 -0
  94. package/dist/document/dtos/pdf.document.options.dto.d.ts.map +1 -0
  95. package/dist/document/dtos/pdf.document.options.dto.js +13 -0
  96. package/dist/document/dtos/pdf.document.options.dto.js.map +1 -0
  97. package/dist/document/dtos/pdf.template.attributes.dto.d.ts +3 -0
  98. package/dist/document/dtos/pdf.template.attributes.dto.d.ts.map +1 -0
  99. package/dist/document/dtos/pdf.template.attributes.dto.js +7 -0
  100. package/dist/document/dtos/pdf.template.attributes.dto.js.map +1 -0
  101. package/dist/document/entities/document.entity.d.ts +1 -0
  102. package/dist/document/entities/document.entity.d.ts.map +1 -1
  103. package/dist/document/entities/document.entity.js +4 -0
  104. package/dist/document/entities/document.entity.js.map +1 -1
  105. package/dist/document/entities/pdf.template.entity.d.ts +9 -0
  106. package/dist/document/entities/pdf.template.entity.d.ts.map +1 -0
  107. package/dist/document/entities/pdf.template.entity.js +38 -0
  108. package/dist/document/entities/pdf.template.entity.js.map +1 -0
  109. package/dist/document/enums/pdf.default.enum.d.ts +2 -1
  110. package/dist/document/enums/pdf.default.enum.d.ts.map +1 -1
  111. package/dist/document/enums/pdf.default.enum.js +1 -0
  112. package/dist/document/enums/pdf.default.enum.js.map +1 -1
  113. package/dist/document/es6.classes.d.ts +6 -5
  114. package/dist/document/es6.classes.d.ts.map +1 -1
  115. package/dist/document/es6.classes.js +14 -2
  116. package/dist/document/es6.classes.js.map +1 -1
  117. package/dist/document/libraries/process.pdf.document.d.ts +16 -0
  118. package/dist/document/libraries/process.pdf.document.d.ts.map +1 -0
  119. package/dist/document/libraries/process.pdf.document.js +47 -0
  120. package/dist/document/libraries/process.pdf.document.js.map +1 -0
  121. package/dist/document/services/document.service.d.ts +2 -2
  122. package/dist/document/services/document.service.d.ts.map +1 -1
  123. package/dist/document/services/document.service.js +5 -2
  124. package/dist/document/services/document.service.js.map +1 -1
  125. package/dist/document/services/pdf.template.service.d.ts +12 -0
  126. package/dist/document/services/pdf.template.service.d.ts.map +1 -0
  127. package/dist/document/services/pdf.template.service.js +57 -0
  128. package/dist/document/services/pdf.template.service.js.map +1 -0
  129. package/dist/document/types/document.types.d.ts +3 -0
  130. package/dist/document/types/document.types.d.ts.map +1 -1
  131. package/dist/document/types/pdf.types.d.ts +4 -0
  132. package/dist/document/types/pdf.types.d.ts.map +1 -1
  133. package/dist/index.d.ts +7 -2
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +15 -3
  136. package/dist/index.js.map +1 -1
  137. package/dist/migrations/1749600000002.CreateSysTenantsTable.d.ts.map +1 -1
  138. package/dist/migrations/1749600000002.CreateSysTenantsTable.js +1 -0
  139. package/dist/migrations/1749600000002.CreateSysTenantsTable.js.map +1 -1
  140. package/dist/migrations/1749600000020.CreateSysEmailTemplatesTable.d.ts.map +1 -1
  141. package/dist/migrations/1749600000020.CreateSysEmailTemplatesTable.js +11 -1
  142. package/dist/migrations/1749600000020.CreateSysEmailTemplatesTable.js.map +1 -1
  143. package/dist/migrations/1749600000028.CreateSysDocumentsTable.d.ts.map +1 -1
  144. package/dist/migrations/1749600000028.CreateSysDocumentsTable.js +1 -0
  145. package/dist/migrations/1749600000028.CreateSysDocumentsTable.js.map +1 -1
  146. package/dist/migrations/1749600000029.CreateSysPdfTemplatesTable.d.ts +6 -0
  147. package/dist/migrations/1749600000029.CreateSysPdfTemplatesTable.d.ts.map +1 -0
  148. package/dist/migrations/1749600000029.CreateSysPdfTemplatesTable.js +33 -0
  149. package/dist/migrations/1749600000029.CreateSysPdfTemplatesTable.js.map +1 -0
  150. package/dist/notification/entities/email.template.entity.d.ts +2 -2
  151. package/dist/notification/entities/email.template.entity.d.ts.map +1 -1
  152. package/dist/notification/entities/email.template.entity.js +2 -2
  153. package/dist/notification/entities/email.template.entity.js.map +1 -1
  154. package/dist/tenant/entities/tenant.entity.d.ts +1 -0
  155. package/dist/tenant/entities/tenant.entity.d.ts.map +1 -1
  156. package/dist/tenant/entities/tenant.entity.js +5 -1
  157. package/dist/tenant/entities/tenant.entity.js.map +1 -1
  158. package/package.json +1 -1
package/README.md CHANGED
@@ -104,7 +104,7 @@ these are free to change without a breaking release.
104
104
  | Area | Key exports | Notes |
105
105
  | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
106
106
  | Entities | `RootEntity`, `CommonEntity`, `CommonAdminEntity`, `UserEntity`, `AdminUserEntity`, `SystemRoleEntity`, `SystemAdminRoleEntity`, ... | uuid PK, soft deletes, `created_by`/`updated_by` (+ `creator`/`updater` relations), jsonb `attributes`; entity-level `findOneOrNew`, `hardDelete`, `restore`, `paginate` statics plus a row-wise `softDelete()` |
107
- | Migrations | `MigrationUtility`, `SeederUtility` (the 28 table migrations ship in `dist/migrations` — glob them, they are not barrel exports) | fluent `this.string()`, `this.numeric()`, `addRecord()` seeding |
107
+ | Migrations | `MigrationUtility`, `SeederUtility` (the 29 table migrations ship in `dist/migrations` — glob them, they are not barrel exports) | fluent `this.string()`, `this.numeric()`, `addRecord()` seeding |
108
108
  | Queue | `QueueModule`, `QueueModule.withConnection()`, `QueueService`, `CommonJob` | BullMQ `@Processor`/`WorkerHost` consumer; auto-discovered jobs, duplicate prevention, recurring schedulers, completed jobs cleared from Redis on success (1-day TTL on failures), `clearQueue()`, retries, failures persisted to `sys_failed_jobs`; connection from `BULL_REDIS_*` or supplied by the app — never register `BullModule.forRoot()` yourself, two roots race over the worker's connection |
109
109
  | Scheduled events | `SystemScheduledTaskEntity`, `ScheduledEventEntity`, `ScheduleKind`, `ScheduleSpec`, `IsCronExpression` | schedule definitions in `sys_scheduled_tasks` → events in `sys_scheduled_events`; interval / cron / once specs with timezones, drift-free slots, horizon materialisation, catch-up + overlap policies, fire-once dispatch with backoff, cadence via `SCHEDULED_EVENT_MIN` |
110
110
  | Auth | `AuthModule`, `AuthService.validateRole()`, `RoleTier`, `TenantRole`, `Auth`, `JwtMiddleware` | imperative auth (open by default); `<module>.<tier>` role hierarchy (manager > writer > viewer), with `global.admin` overriding every role check; JwtMiddleware resolves the user into `Auth`'s AsyncLocalStorage context per request; access + rotating refresh tokens; session-based logout invalidation (`sys_auth_sessions`); Google SSO via ID token at `POST /auth/google`; impersonation — a tenantless `has_global_access` user signs into one organization at `POST /auth/impersonation/login` |
@@ -112,15 +112,15 @@ these are free to change without a breaking release.
112
112
  | API keys | `ApiKeyService`, `ApiKeyGuard` / `ApiKeyMiddleware`, `@ApiKeyScopes()`, `ApiKeyContext` | hashed keys in `sys_api_keys` (admin-owned), one tenant per key, expiry/revocation, `x-api-key` header; `validateAccess(scope)` returns the tenant the key acts for |
113
113
  | Scopes | `ScopeService`, `AuthService.validateAccess()`, `ScopeEntity`, `TenantScopeEntity`, `ApiScopeEntity` | one feature named once in `sys_scopes`, then granted per organization (`sys_tenant_scopes`) or per API key (`sys_api_scopes`) — never an array on the principal |
114
114
  | Multi-tenancy | `TenantModule`, `TenantEntity`, `CommonTenantEntity`, `TenantContextService`, `TenantContextMiddleware` | AsyncLocalStorage tenant context; resolve by header, slug, or domain; tenants are onboarded by admins (`TenantEntity.creator` → `AdminUserEntity`) |
115
- | Admin | `AdminModule` (its controllers, DTOs and processors are internal — import the module and hit the endpoints), `GlobalAdminRoles` | back-office APIs: tenant onboarding, client/admin/system user registration (single + bulk), the `has_global_access` grant that enables impersonation, tenant + scheduled-task listing; 4-tier `GlobalAdminRoles` gate over `sys_admin_roles`; Swagger at `/docs` (hidden in production) |
115
+ | Admin | `AdminModule` (its controllers, DTOs and processors are internal — import the module and hit the endpoints), `GlobalAdminRoles` | back-office APIs: tenant onboarding, client/admin/system user registration (single + bulk), the `has_global_access` grant that enables impersonation, tenant + scheduled-task listing, the email/PDF template catalogues (read at content-reader, written at content-manager, deleted at global admin); 4-tier `GlobalAdminRoles` gate over `sys_admin_roles`; Swagger at `/docs` (hidden in production) |
116
116
  | Notifications | `NotificationModule`, `NotificationService`, `FcmPushNotificationService` | in-app rows + FCM push (optional `firebase-admin`); device token registry |
117
- | Email (SES) | `EmailNotificationService`, `ProcessEmailNotification`, `EmailTemplateEntity`, `EmailNotificationLogEntity` | templates in `sys_email_templates` rendered by a remote service, dispatched via SES per recipient (to/cc/bcc); logged to `sys_email_notification_logs` outside production; dispatch skipped when `AWS_SES_FROM_ADDRESS` unset |
117
+ | Email (SES) | `EmailNotificationService`, `ProcessEmailNotification`, `EmailTemplateEntity`, `EmailNotificationLogEntity` | templates in `sys_email_templates` (managed from the admin surface) rendered by a remote service, dispatched via SES per recipient (to/cc/bcc); logged to `sys_email_notification_logs` outside production; dispatch skipped when `AWS_SES_FROM_ADDRESS` unset |
118
118
  | Audit | `AuditService` | `saveAuditLog(old, new)` with changed-value diffing into `sys_audit_logs` |
119
119
  | Cache | `CacheService` | Redis, TTL objects (`{days, hours, min}`), transparent encryption |
120
120
  | Encryption | `EncryptionService` | AES-256-GCM, scrypt-derived keys |
121
121
  | System properties | `SystemPropertyModule`, `SystemPropertyService` | cached + optionally encrypted key/value settings in `sys_properties` |
122
- | Documents | `DocumentModule`, `DocumentService`, `S3BucketDocumentService`, `MinioBucketDocumentService` | `POST /api/documents/upload` (multipart) or `uploadDocument(multerFiles) → links[]`; driver chosen via `DOCUMENT_STORAGE_DRIVER` |
123
- | PDF generation | `PdfService`, `PdfRenderOptions` | `renderHtmlToPdf(html) → Buffer` via headless Chromium; honours the document's own `@page` rules and paginates to any length; optional peer dep `puppeteer` |
122
+ | Documents | `DocumentModule`, `DocumentService`, `S3BucketDocumentService`, `MinioBucketDocumentService` | `POST /api/documents/upload` (multipart) or `uploadDocument(multerFiles) → links[]`; driver chosen via `DOCUMENT_STORAGE_DRIVER`; `sys_document_uploads` is the file, `sys_documents` the link to one of your records (`system_generated` marks the ones the backend produced itself) |
123
+ | PDF documents | `PdfService`, `PdfTemplateService`, `ProcessPdfDocument`, `PdfTemplateEntity`, `PdfRenderOptions` | templates in `sys_pdf_templates` rendered to HTML by a remote service, rasterized by headless Chromium (`renderHtmlToPdf(html) → Buffer`, honours the document's own `@page` rules and paginates to any length), then stored — `ProcessPdfDocument` writes both rows and flags the `sys_documents` one `system_generated`; optional peer dep `puppeteer` |
124
124
  | HTTP | `CommonController`, `GlobalExceptionFilter`, common DTOs | health endpoint base controller, uniform error envelope |
125
125
  | Raw SQL | `SqlService`, `SqlTarget` | named `:key` placeholders always bound as driver params, `:...key` array expansion; runs on the read replica (`DB_READ_*`) with transparent primary fallback; `fetchOne`/`fetchScalar`/`exists`/`count`/`paginate` helpers |
126
126
  | List endpoints | `CommonListProcessor`, `CommonListFilterDto`, `FilterDto`, `CommonListFilterConfig` | allowlisted columns, parameterised operators (`eq`…`isNull`), typed value casting (`str`/`num`/`date`/`bool`/`null`), multi-sort + paginated on the read replica |
@@ -605,7 +605,7 @@ a subscriber only starts firing once something constructs it.
605
605
  | `MINIO_BUCKET` | `documents` | Bucket name (auto-created if missing) |
606
606
  | `MINIO_PUBLIC_URL` | _(empty)_ | CDN base URL when MinIO sits behind a proxy |
607
607
 
608
- ### PDF Generation
608
+ ### PDF Documents
609
609
 
610
610
  Requires the optional peer dependency `puppeteer`.
611
611
 
@@ -694,9 +694,18 @@ Requires the optional peer dependency `firebase-admin`. Provide **one** of:
694
694
  Storage is split across two tables. `sys_document_uploads` (`DocumentUploadEntity`)
695
695
  is the stored object — name, mime type, size, driver, path, url, `is_public` — and
696
696
  every upload writes one row automatically. `sys_documents` (`DocumentEntity`) is just
697
- the link to one of your records: `upload_id` + `source_type` + `source_id`, no file
698
- metadata. So one file can hang off several records, and a file can exist before
699
- anything owns it.
697
+ the link to one of your records: `upload_id` + `source_type` + `source_id` +
698
+ `system_generated`, no file metadata. So one file can hang off several records, and a
699
+ file can exist before anything owns it.
700
+
701
+ `system_generated` answers a question the two tables otherwise cannot: whether anybody
702
+ uploaded this file. A generated invoice and an uploaded scan of one are the same pair of
703
+ rows, so the flag is what lets a listing tell them apart — and what lets a regeneration
704
+ know which of its records it may replace. It is set through
705
+ `setDocument(dto, { systemGenerated: true })`, which is how
706
+ [`ProcessPdfDocument`](#pdf-documents-pdfservice-pdftemplateservice-processpdfdocument)
707
+ marks what it produces; it is deliberately absent from `SetDocumentDto`, so the HTTP
708
+ endpoint cannot claim it.
700
709
 
701
710
  `DocumentModule` ships two endpoints. `POST /api/documents/upload` is multipart: it
702
711
  takes the files in a `files` field, uploads them through the active driver and returns
@@ -752,43 +761,97 @@ that object from the bucket and soft deletes its row, so one unreachable file re
752
761
  alone instead of stalling the sweep. Schedule it with a `sys_scheduled_tasks` row under
753
762
  that identifier — the module registers the handler but never dispatches it.
754
763
 
755
- ## PDF Generation (PdfService)
764
+ ## PDF Documents (PdfService, PdfTemplateService, ProcessPdfDocument)
756
765
 
757
- `PdfService` (exported by `DocumentModule`) turns an HTML document into PDF
758
- bytes using a headless Chromium.
766
+ The `/pdfs` counterpart of [Templated Email](#templated-email-aws-ses), and it reuses
767
+ that pipeline's shape exactly: a catalogue row names a template, a remote service
768
+ renders it, a processor drives the whole thing. What differs is the last mile — mail is
769
+ handed to SES, a document is rasterized and stored.
759
770
 
760
- It is the backend half of the document rendering service: that service serves
761
- print-ready, A4-locked HTML at `POST /pdfs/<version>/<path>/<template>`, and
762
- this service rasterizes it. The split keeps the template service free of a
763
- browser binary and puts the PDF bytes next to the storage and delivery code
764
- that needs them.
771
+ Three pieces, split along the one line that matters — where the browser binary lives:
772
+
773
+ - **`PdfTemplateService`** — resolves a `sys_pdf_templates` row by `identifier` and
774
+ POSTs your `data` to the remote template service, returning print-ready HTML. Exactly
775
+ `EmailNotificationService.getEmailBody()`, for documents.
776
+ - **`PdfService`** — turns that HTML into PDF bytes with a headless Chromium. Knows
777
+ nothing about templates or storage.
778
+ - **`ProcessPdfDocument`** — the entry point. Validates, renders, rasterizes, stores,
779
+ and returns the `sys_documents` row with its `upload` relation attached.
780
+
781
+ All three are exported by `DocumentModule`.
782
+
783
+ ### The whole thing in one call
765
784
 
766
785
  ```ts
767
- // 1. Fetch the rendered document from the template service.
768
- const html = await this.remoteRequestService.getApiResponse<string>({
769
- url: `${templateBaseUrl}/pdfs/v1/business/summary-report`,
770
- requestType: ApiRequestTypeEnum.POST,
771
- contentType: ApiContentTypeEnum.APPLICATION_JSON,
772
- headers: { 'x-client-key': clientKey },
773
- body: reportPayload,
786
+ const processor = new ProcessPdfDocument(
787
+ this.pdfTemplateService,
788
+ this.pdfService,
789
+ this.documentService,
790
+ );
791
+
792
+ const document = await processor.process({
793
+ identifier: 'purchase-order', // a sys_pdf_templates row
794
+ metadata: {
795
+ fileName: 'po-10432.pdf',
796
+ mimeType: 'application/pdf', // default
797
+ pathIdentifier: 'purchase.order', // → the document.path.purchase.order property
798
+ isPublic: false, // default
799
+ },
800
+ source: { // becomes the sys_documents row
801
+ source_type: 'purchase.order',
802
+ source_id: purchaseOrder.id,
803
+ },
804
+ data: { order: purchaseOrder, lines }, // payload for the remote renderer
774
805
  });
775
806
 
776
- // 2. Rasterize it.
807
+ const link = await this.documentService.getDocumentLink(document.upload);
808
+ ```
809
+
810
+ Four steps, in order:
811
+
812
+ 1. `PdfTemplateService.getPdfHtml()` — loads the template (`OperationException` if the
813
+ identifier is unknown), builds the URL as the `pdf.template.base.url` system
814
+ property + `template.path` + `identifier`, and POSTs `data` to it. The URL is a
815
+ plain concatenation, so the property and `path` carry their own trailing slashes —
816
+ same contract as `email.template.base.url`.
817
+ 2. `PdfService.renderHtmlToUploadableFile()` — the bytes, named (`.pdf` appended when
818
+ the file name lacks it).
819
+ 3. `DocumentService.uploadSingleDocument()` — the object goes to the active driver and
820
+ one `sys_document_uploads` row records it. `pathIdentifier` is resolved through
821
+ `resolvePathPrefix()` first, so the destination folder is a `document.path.*` system
822
+ property rather than a caller-supplied path.
823
+ 4. `DocumentService.setDocument(…, { systemGenerated: true })` — the `sys_documents`
824
+ row linking that upload to your record.
825
+
826
+ The upload is deliberately made _without_ `sourceType`/`sourceId` and linked in a
827
+ separate call: those options attach the document as an ordinary upload, and
828
+ `system_generated` is only settable on the explicit `setDocument()` — never from
829
+ `SetDocumentDto`, so the HTTP endpoint cannot claim it.
830
+
831
+ **Seed the catalogue.** A `sys_pdf_templates` row per document, plus the
832
+ `pdf.template.base.url` property; without either, `getPdfHtml()` raises. Manage them
833
+ through [the admin surface](#admin-module) — content manager to define or edit, global
834
+ admin to delete. There is no `PdfTemplateIdentifier` enum: the library dispatches no
835
+ documents of its own, so name yours in an enum in your app rather than inline.
836
+
837
+ ### Using PdfService on its own
838
+
839
+ Skip the processor when you already have the HTML, or want the bytes rather than a
840
+ stored document:
841
+
842
+ ```ts
777
843
  const pdf: Buffer = await this.pdfService.renderHtmlToPdf(html);
778
844
 
779
845
  // …or go straight to bucket storage.
780
- const file = await this.pdfService.renderHtmlToUploadableFile(
781
- html,
782
- 'summary-report.pdf',
783
- );
846
+ const file = await this.pdfService.renderHtmlToUploadableFile(html, 'report.pdf');
784
847
  const [link] = await this.documentService.uploadDocument([file], {
785
848
  pathPrefix: 'reports',
786
849
  });
787
850
  ```
788
851
 
789
- **Install puppeteer.** It is an _optional_ peer dependency — nothing imports it
790
- until a PDF is actually requested, so apps that never generate one skip the
791
- ~170MB Chromium download entirely:
852
+ **Install puppeteer.** It is an _optional_ peer dependency — nothing imports it until a
853
+ PDF is actually requested, so apps that never generate one skip the ~170MB Chromium
854
+ download entirely:
792
855
 
793
856
  ```bash
794
857
  yarn add puppeteer
@@ -878,9 +941,15 @@ await new ProcessEmailNotification(emailNotificationService).process({
878
941
  });
879
942
  ```
880
943
 
944
+ The catalogue is managed from [the admin surface](#admin-module) —
945
+ `POST /admin/email-templates` and friends — and `EmailTemplateEntity` extends
946
+ `CommonAdminEntity` for that reason: a row is authored from the back office, never by a
947
+ tenant user.
948
+
881
949
  The templates the library itself dispatches are named by the
882
950
  `EmailTemplateIdentifier` enum — seed a matching `sys_email_templates` row for each
883
- one you want delivered:
951
+ one you want delivered, and note that these two are exactly the rows a delete must not
952
+ reach:
884
953
 
885
954
  | Identifier | Sent by | Recipient | `data` keys |
886
955
  | ----------------------- | ------------------------- | ------------------ | --------------------------------------------------------------------------- |
@@ -953,7 +1022,8 @@ SQL runs. Results come back as `{ records, total, page, limit, total_pages }`.
953
1022
  ## Admin Module
954
1023
 
955
1024
  `AdminModule` is the back-office surface — tenant onboarding, client/admin user
956
- registration, tenant listing and scheduled-task management. It uses the same
1025
+ registration, tenant listing, scheduled-task management and the email/PDF template
1026
+ catalogues. It uses the same
957
1027
  imperative auth model as the rest of the app: controllers are open by default and
958
1028
  gate each action through `AdminAccessService` before handing the work to a
959
1029
  processor.
@@ -979,42 +1049,73 @@ pass the actor to a processor.
979
1049
 
980
1050
  ### Endpoints
981
1051
 
982
- | Route | Min. role | Handler |
983
- | ---------------------------------------- | --------------- | ----------------------------------------------------------- |
984
- | `POST /admin/tenants` | super admin | `TenantDataProcessor` (upsert — send `id` to update) |
985
- | `POST /admin/tenants/list` | content reader | `TenantListProcessor` |
986
- | `GET /admin/tenants/:id` | content reader | the row plus its `scopes` |
987
- | `POST /admin/tenants/:id/delete` | super admin | `TenantDeleteProcessor` |
988
- | `POST /admin/tenant-users` | admin | `ClientUserDataProcessor` |
989
- | `POST /admin/tenant-users/bulk` | admin | `BulkUserDataProcessor` |
990
- | `POST /admin/tenant-users/list` | content reader | `ClientUserListProcessor` |
991
- | `GET /admin/tenant-users/:id` | content reader | the row |
992
- | `POST /admin/tenant-users/:id/delete` | admin | `ClientUserDeleteProcessor` |
993
- | `POST /admin/users` | super admin | `AdminUserDataProcessor` |
994
- | `POST /admin/users/list` | content reader | `AdminUserListProcessor` |
995
- | `GET /admin/users/:id` | content reader | the row |
996
- | `POST /admin/users/:id/delete` | super admin | `AdminUserDeleteProcessor` |
997
- | `POST /admin/roles/list` | admin | `AdminRoleListProcessor` |
998
- | `POST /admin/roles/tenant/list` | admin | `RoleListProcessor` |
999
- | `POST /admin/scheduled-tasks` | content manager | `ScheduledTaskDataProcessor` (upsert — send `id` to update) |
1000
- | `POST /admin/scheduled-tasks/list` | content reader | `ScheduledTaskListProcessor` |
1001
- | `GET /admin/scheduled-tasks/:id` | content reader | the row |
1002
- | `POST /admin/scheduled-tasks/:id/delete` | content manager | `ScheduledTaskDeleteProcessor` |
1003
- | `POST /admin/scopes` | content manager | `ScopeDataProcessor` (upsert — send `id` to update) |
1004
- | `POST /admin/scopes/list` | content reader | `ScopeListProcessor` |
1005
- | `GET /admin/scopes/:id` | content reader | the row |
1006
- | `POST /admin/scopes/:id/delete` | content manager | `ScopeService.deleteScope` (cascades to every grant) |
1007
- | `POST /admin/api-keys` | admin | `ApiKeyDataProcessor` — returns `{ raw_key, api_key }` |
1008
- | `POST /admin/api-keys/list` | content reader | `ApiKeyListProcessor` |
1009
- | `GET /admin/api-keys/:id` | content reader | the row, its `scopes`, and `key` from admin up |
1010
- | `POST /admin/api-keys/:id/disable` | admin | `ApiKeyService.disableApiKey` (reversible) |
1011
- | `POST /admin/api-keys/:id/delete` | admin | `ApiKeyService.deleteApiKey` (soft, and revokes) |
1052
+ | Route | Min. role | Handler |
1053
+ | ------------------------------------ | --------------- | --------------------------------------------------------------- |
1054
+ | `POST /admin/tenants` | super admin | `TenantDataProcessor` (upsert — send `id` to update) |
1055
+ | `POST /admin/tenants/list` | content reader | `TenantListProcessor` |
1056
+ | `GET /admin/tenants/:id` | content reader | the row plus its `scopes` |
1057
+ | `DELETE /admin/tenants/:id` | super admin | `TenantDeleteProcessor` (cascades to users, keys, grants) |
1058
+ | `POST /admin/tenant-users` | admin | `ClientUserDataProcessor` |
1059
+ | `POST /admin/tenant-users/bulk` | admin | `BulkUserDataProcessor` |
1060
+ | `POST /admin/tenant-users/list` | content reader | `ClientUserListProcessor` |
1061
+ | `GET /admin/tenant-users/:id` | content reader | the row |
1062
+ | `DELETE /admin/tenant-users/:id` | admin | `ClientUserDeleteProcessor` |
1063
+ | `POST /admin/system-users` | super admin | `SystemUserDataProcessor` (upsert — send `id` to update) |
1064
+ | `POST /admin/system-users/list` | content reader | `SystemUserListProcessor` (scoped to `user_type = system.user`) |
1065
+ | `GET /admin/system-users/:id` | content reader | the row |
1066
+ | `DELETE /admin/system-users/:id` | super admin | `SystemUserService.delete` (revokes live sessions) |
1067
+ | `POST /admin/users` | super admin | `AdminUserDataProcessor` |
1068
+ | `POST /admin/users/list` | content reader | `AdminUserListProcessor` |
1069
+ | `GET /admin/users/:id` | content reader | the row |
1070
+ | `DELETE /admin/users/:id` | super admin | `AdminUserDeleteProcessor` |
1071
+ | `POST /admin/roles/list` | admin | `AdminRoleListProcessor` — picker feed (`sys_admin_roles`) |
1072
+ | `POST /admin/roles/tenant/list` | admin | `RoleListProcessor` — picker feed (`sys_roles`) |
1073
+ | `POST /admin/system-roles` | content manager | `SystemRoleDataProcessor` (upsert — send `id` to update) |
1074
+ | `POST /admin/system-roles/list` | content reader | `RoleListProcessor` |
1075
+ | `GET /admin/system-roles/:id` | content reader | the row |
1076
+ | `DELETE /admin/system-roles/:id` | content manager | `RoleService.deleteRole` (cascades to every grant) |
1077
+ | `POST /admin/scheduled-tasks` | content manager | `ScheduledTaskDataProcessor` (upsert — send `id` to update) |
1078
+ | `POST /admin/scheduled-tasks/list` | content reader | `ScheduledTaskListProcessor` |
1079
+ | `GET /admin/scheduled-tasks/:id` | content reader | the row |
1080
+ | `DELETE /admin/scheduled-tasks/:id` | content manager | `ScheduledTaskDeleteProcessor` |
1081
+ | `POST /admin/email-templates` | content manager | `EmailTemplateDataProcessor` (upsert — send `id` to update) |
1082
+ | `POST /admin/email-templates/list` | content reader | `EmailTemplateListProcessor` |
1083
+ | `GET /admin/email-templates/:id` | content reader | the row |
1084
+ | `DELETE /admin/email-templates/:id` | **admin** | `TemplateService.deleteEmailTemplate` |
1085
+ | `POST /admin/pdf-templates` | content manager | `PdfTemplateDataProcessor` (upsert — send `id` to update) |
1086
+ | `POST /admin/pdf-templates/list` | content reader | `PdfTemplateListProcessor` |
1087
+ | `GET /admin/pdf-templates/:id` | content reader | the row |
1088
+ | `DELETE /admin/pdf-templates/:id` | **admin** | `TemplateService.deletePdfTemplate` |
1089
+ | `POST /admin/scopes` | content manager | `ScopeDataProcessor` (upsert — send `id` to update) |
1090
+ | `POST /admin/scopes/list` | content reader | `ScopeListProcessor` |
1091
+ | `GET /admin/scopes/:id` | content reader | the row |
1092
+ | `DELETE /admin/scopes/:id` | content manager | `ScopeService.deleteScope` (cascades to every grant) |
1093
+ | `POST /admin/api-keys` | admin | `ApiKeyDataProcessor` — returns `{ raw_key, api_key }` |
1094
+ | `POST /admin/api-keys/list` | content reader | `ApiKeyListProcessor` |
1095
+ | `GET /admin/api-keys/:id` | content reader | the row, its `scopes`, and `key` from admin up |
1096
+ | `POST /admin/api-keys/:id/disable` | admin | `ApiKeyService.disableApiKey` (reversible) |
1097
+ | `DELETE /admin/api-keys/:id` | admin | `ApiKeyService.deleteApiKey` (soft, and revokes) |
1012
1098
 
1013
1099
  List endpoints are `POST .../list` with the filter payload in the body (a
1014
1100
  `CommonListFilterDto`) — see [List Endpoints & Filtering](#list-endpoints--filtering).
1015
1101
  Deletes and the API-key disable are single-action, so they sit on the domain service
1016
1102
  rather than in a processor; processors are for the writes that validate a payload.
1017
1103
 
1104
+ **Template catalogues.** `sys_email_templates` and `sys_pdf_templates` are the same
1105
+ surface across two controllers — same routes, same DTO, and a PDF template simply has
1106
+ no `subject` because a document has no envelope to address. Neither row holds markup:
1107
+ `path` + `identifier` are appended to a base-URL system property to reach the remote
1108
+ template service, so the catalogue is a table of pointers.
1109
+
1110
+ Reading is content-reader work and writing content-manager work, the same split scopes
1111
+ get. **Deleting sits one level higher, at global admin** — the one place these differ
1112
+ from every other catalogue. An identifier is named by _code_
1113
+ (`EmailTemplateIdentifier.TENANT_ONBOARDED`, whatever `ProcessPdfDocument` asks for),
1114
+ so deleting a row does not change what a flow says, it stops the flow rendering at all
1115
+ — and only at send/generate time, as an `OperationException`. Nothing cascades: the
1116
+ remote template, every mail already sent and every document already generated are left
1117
+ exactly as they are.
1118
+
1018
1119
  **Scopes and grants.** A scope is defined once in `sys_scopes` (content manager),
1019
1120
  then granted to the principals that hold it. `AddTenantDto.scope_ids` carries the
1020
1121
  tenant's whole scope set — `setScopes()` grants what is new and soft-removes what is
@@ -1 +1 @@
1
- {"version":3,"file":"admin.module.d.ts","sourceRoot":"","sources":["../../src/admin/admin.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAIvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAG9D,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAY9D,qBAMa,WAAW;IACtB,MAAM,CAAC,QAAQ,CAAC,OAAO,GAAE,kBAAuB,GAAG,aAAa;CAcjE"}
1
+ {"version":3,"file":"admin.module.d.ts","sourceRoot":"","sources":["../../src/admin/admin.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAIvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAG9D,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAa9D,qBAMa,WAAW;IACtB,MAAM,CAAC,QAAQ,CAAC,OAAO,GAAE,kBAAuB,GAAG,aAAa;CAcjE"}
@@ -1 +1 @@
1
- {"version":3,"file":"admin.module.js","sourceRoot":"","sources":["../../src/admin/admin.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAuD;AACvD,qDAAiD;AACjD,2DAAuD;AACvD,+CAA2C;AAE3C,6EAAyE;AACzE,6EAAwE;AAmBjE,IAAM,WAAW,mBAAjB,MAAM,WAAW;IACtB,MAAM,CAAC,QAAQ,CAAC,UAA8B,EAAE;QAC9C,OAAO;YACL,MAAM,EAAE,aAAW;YACnB,OAAO,EAAE;gBACP,wBAAU,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAC5B,4BAAY,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAC9B,wCAAkB,CAAC,QAAQ,CAAC,OAAO,CAAC;gBACpC,6CAAoB,CAAC,QAAQ,CAAC,OAAO,CAAC;aACvC;YACD,WAAW,EAAE,CAAC,GAAG,wBAAU,CAAC,WAAW,CAAC;YACxC,SAAS,EAAE,CAAC,GAAG,wBAAU,CAAC,QAAQ,CAAC;YACnC,OAAO,EAAE,CAAC,GAAG,wBAAU,CAAC,QAAQ,CAAC;SAClC,CAAC;IACJ,CAAC;CACF,CAAA;AAfY,kCAAW;sBAAX,WAAW;IANvB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,wBAAU,EAAE,4BAAY,EAAE,wCAAkB,EAAE,6CAAoB,CAAC;QAC7E,WAAW,EAAE,CAAC,GAAG,wBAAU,CAAC,WAAW,CAAC;QACxC,SAAS,EAAE,CAAC,GAAG,wBAAU,CAAC,QAAQ,CAAC;QACnC,OAAO,EAAE,CAAC,GAAG,wBAAU,CAAC,QAAQ,CAAC;KAClC,CAAC;GACW,WAAW,CAevB"}
1
+ {"version":3,"file":"admin.module.js","sourceRoot":"","sources":["../../src/admin/admin.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAuD;AACvD,qDAAiD;AACjD,2DAAuD;AACvD,+CAA2C;AAE3C,6EAAyE;AACzE,6EAAwE;AAoBjE,IAAM,WAAW,mBAAjB,MAAM,WAAW;IACtB,MAAM,CAAC,QAAQ,CAAC,UAA8B,EAAE;QAC9C,OAAO;YACL,MAAM,EAAE,aAAW;YACnB,OAAO,EAAE;gBACP,wBAAU,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAC5B,4BAAY,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAC9B,wCAAkB,CAAC,QAAQ,CAAC,OAAO,CAAC;gBACpC,6CAAoB,CAAC,QAAQ,CAAC,OAAO,CAAC;aACvC;YACD,WAAW,EAAE,CAAC,GAAG,wBAAU,CAAC,WAAW,CAAC;YACxC,SAAS,EAAE,CAAC,GAAG,wBAAU,CAAC,QAAQ,CAAC;YACnC,OAAO,EAAE,CAAC,GAAG,wBAAU,CAAC,QAAQ,CAAC;SAClC,CAAC;IACJ,CAAC;CACF,CAAA;AAfY,kCAAW;sBAAX,WAAW;IANvB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,wBAAU,EAAE,4BAAY,EAAE,wCAAkB,EAAE,6CAAoB,CAAC;QAC7E,WAAW,EAAE,CAAC,GAAG,wBAAU,CAAC,WAAW,CAAC;QACxC,SAAS,EAAE,CAAC,GAAG,wBAAU,CAAC,QAAQ,CAAC;QACnC,OAAO,EAAE,CAAC,GAAG,wBAAU,CAAC,QAAQ,CAAC;KAClC,CAAC;GACW,WAAW,CAevB"}
@@ -98,7 +98,7 @@ __decorate([
98
98
  __metadata("design:returntype", Promise)
99
99
  ], AdminApiKeyController.prototype, "disable", null);
100
100
  __decorate([
101
- (0, common_1.Post)(':id/delete'),
101
+ (0, common_1.Delete)(':id'),
102
102
  (0, swagger_1.ApiOperation)({
103
103
  summary: 'Delete an API key.',
104
104
  description: 'Soft delete: the row keeps its data with `deleted_at` set and drops out of every listing. It is revoked in the same transaction, along with its scope grants — key validation matches on `is_active`/`revoked_at`, so a row that only left the listings would keep authenticating requests. Requires at least the global admin role.',
@@ -1 +1 @@
1
- {"version":3,"file":"admin.api.key.controller.js","sourceRoot":"","sources":["../../../src/admin/controllers/admin.api.key.controller.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"admin.api.key.controller.js","sourceRoot":"","sources":["../../../src/admin/controllers/admin.api.key.controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { SqlService } from '../../common/services/sql.service';
2
+ import { AdminAccessService } from '../services/admin.access.service';
3
+ import { TemplateService } from '../services/template.service';
4
+ import { CommonParamsDto } from '../../common/dtos/common.params.dto';
5
+ import { AddEmailTemplateDto } from '../dtos/add.email.template.dto';
6
+ import { EmailTemplateListDto } from '../dtos/email.template.list.dto';
7
+ import { EmailTemplateEntity } from '../../notification/entities/email.template.entity';
8
+ export declare class AdminEmailTemplateController {
9
+ private readonly adminAccessService;
10
+ private readonly templateService;
11
+ private readonly sqlService;
12
+ constructor(adminAccessService: AdminAccessService, templateService: TemplateService, sqlService: SqlService);
13
+ save(dto: AddEmailTemplateDto): Promise<EmailTemplateEntity>;
14
+ list(dto: EmailTemplateListDto): Promise<{
15
+ records: import("../..").SqlRow[];
16
+ total: number;
17
+ page: number;
18
+ limit: number;
19
+ total_pages: number;
20
+ }>;
21
+ detail({ id }: CommonParamsDto): Promise<EmailTemplateEntity>;
22
+ remove({ id }: CommonParamsDto): Promise<import("../..").DeleteResult>;
23
+ }
24
+ //# sourceMappingURL=admin.email.template.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.email.template.controller.d.ts","sourceRoot":"","sources":["../../../src/admin/controllers/admin.email.template.controller.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAGtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mDAAmD,CAAC;AAQxF,qBAGa,4BAA4B;IAErC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAFV,kBAAkB,EAAE,kBAAkB,EACtC,eAAe,EAAE,eAAe,EAChC,UAAU,EAAE,UAAU;IASnC,IAAI,CAAS,GAAG,EAAE,mBAAmB;IAUrC,IAAI,CAAS,GAAG,EAAE,oBAAoB;;;;;;;IAWtC,MAAM,CAAU,EAAE,EAAE,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAgBtE,MAAM,CAAU,EAAE,EAAE,EAAE,EAAE,eAAe;CAI9C"}
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.AdminEmailTemplateController = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const swagger_1 = require("@nestjs/swagger");
18
+ const sql_service_1 = require("../../common/services/sql.service");
19
+ const admin_access_service_1 = require("../services/admin.access.service");
20
+ const template_service_1 = require("../services/template.service");
21
+ const common_params_dto_1 = require("../../common/dtos/common.params.dto");
22
+ const email_template_data_processor_1 = require("../libraries/email.template.data.processor");
23
+ const email_template_list_processor_1 = require("../libraries/email.template.list.processor");
24
+ const add_email_template_dto_1 = require("../dtos/add.email.template.dto");
25
+ const email_template_list_dto_1 = require("../dtos/email.template.list.dto");
26
+ const email_template_entity_1 = require("../../notification/entities/email.template.entity");
27
+ let AdminEmailTemplateController = class AdminEmailTemplateController {
28
+ constructor(adminAccessService, templateService, sqlService) {
29
+ this.adminAccessService = adminAccessService;
30
+ this.templateService = templateService;
31
+ this.sqlService = sqlService;
32
+ }
33
+ async save(dto) {
34
+ const { user } = await this.adminAccessService.validateContentManager();
35
+ return new email_template_data_processor_1.EmailTemplateDataProcessor(user).process(dto);
36
+ }
37
+ async list(dto) {
38
+ await this.adminAccessService.validateContentReader();
39
+ return new email_template_list_processor_1.EmailTemplateListProcessor(this.sqlService).process(dto);
40
+ }
41
+ async detail({ id }) {
42
+ await this.adminAccessService.validateContentReader();
43
+ const emailTemplate = await email_template_entity_1.EmailTemplateEntity.findOne({ where: { id } });
44
+ if (!emailTemplate)
45
+ throw new common_1.NotFoundException('No email template exists for this id');
46
+ return emailTemplate;
47
+ }
48
+ async remove({ id }) {
49
+ const { user } = await this.adminAccessService.validateAdmin();
50
+ return this.templateService.deleteEmailTemplate(id, user);
51
+ }
52
+ };
53
+ exports.AdminEmailTemplateController = AdminEmailTemplateController;
54
+ __decorate([
55
+ (0, common_1.Post)(),
56
+ (0, swagger_1.ApiOperation)({
57
+ summary: 'Define an email template, or update an existing one.',
58
+ description: 'Send an `id` to edit that template; omit it to define a new one. `identifier` is what sending code names and is unique across the catalogue. Requires at least the global content manager role.',
59
+ }),
60
+ __param(0, (0, common_1.Body)()),
61
+ __metadata("design:type", Function),
62
+ __metadata("design:paramtypes", [add_email_template_dto_1.AddEmailTemplateDto]),
63
+ __metadata("design:returntype", Promise)
64
+ ], AdminEmailTemplateController.prototype, "save", null);
65
+ __decorate([
66
+ (0, common_1.Post)('list'),
67
+ (0, swagger_1.ApiOperation)({
68
+ summary: 'List, search and filter email templates.',
69
+ description: 'Requires at least the global content reader role.',
70
+ }),
71
+ __param(0, (0, common_1.Body)()),
72
+ __metadata("design:type", Function),
73
+ __metadata("design:paramtypes", [email_template_list_dto_1.EmailTemplateListDto]),
74
+ __metadata("design:returntype", Promise)
75
+ ], AdminEmailTemplateController.prototype, "list", null);
76
+ __decorate([
77
+ (0, common_1.Get)(':id'),
78
+ (0, swagger_1.ApiOperation)({
79
+ summary: 'One email template, in full.',
80
+ description: 'Everything the listing leaves out — the `attributes` bag and the authoring trail. Requires at least the global content reader role.',
81
+ }),
82
+ __param(0, (0, common_1.Param)()),
83
+ __metadata("design:type", Function),
84
+ __metadata("design:paramtypes", [common_params_dto_1.CommonParamsDto]),
85
+ __metadata("design:returntype", Promise)
86
+ ], AdminEmailTemplateController.prototype, "detail", null);
87
+ __decorate([
88
+ (0, common_1.Delete)(':id'),
89
+ (0, swagger_1.ApiOperation)({
90
+ summary: 'Delete an email template.',
91
+ description: 'Soft delete: the row keeps its data with `deleted_at` set and drops out of every listing. Nothing cascades — the remote template and every mail already sent from it are untouched — but a flow that still names the identifier stops rendering. Requires at least the global admin role.',
92
+ }),
93
+ __param(0, (0, common_1.Param)()),
94
+ __metadata("design:type", Function),
95
+ __metadata("design:paramtypes", [common_params_dto_1.CommonParamsDto]),
96
+ __metadata("design:returntype", Promise)
97
+ ], AdminEmailTemplateController.prototype, "remove", null);
98
+ exports.AdminEmailTemplateController = AdminEmailTemplateController = __decorate([
99
+ (0, swagger_1.ApiTags)('Admin - Email Templates'),
100
+ (0, swagger_1.ApiBearerAuth)(),
101
+ (0, common_1.Controller)('api/admin/email-templates'),
102
+ __metadata("design:paramtypes", [admin_access_service_1.AdminAccessService,
103
+ template_service_1.TemplateService,
104
+ sql_service_1.SqlService])
105
+ ], AdminEmailTemplateController);
106
+ //# sourceMappingURL=admin.email.template.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.email.template.controller.js","sourceRoot":"","sources":["../../../src/admin/controllers/admin.email.template.controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { SqlService } from '../../common/services/sql.service';
2
+ import { AdminAccessService } from '../services/admin.access.service';
3
+ import { TemplateService } from '../services/template.service';
4
+ import { CommonParamsDto } from '../../common/dtos/common.params.dto';
5
+ import { AddPdfTemplateDto } from '../dtos/add.pdf.template.dto';
6
+ import { PdfTemplateListDto } from '../dtos/pdf.template.list.dto';
7
+ import { PdfTemplateEntity } from '../../document/entities/pdf.template.entity';
8
+ export declare class AdminPdfTemplateController {
9
+ private readonly adminAccessService;
10
+ private readonly templateService;
11
+ private readonly sqlService;
12
+ constructor(adminAccessService: AdminAccessService, templateService: TemplateService, sqlService: SqlService);
13
+ save(dto: AddPdfTemplateDto): Promise<PdfTemplateEntity>;
14
+ list(dto: PdfTemplateListDto): Promise<{
15
+ records: import("../..").SqlRow[];
16
+ total: number;
17
+ page: number;
18
+ limit: number;
19
+ total_pages: number;
20
+ }>;
21
+ detail({ id }: CommonParamsDto): Promise<PdfTemplateEntity>;
22
+ remove({ id }: CommonParamsDto): Promise<import("../..").DeleteResult>;
23
+ }
24
+ //# sourceMappingURL=admin.pdf.template.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.pdf.template.controller.d.ts","sourceRoot":"","sources":["../../../src/admin/controllers/admin.pdf.template.controller.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAGtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAC;AAQhF,qBAGa,0BAA0B;IAEnC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAFV,kBAAkB,EAAE,kBAAkB,EACtC,eAAe,EAAE,eAAe,EAChC,UAAU,EAAE,UAAU;IASnC,IAAI,CAAS,GAAG,EAAE,iBAAiB;IAUnC,IAAI,CAAS,GAAG,EAAE,kBAAkB;;;;;;;IAWpC,MAAM,CAAU,EAAE,EAAE,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAgBpE,MAAM,CAAU,EAAE,EAAE,EAAE,EAAE,eAAe;CAI9C"}