tychat-contracts 1.4.5 → 1.4.7

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 (29) hide show
  1. package/dist/analytics/analytics-kafka-topics.d.ts +4 -0
  2. package/dist/analytics/analytics-kafka-topics.d.ts.map +1 -1
  3. package/dist/analytics/analytics-kafka-topics.js +5 -1
  4. package/dist/analytics/create-tenant-audit-log.dto.d.ts +23 -0
  5. package/dist/analytics/create-tenant-audit-log.dto.d.ts.map +1 -0
  6. package/dist/analytics/create-tenant-audit-log.dto.js +131 -0
  7. package/dist/analytics/index.d.ts +2 -0
  8. package/dist/analytics/index.d.ts.map +1 -1
  9. package/dist/analytics/index.js +2 -0
  10. package/dist/analytics/list-tenant-audit-logs-query.dto.d.ts +12 -0
  11. package/dist/analytics/list-tenant-audit-logs-query.dto.d.ts.map +1 -0
  12. package/dist/analytics/list-tenant-audit-logs-query.dto.js +60 -0
  13. package/dist/storage/index.d.ts +2 -0
  14. package/dist/storage/index.d.ts.map +1 -1
  15. package/dist/storage/index.js +2 -0
  16. package/dist/storage/presign-download-rpc.dto.d.ts +12 -0
  17. package/dist/storage/presign-download-rpc.dto.d.ts.map +1 -0
  18. package/dist/storage/presign-download-rpc.dto.js +64 -0
  19. package/dist/storage/storage-rmq-patterns.d.ts +5 -0
  20. package/dist/storage/storage-rmq-patterns.d.ts.map +1 -0
  21. package/dist/storage/storage-rmq-patterns.js +7 -0
  22. package/package.json +1 -1
  23. package/src/analytics/analytics-kafka-topics.ts +6 -0
  24. package/src/analytics/create-tenant-audit-log.dto.ts +105 -0
  25. package/src/analytics/index.ts +2 -0
  26. package/src/analytics/list-tenant-audit-logs-query.dto.ts +45 -0
  27. package/src/storage/index.ts +2 -0
  28. package/src/storage/presign-download-rpc.dto.ts +38 -0
  29. package/src/storage/storage-rmq-patterns.ts +5 -0
@@ -11,4 +11,8 @@ export declare const TOPIC_ANALYTICS_DASHBOARD = "analytics.dashboard";
11
11
  export declare const TOPIC_ANALYTICS_TIMESERIES = "analytics.timeseries";
12
12
  /** Topic for requesting event details with pagination. */
13
13
  export declare const TOPIC_ANALYTICS_EVENTS_LIST = "analytics.events.list";
14
+ /** Topic for ingesting tenant user-action audit rows (dedicated table). */
15
+ export declare const TOPIC_ANALYTICS_TENANT_AUDIT_INGEST = "analytics.tenant_audit.ingest";
16
+ /** Topic for paginated tenant audit log listing. */
17
+ export declare const TOPIC_ANALYTICS_TENANT_AUDIT_LIST = "analytics.tenant_audit.list";
14
18
  //# sourceMappingURL=analytics-kafka-topics.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"analytics-kafka-topics.d.ts","sourceRoot":"","sources":["../../src/analytics/analytics-kafka-topics.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,kEAAkE;AAClE,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AAEvD,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAEzD,oEAAoE;AACpE,eAAO,MAAM,yBAAyB,wBAAwB,CAAC;AAE/D,8DAA8D;AAC9D,eAAO,MAAM,0BAA0B,yBAAyB,CAAC;AAEjE,0DAA0D;AAC1D,eAAO,MAAM,2BAA2B,0BAA0B,CAAC"}
1
+ {"version":3,"file":"analytics-kafka-topics.d.ts","sourceRoot":"","sources":["../../src/analytics/analytics-kafka-topics.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,kEAAkE;AAClE,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AAEvD,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAEzD,oEAAoE;AACpE,eAAO,MAAM,yBAAyB,wBAAwB,CAAC;AAE/D,8DAA8D;AAC9D,eAAO,MAAM,0BAA0B,yBAAyB,CAAC;AAEjE,0DAA0D;AAC1D,eAAO,MAAM,2BAA2B,0BAA0B,CAAC;AAEnE,2EAA2E;AAC3E,eAAO,MAAM,mCAAmC,kCAAkC,CAAC;AAEnF,oDAAoD;AACpD,eAAO,MAAM,iCAAiC,gCAAgC,CAAC"}
@@ -3,7 +3,7 @@
3
3
  * Kafka topic names used by the analytics service.
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.TOPIC_ANALYTICS_EVENTS_LIST = exports.TOPIC_ANALYTICS_TIMESERIES = exports.TOPIC_ANALYTICS_DASHBOARD = exports.TOPIC_ANALYTICS_REPORT = exports.TOPIC_ANALYTICS_EVENT = void 0;
6
+ exports.TOPIC_ANALYTICS_TENANT_AUDIT_LIST = exports.TOPIC_ANALYTICS_TENANT_AUDIT_INGEST = exports.TOPIC_ANALYTICS_EVENTS_LIST = exports.TOPIC_ANALYTICS_TIMESERIES = exports.TOPIC_ANALYTICS_DASHBOARD = exports.TOPIC_ANALYTICS_REPORT = exports.TOPIC_ANALYTICS_EVENT = void 0;
7
7
  /** Topic for ingesting analytic events from all microservices. */
8
8
  exports.TOPIC_ANALYTICS_EVENT = 'analytics.event';
9
9
  /** Topic for requesting a report grouped by event type and period. */
@@ -14,3 +14,7 @@ exports.TOPIC_ANALYTICS_DASHBOARD = 'analytics.dashboard';
14
14
  exports.TOPIC_ANALYTICS_TIMESERIES = 'analytics.timeseries';
15
15
  /** Topic for requesting event details with pagination. */
16
16
  exports.TOPIC_ANALYTICS_EVENTS_LIST = 'analytics.events.list';
17
+ /** Topic for ingesting tenant user-action audit rows (dedicated table). */
18
+ exports.TOPIC_ANALYTICS_TENANT_AUDIT_INGEST = 'analytics.tenant_audit.ingest';
19
+ /** Topic for paginated tenant audit log listing. */
20
+ exports.TOPIC_ANALYTICS_TENANT_AUDIT_LIST = 'analytics.tenant_audit.list';
@@ -0,0 +1,23 @@
1
+ /** Outcome of the audited HTTP mutation. */
2
+ export declare const TENANT_AUDIT_OUTCOMES: readonly ["success", "failure"];
3
+ export type TenantAuditOutcome = (typeof TENANT_AUDIT_OUTCOMES)[number];
4
+ /**
5
+ * Payload for persisting a tenant-scoped user action audit row (HTTP mutation).
6
+ */
7
+ export declare class CreateTenantAuditLogDto {
8
+ eventId: string;
9
+ tenant: string;
10
+ actorType: string;
11
+ actorId: string;
12
+ action: string;
13
+ targetType?: string | null;
14
+ targetId?: string | null;
15
+ outcome: TenantAuditOutcome;
16
+ httpMethod: string;
17
+ httpPath: string;
18
+ httpStatus: number;
19
+ errorCode?: string | null;
20
+ metadata?: Record<string, unknown> | null;
21
+ occurredAt: string;
22
+ }
23
+ //# sourceMappingURL=create-tenant-audit-log.dto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-tenant-audit-log.dto.d.ts","sourceRoot":"","sources":["../../src/analytics/create-tenant-audit-log.dto.ts"],"names":[],"mappings":"AAgBA,4CAA4C;AAC5C,eAAO,MAAM,qBAAqB,iCAAkC,CAAC;AACrE,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE;;GAEG;AACH,qBAAa,uBAAuB;IAGlC,OAAO,EAAE,MAAM,CAAC;IAOhB,MAAM,EAAE,MAAM,CAAC;IAMf,SAAS,EAAE,MAAM,CAAC;IAMlB,OAAO,EAAE,MAAM,CAAC;IAShB,MAAM,EAAE,MAAM,CAAC;IAMf,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAM3B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAIzB,OAAO,EAAE,kBAAkB,CAAC;IAM5B,UAAU,EAAE,MAAM,CAAC;IAMnB,QAAQ,EAAE,MAAM,CAAC;IAMjB,UAAU,EAAE,MAAM,CAAC;IAMnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAK1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAI1C,UAAU,EAAE,MAAM,CAAC;CACpB"}
@@ -0,0 +1,131 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.CreateTenantAuditLogDto = exports.TENANT_AUDIT_OUTCOMES = void 0;
13
+ const swagger_1 = require("@nestjs/swagger");
14
+ const class_validator_1 = require("class-validator");
15
+ /** Outcome of the audited HTTP mutation. */
16
+ exports.TENANT_AUDIT_OUTCOMES = ['success', 'failure'];
17
+ /**
18
+ * Payload for persisting a tenant-scoped user action audit row (HTTP mutation).
19
+ */
20
+ class CreateTenantAuditLogDto {
21
+ eventId;
22
+ tenant;
23
+ actorType;
24
+ actorId;
25
+ action;
26
+ targetType;
27
+ targetId;
28
+ outcome;
29
+ httpMethod;
30
+ httpPath;
31
+ httpStatus;
32
+ errorCode;
33
+ metadata;
34
+ occurredAt;
35
+ }
36
+ exports.CreateTenantAuditLogDto = CreateTenantAuditLogDto;
37
+ __decorate([
38
+ (0, swagger_1.ApiProperty)({ description: 'Unique id for idempotent insert', format: 'uuid' }),
39
+ (0, class_validator_1.IsUUID)(),
40
+ __metadata("design:type", String)
41
+ ], CreateTenantAuditLogDto.prototype, "eventId", void 0);
42
+ __decorate([
43
+ (0, swagger_1.ApiProperty)({ description: 'Tenant slug' }),
44
+ (0, class_validator_1.IsString)(),
45
+ (0, class_validator_1.IsNotEmpty)(),
46
+ (0, class_validator_1.MinLength)(1),
47
+ (0, class_validator_1.MaxLength)(255),
48
+ __metadata("design:type", String)
49
+ ], CreateTenantAuditLogDto.prototype, "tenant", void 0);
50
+ __decorate([
51
+ (0, swagger_1.ApiProperty)({ example: 'user', description: 'Actor category' }),
52
+ (0, class_validator_1.IsString)(),
53
+ (0, class_validator_1.IsNotEmpty)(),
54
+ (0, class_validator_1.MaxLength)(64),
55
+ __metadata("design:type", String)
56
+ ], CreateTenantAuditLogDto.prototype, "actorType", void 0);
57
+ __decorate([
58
+ (0, swagger_1.ApiProperty)({ description: 'Authenticated user id (sub)' }),
59
+ (0, class_validator_1.IsString)(),
60
+ (0, class_validator_1.IsNotEmpty)(),
61
+ (0, class_validator_1.MaxLength)(255),
62
+ __metadata("design:type", String)
63
+ ], CreateTenantAuditLogDto.prototype, "actorId", void 0);
64
+ __decorate([
65
+ (0, swagger_1.ApiProperty)({
66
+ example: 'http.mutation',
67
+ description: 'Deterministic action key (e.g. http.mutation)',
68
+ }),
69
+ (0, class_validator_1.IsString)(),
70
+ (0, class_validator_1.IsNotEmpty)(),
71
+ (0, class_validator_1.MaxLength)(128),
72
+ __metadata("design:type", String)
73
+ ], CreateTenantAuditLogDto.prototype, "action", void 0);
74
+ __decorate([
75
+ (0, swagger_1.ApiPropertyOptional)({ example: 'http' }),
76
+ (0, class_validator_1.IsOptional)(),
77
+ (0, class_validator_1.IsString)(),
78
+ (0, class_validator_1.MaxLength)(64),
79
+ __metadata("design:type", Object)
80
+ ], CreateTenantAuditLogDto.prototype, "targetType", void 0);
81
+ __decorate([
82
+ (0, swagger_1.ApiPropertyOptional)({ description: 'Route param id when present' }),
83
+ (0, class_validator_1.IsOptional)(),
84
+ (0, class_validator_1.IsString)(),
85
+ (0, class_validator_1.MaxLength)(255),
86
+ __metadata("design:type", Object)
87
+ ], CreateTenantAuditLogDto.prototype, "targetId", void 0);
88
+ __decorate([
89
+ (0, swagger_1.ApiProperty)({ enum: exports.TENANT_AUDIT_OUTCOMES }),
90
+ (0, class_validator_1.IsIn)([...exports.TENANT_AUDIT_OUTCOMES]),
91
+ __metadata("design:type", String)
92
+ ], CreateTenantAuditLogDto.prototype, "outcome", void 0);
93
+ __decorate([
94
+ (0, swagger_1.ApiProperty)({ example: 'POST' }),
95
+ (0, class_validator_1.IsString)(),
96
+ (0, class_validator_1.IsNotEmpty)(),
97
+ (0, class_validator_1.MaxLength)(16),
98
+ __metadata("design:type", String)
99
+ ], CreateTenantAuditLogDto.prototype, "httpMethod", void 0);
100
+ __decorate([
101
+ (0, swagger_1.ApiProperty)({ example: '/patients/123' }),
102
+ (0, class_validator_1.IsString)(),
103
+ (0, class_validator_1.IsNotEmpty)(),
104
+ (0, class_validator_1.MaxLength)(2048),
105
+ __metadata("design:type", String)
106
+ ], CreateTenantAuditLogDto.prototype, "httpPath", void 0);
107
+ __decorate([
108
+ (0, swagger_1.ApiProperty)({ example: 201 }),
109
+ (0, class_validator_1.IsInt)(),
110
+ (0, class_validator_1.Min)(100),
111
+ (0, class_validator_1.Max)(599),
112
+ __metadata("design:type", Number)
113
+ ], CreateTenantAuditLogDto.prototype, "httpStatus", void 0);
114
+ __decorate([
115
+ (0, swagger_1.ApiPropertyOptional)({ description: 'On failure, stable error code if available' }),
116
+ (0, class_validator_1.IsOptional)(),
117
+ (0, class_validator_1.IsString)(),
118
+ (0, class_validator_1.MaxLength)(128),
119
+ __metadata("design:type", Object)
120
+ ], CreateTenantAuditLogDto.prototype, "errorCode", void 0);
121
+ __decorate([
122
+ (0, swagger_1.ApiPropertyOptional)({ description: 'Minimal non-PII context' }),
123
+ (0, class_validator_1.IsOptional)(),
124
+ (0, class_validator_1.IsObject)(),
125
+ __metadata("design:type", Object)
126
+ ], CreateTenantAuditLogDto.prototype, "metadata", void 0);
127
+ __decorate([
128
+ (0, swagger_1.ApiProperty)({ description: 'When the action completed (UTC ISO-8601)' }),
129
+ (0, class_validator_1.IsISO8601)(),
130
+ __metadata("design:type", String)
131
+ ], CreateTenantAuditLogDto.prototype, "occurredAt", void 0);
@@ -1,6 +1,8 @@
1
1
  export * from './event-analytic.enum';
2
2
  export * from './followup-analytic-event-type.util';
3
3
  export * from './create-analytic-event.dto';
4
+ export * from './create-tenant-audit-log.dto';
5
+ export * from './list-tenant-audit-logs-query.dto';
4
6
  export * from './analytics-query.dto';
5
7
  export * from './analytics-kafka-topics';
6
8
  export * from './analytics-emitter.helper';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,qCAAqC,CAAC;AACpD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,qCAAqC,CAAC;AACpD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oCAAoC,CAAC;AACnD,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC"}
@@ -17,6 +17,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./event-analytic.enum"), exports);
18
18
  __exportStar(require("./followup-analytic-event-type.util"), exports);
19
19
  __exportStar(require("./create-analytic-event.dto"), exports);
20
+ __exportStar(require("./create-tenant-audit-log.dto"), exports);
21
+ __exportStar(require("./list-tenant-audit-logs-query.dto"), exports);
20
22
  __exportStar(require("./analytics-query.dto"), exports);
21
23
  __exportStar(require("./analytics-kafka-topics"), exports);
22
24
  __exportStar(require("./analytics-emitter.helper"), exports);
@@ -0,0 +1,12 @@
1
+ import type { ParsedFilterDto } from '../filters/parsed-filter.dto';
2
+ /**
3
+ * Allowed tenant_audit_logs columns for filtering (camelCase API keys).
4
+ */
5
+ export declare const TENANT_AUDIT_LIST_FILTER_KEYS: readonly ["actorId", "action", "outcome", "httpMethod", "httpPath", "httpStatus", "occurredAt"];
6
+ export type TenantAuditListFilterKeyDto = (typeof TENANT_AUDIT_LIST_FILTER_KEYS)[number];
7
+ export declare class ListTenantAuditLogsQueryDto {
8
+ page?: number;
9
+ limit?: number;
10
+ filters?: ParsedFilterDto[];
11
+ }
12
+ //# sourceMappingURL=list-tenant-audit-logs-query.dto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-tenant-audit-logs-query.dto.d.ts","sourceRoot":"","sources":["../../src/analytics/list-tenant-audit-logs-query.dto.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE;;GAEG;AACH,eAAO,MAAM,6BAA6B,iGAQhC,CAAC;AACX,MAAM,MAAM,2BAA2B,GAAG,CAAC,OAAO,6BAA6B,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzF,qBAAa,2BAA2B;IAMtC,IAAI,CAAC,EAAE,MAAM,CAAC;IAQd,KAAK,CAAC,EAAE,MAAM,CAAC;IAUf,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;CAC7B"}
@@ -0,0 +1,60 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ListTenantAuditLogsQueryDto = exports.TENANT_AUDIT_LIST_FILTER_KEYS = void 0;
13
+ const swagger_1 = require("@nestjs/swagger");
14
+ const class_transformer_1 = require("class-transformer");
15
+ const class_validator_1 = require("class-validator");
16
+ /**
17
+ * Allowed tenant_audit_logs columns for filtering (camelCase API keys).
18
+ */
19
+ exports.TENANT_AUDIT_LIST_FILTER_KEYS = [
20
+ 'actorId',
21
+ 'action',
22
+ 'outcome',
23
+ 'httpMethod',
24
+ 'httpPath',
25
+ 'httpStatus',
26
+ 'occurredAt',
27
+ ];
28
+ class ListTenantAuditLogsQueryDto {
29
+ page;
30
+ limit;
31
+ filters;
32
+ }
33
+ exports.ListTenantAuditLogsQueryDto = ListTenantAuditLogsQueryDto;
34
+ __decorate([
35
+ (0, swagger_1.ApiPropertyOptional)({ example: 1, minimum: 1, default: 1 }),
36
+ (0, class_validator_1.IsOptional)(),
37
+ (0, class_transformer_1.Type)(() => Number),
38
+ (0, class_validator_1.IsInt)(),
39
+ (0, class_validator_1.Min)(1),
40
+ __metadata("design:type", Number)
41
+ ], ListTenantAuditLogsQueryDto.prototype, "page", void 0);
42
+ __decorate([
43
+ (0, swagger_1.ApiPropertyOptional)({ example: 20, minimum: 1, maximum: 100, default: 20 }),
44
+ (0, class_validator_1.IsOptional)(),
45
+ (0, class_transformer_1.Type)(() => Number),
46
+ (0, class_validator_1.IsInt)(),
47
+ (0, class_validator_1.Min)(1),
48
+ (0, class_validator_1.Max)(100),
49
+ __metadata("design:type", Number)
50
+ ], ListTenantAuditLogsQueryDto.prototype, "limit", void 0);
51
+ __decorate([
52
+ (0, swagger_1.ApiPropertyOptional)({
53
+ description: 'JSON string with an array of filter objects `{ key, op, value }`. ' +
54
+ 'Example: `[{"key":"outcome","op":"==","value":"success"}]`.',
55
+ type: String,
56
+ example: '[{"key":"outcome","op":"==","value":"success"}]',
57
+ }),
58
+ (0, class_validator_1.IsOptional)(),
59
+ __metadata("design:type", Array)
60
+ ], ListTenantAuditLogsQueryDto.prototype, "filters", void 0);
@@ -4,4 +4,6 @@ export * from './delete-object.dto';
4
4
  export * from './presigned-url-response.dto';
5
5
  export * from './exists-query.dto';
6
6
  export * from './issue-upload-token.dto';
7
+ export * from './presign-download-rpc.dto';
8
+ export * from './storage-rmq-patterns';
7
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC"}
@@ -20,3 +20,5 @@ __exportStar(require("./delete-object.dto"), exports);
20
20
  __exportStar(require("./presigned-url-response.dto"), exports);
21
21
  __exportStar(require("./exists-query.dto"), exports);
22
22
  __exportStar(require("./issue-upload-token.dto"), exports);
23
+ __exportStar(require("./presign-download-rpc.dto"), exports);
24
+ __exportStar(require("./storage-rmq-patterns"), exports);
@@ -0,0 +1,12 @@
1
+ /** RMQ: `tychat-api` pede URL presigned GET após validar o documento no patient-service (confiança interna). */
2
+ export declare class PresignDownloadRpcDto {
3
+ tenantSlug: string;
4
+ objectKey: string;
5
+ expiresInSeconds?: number;
6
+ }
7
+ export declare class PresignDownloadRpcResultDto {
8
+ url: string;
9
+ expiresAt: number;
10
+ expiresInSeconds: number;
11
+ }
12
+ //# sourceMappingURL=presign-download-rpc.dto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presign-download-rpc.dto.d.ts","sourceRoot":"","sources":["../../src/storage/presign-download-rpc.dto.ts"],"names":[],"mappings":"AAGA,gHAAgH;AAChH,qBAAa,qBAAqB;IAKhC,UAAU,EAAE,MAAM,CAAC;IAMnB,SAAS,EAAE,MAAM,CAAC;IAUlB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,2BAA2B;IAEtC,GAAG,EAAE,MAAM,CAAC;IAGZ,SAAS,EAAE,MAAM,CAAC;IAGlB,gBAAgB,EAAE,MAAM,CAAC;CAC1B"}
@@ -0,0 +1,64 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.PresignDownloadRpcResultDto = exports.PresignDownloadRpcDto = void 0;
13
+ const swagger_1 = require("@nestjs/swagger");
14
+ const class_validator_1 = require("class-validator");
15
+ /** RMQ: `tychat-api` pede URL presigned GET após validar o documento no patient-service (confiança interna). */
16
+ class PresignDownloadRpcDto {
17
+ tenantSlug;
18
+ objectKey;
19
+ expiresInSeconds;
20
+ }
21
+ exports.PresignDownloadRpcDto = PresignDownloadRpcDto;
22
+ __decorate([
23
+ (0, swagger_1.ApiProperty)({ description: 'Tenant slug (deve corresponder ao prefixo do objectKey)', example: 'clinica_sampaio' }),
24
+ (0, class_validator_1.IsString)(),
25
+ (0, class_validator_1.MinLength)(1),
26
+ (0, class_validator_1.MaxLength)(255),
27
+ __metadata("design:type", String)
28
+ ], PresignDownloadRpcDto.prototype, "tenantSlug", void 0);
29
+ __decorate([
30
+ (0, swagger_1.ApiProperty)({ description: 'Chave S3 do objeto', example: 'tenants/clinica_sampaio/patients/.../doc.pdf' }),
31
+ (0, class_validator_1.IsString)(),
32
+ (0, class_validator_1.MinLength)(1),
33
+ (0, class_validator_1.MaxLength)(2048),
34
+ __metadata("design:type", String)
35
+ ], PresignDownloadRpcDto.prototype, "objectKey", void 0);
36
+ __decorate([
37
+ (0, swagger_1.ApiPropertyOptional)({
38
+ description: 'TTL da URL em segundos (60–3600; predefinido no storage)',
39
+ example: 300,
40
+ }),
41
+ (0, class_validator_1.IsOptional)(),
42
+ (0, class_validator_1.IsInt)(),
43
+ (0, class_validator_1.Min)(60),
44
+ (0, class_validator_1.Max)(3600),
45
+ __metadata("design:type", Number)
46
+ ], PresignDownloadRpcDto.prototype, "expiresInSeconds", void 0);
47
+ class PresignDownloadRpcResultDto {
48
+ url;
49
+ expiresAt;
50
+ expiresInSeconds;
51
+ }
52
+ exports.PresignDownloadRpcResultDto = PresignDownloadRpcResultDto;
53
+ __decorate([
54
+ (0, swagger_1.ApiProperty)({ description: 'URL GET presigned' }),
55
+ __metadata("design:type", String)
56
+ ], PresignDownloadRpcResultDto.prototype, "url", void 0);
57
+ __decorate([
58
+ (0, swagger_1.ApiProperty)({ description: 'Unix timestamp (ms) quando a URL expira' }),
59
+ __metadata("design:type", Number)
60
+ ], PresignDownloadRpcResultDto.prototype, "expiresAt", void 0);
61
+ __decorate([
62
+ (0, swagger_1.ApiProperty)({ description: 'TTL em segundos' }),
63
+ __metadata("design:type", Number)
64
+ ], PresignDownloadRpcResultDto.prototype, "expiresInSeconds", void 0);
@@ -0,0 +1,5 @@
1
+ /** Pedido de token OTT para HTTP POST /storage/presign-upload */
2
+ export declare const STORAGE_ISSUE_UPLOAD_TOKEN = "storage.issueUploadToken";
3
+ /** URL presigned GET (chamada interna; sem JWT HTTP para o storage) */
4
+ export declare const STORAGE_PRESIGN_DOWNLOAD = "storage.presignDownload";
5
+ //# sourceMappingURL=storage-rmq-patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-rmq-patterns.d.ts","sourceRoot":"","sources":["../../src/storage/storage-rmq-patterns.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,eAAO,MAAM,0BAA0B,6BAA6B,CAAC;AAErE,uEAAuE;AACvE,eAAO,MAAM,wBAAwB,4BAA4B,CAAC"}
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.STORAGE_PRESIGN_DOWNLOAD = exports.STORAGE_ISSUE_UPLOAD_TOKEN = void 0;
4
+ /** Pedido de token OTT para HTTP POST /storage/presign-upload */
5
+ exports.STORAGE_ISSUE_UPLOAD_TOKEN = 'storage.issueUploadToken';
6
+ /** URL presigned GET (chamada interna; sem JWT HTTP para o storage) */
7
+ exports.STORAGE_PRESIGN_DOWNLOAD = 'storage.presignDownload';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tychat-contracts",
3
- "version": "1.4.5",
3
+ "version": "1.4.7",
4
4
  "description": "DTOs compartilhados com class-validator (API e microserviços)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -16,3 +16,9 @@ export const TOPIC_ANALYTICS_TIMESERIES = 'analytics.timeseries';
16
16
 
17
17
  /** Topic for requesting event details with pagination. */
18
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';
@@ -0,0 +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,6 +1,8 @@
1
1
  export * from './event-analytic.enum';
2
2
  export * from './followup-analytic-event-type.util';
3
3
  export * from './create-analytic-event.dto';
4
+ export * from './create-tenant-audit-log.dto';
5
+ export * from './list-tenant-audit-logs-query.dto';
4
6
  export * from './analytics-query.dto';
5
7
  export * from './analytics-kafka-topics';
6
8
  export * from './analytics-emitter.helper';
@@ -0,0 +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
+ }
@@ -4,3 +4,5 @@ export * from './delete-object.dto';
4
4
  export * from './presigned-url-response.dto';
5
5
  export * from './exists-query.dto';
6
6
  export * from './issue-upload-token.dto';
7
+ export * from './presign-download-rpc.dto';
8
+ export * from './storage-rmq-patterns';
@@ -0,0 +1,38 @@
1
+ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
2
+ import { IsInt, IsOptional, IsString, Max, MaxLength, Min, MinLength } from 'class-validator';
3
+
4
+ /** RMQ: `tychat-api` pede URL presigned GET após validar o documento no patient-service (confiança interna). */
5
+ export class PresignDownloadRpcDto {
6
+ @ApiProperty({ description: 'Tenant slug (deve corresponder ao prefixo do objectKey)', example: 'clinica_sampaio' })
7
+ @IsString()
8
+ @MinLength(1)
9
+ @MaxLength(255)
10
+ tenantSlug: string;
11
+
12
+ @ApiProperty({ description: 'Chave S3 do objeto', example: 'tenants/clinica_sampaio/patients/.../doc.pdf' })
13
+ @IsString()
14
+ @MinLength(1)
15
+ @MaxLength(2048)
16
+ objectKey: string;
17
+
18
+ @ApiPropertyOptional({
19
+ description: 'TTL da URL em segundos (60–3600; predefinido no storage)',
20
+ example: 300,
21
+ })
22
+ @IsOptional()
23
+ @IsInt()
24
+ @Min(60)
25
+ @Max(3600)
26
+ expiresInSeconds?: number;
27
+ }
28
+
29
+ export class PresignDownloadRpcResultDto {
30
+ @ApiProperty({ description: 'URL GET presigned' })
31
+ url: string;
32
+
33
+ @ApiProperty({ description: 'Unix timestamp (ms) quando a URL expira' })
34
+ expiresAt: number;
35
+
36
+ @ApiProperty({ description: 'TTL em segundos' })
37
+ expiresInSeconds: number;
38
+ }
@@ -0,0 +1,5 @@
1
+ /** Pedido de token OTT para HTTP POST /storage/presign-upload */
2
+ export const STORAGE_ISSUE_UPLOAD_TOKEN = 'storage.issueUploadToken';
3
+
4
+ /** URL presigned GET (chamada interna; sem JWT HTTP para o storage) */
5
+ export const STORAGE_PRESIGN_DOWNLOAD = 'storage.presignDownload';