tychat-contracts 1.0.76 → 1.0.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics/analytics-kafka-topics.d.ts +14 -0
- package/dist/analytics/analytics-kafka-topics.d.ts.map +1 -0
- package/dist/analytics/analytics-kafka-topics.js +16 -0
- package/dist/analytics/analytics-query.dto.d.ts +25 -0
- package/dist/analytics/analytics-query.dto.d.ts.map +1 -0
- package/dist/analytics/analytics-query.dto.js +108 -0
- package/dist/analytics/create-analytic-event.dto.d.ts +15 -0
- package/dist/analytics/create-analytic-event.dto.d.ts.map +1 -0
- package/dist/analytics/create-analytic-event.dto.js +104 -0
- package/dist/analytics/event-analytic.enum.d.ts +7 -0
- package/dist/analytics/event-analytic.enum.d.ts.map +1 -0
- package/dist/analytics/event-analytic.enum.js +81 -0
- package/dist/analytics/index.d.ts +5 -0
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/index.js +20 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/package.json +1 -1
- package/src/analytics/analytics-kafka-topics.ts +18 -0
- package/src/analytics/analytics-query.dto.ts +89 -0
- package/src/analytics/create-analytic-event.dto.ts +85 -0
- package/src/analytics/event-analytic.enum.ts +98 -0
- package/src/analytics/index.ts +4 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kafka topic names used by the analytics service.
|
|
3
|
+
*/
|
|
4
|
+
/** Topic for ingesting analytic events from all microservices. */
|
|
5
|
+
export declare const TOPIC_ANALYTICS_EVENT = "analytics.event";
|
|
6
|
+
/** Topic for requesting a report grouped by event type and period. */
|
|
7
|
+
export declare const TOPIC_ANALYTICS_REPORT = "analytics.report";
|
|
8
|
+
/** Topic for requesting a dashboard summary (counts per domain). */
|
|
9
|
+
export declare const TOPIC_ANALYTICS_DASHBOARD = "analytics.dashboard";
|
|
10
|
+
/** Topic for requesting a time-series breakdown of events. */
|
|
11
|
+
export declare const TOPIC_ANALYTICS_TIMESERIES = "analytics.timeseries";
|
|
12
|
+
/** Topic for requesting event details with pagination. */
|
|
13
|
+
export declare const TOPIC_ANALYTICS_EVENTS_LIST = "analytics.events.list";
|
|
14
|
+
//# sourceMappingURL=analytics-kafka-topics.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Kafka topic names used by the analytics service.
|
|
4
|
+
*/
|
|
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;
|
|
7
|
+
/** Topic for ingesting analytic events from all microservices. */
|
|
8
|
+
exports.TOPIC_ANALYTICS_EVENT = 'analytics.event';
|
|
9
|
+
/** Topic for requesting a report grouped by event type and period. */
|
|
10
|
+
exports.TOPIC_ANALYTICS_REPORT = 'analytics.report';
|
|
11
|
+
/** Topic for requesting a dashboard summary (counts per domain). */
|
|
12
|
+
exports.TOPIC_ANALYTICS_DASHBOARD = 'analytics.dashboard';
|
|
13
|
+
/** Topic for requesting a time-series breakdown of events. */
|
|
14
|
+
exports.TOPIC_ANALYTICS_TIMESERIES = 'analytics.timeseries';
|
|
15
|
+
/** Topic for requesting event details with pagination. */
|
|
16
|
+
exports.TOPIC_ANALYTICS_EVENTS_LIST = 'analytics.events.list';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { EventAnalyticType } from './event-analytic.enum';
|
|
2
|
+
/**
|
|
3
|
+
* Grouping granularity for time-series report data.
|
|
4
|
+
*/
|
|
5
|
+
export declare const ANALYTICS_GROUP_BY: readonly ["hour", "day", "week", "month"];
|
|
6
|
+
export type AnalyticsGroupBy = (typeof ANALYTICS_GROUP_BY)[number];
|
|
7
|
+
/**
|
|
8
|
+
* Query DTO used to request analytics reports.
|
|
9
|
+
*/
|
|
10
|
+
export declare class AnalyticsReportQueryDto {
|
|
11
|
+
startDate: string;
|
|
12
|
+
endDate: string;
|
|
13
|
+
eventType?: EventAnalyticType;
|
|
14
|
+
groupBy?: AnalyticsGroupBy;
|
|
15
|
+
page?: number;
|
|
16
|
+
limit?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Query DTO for the dashboard summary endpoint.
|
|
20
|
+
*/
|
|
21
|
+
export declare class AnalyticsDashboardQueryDto {
|
|
22
|
+
startDate: string;
|
|
23
|
+
endDate: string;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=analytics-query.dto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics-query.dto.d.ts","sourceRoot":"","sources":["../../src/analytics/analytics-query.dto.ts"],"names":[],"mappings":"AAYA,OAAO,EAAwB,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAEhF;;GAEG;AACH,eAAO,MAAM,kBAAkB,2CAA4C,CAAC;AAC5E,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnE;;GAEG;AACH,qBAAa,uBAAuB;IAMlC,SAAS,EAAE,MAAM,CAAC;IAOlB,OAAO,EAAE,MAAM,CAAC;IAShB,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAS9B,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAO3B,IAAI,CAAC,EAAE,MAAM,CAAC;IAOd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,0BAA0B;IAMrC,SAAS,EAAE,MAAM,CAAC;IAOlB,OAAO,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
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.AnalyticsDashboardQueryDto = exports.AnalyticsReportQueryDto = exports.ANALYTICS_GROUP_BY = void 0;
|
|
13
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
const class_transformer_1 = require("class-transformer");
|
|
16
|
+
const event_analytic_enum_1 = require("./event-analytic.enum");
|
|
17
|
+
/**
|
|
18
|
+
* Grouping granularity for time-series report data.
|
|
19
|
+
*/
|
|
20
|
+
exports.ANALYTICS_GROUP_BY = ['hour', 'day', 'week', 'month'];
|
|
21
|
+
/**
|
|
22
|
+
* Query DTO used to request analytics reports.
|
|
23
|
+
*/
|
|
24
|
+
class AnalyticsReportQueryDto {
|
|
25
|
+
startDate;
|
|
26
|
+
endDate;
|
|
27
|
+
eventType;
|
|
28
|
+
groupBy;
|
|
29
|
+
page;
|
|
30
|
+
limit;
|
|
31
|
+
}
|
|
32
|
+
exports.AnalyticsReportQueryDto = AnalyticsReportQueryDto;
|
|
33
|
+
__decorate([
|
|
34
|
+
(0, swagger_1.ApiProperty)({
|
|
35
|
+
description: 'Start of the reporting period (inclusive)',
|
|
36
|
+
example: '2026-03-01T00:00:00.000Z',
|
|
37
|
+
}),
|
|
38
|
+
(0, class_validator_1.IsISO8601)(),
|
|
39
|
+
__metadata("design:type", String)
|
|
40
|
+
], AnalyticsReportQueryDto.prototype, "startDate", void 0);
|
|
41
|
+
__decorate([
|
|
42
|
+
(0, swagger_1.ApiProperty)({
|
|
43
|
+
description: 'End of the reporting period (exclusive)',
|
|
44
|
+
example: '2026-04-01T00:00:00.000Z',
|
|
45
|
+
}),
|
|
46
|
+
(0, class_validator_1.IsISO8601)(),
|
|
47
|
+
__metadata("design:type", String)
|
|
48
|
+
], AnalyticsReportQueryDto.prototype, "endDate", void 0);
|
|
49
|
+
__decorate([
|
|
50
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
51
|
+
description: 'Filter by event type',
|
|
52
|
+
enum: event_analytic_enum_1.EVENT_ANALYTIC_TYPES,
|
|
53
|
+
example: 'patient.created',
|
|
54
|
+
}),
|
|
55
|
+
(0, class_validator_1.IsOptional)(),
|
|
56
|
+
(0, class_validator_1.IsIn)([...event_analytic_enum_1.EVENT_ANALYTIC_TYPES]),
|
|
57
|
+
__metadata("design:type", String)
|
|
58
|
+
], AnalyticsReportQueryDto.prototype, "eventType", void 0);
|
|
59
|
+
__decorate([
|
|
60
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
61
|
+
description: 'Group results by time granularity',
|
|
62
|
+
enum: exports.ANALYTICS_GROUP_BY,
|
|
63
|
+
example: 'day',
|
|
64
|
+
}),
|
|
65
|
+
(0, class_validator_1.IsOptional)(),
|
|
66
|
+
(0, class_validator_1.IsIn)([...exports.ANALYTICS_GROUP_BY]),
|
|
67
|
+
__metadata("design:type", String)
|
|
68
|
+
], AnalyticsReportQueryDto.prototype, "groupBy", void 0);
|
|
69
|
+
__decorate([
|
|
70
|
+
(0, swagger_1.ApiPropertyOptional)({ description: 'Page number (starts at 1)', example: 1 }),
|
|
71
|
+
(0, class_validator_1.IsOptional)(),
|
|
72
|
+
(0, class_transformer_1.Type)(() => Number),
|
|
73
|
+
(0, class_validator_1.IsPositive)(),
|
|
74
|
+
(0, class_validator_1.Min)(1),
|
|
75
|
+
__metadata("design:type", Number)
|
|
76
|
+
], AnalyticsReportQueryDto.prototype, "page", void 0);
|
|
77
|
+
__decorate([
|
|
78
|
+
(0, swagger_1.ApiPropertyOptional)({ description: 'Records per page', example: 20 }),
|
|
79
|
+
(0, class_validator_1.IsOptional)(),
|
|
80
|
+
(0, class_transformer_1.Type)(() => Number),
|
|
81
|
+
(0, class_validator_1.IsPositive)(),
|
|
82
|
+
(0, class_validator_1.Min)(1),
|
|
83
|
+
__metadata("design:type", Number)
|
|
84
|
+
], AnalyticsReportQueryDto.prototype, "limit", void 0);
|
|
85
|
+
/**
|
|
86
|
+
* Query DTO for the dashboard summary endpoint.
|
|
87
|
+
*/
|
|
88
|
+
class AnalyticsDashboardQueryDto {
|
|
89
|
+
startDate;
|
|
90
|
+
endDate;
|
|
91
|
+
}
|
|
92
|
+
exports.AnalyticsDashboardQueryDto = AnalyticsDashboardQueryDto;
|
|
93
|
+
__decorate([
|
|
94
|
+
(0, swagger_1.ApiProperty)({
|
|
95
|
+
description: 'Start of the reporting period (inclusive)',
|
|
96
|
+
example: '2026-03-01T00:00:00.000Z',
|
|
97
|
+
}),
|
|
98
|
+
(0, class_validator_1.IsISO8601)(),
|
|
99
|
+
__metadata("design:type", String)
|
|
100
|
+
], AnalyticsDashboardQueryDto.prototype, "startDate", void 0);
|
|
101
|
+
__decorate([
|
|
102
|
+
(0, swagger_1.ApiProperty)({
|
|
103
|
+
description: 'End of the reporting period (exclusive)',
|
|
104
|
+
example: '2026-04-01T00:00:00.000Z',
|
|
105
|
+
}),
|
|
106
|
+
(0, class_validator_1.IsISO8601)(),
|
|
107
|
+
__metadata("design:type", String)
|
|
108
|
+
], AnalyticsDashboardQueryDto.prototype, "endDate", void 0);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { EventAnalyticType } from './event-analytic.enum';
|
|
2
|
+
/**
|
|
3
|
+
* Payload that every microservice must send to the analytics topic.
|
|
4
|
+
*/
|
|
5
|
+
export declare class CreateAnalyticEventDto {
|
|
6
|
+
eventId: string;
|
|
7
|
+
tenant: string;
|
|
8
|
+
eventType: EventAnalyticType;
|
|
9
|
+
entityId?: string;
|
|
10
|
+
source?: string;
|
|
11
|
+
userId?: string;
|
|
12
|
+
metadata?: Record<string, unknown>;
|
|
13
|
+
occurredAt: string;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=create-analytic-event.dto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-analytic-event.dto.d.ts","sourceRoot":"","sources":["../../src/analytics/create-analytic-event.dto.ts"],"names":[],"mappings":"AAYA,OAAO,EAAwB,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAEhF;;GAEG;AACH,qBAAa,sBAAsB;IAMjC,OAAO,EAAE,MAAM,CAAC;IAUhB,MAAM,EAAE,MAAM,CAAC;IAQf,SAAS,EAAE,iBAAiB,CAAC;IAS7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IASlB,MAAM,CAAC,EAAE,MAAM,CAAC;IAShB,MAAM,CAAC,EAAE,MAAM,CAAC;IAQhB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAOnC,UAAU,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -0,0 +1,104 @@
|
|
|
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.CreateAnalyticEventDto = void 0;
|
|
13
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
const event_analytic_enum_1 = require("./event-analytic.enum");
|
|
16
|
+
/**
|
|
17
|
+
* Payload that every microservice must send to the analytics topic.
|
|
18
|
+
*/
|
|
19
|
+
class CreateAnalyticEventDto {
|
|
20
|
+
eventId;
|
|
21
|
+
tenant;
|
|
22
|
+
eventType;
|
|
23
|
+
entityId;
|
|
24
|
+
source;
|
|
25
|
+
userId;
|
|
26
|
+
metadata;
|
|
27
|
+
occurredAt;
|
|
28
|
+
}
|
|
29
|
+
exports.CreateAnalyticEventDto = CreateAnalyticEventDto;
|
|
30
|
+
__decorate([
|
|
31
|
+
(0, swagger_1.ApiProperty)({
|
|
32
|
+
description: 'Unique event ID for idempotent processing',
|
|
33
|
+
example: 'f3f50ecb-fb71-4d4b-a0dd-910ef6e3fd0a',
|
|
34
|
+
}),
|
|
35
|
+
(0, class_validator_1.IsUUID)(),
|
|
36
|
+
__metadata("design:type", String)
|
|
37
|
+
], CreateAnalyticEventDto.prototype, "eventId", void 0);
|
|
38
|
+
__decorate([
|
|
39
|
+
(0, swagger_1.ApiProperty)({
|
|
40
|
+
description: 'Tenant slug that originated the event',
|
|
41
|
+
example: 'homolog',
|
|
42
|
+
}),
|
|
43
|
+
(0, class_validator_1.IsString)(),
|
|
44
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
45
|
+
(0, class_validator_1.MinLength)(1),
|
|
46
|
+
(0, class_validator_1.MaxLength)(255),
|
|
47
|
+
__metadata("design:type", String)
|
|
48
|
+
], CreateAnalyticEventDto.prototype, "tenant", void 0);
|
|
49
|
+
__decorate([
|
|
50
|
+
(0, swagger_1.ApiProperty)({
|
|
51
|
+
description: 'Type of analytic event',
|
|
52
|
+
enum: event_analytic_enum_1.EVENT_ANALYTIC_TYPES,
|
|
53
|
+
example: 'patient.created',
|
|
54
|
+
}),
|
|
55
|
+
(0, class_validator_1.IsIn)([...event_analytic_enum_1.EVENT_ANALYTIC_TYPES]),
|
|
56
|
+
__metadata("design:type", String)
|
|
57
|
+
], CreateAnalyticEventDto.prototype, "eventType", void 0);
|
|
58
|
+
__decorate([
|
|
59
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
60
|
+
description: 'ID of the entity related to this event (patient, appointment, etc.)',
|
|
61
|
+
example: '3c593727-4505-495a-a054-c052acb4cf19',
|
|
62
|
+
}),
|
|
63
|
+
(0, class_validator_1.IsOptional)(),
|
|
64
|
+
(0, class_validator_1.IsString)(),
|
|
65
|
+
(0, class_validator_1.MaxLength)(255),
|
|
66
|
+
__metadata("design:type", String)
|
|
67
|
+
], CreateAnalyticEventDto.prototype, "entityId", void 0);
|
|
68
|
+
__decorate([
|
|
69
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
70
|
+
description: 'Name of the source microservice',
|
|
71
|
+
example: 'tychat-patient-service',
|
|
72
|
+
}),
|
|
73
|
+
(0, class_validator_1.IsOptional)(),
|
|
74
|
+
(0, class_validator_1.IsString)(),
|
|
75
|
+
(0, class_validator_1.MaxLength)(255),
|
|
76
|
+
__metadata("design:type", String)
|
|
77
|
+
], CreateAnalyticEventDto.prototype, "source", void 0);
|
|
78
|
+
__decorate([
|
|
79
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
80
|
+
description: 'Optional user ID who triggered the action',
|
|
81
|
+
example: 'a1b2c3d4-e5f6-4789-abcd-ef0123456789',
|
|
82
|
+
}),
|
|
83
|
+
(0, class_validator_1.IsOptional)(),
|
|
84
|
+
(0, class_validator_1.IsString)(),
|
|
85
|
+
(0, class_validator_1.MaxLength)(255),
|
|
86
|
+
__metadata("design:type", String)
|
|
87
|
+
], CreateAnalyticEventDto.prototype, "userId", void 0);
|
|
88
|
+
__decorate([
|
|
89
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
90
|
+
description: 'Additional metadata for the event (flexible JSON)',
|
|
91
|
+
example: { previousStatus: 'pending', newStatus: 'finished' },
|
|
92
|
+
}),
|
|
93
|
+
(0, class_validator_1.IsOptional)(),
|
|
94
|
+
(0, class_validator_1.IsObject)(),
|
|
95
|
+
__metadata("design:type", Object)
|
|
96
|
+
], CreateAnalyticEventDto.prototype, "metadata", void 0);
|
|
97
|
+
__decorate([
|
|
98
|
+
(0, swagger_1.ApiProperty)({
|
|
99
|
+
description: 'ISO 8601 timestamp when the event occurred',
|
|
100
|
+
example: '2026-04-02T12:00:00.000Z',
|
|
101
|
+
}),
|
|
102
|
+
(0, class_validator_1.IsISO8601)(),
|
|
103
|
+
__metadata("design:type", String)
|
|
104
|
+
], CreateAnalyticEventDto.prototype, "occurredAt", void 0);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enum of all analytic event types emitted by microservices.
|
|
3
|
+
* Each value follows the pattern: `domain.action`.
|
|
4
|
+
*/
|
|
5
|
+
export declare const EVENT_ANALYTIC_TYPES: readonly ["patient.created", "patient.updated", "patient.deleted", "patient.status_changed", "appointment.created", "appointment.updated", "appointment.canceled", "appointment.rescheduled", "appointment.no_show", "appointment.finished", "checkin.effectued", "checkout.effectued", "message.sent", "message.received", "conversation.session_started", "conversation.session_ended", "conversation.transferred_to_human", "followup.triggered", "followup.completed", "followup.config_updated", "payment.created", "payment.payed", "payment.refunded", "payment.canceled", "payment.overdue", "billing.invoice_created", "billing.invoice_paid", "ai.interaction", "ai.fallback", "auth.login", "auth.logout", "auth.password_reset", "user.created", "user.updated", "user.deleted", "notification.sent", "notification.failed", "whatsapp.connection_established", "whatsapp.connection_lost", "procedure.created", "procedure.updated", "procedure.deleted", "specialty.created", "specialty.updated", "specialty.deleted", "professional.created", "professional.updated", "professional.deleted", "configuration.updated", "storage.file_uploaded", "storage.file_deleted", "tenant.created", "tenant.updated"];
|
|
6
|
+
export type EventAnalyticType = (typeof EVENT_ANALYTIC_TYPES)[number];
|
|
7
|
+
//# sourceMappingURL=event-analytic.enum.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-analytic.enum.d.ts","sourceRoot":"","sources":["../../src/analytics/event-analytic.enum.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,oBAAoB,6pCA2FvB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EVENT_ANALYTIC_TYPES = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Enum of all analytic event types emitted by microservices.
|
|
6
|
+
* Each value follows the pattern: `domain.action`.
|
|
7
|
+
*/
|
|
8
|
+
exports.EVENT_ANALYTIC_TYPES = [
|
|
9
|
+
// ── Patient events ──────────────────────────────────────────────
|
|
10
|
+
'patient.created',
|
|
11
|
+
'patient.updated',
|
|
12
|
+
'patient.deleted',
|
|
13
|
+
'patient.status_changed',
|
|
14
|
+
// ── Appointment events ──────────────────────────────────────────
|
|
15
|
+
'appointment.created',
|
|
16
|
+
'appointment.updated',
|
|
17
|
+
'appointment.canceled',
|
|
18
|
+
'appointment.rescheduled',
|
|
19
|
+
'appointment.no_show',
|
|
20
|
+
'appointment.finished',
|
|
21
|
+
// ── Check-in / Check-out events ─────────────────────────────────
|
|
22
|
+
'checkin.effectued',
|
|
23
|
+
'checkout.effectued',
|
|
24
|
+
// ── Message events ──────────────────────────────────────────────
|
|
25
|
+
'message.sent',
|
|
26
|
+
'message.received',
|
|
27
|
+
// ── Conversation / Session events ───────────────────────────────
|
|
28
|
+
'conversation.session_started',
|
|
29
|
+
'conversation.session_ended',
|
|
30
|
+
'conversation.transferred_to_human',
|
|
31
|
+
// ── Follow-up events ────────────────────────────────────────────
|
|
32
|
+
'followup.triggered',
|
|
33
|
+
'followup.completed',
|
|
34
|
+
'followup.config_updated',
|
|
35
|
+
// ── Payment events ──────────────────────────────────────────────
|
|
36
|
+
'payment.created',
|
|
37
|
+
'payment.payed',
|
|
38
|
+
'payment.refunded',
|
|
39
|
+
'payment.canceled',
|
|
40
|
+
'payment.overdue',
|
|
41
|
+
// ── Billing events ──────────────────────────────────────────────
|
|
42
|
+
'billing.invoice_created',
|
|
43
|
+
'billing.invoice_paid',
|
|
44
|
+
// ── AI events ───────────────────────────────────────────────────
|
|
45
|
+
'ai.interaction',
|
|
46
|
+
'ai.fallback',
|
|
47
|
+
// ── Auth events ─────────────────────────────────────────────────
|
|
48
|
+
'auth.login',
|
|
49
|
+
'auth.logout',
|
|
50
|
+
'auth.password_reset',
|
|
51
|
+
// ── User / Staff events ─────────────────────────────────────────
|
|
52
|
+
'user.created',
|
|
53
|
+
'user.updated',
|
|
54
|
+
'user.deleted',
|
|
55
|
+
// ── Notification events ─────────────────────────────────────────
|
|
56
|
+
'notification.sent',
|
|
57
|
+
'notification.failed',
|
|
58
|
+
// ── WhatsApp events ─────────────────────────────────────────────
|
|
59
|
+
'whatsapp.connection_established',
|
|
60
|
+
'whatsapp.connection_lost',
|
|
61
|
+
// ── Procedure events ────────────────────────────────────────────
|
|
62
|
+
'procedure.created',
|
|
63
|
+
'procedure.updated',
|
|
64
|
+
'procedure.deleted',
|
|
65
|
+
// ── Specialty events ────────────────────────────────────────────
|
|
66
|
+
'specialty.created',
|
|
67
|
+
'specialty.updated',
|
|
68
|
+
'specialty.deleted',
|
|
69
|
+
// ── Professional events ─────────────────────────────────────────
|
|
70
|
+
'professional.created',
|
|
71
|
+
'professional.updated',
|
|
72
|
+
'professional.deleted',
|
|
73
|
+
// ── Configuration events ────────────────────────────────────────
|
|
74
|
+
'configuration.updated',
|
|
75
|
+
// ── Storage events ──────────────────────────────────────────────
|
|
76
|
+
'storage.file_uploaded',
|
|
77
|
+
'storage.file_deleted',
|
|
78
|
+
// ── Tenant events ───────────────────────────────────────────────
|
|
79
|
+
'tenant.created',
|
|
80
|
+
'tenant.updated',
|
|
81
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./event-analytic.enum"), exports);
|
|
18
|
+
__exportStar(require("./create-analytic-event.dto"), exports);
|
|
19
|
+
__exportStar(require("./analytics-query.dto"), exports);
|
|
20
|
+
__exportStar(require("./analytics-kafka-topics"), exports);
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,MAAM,CAAC;AACrB,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,MAAM,CAAC;AACrB,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
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';
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
2
|
+
import {
|
|
3
|
+
IsIn,
|
|
4
|
+
IsISO8601,
|
|
5
|
+
IsNotEmpty,
|
|
6
|
+
IsOptional,
|
|
7
|
+
IsPositive,
|
|
8
|
+
IsString,
|
|
9
|
+
MaxLength,
|
|
10
|
+
Min,
|
|
11
|
+
} from 'class-validator';
|
|
12
|
+
import { Type } from 'class-transformer';
|
|
13
|
+
import { EVENT_ANALYTIC_TYPES, EventAnalyticType } from './event-analytic.enum';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Grouping granularity for time-series report data.
|
|
17
|
+
*/
|
|
18
|
+
export const ANALYTICS_GROUP_BY = ['hour', 'day', 'week', 'month'] as const;
|
|
19
|
+
export type AnalyticsGroupBy = (typeof ANALYTICS_GROUP_BY)[number];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Query DTO used to request analytics reports.
|
|
23
|
+
*/
|
|
24
|
+
export class AnalyticsReportQueryDto {
|
|
25
|
+
@ApiProperty({
|
|
26
|
+
description: 'Start of the reporting period (inclusive)',
|
|
27
|
+
example: '2026-03-01T00:00:00.000Z',
|
|
28
|
+
})
|
|
29
|
+
@IsISO8601()
|
|
30
|
+
startDate: string;
|
|
31
|
+
|
|
32
|
+
@ApiProperty({
|
|
33
|
+
description: 'End of the reporting period (exclusive)',
|
|
34
|
+
example: '2026-04-01T00:00:00.000Z',
|
|
35
|
+
})
|
|
36
|
+
@IsISO8601()
|
|
37
|
+
endDate: string;
|
|
38
|
+
|
|
39
|
+
@ApiPropertyOptional({
|
|
40
|
+
description: 'Filter by event type',
|
|
41
|
+
enum: EVENT_ANALYTIC_TYPES,
|
|
42
|
+
example: 'patient.created',
|
|
43
|
+
})
|
|
44
|
+
@IsOptional()
|
|
45
|
+
@IsIn([...EVENT_ANALYTIC_TYPES])
|
|
46
|
+
eventType?: EventAnalyticType;
|
|
47
|
+
|
|
48
|
+
@ApiPropertyOptional({
|
|
49
|
+
description: 'Group results by time granularity',
|
|
50
|
+
enum: ANALYTICS_GROUP_BY,
|
|
51
|
+
example: 'day',
|
|
52
|
+
})
|
|
53
|
+
@IsOptional()
|
|
54
|
+
@IsIn([...ANALYTICS_GROUP_BY])
|
|
55
|
+
groupBy?: AnalyticsGroupBy;
|
|
56
|
+
|
|
57
|
+
@ApiPropertyOptional({ description: 'Page number (starts at 1)', example: 1 })
|
|
58
|
+
@IsOptional()
|
|
59
|
+
@Type(() => Number)
|
|
60
|
+
@IsPositive()
|
|
61
|
+
@Min(1)
|
|
62
|
+
page?: number;
|
|
63
|
+
|
|
64
|
+
@ApiPropertyOptional({ description: 'Records per page', example: 20 })
|
|
65
|
+
@IsOptional()
|
|
66
|
+
@Type(() => Number)
|
|
67
|
+
@IsPositive()
|
|
68
|
+
@Min(1)
|
|
69
|
+
limit?: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Query DTO for the dashboard summary endpoint.
|
|
74
|
+
*/
|
|
75
|
+
export class AnalyticsDashboardQueryDto {
|
|
76
|
+
@ApiProperty({
|
|
77
|
+
description: 'Start of the reporting period (inclusive)',
|
|
78
|
+
example: '2026-03-01T00:00:00.000Z',
|
|
79
|
+
})
|
|
80
|
+
@IsISO8601()
|
|
81
|
+
startDate: string;
|
|
82
|
+
|
|
83
|
+
@ApiProperty({
|
|
84
|
+
description: 'End of the reporting period (exclusive)',
|
|
85
|
+
example: '2026-04-01T00:00:00.000Z',
|
|
86
|
+
})
|
|
87
|
+
@IsISO8601()
|
|
88
|
+
endDate: string;
|
|
89
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
2
|
+
import {
|
|
3
|
+
IsIn,
|
|
4
|
+
IsISO8601,
|
|
5
|
+
IsNotEmpty,
|
|
6
|
+
IsObject,
|
|
7
|
+
IsOptional,
|
|
8
|
+
IsString,
|
|
9
|
+
IsUUID,
|
|
10
|
+
MaxLength,
|
|
11
|
+
MinLength,
|
|
12
|
+
} from 'class-validator';
|
|
13
|
+
import { EVENT_ANALYTIC_TYPES, EventAnalyticType } from './event-analytic.enum';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Payload that every microservice must send to the analytics topic.
|
|
17
|
+
*/
|
|
18
|
+
export class CreateAnalyticEventDto {
|
|
19
|
+
@ApiProperty({
|
|
20
|
+
description: 'Unique event ID for idempotent processing',
|
|
21
|
+
example: 'f3f50ecb-fb71-4d4b-a0dd-910ef6e3fd0a',
|
|
22
|
+
})
|
|
23
|
+
@IsUUID()
|
|
24
|
+
eventId: string;
|
|
25
|
+
|
|
26
|
+
@ApiProperty({
|
|
27
|
+
description: 'Tenant slug that originated the event',
|
|
28
|
+
example: 'homolog',
|
|
29
|
+
})
|
|
30
|
+
@IsString()
|
|
31
|
+
@IsNotEmpty()
|
|
32
|
+
@MinLength(1)
|
|
33
|
+
@MaxLength(255)
|
|
34
|
+
tenant: string;
|
|
35
|
+
|
|
36
|
+
@ApiProperty({
|
|
37
|
+
description: 'Type of analytic event',
|
|
38
|
+
enum: EVENT_ANALYTIC_TYPES,
|
|
39
|
+
example: 'patient.created',
|
|
40
|
+
})
|
|
41
|
+
@IsIn([...EVENT_ANALYTIC_TYPES])
|
|
42
|
+
eventType: EventAnalyticType;
|
|
43
|
+
|
|
44
|
+
@ApiPropertyOptional({
|
|
45
|
+
description: 'ID of the entity related to this event (patient, appointment, etc.)',
|
|
46
|
+
example: '3c593727-4505-495a-a054-c052acb4cf19',
|
|
47
|
+
})
|
|
48
|
+
@IsOptional()
|
|
49
|
+
@IsString()
|
|
50
|
+
@MaxLength(255)
|
|
51
|
+
entityId?: string;
|
|
52
|
+
|
|
53
|
+
@ApiPropertyOptional({
|
|
54
|
+
description: 'Name of the source microservice',
|
|
55
|
+
example: 'tychat-patient-service',
|
|
56
|
+
})
|
|
57
|
+
@IsOptional()
|
|
58
|
+
@IsString()
|
|
59
|
+
@MaxLength(255)
|
|
60
|
+
source?: string;
|
|
61
|
+
|
|
62
|
+
@ApiPropertyOptional({
|
|
63
|
+
description: 'Optional user ID who triggered the action',
|
|
64
|
+
example: 'a1b2c3d4-e5f6-4789-abcd-ef0123456789',
|
|
65
|
+
})
|
|
66
|
+
@IsOptional()
|
|
67
|
+
@IsString()
|
|
68
|
+
@MaxLength(255)
|
|
69
|
+
userId?: string;
|
|
70
|
+
|
|
71
|
+
@ApiPropertyOptional({
|
|
72
|
+
description: 'Additional metadata for the event (flexible JSON)',
|
|
73
|
+
example: { previousStatus: 'pending', newStatus: 'finished' },
|
|
74
|
+
})
|
|
75
|
+
@IsOptional()
|
|
76
|
+
@IsObject()
|
|
77
|
+
metadata?: Record<string, unknown>;
|
|
78
|
+
|
|
79
|
+
@ApiProperty({
|
|
80
|
+
description: 'ISO 8601 timestamp when the event occurred',
|
|
81
|
+
example: '2026-04-02T12:00:00.000Z',
|
|
82
|
+
})
|
|
83
|
+
@IsISO8601()
|
|
84
|
+
occurredAt: string;
|
|
85
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enum of all analytic event types emitted by microservices.
|
|
3
|
+
* Each value follows the pattern: `domain.action`.
|
|
4
|
+
*/
|
|
5
|
+
export const EVENT_ANALYTIC_TYPES = [
|
|
6
|
+
// ── Patient events ──────────────────────────────────────────────
|
|
7
|
+
'patient.created',
|
|
8
|
+
'patient.updated',
|
|
9
|
+
'patient.deleted',
|
|
10
|
+
'patient.status_changed',
|
|
11
|
+
|
|
12
|
+
// ── Appointment events ──────────────────────────────────────────
|
|
13
|
+
'appointment.created',
|
|
14
|
+
'appointment.updated',
|
|
15
|
+
'appointment.canceled',
|
|
16
|
+
'appointment.rescheduled',
|
|
17
|
+
'appointment.no_show',
|
|
18
|
+
'appointment.finished',
|
|
19
|
+
|
|
20
|
+
// ── Check-in / Check-out events ─────────────────────────────────
|
|
21
|
+
'checkin.effectued',
|
|
22
|
+
'checkout.effectued',
|
|
23
|
+
|
|
24
|
+
// ── Message events ──────────────────────────────────────────────
|
|
25
|
+
'message.sent',
|
|
26
|
+
'message.received',
|
|
27
|
+
|
|
28
|
+
// ── Conversation / Session events ───────────────────────────────
|
|
29
|
+
'conversation.session_started',
|
|
30
|
+
'conversation.session_ended',
|
|
31
|
+
'conversation.transferred_to_human',
|
|
32
|
+
|
|
33
|
+
// ── Follow-up events ────────────────────────────────────────────
|
|
34
|
+
'followup.triggered',
|
|
35
|
+
'followup.completed',
|
|
36
|
+
'followup.config_updated',
|
|
37
|
+
|
|
38
|
+
// ── Payment events ──────────────────────────────────────────────
|
|
39
|
+
'payment.created',
|
|
40
|
+
'payment.payed',
|
|
41
|
+
'payment.refunded',
|
|
42
|
+
'payment.canceled',
|
|
43
|
+
'payment.overdue',
|
|
44
|
+
|
|
45
|
+
// ── Billing events ──────────────────────────────────────────────
|
|
46
|
+
'billing.invoice_created',
|
|
47
|
+
'billing.invoice_paid',
|
|
48
|
+
|
|
49
|
+
// ── AI events ───────────────────────────────────────────────────
|
|
50
|
+
'ai.interaction',
|
|
51
|
+
'ai.fallback',
|
|
52
|
+
|
|
53
|
+
// ── Auth events ─────────────────────────────────────────────────
|
|
54
|
+
'auth.login',
|
|
55
|
+
'auth.logout',
|
|
56
|
+
'auth.password_reset',
|
|
57
|
+
|
|
58
|
+
// ── User / Staff events ─────────────────────────────────────────
|
|
59
|
+
'user.created',
|
|
60
|
+
'user.updated',
|
|
61
|
+
'user.deleted',
|
|
62
|
+
|
|
63
|
+
// ── Notification events ─────────────────────────────────────────
|
|
64
|
+
'notification.sent',
|
|
65
|
+
'notification.failed',
|
|
66
|
+
|
|
67
|
+
// ── WhatsApp events ─────────────────────────────────────────────
|
|
68
|
+
'whatsapp.connection_established',
|
|
69
|
+
'whatsapp.connection_lost',
|
|
70
|
+
|
|
71
|
+
// ── Procedure events ────────────────────────────────────────────
|
|
72
|
+
'procedure.created',
|
|
73
|
+
'procedure.updated',
|
|
74
|
+
'procedure.deleted',
|
|
75
|
+
|
|
76
|
+
// ── Specialty events ────────────────────────────────────────────
|
|
77
|
+
'specialty.created',
|
|
78
|
+
'specialty.updated',
|
|
79
|
+
'specialty.deleted',
|
|
80
|
+
|
|
81
|
+
// ── Professional events ─────────────────────────────────────────
|
|
82
|
+
'professional.created',
|
|
83
|
+
'professional.updated',
|
|
84
|
+
'professional.deleted',
|
|
85
|
+
|
|
86
|
+
// ── Configuration events ────────────────────────────────────────
|
|
87
|
+
'configuration.updated',
|
|
88
|
+
|
|
89
|
+
// ── Storage events ──────────────────────────────────────────────
|
|
90
|
+
'storage.file_uploaded',
|
|
91
|
+
'storage.file_deleted',
|
|
92
|
+
|
|
93
|
+
// ── Tenant events ───────────────────────────────────────────────
|
|
94
|
+
'tenant.created',
|
|
95
|
+
'tenant.updated',
|
|
96
|
+
] as const;
|
|
97
|
+
|
|
98
|
+
export type EventAnalyticType = (typeof EVENT_ANALYTIC_TYPES)[number];
|
package/src/index.ts
CHANGED