tychat-contracts 1.6.8 → 1.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,26 +1,26 @@
1
- import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
2
-
3
- /**
4
- * Resposta de `POST /auth/password-reset/request`.
5
- * - Sem utilizador ou utilizador sem 2FA: apenas mensagem genérica (e e-mail com senha provisória se existir conta sem 2FA).
6
- * - Utilizador com 2FA: inclui token para o passo seguinte (`finalize-2fa`).
7
- */
8
- export class RequestPasswordResetResponseDto {
9
- @ApiProperty({ example: true })
10
- success: boolean;
11
-
12
- @ApiProperty({
13
- description: 'Mensagem genérica (não revela se o e-mail existe, exceto quando two_factor_required é true)',
14
- })
15
- message: string;
16
-
17
- @ApiPropertyOptional({
18
- description: 'Presente quando o e-mail existe e o utilizador tem 2FA ativo',
19
- })
20
- two_factor_required?: boolean;
21
-
22
- @ApiPropertyOptional({
23
- description: 'JWT de curta duração para `POST /auth/password-reset/finalize-2fa`',
24
- })
25
- pre_recovery_token?: string;
26
- }
1
+ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
2
+
3
+ /**
4
+ * Resposta de `POST /auth/password-reset/request`.
5
+ * - Sem utilizador ou utilizador sem 2FA: apenas mensagem genérica (e e-mail com senha provisória se existir conta sem 2FA).
6
+ * - Utilizador com 2FA: inclui token para o passo seguinte (`finalize-2fa`).
7
+ */
8
+ export class RequestPasswordResetResponseDto {
9
+ @ApiProperty({ example: true })
10
+ success: boolean;
11
+
12
+ @ApiProperty({
13
+ description: 'Mensagem genérica (não revela se o e-mail existe, exceto quando two_factor_required é true)',
14
+ })
15
+ message: string;
16
+
17
+ @ApiPropertyOptional({
18
+ description: 'Presente quando o e-mail existe e o utilizador tem 2FA ativo',
19
+ })
20
+ two_factor_required?: boolean;
21
+
22
+ @ApiPropertyOptional({
23
+ description: 'JWT de curta duração para `POST /auth/password-reset/finalize-2fa`',
24
+ })
25
+ pre_recovery_token?: string;
26
+ }
@@ -1,19 +1,19 @@
1
- import { ApiPropertyOptional } from '@nestjs/swagger';
2
- import { IsOptional, IsString, MaxLength, MinLength } from 'class-validator';
3
-
4
- /** Corpo de `POST /device-sessions/:id/revoke` — confirma identidade antes do logout remoto. */
5
- export class RevokeDeviceSessionDto {
6
- @ApiPropertyOptional({ description: 'Senha atual (obrigatória se 2FA não estiver ativo)' })
7
- @IsOptional()
8
- @IsString()
9
- @MinLength(1)
10
- @MaxLength(255)
11
- password?: string;
12
-
13
- @ApiPropertyOptional({ description: 'Código TOTP de 6 dígitos (obrigatório se 2FA estiver ativo)' })
14
- @IsOptional()
15
- @IsString()
16
- @MinLength(6)
17
- @MaxLength(6)
18
- totp?: string;
19
- }
1
+ import { ApiPropertyOptional } from '@nestjs/swagger';
2
+ import { IsOptional, IsString, MaxLength, MinLength } from 'class-validator';
3
+
4
+ /** Corpo de `POST /device-sessions/:id/revoke` — confirma identidade antes do logout remoto. */
5
+ export class RevokeDeviceSessionDto {
6
+ @ApiPropertyOptional({ description: 'Senha atual (obrigatória se 2FA não estiver ativo)' })
7
+ @IsOptional()
8
+ @IsString()
9
+ @MinLength(1)
10
+ @MaxLength(255)
11
+ password?: string;
12
+
13
+ @ApiPropertyOptional({ description: 'Código TOTP de 6 dígitos (obrigatório se 2FA estiver ativo)' })
14
+ @IsOptional()
15
+ @IsString()
16
+ @MinLength(6)
17
+ @MaxLength(6)
18
+ totp?: string;
19
+ }
@@ -1,58 +1,58 @@
1
- import { ApiProperty } from '@nestjs/swagger';
2
- import { IsString, Matches, MaxLength, MinLength, ValidateIf } from 'class-validator';
3
-
4
- export class TotpSetupConfirmDto {
5
- @ApiProperty({ description: 'Código TOTP de 6 dígitos para confirmar o pareamento' })
6
- @IsString()
7
- @Matches(/^\d{6}$/, { message: 'totp deve ser exatamente 6 dígitos' })
8
- totp: string;
9
- }
10
-
11
- /** Resposta após confirmar o 2FA: códigos de recuperação mostrados uma única vez. */
12
- export class TotpSetupConfirmResponseDto {
13
- @ApiProperty({ description: 'Confirmação de sucesso' })
14
- success: true;
15
-
16
- @ApiProperty({
17
- type: [String],
18
- description:
19
- 'Seis códigos de recuperação (hex, 10 caracteres). Guardar em local seguro; não serão repetidos pela API.',
20
- })
21
- recovery_codes: string[];
22
- }
23
-
24
- export class TotpDisableDto {
25
- @ApiProperty({ description: 'Senha atual do utilizador' })
26
- @IsString()
27
- @MinLength(1, { message: 'current_password não pode ser vazio' })
28
- current_password: string;
29
-
30
- @ApiProperty({
31
- required: false,
32
- description: 'Código TOTP atual de 6 dígitos (obrigatório se não enviar recovery_code)',
33
- })
34
- @ValidateIf((o) => o.recovery_code == null || String(o.recovery_code).trim() === '')
35
- @IsString()
36
- @Matches(/^\d{6}$/, { message: 'totp deve ser exatamente 6 dígitos' })
37
- totp?: string;
38
-
39
- @ApiProperty({
40
- required: false,
41
- description:
42
- 'Um dos códigos de recuperação gerados na ativação (obrigatório se não enviar totp)',
43
- })
44
- @ValidateIf((o) => o.totp == null || String(o.totp).trim() === '')
45
- @IsString()
46
- @MinLength(10, { message: 'recovery_code inválido' })
47
- @MaxLength(64, { message: 'recovery_code inválido' })
48
- @Matches(/^[a-fA-F0-9\s-]+$/, { message: 'recovery_code inválido' })
49
- recovery_code?: string;
50
- }
51
-
52
- export class TotpSetupStartResponseDto {
53
- @ApiProperty({ description: 'URI otpauth para QR code' })
54
- otpauth_url: string;
55
-
56
- @ApiProperty({ description: 'Segredo em Base32 para entrada manual' })
57
- secret_base32: string;
58
- }
1
+ import { ApiProperty } from '@nestjs/swagger';
2
+ import { IsString, Matches, MaxLength, MinLength, ValidateIf } from 'class-validator';
3
+
4
+ export class TotpSetupConfirmDto {
5
+ @ApiProperty({ description: 'Código TOTP de 6 dígitos para confirmar o pareamento' })
6
+ @IsString()
7
+ @Matches(/^\d{6}$/, { message: 'totp deve ser exatamente 6 dígitos' })
8
+ totp: string;
9
+ }
10
+
11
+ /** Resposta após confirmar o 2FA: códigos de recuperação mostrados uma única vez. */
12
+ export class TotpSetupConfirmResponseDto {
13
+ @ApiProperty({ description: 'Confirmação de sucesso' })
14
+ success: true;
15
+
16
+ @ApiProperty({
17
+ type: [String],
18
+ description:
19
+ 'Seis códigos de recuperação (hex, 10 caracteres). Guardar em local seguro; não serão repetidos pela API.',
20
+ })
21
+ recovery_codes: string[];
22
+ }
23
+
24
+ export class TotpDisableDto {
25
+ @ApiProperty({ description: 'Senha atual do utilizador' })
26
+ @IsString()
27
+ @MinLength(1, { message: 'current_password não pode ser vazio' })
28
+ current_password: string;
29
+
30
+ @ApiProperty({
31
+ required: false,
32
+ description: 'Código TOTP atual de 6 dígitos (obrigatório se não enviar recovery_code)',
33
+ })
34
+ @ValidateIf((o) => o.recovery_code == null || String(o.recovery_code).trim() === '')
35
+ @IsString()
36
+ @Matches(/^\d{6}$/, { message: 'totp deve ser exatamente 6 dígitos' })
37
+ totp?: string;
38
+
39
+ @ApiProperty({
40
+ required: false,
41
+ description:
42
+ 'Um dos códigos de recuperação gerados na ativação (obrigatório se não enviar totp)',
43
+ })
44
+ @ValidateIf((o) => o.totp == null || String(o.totp).trim() === '')
45
+ @IsString()
46
+ @MinLength(10, { message: 'recovery_code inválido' })
47
+ @MaxLength(64, { message: 'recovery_code inválido' })
48
+ @Matches(/^[a-fA-F0-9\s-]+$/, { message: 'recovery_code inválido' })
49
+ recovery_code?: string;
50
+ }
51
+
52
+ export class TotpSetupStartResponseDto {
53
+ @ApiProperty({ description: 'URI otpauth para QR code' })
54
+ otpauth_url: string;
55
+
56
+ @ApiProperty({ description: 'Segredo em Base32 para entrada manual' })
57
+ secret_base32: string;
58
+ }
@@ -1,72 +1,72 @@
1
- import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
2
- import { Type } from 'class-transformer';
3
- import {
4
- IsArray,
5
- IsBoolean,
6
- IsEnum,
7
- IsNotEmpty,
8
- IsOptional,
9
- IsString,
10
- ValidateNested,
11
- } from 'class-validator';
12
- import {
13
- TYCHAT_APP_MODULE_KEYS,
14
- TYCHAT_APP_MODULE_POLICY_LEVELS,
15
- type TychatAppModuleKey,
16
- type TychatAppModulePolicyLevel,
17
- } from './app-module-policy.enums';
18
-
19
- export class AppModulePolicyDto {
20
- @ApiProperty({ enum: TYCHAT_APP_MODULE_KEYS })
21
- @IsEnum(TYCHAT_APP_MODULE_KEYS)
22
- moduleKey: TychatAppModuleKey;
23
-
24
- @ApiProperty()
25
- @IsBoolean()
26
- enabled: boolean;
27
-
28
- @ApiPropertyOptional({ enum: TYCHAT_APP_MODULE_POLICY_LEVELS })
29
- @IsOptional()
30
- @IsEnum(TYCHAT_APP_MODULE_POLICY_LEVELS)
31
- level?: TychatAppModulePolicyLevel;
32
- }
33
-
34
- export class UpdateAppModulePolicyDto {
35
- @ApiProperty({ enum: TYCHAT_APP_MODULE_KEYS })
36
- @IsEnum(TYCHAT_APP_MODULE_KEYS)
37
- moduleKey: TychatAppModuleKey;
38
-
39
- @ApiProperty()
40
- @IsBoolean()
41
- enabled: boolean;
42
- }
43
-
44
- export class UpdateAppModulePoliciesDto {
45
- @ApiProperty({ type: () => [UpdateAppModulePolicyDto] })
46
- @IsArray()
47
- @ValidateNested({ each: true })
48
- @Type(() => UpdateAppModulePolicyDto)
49
- policies: UpdateAppModulePolicyDto[];
50
- }
51
-
52
- export class ResolveAppModulePoliciesQueryDto {
53
- @ApiProperty()
54
- @IsString()
55
- @IsNotEmpty()
56
- tenantId: string;
57
- }
58
-
59
- export class EffectiveAppModulePolicyDto extends AppModulePolicyDto {
60
- @ApiPropertyOptional()
61
- @IsOptional()
62
- @IsString()
63
- reasonCode?: string;
64
- }
65
-
66
- export class EffectiveAppModulePoliciesDto {
67
- @ApiProperty({ type: () => [EffectiveAppModulePolicyDto] })
68
- @IsArray()
69
- @ValidateNested({ each: true })
70
- @Type(() => EffectiveAppModulePolicyDto)
71
- policies: EffectiveAppModulePolicyDto[];
72
- }
1
+ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
2
+ import { Type } from 'class-transformer';
3
+ import {
4
+ IsArray,
5
+ IsBoolean,
6
+ IsEnum,
7
+ IsNotEmpty,
8
+ IsOptional,
9
+ IsString,
10
+ ValidateNested,
11
+ } from 'class-validator';
12
+ import {
13
+ TYCHAT_APP_MODULE_KEYS,
14
+ TYCHAT_APP_MODULE_POLICY_LEVELS,
15
+ type TychatAppModuleKey,
16
+ type TychatAppModulePolicyLevel,
17
+ } from './app-module-policy.enums';
18
+
19
+ export class AppModulePolicyDto {
20
+ @ApiProperty({ enum: TYCHAT_APP_MODULE_KEYS })
21
+ @IsEnum(TYCHAT_APP_MODULE_KEYS)
22
+ moduleKey: TychatAppModuleKey;
23
+
24
+ @ApiProperty()
25
+ @IsBoolean()
26
+ enabled: boolean;
27
+
28
+ @ApiPropertyOptional({ enum: TYCHAT_APP_MODULE_POLICY_LEVELS })
29
+ @IsOptional()
30
+ @IsEnum(TYCHAT_APP_MODULE_POLICY_LEVELS)
31
+ level?: TychatAppModulePolicyLevel;
32
+ }
33
+
34
+ export class UpdateAppModulePolicyDto {
35
+ @ApiProperty({ enum: TYCHAT_APP_MODULE_KEYS })
36
+ @IsEnum(TYCHAT_APP_MODULE_KEYS)
37
+ moduleKey: TychatAppModuleKey;
38
+
39
+ @ApiProperty()
40
+ @IsBoolean()
41
+ enabled: boolean;
42
+ }
43
+
44
+ export class UpdateAppModulePoliciesDto {
45
+ @ApiProperty({ type: () => [UpdateAppModulePolicyDto] })
46
+ @IsArray()
47
+ @ValidateNested({ each: true })
48
+ @Type(() => UpdateAppModulePolicyDto)
49
+ policies: UpdateAppModulePolicyDto[];
50
+ }
51
+
52
+ export class ResolveAppModulePoliciesQueryDto {
53
+ @ApiProperty()
54
+ @IsString()
55
+ @IsNotEmpty()
56
+ tenantId: string;
57
+ }
58
+
59
+ export class EffectiveAppModulePolicyDto extends AppModulePolicyDto {
60
+ @ApiPropertyOptional()
61
+ @IsOptional()
62
+ @IsString()
63
+ reasonCode?: string;
64
+ }
65
+
66
+ export class EffectiveAppModulePoliciesDto {
67
+ @ApiProperty({ type: () => [EffectiveAppModulePolicyDto] })
68
+ @IsArray()
69
+ @ValidateNested({ each: true })
70
+ @Type(() => EffectiveAppModulePolicyDto)
71
+ policies: EffectiveAppModulePolicyDto[];
72
+ }
@@ -1,30 +1,30 @@
1
- /**
2
- * Módulos da aplicação web do tenant (Tychat-v2), controlados por plano e override por tenant.
3
- * Valores estáveis para API e persistência.
4
- */
5
- export const TYCHAT_APP_MODULE_KEYS = [
6
- 'dashboard',
7
- 'check_in',
8
- 'check_out',
9
- 'schedule',
10
- 'conversations',
11
- 'patients',
12
- 'patients_documents',
13
- 'patients_legal_terms',
14
- 'clinic_legal_terms',
15
- 'patients_anamneses',
16
- 'clinic_anamneses',
17
- 'ai_conversation',
18
- 'follow_up',
19
- 'funnel',
20
- 'satisfaction',
21
- 'clinic',
22
- 'billings',
23
- 'connections',
24
- 'settings',
25
- ] as const;
26
-
27
- export type TychatAppModuleKey = (typeof TYCHAT_APP_MODULE_KEYS)[number];
28
-
29
- export const TYCHAT_APP_MODULE_POLICY_LEVELS = ['default', 'plan', 'tenant'] as const;
30
- export type TychatAppModulePolicyLevel = (typeof TYCHAT_APP_MODULE_POLICY_LEVELS)[number];
1
+ /**
2
+ * Módulos da aplicação web do tenant (Tychat-v2), controlados por plano e override por tenant.
3
+ * Valores estáveis para API e persistência.
4
+ */
5
+ export const TYCHAT_APP_MODULE_KEYS = [
6
+ 'dashboard',
7
+ 'check_in',
8
+ 'check_out',
9
+ 'schedule',
10
+ 'conversations',
11
+ 'patients',
12
+ 'patients_documents',
13
+ 'patients_legal_terms',
14
+ 'clinic_legal_terms',
15
+ 'patients_anamneses',
16
+ 'clinic_anamneses',
17
+ 'ai_conversation',
18
+ 'follow_up',
19
+ 'funnel',
20
+ 'satisfaction',
21
+ 'clinic',
22
+ 'billings',
23
+ 'connections',
24
+ 'settings',
25
+ ] as const;
26
+
27
+ export type TychatAppModuleKey = (typeof TYCHAT_APP_MODULE_KEYS)[number];
28
+
29
+ export const TYCHAT_APP_MODULE_POLICY_LEVELS = ['default', 'plan', 'tenant'] as const;
30
+ export type TychatAppModulePolicyLevel = (typeof TYCHAT_APP_MODULE_POLICY_LEVELS)[number];
@@ -1,79 +1,79 @@
1
- import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
2
- import { TenantAiTokenStateDto } from '../tenants/tenant-ai-token-state.dto';
3
- import { EffectiveAppModulePolicyDto } from './app-module-policy.dto';
4
- import { PlanSummaryDto } from './plan-summary.dto';
5
- import { TenantLimitsSummaryDto } from './tenant-limits-summary.dto';
6
- import { TenantStorageUsageSummaryDto } from './tenant-storage-usage-summary.dto';
7
-
8
- /**
9
- * Tenant branding and subscription info returned with clinic configuration (no DB credentials).
10
- */
11
- export class ConfigurationTenantSummaryDto {
12
- @ApiProperty({ description: 'Tenant display name', example: 'Clínica Demo' })
13
- name: string;
14
-
15
- @ApiProperty({ description: 'CNPJ', example: '12345678000199' })
16
- cnpj: string;
17
-
18
- @ApiPropertyOptional({ description: 'Location / address', nullable: true })
19
- location: string | null;
20
-
21
- @ApiPropertyOptional({ description: 'Logo URL (light background)', nullable: true })
22
- logoWhite: string | null;
23
-
24
- @ApiPropertyOptional({ description: 'Logo URL (dark background)', nullable: true })
25
- logoDark: string | null;
26
-
27
- @ApiProperty({ description: 'Tenant status', enum: ['active', 'inactive'] })
28
- status: 'active' | 'inactive';
29
-
30
- @ApiPropertyOptional({
31
- description: 'Subscription plan',
32
- type: () => PlanSummaryDto,
33
- nullable: true,
34
- })
35
- plan: PlanSummaryDto | null;
36
-
37
- @ApiPropertyOptional({
38
- description: 'Per-tenant limit overrides',
39
- type: () => TenantLimitsSummaryDto,
40
- nullable: true,
41
- })
42
- limits: TenantLimitsSummaryDto | null;
43
-
44
- @ApiPropertyOptional({
45
- description: 'Uso acumulado por tipo (bytes como string)',
46
- type: () => TenantStorageUsageSummaryDto,
47
- nullable: true,
48
- })
49
- storageUsage: TenantStorageUsageSummaryDto | null;
50
-
51
- @ApiPropertyOptional({
52
- description: 'Saldo e cota de tokens de IA no ciclo atual',
53
- type: () => TenantAiTokenStateDto,
54
- nullable: true,
55
- })
56
- aiTokenState?: TenantAiTokenStateDto | null;
57
-
58
- @ApiPropertyOptional({ description: 'Limite efetivo de conversas em bytes (plano + extras)' })
59
- conversationEffectiveLimitBytes?: string;
60
-
61
- @ApiPropertyOptional({ description: 'Limite efetivo clínico em bytes (plano + extras)' })
62
- clinicEffectiveLimitBytes?: string;
63
-
64
- @ApiPropertyOptional({
65
- description: 'Valor mensal estimado pelos GB extras de armazenamento (soma dos dois tipos)',
66
- })
67
- extraStorageCharge?: number;
68
-
69
- @ApiPropertyOptional({
70
- description: 'Preço base do plano + extraStorageCharge',
71
- })
72
- effectivePlanPrice?: number;
73
-
74
- @ApiPropertyOptional({
75
- description: 'Módulos do app liberados para o tenant (resolução plano + override)',
76
- type: () => [EffectiveAppModulePolicyDto],
77
- })
78
- appModules?: EffectiveAppModulePolicyDto[];
79
- }
1
+ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
2
+ import { TenantAiTokenStateDto } from '../tenants/tenant-ai-token-state.dto';
3
+ import { EffectiveAppModulePolicyDto } from './app-module-policy.dto';
4
+ import { PlanSummaryDto } from './plan-summary.dto';
5
+ import { TenantLimitsSummaryDto } from './tenant-limits-summary.dto';
6
+ import { TenantStorageUsageSummaryDto } from './tenant-storage-usage-summary.dto';
7
+
8
+ /**
9
+ * Tenant branding and subscription info returned with clinic configuration (no DB credentials).
10
+ */
11
+ export class ConfigurationTenantSummaryDto {
12
+ @ApiProperty({ description: 'Tenant display name', example: 'Clínica Demo' })
13
+ name: string;
14
+
15
+ @ApiProperty({ description: 'CNPJ', example: '12345678000199' })
16
+ cnpj: string;
17
+
18
+ @ApiPropertyOptional({ description: 'Location / address', nullable: true })
19
+ location: string | null;
20
+
21
+ @ApiPropertyOptional({ description: 'Logo URL (light background)', nullable: true })
22
+ logoWhite: string | null;
23
+
24
+ @ApiPropertyOptional({ description: 'Logo URL (dark background)', nullable: true })
25
+ logoDark: string | null;
26
+
27
+ @ApiProperty({ description: 'Tenant status', enum: ['active', 'inactive'] })
28
+ status: 'active' | 'inactive';
29
+
30
+ @ApiPropertyOptional({
31
+ description: 'Subscription plan',
32
+ type: () => PlanSummaryDto,
33
+ nullable: true,
34
+ })
35
+ plan: PlanSummaryDto | null;
36
+
37
+ @ApiPropertyOptional({
38
+ description: 'Per-tenant limit overrides',
39
+ type: () => TenantLimitsSummaryDto,
40
+ nullable: true,
41
+ })
42
+ limits: TenantLimitsSummaryDto | null;
43
+
44
+ @ApiPropertyOptional({
45
+ description: 'Uso acumulado por tipo (bytes como string)',
46
+ type: () => TenantStorageUsageSummaryDto,
47
+ nullable: true,
48
+ })
49
+ storageUsage: TenantStorageUsageSummaryDto | null;
50
+
51
+ @ApiPropertyOptional({
52
+ description: 'Saldo e cota de tokens de IA no ciclo atual',
53
+ type: () => TenantAiTokenStateDto,
54
+ nullable: true,
55
+ })
56
+ aiTokenState?: TenantAiTokenStateDto | null;
57
+
58
+ @ApiPropertyOptional({ description: 'Limite efetivo de conversas em bytes (plano + extras)' })
59
+ conversationEffectiveLimitBytes?: string;
60
+
61
+ @ApiPropertyOptional({ description: 'Limite efetivo clínico em bytes (plano + extras)' })
62
+ clinicEffectiveLimitBytes?: string;
63
+
64
+ @ApiPropertyOptional({
65
+ description: 'Valor mensal estimado pelos GB extras de armazenamento (soma dos dois tipos)',
66
+ })
67
+ extraStorageCharge?: number;
68
+
69
+ @ApiPropertyOptional({
70
+ description: 'Preço base do plano + extraStorageCharge',
71
+ })
72
+ effectivePlanPrice?: number;
73
+
74
+ @ApiPropertyOptional({
75
+ description: 'Módulos do app liberados para o tenant (resolução plano + override)',
76
+ type: () => [EffectiveAppModulePolicyDto],
77
+ })
78
+ appModules?: EffectiveAppModulePolicyDto[];
79
+ }
@@ -1,13 +1,13 @@
1
- export * from './opening-hours-slot.dto';
2
- export * from './anamnesis-custom-field.dto';
3
- export * from './update-clinic-configuration.dto';
4
- export * from './clinic-configuration.dto';
5
- export * from './ai-tool-policy.enums';
6
- export * from './ai-tool-policy.dto';
7
- export * from './app-module-policy.enums';
8
- export * from './app-module-policy.dto';
9
- export * from './plan-summary.dto';
10
- export * from './tenant-limits-summary.dto';
11
- export * from './tenant-storage-usage-summary.dto';
12
- export * from './configuration-tenant-summary.dto';
13
- export * from './clinic-configuration-with-tenant.dto';
1
+ export * from './opening-hours-slot.dto';
2
+ export * from './anamnesis-custom-field.dto';
3
+ export * from './update-clinic-configuration.dto';
4
+ export * from './clinic-configuration.dto';
5
+ export * from './ai-tool-policy.enums';
6
+ export * from './ai-tool-policy.dto';
7
+ export * from './app-module-policy.enums';
8
+ export * from './app-module-policy.dto';
9
+ export * from './plan-summary.dto';
10
+ export * from './tenant-limits-summary.dto';
11
+ export * from './tenant-storage-usage-summary.dto';
12
+ export * from './configuration-tenant-summary.dto';
13
+ export * from './clinic-configuration-with-tenant.dto';
@@ -7,7 +7,17 @@ export type SignatureDocumentStatusValue =
7
7
  | 'signed'
8
8
  | 'refused'
9
9
  | 'cancelled'
10
- | 'expired';
10
+ | 'expired'
11
+ /** Fluxo impresso: aguardando upload da digitalização assinada (sem registro em signature-service). */
12
+ | 'upload_required';
13
+
14
+ /** Método de assinatura escolhido no envio do termo. */
15
+ export type LegalTermSignatureMethodValue = 'digital' | 'printed';
16
+
17
+ /** Política por tenant (admin): quais métodos o produto oferece. */
18
+ export type LegalTermSignaturePolicyValue =
19
+ | 'printed_only'
20
+ | 'printed_and_integrations';
11
21
 
12
22
  /** Item agregado para a ficha do paciente (API: clinic + signature). */
13
23
  export type PatientLegalTermDispatchItemDto = {
@@ -17,6 +27,7 @@ export type PatientLegalTermDispatchItemDto = {
17
27
  procedure_names: string[];
18
28
  dispatch_status: LegalTermDispatchStatusValue;
19
29
  error_code: string | null;
30
+ signature_method: LegalTermSignatureMethodValue;
20
31
  signature_document_id: string | null;
21
32
  signature_status: SignatureDocumentStatusValue | null;
22
33
  signed_at: string | null;
@@ -14,6 +14,9 @@ import {
14
14
  } from 'class-validator';
15
15
  import { LEGAL_TERM_BODY_FORMATS, type LegalTermBodyFormat } from './legal-term-body-format';
16
16
 
17
+ const LEGAL_TERM_SIGNATURE_METHODS = ['digital', 'printed'] as const;
18
+ export type LegalTermSignatureMethodDto = (typeof LEGAL_TERM_SIGNATURE_METHODS)[number];
19
+
17
20
  /** Valores explícitos para substituição na pré-visualização (sem inferência heurística). */
18
21
  export class LegalTermPreviewRequestDto {
19
22
  @ApiPropertyOptional({
@@ -69,13 +72,24 @@ export class LegalTermPreviewRequestDto {
69
72
  }
70
73
 
71
74
  export class LegalTermSendDto {
75
+ @ApiPropertyOptional({
76
+ enum: LEGAL_TERM_SIGNATURE_METHODS,
77
+ description:
78
+ 'Método de assinatura: digital (Clicksign + link no WhatsApp) ou printed (PDF para impressão, sem Clicksign). Padrão: digital.',
79
+ default: 'digital',
80
+ })
81
+ @IsOptional()
82
+ @IsIn(LEGAL_TERM_SIGNATURE_METHODS)
83
+ signatureMethod?: LegalTermSignatureMethodDto;
84
+
72
85
  @ApiProperty({ type: [String], format: 'uuid' })
73
86
  @IsArray()
74
87
  @IsUUID('4', { each: true })
75
88
  procedureIds: string[];
76
89
 
77
90
  @ApiProperty({
78
- description: 'Mensagem WhatsApp; deve conter exatamente {{ link_termo_juridico }}',
91
+ description:
92
+ 'Mensagem WhatsApp. Com signatureMethod digital (padrão), deve conter exatamente {{ link_termo_juridico }}. Com printed, qualquer texto (sem esse placeholder).',
79
93
  example: 'Olá, assine seu termo: {{ link_termo_juridico }}',
80
94
  })
81
95
  @IsString()