tychat-contracts 1.6.8 → 1.6.9

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.
@@ -1,25 +1,25 @@
1
- name: Publish packages
2
-
3
- on:
4
- workflow_dispatch:
5
- push:
6
- tags:
7
- - 'v*.*.*'
8
-
9
- jobs:
10
- build:
11
- runs-on: ubuntu-latest
12
- permissions:
13
- contents: read
14
- id-token: write
15
- steps:
16
- - uses: actions/checkout@v5
17
- - uses: actions/setup-node@v4
18
- with:
19
- node-version: '20'
20
- registry-url: 'https://registry.npmjs.org'
21
- cache: npm
22
- - run: npm ci
23
- - run: npm publish --provenance --access public
24
- env:
25
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
1
+ name: Publish packages
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ tags:
7
+ - 'v*.*.*'
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ contents: read
14
+ id-token: write
15
+ steps:
16
+ - uses: actions/checkout@v5
17
+ - uses: actions/setup-node@v4
18
+ with:
19
+ node-version: '20'
20
+ registry-url: 'https://registry.npmjs.org'
21
+ cache: npm
22
+ - run: npm ci
23
+ - run: npm publish --provenance --access public
24
+ env:
25
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -1,7 +1,13 @@
1
1
  /** Status do registro de envio na clínica (WhatsApp / fluxo). */
2
2
  export type LegalTermDispatchStatusValue = 'created' | 'sent' | 'failed';
3
3
  /** Status do documento na Clicksign (signature-service). */
4
- export type SignatureDocumentStatusValue = 'pending' | 'signed' | 'refused' | 'cancelled' | 'expired';
4
+ export type SignatureDocumentStatusValue = 'pending' | 'signed' | 'refused' | 'cancelled' | 'expired'
5
+ /** Fluxo impresso: aguardando upload da digitalização assinada (sem registro em signature-service). */
6
+ | 'upload_required';
7
+ /** Método de assinatura escolhido no envio do termo. */
8
+ export type LegalTermSignatureMethodValue = 'digital' | 'printed';
9
+ /** Política por tenant (admin): quais métodos o produto oferece. */
10
+ export type LegalTermSignaturePolicyValue = 'printed_only' | 'printed_and_integrations';
5
11
  /** Item agregado para a ficha do paciente (API: clinic + signature). */
6
12
  export type PatientLegalTermDispatchItemDto = {
7
13
  id: string;
@@ -10,6 +16,7 @@ export type PatientLegalTermDispatchItemDto = {
10
16
  procedure_names: string[];
11
17
  dispatch_status: LegalTermDispatchStatusValue;
12
18
  error_code: string | null;
19
+ signature_method: LegalTermSignatureMethodValue;
13
20
  signature_document_id: string | null;
14
21
  signature_status: SignatureDocumentStatusValue | null;
15
22
  signed_at: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"legal-term-dispatch.dto.d.ts","sourceRoot":"","sources":["../../src/legal-terms/legal-term-dispatch.dto.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,MAAM,4BAA4B,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEzE,4DAA4D;AAC5D,MAAM,MAAM,4BAA4B,GACpC,SAAS,GACT,QAAQ,GACR,SAAS,GACT,WAAW,GACX,SAAS,CAAC;AAEd,wEAAwE;AACxE,MAAM,MAAM,+BAA+B,GAAG;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,EAAE,4BAA4B,CAAC;IAC9C,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,gBAAgB,EAAE,4BAA4B,GAAG,IAAI,CAAC;IACtD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,cAAc,EAAE,OAAO,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,qCAAqC,GAAG;IAClD,KAAK,EAAE,+BAA+B,EAAE,CAAC;CAC1C,CAAC"}
1
+ {"version":3,"file":"legal-term-dispatch.dto.d.ts","sourceRoot":"","sources":["../../src/legal-terms/legal-term-dispatch.dto.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,MAAM,4BAA4B,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEzE,4DAA4D;AAC5D,MAAM,MAAM,4BAA4B,GACpC,SAAS,GACT,QAAQ,GACR,SAAS,GACT,WAAW,GACX,SAAS;AACX,uGAAuG;GACrG,iBAAiB,CAAC;AAEtB,wDAAwD;AACxD,MAAM,MAAM,6BAA6B,GAAG,SAAS,GAAG,SAAS,CAAC;AAElE,oEAAoE;AACpE,MAAM,MAAM,6BAA6B,GACrC,cAAc,GACd,0BAA0B,CAAC;AAE/B,wEAAwE;AACxE,MAAM,MAAM,+BAA+B,GAAG;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,EAAE,4BAA4B,CAAC;IAC9C,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gBAAgB,EAAE,6BAA6B,CAAC;IAChD,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,gBAAgB,EAAE,4BAA4B,GAAG,IAAI,CAAC;IACtD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,cAAc,EAAE,OAAO,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,qCAAqC,GAAG;IAClD,KAAK,EAAE,+BAA+B,EAAE,CAAC;CAC1C,CAAC"}
@@ -1,4 +1,6 @@
1
1
  import { type LegalTermBodyFormat } from './legal-term-body-format';
2
+ declare const LEGAL_TERM_SIGNATURE_METHODS: readonly ["digital", "printed"];
3
+ export type LegalTermSignatureMethodDto = (typeof LEGAL_TERM_SIGNATURE_METHODS)[number];
2
4
  /** Valores explícitos para substituição na pré-visualização (sem inferência heurística). */
3
5
  export declare class LegalTermPreviewRequestDto {
4
6
  body_html?: string;
@@ -10,6 +12,7 @@ export declare class LegalTermPreviewRequestDto {
10
12
  data_hora_iso?: string;
11
13
  }
12
14
  export declare class LegalTermSendDto {
15
+ signatureMethod?: LegalTermSignatureMethodDto;
13
16
  procedureIds: string[];
14
17
  whatsappMessage: string;
15
18
  signerEmail?: string;
@@ -21,4 +24,5 @@ export declare class LegalTermSendDto {
21
24
  tenantSignerDocumentation?: string;
22
25
  tenantSignerPhone?: string;
23
26
  }
27
+ export {};
24
28
  //# sourceMappingURL=legal-term-preview.dto.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"legal-term-preview.dto.d.ts","sourceRoot":"","sources":["../../src/legal-terms/legal-term-preview.dto.ts"],"names":[],"mappings":"AAcA,OAAO,EAA2B,KAAK,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE7F,4FAA4F;AAC5F,qBAAa,0BAA0B;IAQrC,SAAS,CAAC,EAAE,MAAM,CAAC;IAQnB,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAMlC,aAAa,CAAC,EAAE,MAAM,CAAC;IAMvB,WAAW,CAAC,EAAE,MAAM,CAAC;IAMrB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAU9B,+BAA+B,CAAC,EAAE,MAAM,EAAE,CAAC;IAM3C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,gBAAgB;IAI3B,YAAY,EAAE,MAAM,EAAE,CAAC;IASvB,eAAe,EAAE,MAAM,CAAC;IAMxB,WAAW,CAAC,EAAE,MAAM,CAAC;IASrB,WAAW,CAAC,EAAE,MAAM,CAAC;IAQrB,cAAc,CAAC,EAAE,OAAO,CAAC;IAMzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAK1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAO3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAM9B,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAWnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B"}
1
+ {"version":3,"file":"legal-term-preview.dto.d.ts","sourceRoot":"","sources":["../../src/legal-terms/legal-term-preview.dto.ts"],"names":[],"mappings":"AAcA,OAAO,EAA2B,KAAK,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE7F,QAAA,MAAM,4BAA4B,iCAAkC,CAAC;AACrE,MAAM,MAAM,2BAA2B,GAAG,CAAC,OAAO,4BAA4B,CAAC,CAAC,MAAM,CAAC,CAAC;AAExF,4FAA4F;AAC5F,qBAAa,0BAA0B;IAQrC,SAAS,CAAC,EAAE,MAAM,CAAC;IAQnB,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAMlC,aAAa,CAAC,EAAE,MAAM,CAAC;IAMvB,WAAW,CAAC,EAAE,MAAM,CAAC;IAMrB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAU9B,+BAA+B,CAAC,EAAE,MAAM,EAAE,CAAC;IAM3C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,gBAAgB;IAS3B,eAAe,CAAC,EAAE,2BAA2B,CAAC;IAK9C,YAAY,EAAE,MAAM,EAAE,CAAC;IAUvB,eAAe,EAAE,MAAM,CAAC;IAMxB,WAAW,CAAC,EAAE,MAAM,CAAC;IASrB,WAAW,CAAC,EAAE,MAAM,CAAC;IAQrB,cAAc,CAAC,EAAE,OAAO,CAAC;IAMzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAK1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAO3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAM9B,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAWnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B"}
@@ -13,6 +13,7 @@ exports.LegalTermSendDto = exports.LegalTermPreviewRequestDto = void 0;
13
13
  const swagger_1 = require("@nestjs/swagger");
14
14
  const class_validator_1 = require("class-validator");
15
15
  const legal_term_body_format_1 = require("./legal-term-body-format");
16
+ const LEGAL_TERM_SIGNATURE_METHODS = ['digital', 'printed'];
16
17
  /** Valores explícitos para substituição na pré-visualização (sem inferência heurística). */
17
18
  class LegalTermPreviewRequestDto {
18
19
  body_html;
@@ -82,6 +83,7 @@ __decorate([
82
83
  __metadata("design:type", String)
83
84
  ], LegalTermPreviewRequestDto.prototype, "data_hora_iso", void 0);
84
85
  class LegalTermSendDto {
86
+ signatureMethod;
85
87
  procedureIds;
86
88
  whatsappMessage;
87
89
  signerEmail;
@@ -94,6 +96,16 @@ class LegalTermSendDto {
94
96
  tenantSignerPhone;
95
97
  }
96
98
  exports.LegalTermSendDto = LegalTermSendDto;
99
+ __decorate([
100
+ (0, swagger_1.ApiPropertyOptional)({
101
+ enum: LEGAL_TERM_SIGNATURE_METHODS,
102
+ description: 'Método de assinatura: digital (Clicksign + link no WhatsApp) ou printed (PDF para impressão, sem Clicksign). Padrão: digital.',
103
+ default: 'digital',
104
+ }),
105
+ (0, class_validator_1.IsOptional)(),
106
+ (0, class_validator_1.IsIn)(LEGAL_TERM_SIGNATURE_METHODS),
107
+ __metadata("design:type", String)
108
+ ], LegalTermSendDto.prototype, "signatureMethod", void 0);
97
109
  __decorate([
98
110
  (0, swagger_1.ApiProperty)({ type: [String], format: 'uuid' }),
99
111
  (0, class_validator_1.IsArray)(),
@@ -102,7 +114,7 @@ __decorate([
102
114
  ], LegalTermSendDto.prototype, "procedureIds", void 0);
103
115
  __decorate([
104
116
  (0, swagger_1.ApiProperty)({
105
- description: 'Mensagem WhatsApp; deve conter exatamente {{ link_termo_juridico }}',
117
+ description: 'Mensagem WhatsApp. Com signatureMethod digital (padrão), deve conter exatamente {{ link_termo_juridico }}. Com printed, qualquer texto (sem esse placeholder).',
106
118
  example: 'Olá, assine seu termo: {{ link_termo_juridico }}',
107
119
  }),
108
120
  (0, class_validator_1.IsString)(),
package/package.json CHANGED
@@ -1,29 +1,29 @@
1
- {
2
- "name": "tychat-contracts",
3
- "version": "1.6.8",
4
- "description": "DTOs compartilhados com class-validator (API e microserviços)",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "private": false,
8
- "scripts": {
9
- "build": "tsc",
10
- "prepublishOnly": "npm run build"
11
- },
12
- "dependencies": {
13
- "class-transformer": "^0.5.1",
14
- "class-validator": "^0.14.1",
15
- "ioredis": "^5.10.0",
16
- "jest": "^30.3.0",
17
- "reflect-metadata": "*"
18
- },
19
- "devDependencies": {
20
- "@nestjs/swagger": "^11.2.6",
21
- "@types/jest": "^30.0.0",
22
- "ts-jest": "^29.4.9",
23
- "typescript": "^5.7.3"
24
- },
25
- "peerDependencies": {
26
- "@nestjs/swagger": "^11.2.6",
27
- "reflect-metadata": "*"
28
- }
29
- }
1
+ {
2
+ "name": "tychat-contracts",
3
+ "version": "1.6.9",
4
+ "description": "DTOs compartilhados com class-validator (API e microserviços)",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "private": false,
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "prepublishOnly": "npm run build"
11
+ },
12
+ "dependencies": {
13
+ "class-transformer": "^0.5.1",
14
+ "class-validator": "^0.14.1",
15
+ "ioredis": "^5.10.0",
16
+ "jest": "^30.3.0",
17
+ "reflect-metadata": "*"
18
+ },
19
+ "devDependencies": {
20
+ "@nestjs/swagger": "^11.2.6",
21
+ "@types/jest": "^30.0.0",
22
+ "ts-jest": "^29.4.9",
23
+ "typescript": "^5.7.3"
24
+ },
25
+ "peerDependencies": {
26
+ "@nestjs/swagger": "^11.2.6",
27
+ "reflect-metadata": "*"
28
+ }
29
+ }
@@ -1,24 +1,24 @@
1
- /**
2
- * Kafka topic names used by the analytics service.
3
- */
4
-
5
- /** Topic for ingesting analytic events from all microservices. */
6
- export const TOPIC_ANALYTICS_EVENT = 'analytics.event';
7
-
8
- /** Topic for requesting a report grouped by event type and period. */
9
- export const TOPIC_ANALYTICS_REPORT = 'analytics.report';
10
-
11
- /** Topic for requesting a dashboard summary (counts per domain). */
12
- export const TOPIC_ANALYTICS_DASHBOARD = 'analytics.dashboard';
13
-
14
- /** Topic for requesting a time-series breakdown of events. */
15
- export const TOPIC_ANALYTICS_TIMESERIES = 'analytics.timeseries';
16
-
17
- /** Topic for requesting event details with pagination. */
18
- export const TOPIC_ANALYTICS_EVENTS_LIST = 'analytics.events.list';
19
-
20
- /** Topic for ingesting tenant user-action audit rows (dedicated table). */
21
- export const TOPIC_ANALYTICS_TENANT_AUDIT_INGEST = 'analytics.tenant_audit.ingest';
22
-
23
- /** Topic for paginated tenant audit log listing. */
24
- export const TOPIC_ANALYTICS_TENANT_AUDIT_LIST = 'analytics.tenant_audit.list';
1
+ /**
2
+ * Kafka topic names used by the analytics service.
3
+ */
4
+
5
+ /** Topic for ingesting analytic events from all microservices. */
6
+ export const TOPIC_ANALYTICS_EVENT = 'analytics.event';
7
+
8
+ /** Topic for requesting a report grouped by event type and period. */
9
+ export const TOPIC_ANALYTICS_REPORT = 'analytics.report';
10
+
11
+ /** Topic for requesting a dashboard summary (counts per domain). */
12
+ export const TOPIC_ANALYTICS_DASHBOARD = 'analytics.dashboard';
13
+
14
+ /** Topic for requesting a time-series breakdown of events. */
15
+ export const TOPIC_ANALYTICS_TIMESERIES = 'analytics.timeseries';
16
+
17
+ /** Topic for requesting event details with pagination. */
18
+ export const TOPIC_ANALYTICS_EVENTS_LIST = 'analytics.events.list';
19
+
20
+ /** Topic for ingesting tenant user-action audit rows (dedicated table). */
21
+ export const TOPIC_ANALYTICS_TENANT_AUDIT_INGEST = 'analytics.tenant_audit.ingest';
22
+
23
+ /** Topic for paginated tenant audit log listing. */
24
+ export const TOPIC_ANALYTICS_TENANT_AUDIT_LIST = 'analytics.tenant_audit.list';
@@ -1,105 +1,105 @@
1
- import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
2
- import {
3
- IsIn,
4
- IsInt,
5
- IsISO8601,
6
- IsNotEmpty,
7
- IsObject,
8
- IsOptional,
9
- IsString,
10
- IsUUID,
11
- Max,
12
- MaxLength,
13
- Min,
14
- MinLength,
15
- } from 'class-validator';
16
-
17
- /** Outcome of the audited HTTP mutation. */
18
- export const TENANT_AUDIT_OUTCOMES = ['success', 'failure'] as const;
19
- export type TenantAuditOutcome = (typeof TENANT_AUDIT_OUTCOMES)[number];
20
-
21
- /**
22
- * Payload for persisting a tenant-scoped user action audit row (HTTP mutation).
23
- */
24
- export class CreateTenantAuditLogDto {
25
- @ApiProperty({ description: 'Unique id for idempotent insert', format: 'uuid' })
26
- @IsUUID()
27
- eventId: string;
28
-
29
- @ApiProperty({ description: 'Tenant slug' })
30
- @IsString()
31
- @IsNotEmpty()
32
- @MinLength(1)
33
- @MaxLength(255)
34
- tenant: string;
35
-
36
- @ApiProperty({ example: 'user', description: 'Actor category' })
37
- @IsString()
38
- @IsNotEmpty()
39
- @MaxLength(64)
40
- actorType: string;
41
-
42
- @ApiProperty({ description: 'Authenticated user id (sub)' })
43
- @IsString()
44
- @IsNotEmpty()
45
- @MaxLength(255)
46
- actorId: string;
47
-
48
- @ApiProperty({
49
- example: 'http.mutation',
50
- description: 'Deterministic action key (e.g. http.mutation)',
51
- })
52
- @IsString()
53
- @IsNotEmpty()
54
- @MaxLength(128)
55
- action: string;
56
-
57
- @ApiPropertyOptional({ example: 'http' })
58
- @IsOptional()
59
- @IsString()
60
- @MaxLength(64)
61
- targetType?: string | null;
62
-
63
- @ApiPropertyOptional({ description: 'Route param id when present' })
64
- @IsOptional()
65
- @IsString()
66
- @MaxLength(255)
67
- targetId?: string | null;
68
-
69
- @ApiProperty({ enum: TENANT_AUDIT_OUTCOMES })
70
- @IsIn([...TENANT_AUDIT_OUTCOMES])
71
- outcome: TenantAuditOutcome;
72
-
73
- @ApiProperty({ example: 'POST' })
74
- @IsString()
75
- @IsNotEmpty()
76
- @MaxLength(16)
77
- httpMethod: string;
78
-
79
- @ApiProperty({ example: '/patients/123' })
80
- @IsString()
81
- @IsNotEmpty()
82
- @MaxLength(2048)
83
- httpPath: string;
84
-
85
- @ApiProperty({ example: 201 })
86
- @IsInt()
87
- @Min(100)
88
- @Max(599)
89
- httpStatus: number;
90
-
91
- @ApiPropertyOptional({ description: 'On failure, stable error code if available' })
92
- @IsOptional()
93
- @IsString()
94
- @MaxLength(128)
95
- errorCode?: string | null;
96
-
97
- @ApiPropertyOptional({ description: 'Minimal non-PII context' })
98
- @IsOptional()
99
- @IsObject()
100
- metadata?: Record<string, unknown> | null;
101
-
102
- @ApiProperty({ description: 'When the action completed (UTC ISO-8601)' })
103
- @IsISO8601()
104
- occurredAt: string;
105
- }
1
+ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
2
+ import {
3
+ IsIn,
4
+ IsInt,
5
+ IsISO8601,
6
+ IsNotEmpty,
7
+ IsObject,
8
+ IsOptional,
9
+ IsString,
10
+ IsUUID,
11
+ Max,
12
+ MaxLength,
13
+ Min,
14
+ MinLength,
15
+ } from 'class-validator';
16
+
17
+ /** Outcome of the audited HTTP mutation. */
18
+ export const TENANT_AUDIT_OUTCOMES = ['success', 'failure'] as const;
19
+ export type TenantAuditOutcome = (typeof TENANT_AUDIT_OUTCOMES)[number];
20
+
21
+ /**
22
+ * Payload for persisting a tenant-scoped user action audit row (HTTP mutation).
23
+ */
24
+ export class CreateTenantAuditLogDto {
25
+ @ApiProperty({ description: 'Unique id for idempotent insert', format: 'uuid' })
26
+ @IsUUID()
27
+ eventId: string;
28
+
29
+ @ApiProperty({ description: 'Tenant slug' })
30
+ @IsString()
31
+ @IsNotEmpty()
32
+ @MinLength(1)
33
+ @MaxLength(255)
34
+ tenant: string;
35
+
36
+ @ApiProperty({ example: 'user', description: 'Actor category' })
37
+ @IsString()
38
+ @IsNotEmpty()
39
+ @MaxLength(64)
40
+ actorType: string;
41
+
42
+ @ApiProperty({ description: 'Authenticated user id (sub)' })
43
+ @IsString()
44
+ @IsNotEmpty()
45
+ @MaxLength(255)
46
+ actorId: string;
47
+
48
+ @ApiProperty({
49
+ example: 'http.mutation',
50
+ description: 'Deterministic action key (e.g. http.mutation)',
51
+ })
52
+ @IsString()
53
+ @IsNotEmpty()
54
+ @MaxLength(128)
55
+ action: string;
56
+
57
+ @ApiPropertyOptional({ example: 'http' })
58
+ @IsOptional()
59
+ @IsString()
60
+ @MaxLength(64)
61
+ targetType?: string | null;
62
+
63
+ @ApiPropertyOptional({ description: 'Route param id when present' })
64
+ @IsOptional()
65
+ @IsString()
66
+ @MaxLength(255)
67
+ targetId?: string | null;
68
+
69
+ @ApiProperty({ enum: TENANT_AUDIT_OUTCOMES })
70
+ @IsIn([...TENANT_AUDIT_OUTCOMES])
71
+ outcome: TenantAuditOutcome;
72
+
73
+ @ApiProperty({ example: 'POST' })
74
+ @IsString()
75
+ @IsNotEmpty()
76
+ @MaxLength(16)
77
+ httpMethod: string;
78
+
79
+ @ApiProperty({ example: '/patients/123' })
80
+ @IsString()
81
+ @IsNotEmpty()
82
+ @MaxLength(2048)
83
+ httpPath: string;
84
+
85
+ @ApiProperty({ example: 201 })
86
+ @IsInt()
87
+ @Min(100)
88
+ @Max(599)
89
+ httpStatus: number;
90
+
91
+ @ApiPropertyOptional({ description: 'On failure, stable error code if available' })
92
+ @IsOptional()
93
+ @IsString()
94
+ @MaxLength(128)
95
+ errorCode?: string | null;
96
+
97
+ @ApiPropertyOptional({ description: 'Minimal non-PII context' })
98
+ @IsOptional()
99
+ @IsObject()
100
+ metadata?: Record<string, unknown> | null;
101
+
102
+ @ApiProperty({ description: 'When the action completed (UTC ISO-8601)' })
103
+ @IsISO8601()
104
+ occurredAt: string;
105
+ }
@@ -1,8 +1,8 @@
1
- export * from './event-analytic.enum';
2
- export * from './followup-analytic-event-type.util';
3
- export * from './create-analytic-event.dto';
4
- export * from './create-tenant-audit-log.dto';
5
- export * from './list-tenant-audit-logs-query.dto';
6
- export * from './analytics-query.dto';
7
- export * from './analytics-kafka-topics';
8
- export * from './analytics-emitter.helper';
1
+ export * from './event-analytic.enum';
2
+ export * from './followup-analytic-event-type.util';
3
+ export * from './create-analytic-event.dto';
4
+ export * from './create-tenant-audit-log.dto';
5
+ export * from './list-tenant-audit-logs-query.dto';
6
+ export * from './analytics-query.dto';
7
+ export * from './analytics-kafka-topics';
8
+ export * from './analytics-emitter.helper';
@@ -1,45 +1,45 @@
1
- import { ApiPropertyOptional } from '@nestjs/swagger';
2
- import { Type } from 'class-transformer';
3
- import { IsInt, IsOptional, Max, Min } from 'class-validator';
4
- import type { ParsedFilterDto } from '../filters/parsed-filter.dto';
5
-
6
- /**
7
- * Allowed tenant_audit_logs columns for filtering (camelCase API keys).
8
- */
9
- export const TENANT_AUDIT_LIST_FILTER_KEYS = [
10
- 'actorId',
11
- 'action',
12
- 'outcome',
13
- 'httpMethod',
14
- 'httpPath',
15
- 'httpStatus',
16
- 'occurredAt',
17
- ] as const;
18
- export type TenantAuditListFilterKeyDto = (typeof TENANT_AUDIT_LIST_FILTER_KEYS)[number];
19
-
20
- export class ListTenantAuditLogsQueryDto {
21
- @ApiPropertyOptional({ example: 1, minimum: 1, default: 1 })
22
- @IsOptional()
23
- @Type(() => Number)
24
- @IsInt()
25
- @Min(1)
26
- page?: number;
27
-
28
- @ApiPropertyOptional({ example: 20, minimum: 1, maximum: 100, default: 20 })
29
- @IsOptional()
30
- @Type(() => Number)
31
- @IsInt()
32
- @Min(1)
33
- @Max(100)
34
- limit?: number;
35
-
36
- @ApiPropertyOptional({
37
- description:
38
- 'JSON string with an array of filter objects `{ key, op, value }`. ' +
39
- 'Example: `[{"key":"outcome","op":"==","value":"success"}]`.',
40
- type: String,
41
- example: '[{"key":"outcome","op":"==","value":"success"}]',
42
- })
43
- @IsOptional()
44
- filters?: ParsedFilterDto[];
45
- }
1
+ import { ApiPropertyOptional } from '@nestjs/swagger';
2
+ import { Type } from 'class-transformer';
3
+ import { IsInt, IsOptional, Max, Min } from 'class-validator';
4
+ import type { ParsedFilterDto } from '../filters/parsed-filter.dto';
5
+
6
+ /**
7
+ * Allowed tenant_audit_logs columns for filtering (camelCase API keys).
8
+ */
9
+ export const TENANT_AUDIT_LIST_FILTER_KEYS = [
10
+ 'actorId',
11
+ 'action',
12
+ 'outcome',
13
+ 'httpMethod',
14
+ 'httpPath',
15
+ 'httpStatus',
16
+ 'occurredAt',
17
+ ] as const;
18
+ export type TenantAuditListFilterKeyDto = (typeof TENANT_AUDIT_LIST_FILTER_KEYS)[number];
19
+
20
+ export class ListTenantAuditLogsQueryDto {
21
+ @ApiPropertyOptional({ example: 1, minimum: 1, default: 1 })
22
+ @IsOptional()
23
+ @Type(() => Number)
24
+ @IsInt()
25
+ @Min(1)
26
+ page?: number;
27
+
28
+ @ApiPropertyOptional({ example: 20, minimum: 1, maximum: 100, default: 20 })
29
+ @IsOptional()
30
+ @Type(() => Number)
31
+ @IsInt()
32
+ @Min(1)
33
+ @Max(100)
34
+ limit?: number;
35
+
36
+ @ApiPropertyOptional({
37
+ description:
38
+ 'JSON string with an array of filter objects `{ key, op, value }`. ' +
39
+ 'Example: `[{"key":"outcome","op":"==","value":"success"}]`.',
40
+ type: String,
41
+ example: '[{"key":"outcome","op":"==","value":"success"}]',
42
+ })
43
+ @IsOptional()
44
+ filters?: ParsedFilterDto[];
45
+ }