tychat-contracts 1.0.100 → 1.0.102

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.
@@ -32,6 +32,18 @@ export declare class AnalyticsDashboardTopProcedureDto {
32
32
  name: string;
33
33
  count: number;
34
34
  }
35
+ /** Média de `message.sent` por hora do relógio durante o expediente configurado. */
36
+ export declare class AnalyticsDashboardMessageHourDto {
37
+ hour: number;
38
+ averageSent: number;
39
+ totalSent: number;
40
+ openOccurrencesInPeriod: number;
41
+ }
42
+ export declare class AnalyticsDashboardMessagePeakDto {
43
+ hour: number;
44
+ totalSent: number;
45
+ averageSent: number;
46
+ }
35
47
  /**
36
48
  * Resposta enriquecida de `GET /analytics/dashboard` (mantém campos legados `total`, `byEventType`, `byDomain`).
37
49
  */
@@ -44,6 +56,9 @@ export declare class AnalyticsDashboardResponseDto {
44
56
  noShowRatePercent: number;
45
57
  financialSummary: AnalyticsDashboardFinancialDto;
46
58
  topProcedures: AnalyticsDashboardTopProcedureDto[];
59
+ messagesByClinicHour: AnalyticsDashboardMessageHourDto[];
60
+ messagesPeakHour: AnalyticsDashboardMessagePeakDto | null;
61
+ clinicTimezone: string;
47
62
  total: number;
48
63
  byEventType: Array<{
49
64
  eventType: string;
@@ -1 +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;AAED,8FAA8F;AAC9F,qBAAa,8BAA8B;IAKzC,OAAO,EAAE,MAAM,CAAC;IAMhB,aAAa,EAAE,MAAM,CAAC;IAMtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,iCAAiC;IAE5C,IAAI,EAAE,MAAM,CAAC;IAGb,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,qBAAa,6BAA6B;IAExC,mBAAmB,EAAE,MAAM,CAAC;IAG5B,oBAAoB,EAAE,MAAM,CAAC;IAM7B,mBAAmB,EAAE,MAAM,CAAC;IAK5B,kBAAkB,EAAE,MAAM,CAAC;IAO3B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IAMnC,iBAAiB,EAAE,MAAM,CAAC;IAG1B,gBAAgB,EAAE,8BAA8B,CAAC;IAGjD,aAAa,EAAE,iCAAiC,EAAE,CAAC;IAGnD,KAAK,EAAE,MAAM,CAAC;IAKd,WAAW,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAKzD,QAAQ,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD"}
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;AAED,8FAA8F;AAC9F,qBAAa,8BAA8B;IAKzC,OAAO,EAAE,MAAM,CAAC;IAMhB,aAAa,EAAE,MAAM,CAAC;IAMtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,iCAAiC;IAE5C,IAAI,EAAE,MAAM,CAAC;IAGb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,oFAAoF;AACpF,qBAAa,gCAAgC;IAE3C,IAAI,EAAE,MAAM,CAAC;IAMb,WAAW,EAAE,MAAM,CAAC;IAGpB,SAAS,EAAE,MAAM,CAAC;IAMlB,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAED,qBAAa,gCAAgC;IAE3C,IAAI,EAAE,MAAM,CAAC;IAEE,SAAS,EAAE,MAAM,CAAC;IAElB,WAAW,EAAE,MAAM,CAAC;CACpC;AAED;;GAEG;AACH,qBAAa,6BAA6B;IAExC,mBAAmB,EAAE,MAAM,CAAC;IAG5B,oBAAoB,EAAE,MAAM,CAAC;IAM7B,mBAAmB,EAAE,MAAM,CAAC;IAK5B,kBAAkB,EAAE,MAAM,CAAC;IAO3B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IAMnC,iBAAiB,EAAE,MAAM,CAAC;IAG1B,gBAAgB,EAAE,8BAA8B,CAAC;IAGjD,aAAa,EAAE,iCAAiC,EAAE,CAAC;IAOnD,oBAAoB,EAAE,gCAAgC,EAAE,CAAC;IAOzD,gBAAgB,EAAE,gCAAgC,GAAG,IAAI,CAAC;IAM1D,cAAc,EAAE,MAAM,CAAC;IAGvB,KAAK,EAAE,MAAM,CAAC;IAKd,WAAW,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAKzD,QAAQ,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD"}
@@ -9,7 +9,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.AnalyticsDashboardResponseDto = exports.AnalyticsDashboardTopProcedureDto = exports.AnalyticsDashboardFinancialDto = exports.AnalyticsDashboardQueryDto = exports.AnalyticsReportQueryDto = exports.ANALYTICS_GROUP_BY = void 0;
12
+ exports.AnalyticsDashboardResponseDto = exports.AnalyticsDashboardMessagePeakDto = exports.AnalyticsDashboardMessageHourDto = exports.AnalyticsDashboardTopProcedureDto = exports.AnalyticsDashboardFinancialDto = exports.AnalyticsDashboardQueryDto = exports.AnalyticsReportQueryDto = exports.ANALYTICS_GROUP_BY = void 0;
13
13
  const swagger_1 = require("@nestjs/swagger");
14
14
  const class_validator_1 = require("class-validator");
15
15
  const class_transformer_1 = require("class-transformer");
@@ -127,7 +127,7 @@ __decorate([
127
127
  ], AnalyticsDashboardFinancialDto.prototype, "averageTicket", void 0);
128
128
  __decorate([
129
129
  (0, swagger_1.ApiProperty)({
130
- description: 'Volume de cobranças criadas no período ainda não quitadas no momento do registro: soma de `payment.created` + faturas `billing.invoice_created` com status PENDING ou OVERDUE no metadata (aproximação; não substitui saldo contábil)',
130
+ description: 'Valor ainda em aberto no fim do período (exclusive endDate): soma de `payment.created` no intervalo sem `payment.payed` correspondente (mesmo paymentId) com occurredAt anterior a endDate; mais faturas `billing.invoice_created` PENDING/OVERDUE sem `billing.invoice_paid` (mesmo invoiceId). Baseado em eventos de analytics.',
131
131
  }),
132
132
  __metadata("design:type", Number)
133
133
  ], AnalyticsDashboardFinancialDto.prototype, "pending", void 0);
@@ -144,6 +144,52 @@ __decorate([
144
144
  (0, swagger_1.ApiProperty)({ description: 'Quantidade de ocorrências no período' }),
145
145
  __metadata("design:type", Number)
146
146
  ], AnalyticsDashboardTopProcedureDto.prototype, "count", void 0);
147
+ /** Média de `message.sent` por hora do relógio durante o expediente configurado. */
148
+ class AnalyticsDashboardMessageHourDto {
149
+ hour;
150
+ averageSent;
151
+ totalSent;
152
+ openOccurrencesInPeriod;
153
+ }
154
+ exports.AnalyticsDashboardMessageHourDto = AnalyticsDashboardMessageHourDto;
155
+ __decorate([
156
+ (0, swagger_1.ApiProperty)({ description: 'Hora local (0–23) no fuso clinicTimezone' }),
157
+ __metadata("design:type", Number)
158
+ ], AnalyticsDashboardMessageHourDto.prototype, "hour", void 0);
159
+ __decorate([
160
+ (0, swagger_1.ApiProperty)({
161
+ description: 'Média de mensagens enviadas nessa hora: totalSent / openOccurrencesInPeriod (0 se não houve expediente nessa hora no período)',
162
+ }),
163
+ __metadata("design:type", Number)
164
+ ], AnalyticsDashboardMessageHourDto.prototype, "averageSent", void 0);
165
+ __decorate([
166
+ (0, swagger_1.ApiProperty)({ description: 'Total de eventos message.sent nessa hora local, só dentro do horário da clínica' }),
167
+ __metadata("design:type", Number)
168
+ ], AnalyticsDashboardMessageHourDto.prototype, "totalSent", void 0);
169
+ __decorate([
170
+ (0, swagger_1.ApiProperty)({
171
+ description: 'Quantas vezes essa hora calendário integrou o expediente (dias locais no intervalo × slots de opening_hours)',
172
+ }),
173
+ __metadata("design:type", Number)
174
+ ], AnalyticsDashboardMessageHourDto.prototype, "openOccurrencesInPeriod", void 0);
175
+ class AnalyticsDashboardMessagePeakDto {
176
+ hour;
177
+ totalSent;
178
+ averageSent;
179
+ }
180
+ exports.AnalyticsDashboardMessagePeakDto = AnalyticsDashboardMessagePeakDto;
181
+ __decorate([
182
+ (0, swagger_1.ApiProperty)({ description: 'Hora local (0–23) com maior totalSent entre as horas de expediente' }),
183
+ __metadata("design:type", Number)
184
+ ], AnalyticsDashboardMessagePeakDto.prototype, "hour", void 0);
185
+ __decorate([
186
+ (0, swagger_1.ApiProperty)(),
187
+ __metadata("design:type", Number)
188
+ ], AnalyticsDashboardMessagePeakDto.prototype, "totalSent", void 0);
189
+ __decorate([
190
+ (0, swagger_1.ApiProperty)(),
191
+ __metadata("design:type", Number)
192
+ ], AnalyticsDashboardMessagePeakDto.prototype, "averageSent", void 0);
147
193
  /**
148
194
  * Resposta enriquecida de `GET /analytics/dashboard` (mantém campos legados `total`, `byEventType`, `byDomain`).
149
195
  */
@@ -156,6 +202,9 @@ class AnalyticsDashboardResponseDto {
156
202
  noShowRatePercent;
157
203
  financialSummary;
158
204
  topProcedures;
205
+ messagesByClinicHour;
206
+ messagesPeakHour;
207
+ clinicTimezone;
159
208
  total;
160
209
  byEventType;
161
210
  byDomain;
@@ -202,6 +251,28 @@ __decorate([
202
251
  (0, swagger_1.ApiProperty)({ type: [AnalyticsDashboardTopProcedureDto], maxItems: 5 }),
203
252
  __metadata("design:type", Array)
204
253
  ], AnalyticsDashboardResponseDto.prototype, "topProcedures", void 0);
254
+ __decorate([
255
+ (0, swagger_1.ApiProperty)({
256
+ description: 'Pico / distribuição de mensagens no horário da clínica: médias por hora local (só `message.sent` dentro de opening_hours). Ordenado por hora crescente. Vazio se não houver opening_hours.',
257
+ type: [AnalyticsDashboardMessageHourDto],
258
+ }),
259
+ __metadata("design:type", Array)
260
+ ], AnalyticsDashboardResponseDto.prototype, "messagesByClinicHour", void 0);
261
+ __decorate([
262
+ (0, swagger_1.ApiProperty)({
263
+ description: 'Hora com maior volume de mensagens no expediente; null se não houver dados ou horário configurado',
264
+ nullable: true,
265
+ type: AnalyticsDashboardMessagePeakDto,
266
+ }),
267
+ __metadata("design:type", Object)
268
+ ], AnalyticsDashboardResponseDto.prototype, "messagesPeakHour", void 0);
269
+ __decorate([
270
+ (0, swagger_1.ApiProperty)({
271
+ description: 'Fuso IANA usado para hora local e opening_hours (env ANALYTICS_CLINIC_TIMEZONE ou America/Sao_Paulo)',
272
+ example: 'America/Sao_Paulo',
273
+ }),
274
+ __metadata("design:type", String)
275
+ ], AnalyticsDashboardResponseDto.prototype, "clinicTimezone", void 0);
205
276
  __decorate([
206
277
  (0, swagger_1.ApiProperty)({ description: 'Total de eventos de analytics no período (legado)' }),
207
278
  __metadata("design:type", Number)
@@ -1,6 +1,7 @@
1
1
  export { NotificationUserCreatedEventPayload, NotificationPasswordResetRequestedEventPayload, } from './notifications-kafka.payloads';
2
- export { TOPIC_NOTIFICATIONS_FIND_ALL, TOPIC_NOTIFICATIONS_REGISTER_PUSH_TOKEN, } from './notifications-kafka-topics';
2
+ export { TOPIC_NOTIFICATIONS_FIND_ALL, TOPIC_NOTIFICATIONS_REGISTER_PUSH_TOKEN, TOPIC_NOTIFICATIONS_UPDATE_VIEWED, } from './notifications-kafka-topics';
3
3
  export { RegisterPushTokenDto, NotificationsRegisterPushTokenKafkaDto, } from './register-push-token.dto';
4
4
  export { ListNotificationsQueryDto, NOTIFICATION_PROVIDER_FILTERS, NOTIFICATION_STATUS_FILTERS, type NotificationProviderFilterDto, type NotificationStatusFilterDto, } from './list-notifications-query.dto';
5
5
  export { NotificationListItemDto } from './notification-list-item.dto';
6
+ export { UpdateNotificationViewedDto, NotificationsUpdateViewedKafkaDto, } from './update-notification-viewed.dto';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/notifications/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mCAAmC,EACnC,8CAA8C,GAC/C,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,4BAA4B,EAC5B,uCAAuC,GACxC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,oBAAoB,EACpB,sCAAsC,GACvC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,yBAAyB,EACzB,6BAA6B,EAC7B,2BAA2B,EAC3B,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,GACjC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/notifications/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mCAAmC,EACnC,8CAA8C,GAC/C,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,4BAA4B,EAC5B,uCAAuC,EACvC,iCAAiC,GAClC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,oBAAoB,EACpB,sCAAsC,GACvC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,yBAAyB,EACzB,6BAA6B,EAC7B,2BAA2B,EAC3B,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,GACjC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EACL,2BAA2B,EAC3B,iCAAiC,GAClC,MAAM,kCAAkC,CAAC"}
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NotificationListItemDto = exports.NOTIFICATION_STATUS_FILTERS = exports.NOTIFICATION_PROVIDER_FILTERS = exports.ListNotificationsQueryDto = exports.NotificationsRegisterPushTokenKafkaDto = exports.RegisterPushTokenDto = exports.TOPIC_NOTIFICATIONS_REGISTER_PUSH_TOKEN = exports.TOPIC_NOTIFICATIONS_FIND_ALL = exports.NotificationPasswordResetRequestedEventPayload = exports.NotificationUserCreatedEventPayload = void 0;
3
+ exports.NotificationsUpdateViewedKafkaDto = exports.UpdateNotificationViewedDto = exports.NotificationListItemDto = exports.NOTIFICATION_STATUS_FILTERS = exports.NOTIFICATION_PROVIDER_FILTERS = exports.ListNotificationsQueryDto = exports.NotificationsRegisterPushTokenKafkaDto = exports.RegisterPushTokenDto = exports.TOPIC_NOTIFICATIONS_UPDATE_VIEWED = exports.TOPIC_NOTIFICATIONS_REGISTER_PUSH_TOKEN = exports.TOPIC_NOTIFICATIONS_FIND_ALL = exports.NotificationPasswordResetRequestedEventPayload = exports.NotificationUserCreatedEventPayload = void 0;
4
4
  var notifications_kafka_payloads_1 = require("./notifications-kafka.payloads");
5
5
  Object.defineProperty(exports, "NotificationUserCreatedEventPayload", { enumerable: true, get: function () { return notifications_kafka_payloads_1.NotificationUserCreatedEventPayload; } });
6
6
  Object.defineProperty(exports, "NotificationPasswordResetRequestedEventPayload", { enumerable: true, get: function () { return notifications_kafka_payloads_1.NotificationPasswordResetRequestedEventPayload; } });
7
7
  var notifications_kafka_topics_1 = require("./notifications-kafka-topics");
8
8
  Object.defineProperty(exports, "TOPIC_NOTIFICATIONS_FIND_ALL", { enumerable: true, get: function () { return notifications_kafka_topics_1.TOPIC_NOTIFICATIONS_FIND_ALL; } });
9
9
  Object.defineProperty(exports, "TOPIC_NOTIFICATIONS_REGISTER_PUSH_TOKEN", { enumerable: true, get: function () { return notifications_kafka_topics_1.TOPIC_NOTIFICATIONS_REGISTER_PUSH_TOKEN; } });
10
+ Object.defineProperty(exports, "TOPIC_NOTIFICATIONS_UPDATE_VIEWED", { enumerable: true, get: function () { return notifications_kafka_topics_1.TOPIC_NOTIFICATIONS_UPDATE_VIEWED; } });
10
11
  var register_push_token_dto_1 = require("./register-push-token.dto");
11
12
  Object.defineProperty(exports, "RegisterPushTokenDto", { enumerable: true, get: function () { return register_push_token_dto_1.RegisterPushTokenDto; } });
12
13
  Object.defineProperty(exports, "NotificationsRegisterPushTokenKafkaDto", { enumerable: true, get: function () { return register_push_token_dto_1.NotificationsRegisterPushTokenKafkaDto; } });
@@ -16,3 +17,6 @@ Object.defineProperty(exports, "NOTIFICATION_PROVIDER_FILTERS", { enumerable: tr
16
17
  Object.defineProperty(exports, "NOTIFICATION_STATUS_FILTERS", { enumerable: true, get: function () { return list_notifications_query_dto_1.NOTIFICATION_STATUS_FILTERS; } });
17
18
  var notification_list_item_dto_1 = require("./notification-list-item.dto");
18
19
  Object.defineProperty(exports, "NotificationListItemDto", { enumerable: true, get: function () { return notification_list_item_dto_1.NotificationListItemDto; } });
20
+ var update_notification_viewed_dto_1 = require("./update-notification-viewed.dto");
21
+ Object.defineProperty(exports, "UpdateNotificationViewedDto", { enumerable: true, get: function () { return update_notification_viewed_dto_1.UpdateNotificationViewedDto; } });
22
+ Object.defineProperty(exports, "NotificationsUpdateViewedKafkaDto", { enumerable: true, get: function () { return update_notification_viewed_dto_1.NotificationsUpdateViewedKafkaDto; } });
@@ -6,5 +6,7 @@ export declare class NotificationListItemDto {
6
6
  status: string;
7
7
  createdAt: string;
8
8
  updatedAt: string;
9
+ viewed: boolean;
10
+ viewedAt: string | null;
9
11
  }
10
12
  //# sourceMappingURL=notification-list-item.dto.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"notification-list-item.dto.d.ts","sourceRoot":"","sources":["../../src/notifications/notification-list-item.dto.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,qBAAa,uBAAuB;IAElC,EAAE,EAAE,MAAM,CAAC;IAGX,iBAAiB,EAAE,MAAM,CAAC;IAG1B,QAAQ,EAAE,MAAM,CAAC;IAGjB,MAAM,EAAE,MAAM,CAAC;IAGf,SAAS,EAAE,MAAM,CAAC;IAGlB,SAAS,EAAE,MAAM,CAAC;CACnB"}
1
+ {"version":3,"file":"notification-list-item.dto.d.ts","sourceRoot":"","sources":["../../src/notifications/notification-list-item.dto.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,qBAAa,uBAAuB;IAElC,EAAE,EAAE,MAAM,CAAC;IAGX,iBAAiB,EAAE,MAAM,CAAC;IAG1B,QAAQ,EAAE,MAAM,CAAC;IAGjB,MAAM,EAAE,MAAM,CAAC;IAGf,SAAS,EAAE,MAAM,CAAC;IAGlB,SAAS,EAAE,MAAM,CAAC;IAMlB,MAAM,EAAE,OAAO,CAAC;IAOhB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB"}
@@ -19,6 +19,8 @@ class NotificationListItemDto {
19
19
  status;
20
20
  createdAt;
21
21
  updatedAt;
22
+ viewed;
23
+ viewedAt;
22
24
  }
23
25
  exports.NotificationListItemDto = NotificationListItemDto;
24
26
  __decorate([
@@ -45,3 +47,18 @@ __decorate([
45
47
  (0, swagger_1.ApiProperty)({ example: '2026-04-08T12:00:00.000Z' }),
46
48
  __metadata("design:type", String)
47
49
  ], NotificationListItemDto.prototype, "updatedAt", void 0);
50
+ __decorate([
51
+ (0, swagger_1.ApiProperty)({
52
+ description: 'Indica se foi marcada como visualizada (viewedAt != null)',
53
+ example: false,
54
+ }),
55
+ __metadata("design:type", Boolean)
56
+ ], NotificationListItemDto.prototype, "viewed", void 0);
57
+ __decorate([
58
+ (0, swagger_1.ApiProperty)({
59
+ description: 'Instante em que foi marcada como visualizada; null se não visualizada',
60
+ nullable: true,
61
+ example: null,
62
+ }),
63
+ __metadata("design:type", Object)
64
+ ], NotificationListItemDto.prototype, "viewedAt", void 0);
@@ -1,4 +1,6 @@
1
1
  /** Kafka request–reply: lista notificações persistidas no banco do tenant. */
2
2
  export declare const TOPIC_NOTIFICATIONS_FIND_ALL = "notifications.findAll";
3
3
  export declare const TOPIC_NOTIFICATIONS_REGISTER_PUSH_TOKEN = "notifications.registerPushToken";
4
+ /** Kafka request–reply: atualizar visualização de uma notificação persistida. */
5
+ export declare const TOPIC_NOTIFICATIONS_UPDATE_VIEWED = "notifications.updateViewed";
4
6
  //# sourceMappingURL=notifications-kafka-topics.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"notifications-kafka-topics.d.ts","sourceRoot":"","sources":["../../src/notifications/notifications-kafka-topics.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,eAAO,MAAM,4BAA4B,0BAA0B,CAAC;AAEpE,eAAO,MAAM,uCAAuC,oCACjB,CAAC"}
1
+ {"version":3,"file":"notifications-kafka-topics.d.ts","sourceRoot":"","sources":["../../src/notifications/notifications-kafka-topics.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,eAAO,MAAM,4BAA4B,0BAA0B,CAAC;AAEpE,eAAO,MAAM,uCAAuC,oCACjB,CAAC;AAEpC,iFAAiF;AACjF,eAAO,MAAM,iCAAiC,+BAA+B,CAAC"}
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TOPIC_NOTIFICATIONS_REGISTER_PUSH_TOKEN = exports.TOPIC_NOTIFICATIONS_FIND_ALL = void 0;
3
+ exports.TOPIC_NOTIFICATIONS_UPDATE_VIEWED = exports.TOPIC_NOTIFICATIONS_REGISTER_PUSH_TOKEN = exports.TOPIC_NOTIFICATIONS_FIND_ALL = void 0;
4
4
  /** Kafka request–reply: lista notificações persistidas no banco do tenant. */
5
5
  exports.TOPIC_NOTIFICATIONS_FIND_ALL = 'notifications.findAll';
6
6
  exports.TOPIC_NOTIFICATIONS_REGISTER_PUSH_TOKEN = 'notifications.registerPushToken';
7
+ /** Kafka request–reply: atualizar visualização de uma notificação persistida. */
8
+ exports.TOPIC_NOTIFICATIONS_UPDATE_VIEWED = 'notifications.updateViewed';
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Corpo HTTP PUT /notifications/:id — marca se o registo foi visualizado.
3
+ */
4
+ export declare class UpdateNotificationViewedDto {
5
+ viewed: boolean;
6
+ }
7
+ /**
8
+ * Payload Kafka `notifications.updateViewed`.
9
+ */
10
+ export declare class NotificationsUpdateViewedKafkaDto {
11
+ tenant: string;
12
+ id: string;
13
+ payload: UpdateNotificationViewedDto;
14
+ }
15
+ //# sourceMappingURL=update-notification-viewed.dto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-notification-viewed.dto.d.ts","sourceRoot":"","sources":["../../src/notifications/update-notification-viewed.dto.ts"],"names":[],"mappings":"AAUA;;GAEG;AACH,qBAAa,2BAA2B;IAMtC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,iCAAiC;IAG5C,MAAM,EAAE,MAAM,CAAC;IAGf,EAAE,EAAE,MAAM,CAAC;IAIX,OAAO,EAAE,2BAA2B,CAAC;CACtC"}
@@ -0,0 +1,53 @@
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.NotificationsUpdateViewedKafkaDto = exports.UpdateNotificationViewedDto = 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
+ * Corpo HTTP PUT /notifications/:id — marca se o registo foi visualizado.
18
+ */
19
+ class UpdateNotificationViewedDto {
20
+ viewed;
21
+ }
22
+ exports.UpdateNotificationViewedDto = UpdateNotificationViewedDto;
23
+ __decorate([
24
+ (0, swagger_1.ApiProperty)({
25
+ description: 'true = visualizada (grava viewedAt); false = não visualizada (limpa viewedAt)',
26
+ example: true,
27
+ }),
28
+ (0, class_validator_1.IsBoolean)(),
29
+ __metadata("design:type", Boolean)
30
+ ], UpdateNotificationViewedDto.prototype, "viewed", void 0);
31
+ /**
32
+ * Payload Kafka `notifications.updateViewed`.
33
+ */
34
+ class NotificationsUpdateViewedKafkaDto {
35
+ tenant;
36
+ id;
37
+ payload;
38
+ }
39
+ exports.NotificationsUpdateViewedKafkaDto = NotificationsUpdateViewedKafkaDto;
40
+ __decorate([
41
+ (0, class_validator_1.IsString)(),
42
+ (0, class_validator_1.IsNotEmpty)(),
43
+ __metadata("design:type", String)
44
+ ], NotificationsUpdateViewedKafkaDto.prototype, "tenant", void 0);
45
+ __decorate([
46
+ (0, class_validator_1.IsUUID)('4'),
47
+ __metadata("design:type", String)
48
+ ], NotificationsUpdateViewedKafkaDto.prototype, "id", void 0);
49
+ __decorate([
50
+ (0, class_validator_1.ValidateNested)(),
51
+ (0, class_transformer_1.Type)(() => UpdateNotificationViewedDto),
52
+ __metadata("design:type", UpdateNotificationViewedDto)
53
+ ], NotificationsUpdateViewedKafkaDto.prototype, "payload", void 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tychat-contracts",
3
- "version": "1.0.100",
3
+ "version": "1.0.102",
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",
@@ -104,7 +104,7 @@ export class AnalyticsDashboardFinancialDto {
104
104
 
105
105
  @ApiProperty({
106
106
  description:
107
- 'Volume de cobranças criadas no período ainda não quitadas no momento do registro: soma de `payment.created` + faturas `billing.invoice_created` com status PENDING ou OVERDUE no metadata (aproximação; não substitui saldo contábil)',
107
+ 'Valor ainda em aberto no fim do período (exclusive endDate): soma de `payment.created` no intervalo sem `payment.payed` correspondente (mesmo paymentId) com occurredAt anterior a endDate; mais faturas `billing.invoice_created` PENDING/OVERDUE sem `billing.invoice_paid` (mesmo invoiceId). Baseado em eventos de analytics.',
108
108
  })
109
109
  pending: number;
110
110
  }
@@ -117,6 +117,36 @@ export class AnalyticsDashboardTopProcedureDto {
117
117
  count: number;
118
118
  }
119
119
 
120
+ /** Média de `message.sent` por hora do relógio durante o expediente configurado. */
121
+ export class AnalyticsDashboardMessageHourDto {
122
+ @ApiProperty({ description: 'Hora local (0–23) no fuso clinicTimezone' })
123
+ hour: number;
124
+
125
+ @ApiProperty({
126
+ description:
127
+ 'Média de mensagens enviadas nessa hora: totalSent / openOccurrencesInPeriod (0 se não houve expediente nessa hora no período)',
128
+ })
129
+ averageSent: number;
130
+
131
+ @ApiProperty({ description: 'Total de eventos message.sent nessa hora local, só dentro do horário da clínica' })
132
+ totalSent: number;
133
+
134
+ @ApiProperty({
135
+ description:
136
+ 'Quantas vezes essa hora calendário integrou o expediente (dias locais no intervalo × slots de opening_hours)',
137
+ })
138
+ openOccurrencesInPeriod: number;
139
+ }
140
+
141
+ export class AnalyticsDashboardMessagePeakDto {
142
+ @ApiProperty({ description: 'Hora local (0–23) com maior totalSent entre as horas de expediente' })
143
+ hour: number;
144
+
145
+ @ApiProperty() totalSent: number;
146
+
147
+ @ApiProperty() averageSent: number;
148
+ }
149
+
120
150
  /**
121
151
  * Resposta enriquecida de `GET /analytics/dashboard` (mantém campos legados `total`, `byEventType`, `byDomain`).
122
152
  */
@@ -157,6 +187,26 @@ export class AnalyticsDashboardResponseDto {
157
187
  @ApiProperty({ type: [AnalyticsDashboardTopProcedureDto], maxItems: 5 })
158
188
  topProcedures: AnalyticsDashboardTopProcedureDto[];
159
189
 
190
+ @ApiProperty({
191
+ description:
192
+ 'Pico / distribuição de mensagens no horário da clínica: médias por hora local (só `message.sent` dentro de opening_hours). Ordenado por hora crescente. Vazio se não houver opening_hours.',
193
+ type: [AnalyticsDashboardMessageHourDto],
194
+ })
195
+ messagesByClinicHour: AnalyticsDashboardMessageHourDto[];
196
+
197
+ @ApiProperty({
198
+ description: 'Hora com maior volume de mensagens no expediente; null se não houver dados ou horário configurado',
199
+ nullable: true,
200
+ type: AnalyticsDashboardMessagePeakDto,
201
+ })
202
+ messagesPeakHour: AnalyticsDashboardMessagePeakDto | null;
203
+
204
+ @ApiProperty({
205
+ description: 'Fuso IANA usado para hora local e opening_hours (env ANALYTICS_CLINIC_TIMEZONE ou America/Sao_Paulo)',
206
+ example: 'America/Sao_Paulo',
207
+ })
208
+ clinicTimezone: string;
209
+
160
210
  @ApiProperty({ description: 'Total de eventos de analytics no período (legado)' })
161
211
  total: number;
162
212
 
@@ -5,6 +5,7 @@ export {
5
5
  export {
6
6
  TOPIC_NOTIFICATIONS_FIND_ALL,
7
7
  TOPIC_NOTIFICATIONS_REGISTER_PUSH_TOKEN,
8
+ TOPIC_NOTIFICATIONS_UPDATE_VIEWED,
8
9
  } from './notifications-kafka-topics';
9
10
  export {
10
11
  RegisterPushTokenDto,
@@ -18,3 +19,7 @@ export {
18
19
  type NotificationStatusFilterDto,
19
20
  } from './list-notifications-query.dto';
20
21
  export { NotificationListItemDto } from './notification-list-item.dto';
22
+ export {
23
+ UpdateNotificationViewedDto,
24
+ NotificationsUpdateViewedKafkaDto,
25
+ } from './update-notification-viewed.dto';
@@ -19,4 +19,17 @@ export class NotificationListItemDto {
19
19
 
20
20
  @ApiProperty({ example: '2026-04-08T12:00:00.000Z' })
21
21
  updatedAt: string;
22
+
23
+ @ApiProperty({
24
+ description: 'Indica se foi marcada como visualizada (viewedAt != null)',
25
+ example: false,
26
+ })
27
+ viewed: boolean;
28
+
29
+ @ApiProperty({
30
+ description: 'Instante em que foi marcada como visualizada; null se não visualizada',
31
+ nullable: true,
32
+ example: null,
33
+ })
34
+ viewedAt: string | null;
22
35
  }
@@ -3,3 +3,6 @@ export const TOPIC_NOTIFICATIONS_FIND_ALL = 'notifications.findAll';
3
3
 
4
4
  export const TOPIC_NOTIFICATIONS_REGISTER_PUSH_TOKEN =
5
5
  'notifications.registerPushToken';
6
+
7
+ /** Kafka request–reply: atualizar visualização de uma notificação persistida. */
8
+ export const TOPIC_NOTIFICATIONS_UPDATE_VIEWED = 'notifications.updateViewed';
@@ -0,0 +1,37 @@
1
+ import { ApiProperty } from '@nestjs/swagger';
2
+ import { Type } from 'class-transformer';
3
+ import {
4
+ IsBoolean,
5
+ IsNotEmpty,
6
+ IsString,
7
+ IsUUID,
8
+ ValidateNested,
9
+ } from 'class-validator';
10
+
11
+ /**
12
+ * Corpo HTTP PUT /notifications/:id — marca se o registo foi visualizado.
13
+ */
14
+ export class UpdateNotificationViewedDto {
15
+ @ApiProperty({
16
+ description: 'true = visualizada (grava viewedAt); false = não visualizada (limpa viewedAt)',
17
+ example: true,
18
+ })
19
+ @IsBoolean()
20
+ viewed: boolean;
21
+ }
22
+
23
+ /**
24
+ * Payload Kafka `notifications.updateViewed`.
25
+ */
26
+ export class NotificationsUpdateViewedKafkaDto {
27
+ @IsString()
28
+ @IsNotEmpty()
29
+ tenant: string;
30
+
31
+ @IsUUID('4')
32
+ id: string;
33
+
34
+ @ValidateNested()
35
+ @Type(() => UpdateNotificationViewedDto)
36
+ payload: UpdateNotificationViewedDto;
37
+ }