{"_id":"@adatechnology/scheduling-contracts","_rev":"4-4d0af2c466c70b7ce241141dad7c4239","name":"@adatechnology/scheduling-contracts","dist-tags":{"latest":"0.1.0","rc":"0.1.0-rc.2"},"versions":{"0.1.0-rc.1":{"name":"@adatechnology/scheduling-contracts","version":"0.1.0-rc.1","license":"MIT","_id":"@adatechnology/scheduling-contracts@0.1.0-rc.1","maintainers":[{"name":"miyazaki","email":"andersonfrfilho@gmail.com"}],"dist":{"shasum":"c3ffcb677a17f81458af76cd05a257507a155adf","tarball":"https://registry.npmjs.org/@adatechnology/scheduling-contracts/-/scheduling-contracts-0.1.0-rc.1.tgz","fileCount":8,"integrity":"sha512-TUK/BnX710FyJ0R7jIsLgvTigom2upjd//o1mwwrcixTpx3VdUAAAJgnDM4x0TAnoHwqQowE+BxItqR690bbXg==","signatures":[{"sig":"MEUCIQDdnA3DFSa3AM6/6ZdniU6UnHQdPIRwfcWOyIv3D1+8ugIgQAVNA+y+02RAA+/Ux1/+1tB53aZcKz9hDgjH7GLG2L0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":191947},"main":"dist/index.js","type":"module","_from":"file:adatechnology-scheduling-contracts-0.1.0-rc.1.tgz","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"scripts":{"test":"bun test","build":"tsup","check":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"miyazaki","email":"andersonfrfilho@gmail.com"},"_resolved":"/tmp/e3ffadea752b6cf98eb281015132bf65/adatechnology-scheduling-contracts-0.1.0-rc.1.tgz","_integrity":"sha512-TUK/BnX710FyJ0R7jIsLgvTigom2upjd//o1mwwrcixTpx3VdUAAAJgnDM4x0TAnoHwqQowE+BxItqR690bbXg==","_npmVersion":"10.9.8","description":"Shared types, zod schemas and port interfaces for the scheduling trio (contracts only — no runtime behavior)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"zod":"^3.24.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","@types/bun":"1.3.14","typescript":"^5.7.3"},"_npmOperationalInternal":{"tmp":"tmp/scheduling-contracts_0.1.0-rc.1_1787008173834_0.7661159321331754","host":"s3://npm-registry-packages-npm-production"}},"0.1.0-rc.2":{"name":"@adatechnology/scheduling-contracts","version":"0.1.0-rc.2","license":"MIT","_id":"@adatechnology/scheduling-contracts@0.1.0-rc.2","maintainers":[{"name":"miyazaki","email":"andersonfrfilho@gmail.com"}],"dist":{"shasum":"9d6c0b8424848a06249927de09e432c7ccffe6b7","tarball":"https://registry.npmjs.org/@adatechnology/scheduling-contracts/-/scheduling-contracts-0.1.0-rc.2.tgz","fileCount":8,"integrity":"sha512-HjNwfZQUEVa5fNrQ3S05IuoiuUivu36FamMx+3JNzYuAdWpXwZ5djHbELKATWsNYmwm0GPIdkj5PZlUgdkcpDg==","signatures":[{"sig":"MEQCIGluwoPhAbmOCf+WgLo1/F3aE5tuWntXUKqR25YJf3QaAiAefvHRJNmN1M+bx28s908xY1CKFwvo+AGTXNTV2oKbtw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":196461},"main":"dist/index.js","type":"module","_from":"file:adatechnology-scheduling-contracts-0.1.0-rc.2.tgz","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"scripts":{"test":"bun test","build":"tsup","check":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"miyazaki","email":"andersonfrfilho@gmail.com"},"_resolved":"/tmp/4c5726ffa7c8b868f11350fb7e9bfe10/adatechnology-scheduling-contracts-0.1.0-rc.2.tgz","_integrity":"sha512-HjNwfZQUEVa5fNrQ3S05IuoiuUivu36FamMx+3JNzYuAdWpXwZ5djHbELKATWsNYmwm0GPIdkj5PZlUgdkcpDg==","_npmVersion":"10.9.8","description":"Shared types, zod schemas and port interfaces for the scheduling trio (contracts only — no runtime behavior)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"zod":"^3.24.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","@types/bun":"1.3.14","typescript":"^5.7.3"},"_npmOperationalInternal":{"tmp":"tmp/scheduling-contracts_0.1.0-rc.2_1787460517968_0.06294122740779495","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@adatechnology/scheduling-contracts","version":"0.1.0","license":"MIT","description":"Shared types, zod schemas and port interfaces for the scheduling trio (contracts only — no runtime behavior)","publishConfig":{"access":"public"},"type":"module","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"dependencies":{"zod":"^3.24.1"},"devDependencies":{"@types/bun":"1.3.14","tsup":"^8.5.1","typescript":"^5.7.3"},"scripts":{"build":"tsup","check":"tsc -p tsconfig.json --noEmit","test":"bun test"},"_id":"@adatechnology/scheduling-contracts@0.1.0","_integrity":"sha512-gYMuH2RErjv51ZSb/bGwtoSnHxIKSRRjqCVpSUIKwNzjk7EEvqaurDDQ5+phh5BDDsDh19Xl+CF5UzEGOvZPuQ==","_resolved":"/tmp/d636d56da587e4a15feab4ccd0de2e8a/adatechnology-scheduling-contracts-0.1.0.tgz","_from":"file:adatechnology-scheduling-contracts-0.1.0.tgz","_nodeVersion":"22.23.2","_npmVersion":"10.9.8","dist":{"integrity":"sha512-gYMuH2RErjv51ZSb/bGwtoSnHxIKSRRjqCVpSUIKwNzjk7EEvqaurDDQ5+phh5BDDsDh19Xl+CF5UzEGOvZPuQ==","shasum":"8be6a9b9f6c7bf51cc3b53518b50eaf79a233ffb","tarball":"https://registry.npmjs.org/@adatechnology/scheduling-contracts/-/scheduling-contracts-0.1.0.tgz","fileCount":8,"unpackedSize":196456,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDEzoCLmLxHZDrP3VGHHVpuU5rLo+UYJnhIrIJ60HafRgIgE8eyIQPiGcNARajb14nGjJy1wJmLsnygDfOFqAaHDVc="}]},"_npmUser":{"name":"miyazaki","email":"andersonfrfilho@gmail.com"},"directories":{},"maintainers":[{"name":"miyazaki","email":"andersonfrfilho@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/scheduling-contracts_0.1.0_1788318101926_0.25734510729968285"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-17T23:09:33.535Z","modified":"2026-09-02T03:01:42.238Z","0.1.0-rc.1":"2026-08-17T23:09:33.981Z","0.1.0-rc.2":"2026-08-23T04:48:38.111Z","0.1.0":"2026-09-02T03:01:42.089Z"},"license":"MIT","description":"Shared types, zod schemas and port interfaces for the scheduling trio (contracts only — no runtime behavior)","maintainers":[{"name":"miyazaki","email":"andersonfrfilho@gmail.com"}],"readme":"# @adatechnology/scheduling-contracts\n\n**Tipos, schemas e contratos de porta** para o módulo de agendamento.\nTypeScript, sem dependências de runtime (só Zod para validação em boundaries).\n\n- **Tipos de domínio** — `Resource`, `Service`, `Booking`, `AvailabilityRule`, `AvailabilityException`\n- **Schemas Zod** — validação de entrada para todo endpoint e worker\n- **Interfaces de porta** — contratos de inversão que o host implementa (`VideoMeetingPort`, `CalendarSyncPort`, etc)\n- **Eventos e hooks** — sete eventos de ciclo de vida, com hooks opcionais para regra comercial\n\nPacote-irmão do `scheduling-module` (a implementação); consumido também pelo host (API, BFF, worker).\n\n---\n\n## Instalação\n\n```bash\nnpm i @adatechnology/scheduling-contracts\n# ou: pnpm add / bun add\n```\n\nNenhuma dependência de runtime além de `zod`.\n\n---\n\n## O que este pacote exporta\n\n### Tipos de domínio\n\nToda entidade de agendamento tem seu tipo TypeScript correspondente:\n\n```ts\nimport type {\n  Resource,\n  Service,\n  Booking,\n  BookingSlot,\n  AvailabilityRule,\n  AvailabilityException,\n} from '@adatechnology/scheduling-contracts'\n```\n\nEnums são constantes (`as const`): `RESOURCE_KIND`, `BOOKING_STATUS`, `BOOKING_PARTICIPANT_RESPONSE_STATUS`, etc.\n\n### Schemas de validação\n\nZod schemas para toda entrada (body, query, path, eventos):\n\n```ts\nimport {\n  createResourceSchema,\n  updateResourceSchema,\n  requestBookingSchema,\n  rescheduleBookingSchema,\n  cancelBookingSchema,\n  listBookingsQuerySchema,\n  getAvailabilityQuerySchema,\n} from '@adatechnology/scheduling-contracts'\n\n// Validar entrada de API\nconst input = createResourceSchema.parse(req.body)\n```\n\n---\n\n## Portas (interfaces de integração)\n\nPortas são contratos que o **host implementa** — o módulo não conhece a implementação concreta,\nsó chama pelo contrato. Ausência de uma porta = capacidade desligada (não é erro, é opção).\n\n### `AuthContextResolverPort`\n\nResolve identidade do usuário a partir de headers HTTP:\n\n```ts\nimport type { AuthContextResolverPort } from '@adatechnology/scheduling-contracts'\n\nconst resolver: AuthContextResolverPort = {\n  async resolve({ headers }) {\n    // Validação de token, JWT, sessão — já feita fora\n    // Retorna contexto ou undefined (não autenticado)\n    return {\n      companyId: '...',\n      userId: '...',\n      scopes: ['scheduling:read', 'scheduling:write'],\n    }\n  },\n}\n```\n\n`AuthContext` já vem **validado pelo host** — o módulo não verifica token nem descobre o emissor.\nVem apenas `companyId` (obrigatório) e `userId` (opcional para máquina-a-máquina).\n\n### `VideoMeetingPort`\n\nCriar/deletar links de reunião (Zoom, Google Meet, etc):\n\n```ts\nimport type { VideoMeetingPort } from '@adatechnology/scheduling-contracts'\n\nconst videoMeeting: VideoMeetingPort = {\n  async createMeeting({ bookingId, title, startsAt, endsAt }) {\n    // Chamar Zoom, Google Calendar, etc\n    // Retorna meetingUrl ou erro\n    return {\n      outcome: 'created',\n      meetingUrl: 'https://zoom.us/j/...',\n    }\n  },\n  \n  async deleteMeeting(meetingUrl) {\n    // Remover a reunião\n  },\n}\n```\n\n**Ausente = presencial.** Se você não injetar `VideoMeetingPort`, o módulo não cria link.\nFalha ao criar link **não bloqueia** a confirmação de reserva — o módulo loga e segue.\n\n### `CalendarSyncPort`\n\nEspelho unidirecional (push) em Google Calendar, Outlook, etc:\n\n```ts\nimport type { CalendarSyncPort } from '@adatechnology/scheduling-contracts'\n\nconst calendarSync: CalendarSyncPort = {\n  async upsertEvent({ externalCalendarId, title, startsAt, endsAt, notes }) {\n    // Criar ou atualizar evento no calendário externo\n    return {\n      outcome: 'synced',\n      externalEventId: 'event-123',\n    }\n  },\n  \n  async deleteEvent(externalEventId) {\n    // Remover evento do calendário externo\n  },\n  \n  async readEvents({ from, until }) {\n    // Listar eventos no intervalo (implementado na v2)\n    // Por enquanto retorna array vazio\n    return []\n  },\n}\n```\n\n**Push-only na v1** — sem webhook do fornecedor, sem sync bidirecional, sem resolução de conflito.\n`readEvents` já vem declarado (sem implementação) para não virar breaking change depois.\n\n**Ausente = sem espelho.** Config `calendarSync.enabled: true` sem porta plugada = erro no boot (`CalendarSyncDisabledError`).\n\n### `ClockPort`\n\nRelógio injetável (para teste, para lidar com clock skew):\n\n```ts\nimport type { ClockPort } from '@adatechnology/scheduling-contracts'\n\nconst clock: ClockPort = {\n  now() {\n    return new Date()\n  },\n}\n```\n\n### `LoggerPort`\n\nLogger estruturado (máscara de PII obrigatória):\n\n```ts\nimport type { LoggerPort } from '@adatechnology/scheduling-contracts'\n\nconst logger: LoggerPort = {\n  debug(message, meta) { /* ... */ },\n  info(message, meta) { /* ... */ },\n  warn(message, meta) { /* ... */ },\n  error(message, meta) { /* ... */ },\n}\n```\n\n---\n\n## Configuração do módulo\n\n`SchedulingModuleConfig` agrupa opções de negócio e capacidade:\n\n```ts\nimport type { SchedulingModuleConfig } from '@adatechnology/scheduling-contracts'\n\nconst config: SchedulingModuleConfig = {\n  // Teto de dias consultáveis numa janela de disponibilidade\n  maxLookaheadDays: 90,\n  \n  // Prazo mínimo para cancelamento (em minutos), 0 = desliga\n  defaultMinCancellationNoticeMinutes: 1440, // 24h\n  \n  // Tolerância para \"horário no passado\" em criação/remarcação\n  pastBookingToleranceMinutes: 0,\n  \n  // Janela de antecedência para lembrete (padrão 1440 = 24h)\n  reminderAdvanceMinutes: 1440,\n  \n  // Ligar espelho em calendário externo\n  calendarSync: {\n    enabled: true,\n  },\n}\n```\n\n---\n\n## Eventos e hooks\n\nO módulo dispara sete eventos ao longo do ciclo de vida de uma reserva.\n**Hooks são opcionais** — você só implementa o que precisa.\n\n### Hooks são void-tolerantes\n\nSe um hook lançar erro, o módulo **captura, loga e segue**. Regra comercial (notificar por WhatsApp,\ngravar em CRM, multa por no-show) nunca vira `if` dentro do agendamento — sempre um hook plugado aqui.\n\n```ts\nimport type { SchedulingHooks } from '@adatechnology/scheduling-contracts'\n\nconst hooks: SchedulingHooks = {\n  async onBookingRequested(event) {\n    // Reserva foi solicitada (ainda não confirmada)\n    // Integrar com CRM, notificar, aplicar política de sinal\n  },\n  \n  async onBookingConfirmed(event) {\n    // Reserva foi confirmada\n    // Notificar cliente, criar tarefa, registrar contato\n  },\n  \n  async onBookingRescheduled(event) {\n    // Reserva foi remarcada (event.previousDuring tem a faixa anterior)\n    // Notificar: \"mudou de X para Y\"\n  },\n  \n  async onBookingCancelled(event) {\n    // Reserva foi cancelada (event.cancelledBy é quem pediu)\n    // Notificar, reembolsar, aplicar multa por no-show\n  },\n  \n  async onBookingReminderDue(event) {\n    // Reminder foi disparado (geralmente 24h antes)\n    // Enviar SMS, WhatsApp, notificação push\n  },\n  \n  async onBookingCompleted(event) {\n    // Reserva transcorreu (passou a hora)\n    // Registrar no histórico, liberar para feedback\n  },\n  \n  async onBookingNoShow(event) {\n    // Cliente não compareceu\n    // Multa, entrada em blacklist, CRM updated\n  },\n}\n```\n\nCada hook recebe evento tipado com metadados — `companyId`, `bookingId`, `resourceIds`, `serviceId` (quando houver).\n\n---\n\n## Erros\n\nToda operação falha com uma das erros especializados:\n\n```ts\nimport {\n  SchedulingError,\n  SCHEDULING_ERROR_CODES,\n  ResourceNotFoundError,\n  ServiceNotFoundError,\n  AvailabilityExceptionNotFoundError,\n  BookingNotFoundError,\n  SlotUnavailableError,\n  CancellationTooLateError,\n  BookingInPastError,\n  ResourceUnavailableError,\n  ServiceNotOfferedByResourceError,\n  ConfigMissingError,\n  LookaheadWindowTooLargeError,\n  CalendarSyncDisabledError,\n} from '@adatechnology/scheduling-contracts'\n```\n\nCada erro estende `SchedulingError` e carrega:\n- `statusCode` — HTTP apropriado (404, 409, 400, 500)\n- `code` — chave estável para tratamento na UI (`SCHEDULING_SLOT_UNAVAILABLE`, etc)\n- `details` — contexto tipado (ex: `{ resourceId, during }`)\n\n| Erro | Causa | Status |\n|---|---|---|\n| `ResourceNotFoundError` | Recurso não existe ou foi deletado | 404 |\n| `ServiceNotFoundError` | Serviço não existe | 404 |\n| `AvailabilityExceptionNotFoundError` | Exceção de disponibilidade não existe | 404 |\n| `BookingNotFoundError` | Reserva não existe | 404 |\n| `SlotUnavailableError` | Horário já foi ocupado por outra reserva (constraint `booking_slot_no_overlap`) | 409 |\n| `CancellationTooLateError` | Prazo mínimo de cancelamento passou | 409 |\n| `BookingInPastError` | Tentou agendar/remarcar para o passado | 400 |\n| `ResourceUnavailableError` | Recurso inativo, deletado ou fora da janela de validade | 409 |\n| `ServiceNotOfferedByResourceError` | Este recurso não oferece este serviço | 400 |\n| `ConfigMissingError` | Campo obrigatório da config falta no boot | 500 |\n| `LookaheadWindowTooLargeError` | Consultou mais dias que `maxLookaheadDays` | 400 |\n| `CalendarSyncDisabledError` | Config habilitou sync mas porta não foi plugada | 409 |\n\n---\n\n## Utilitários exportados\n\n| Tipo | Uso |\n|---|---|\n| Tipos de domínio | `Resource`, `Service`, `Booking`, `AvailabilityRule`, `AvailabilityException`, `BookingSlot`, `BookingParticipant` |\n| Schemas Zod | `createResourceSchema`, `requestBookingSchema`, `listBookingsQuerySchema`, `getAvailabilityQuerySchema`, etc |\n| Portas | `AuthContextResolverPort`, `VideoMeetingPort`, `CalendarSyncPort`, `ClockPort`, `LoggerPort` |\n| Tipos de porta | `AuthContext`, `VideoMeetingRequest`, `CalendarEventPayload`, `LogMeta`, `SchedulingModuleConfig` |\n| Eventos | `SCHEDULING_EVENT` (constantes), `SchedulingHooks`, `BookingRequestedEvent`, `BookingConfirmedEvent`, etc |\n| Erros | `SchedulingError`, `SCHEDULING_ERROR_CODES`, 12 erros especializados |\n\n---\n\n## Pré-requisitos\n\n- **TypeScript 5.0+**\n- **Zod 3.x** — importado automaticamente em schemas\n- **Conhecimento de portas/inversão de controle** — o pacote é contrato puro\n\n---\n\n## Como consumir em `scheduling-module`\n\nO módulo é uma função fábrica que injeta portas e hooks — não uma classe:\n\n```ts\nimport { createSchedulingModule } from '@adatechnology/scheduling-module'\nimport type { SchedulingModuleConfig } from '@adatechnology/scheduling-contracts'\n\nconst scheduling = createSchedulingModule({\n  db,\n  config,\n  providers: {\n    clock,\n    logger,\n    videoMeeting, // opcional\n    calendarSync, // opcional\n  },\n  hooks, // opcional\n})\n```\n\nQuando uma porta está ausente, a capacidade é desligada — sem flag, sem null check em callback.\n\n---\n\n## Licença\n\nMIT © Ada Technology\n","readmeFilename":"README.md"}