Contratos de API¶
Versão: 1.0
<Backward:- Container “API Backend” (C4 Nível 2,
01-Contexto-Container.md); - RF-001 a RF-024;
- UC-001 a UC-028.
- Container “API Backend” (C4 Nível 2,
>Forward:- TASK-001 a TASK-082.
Convenções gerais:
- Base URL:
/api(sem prefixo de versão — convenção já em uso nas tasks TASK-001 a TASK-070; caso o projeto evolua para múltiplas versões públicas, adotar/api/v1a partir daí, mediante ADR de breaking change) - Autenticação: Access Token JWT via cookie
httpOnly,Secure,SameSite(RF-021); rotas protegidas porAuthGuardglobal (ADR-008), exceto as marcadas como@Public() - Formato: JSON (
Content-Type: application/json) - Erros seguem o padrão:
{ "erro": string, "codigo": string } - Paginação:
?page=1&limit=20 - Datas: ISO 8601 (UTC)
- Toda rota protegida aplica RNF-002 (isolamento por usuário) implicitamente — o
userIdnunca é recebido no corpo da requisição, sempre extraído do Access Token
Autenticação¶
POST /auth/register¶
< Backward: RF-017, G-014.1, UC-019, US-036, US-037
Autenticação: Não requerida (@Public())
Request:
Response 201:
{
"id": "uuid",
"name": "Maria Silva",
"email": "maria@exemplo.com",
"status": "ATIVA",
"createdAt": "2026-07-24T12:00:00Z"
}
Response 400/409:
Não dispara verificação de e-mail (RNF-003) — conta criada Ativa imediatamente.
> Forward: TASK-061, TASK-062, TASK-063
POST /auth/login¶
< Backward: RF-018, RF-019, RF-020, G-014.2, G-014.2.3, UC-015, UC-016, UC-018, US-030, US-031, US-032, US-035
Autenticação: Não requerida (@Public())
Request:
Response 200 (sucesso):
{
"status": "success",
"user": { "id": "uuid", "name": "Maria Silva", "email": "maria@exemplo.com" }
}
Tokens setados via cookie httpOnly/Secure/SameSite (accessToken, refreshToken) — não retornados no corpo (ADR-006, ASR-003).
Response 403 (conta desativada, credenciais válidas — ver ADR-011):
{ "status": "requires_reactivation", "erro": "Conta desativada", "codigo": "ACCOUNT_REQUIRES_REACTIVATION" }
Response 401 (credenciais inválidas — genérico, RF-018):
Response 429 (bloqueio por força bruta, RF-019 — ver ADR-029):
{ "erro": "Conta temporariamente bloqueada. Tente novamente em 15 minutos.", "codigo": "ACCOUNT_LOCKED" }
> Forward: TASK-050, TASK-051, TASK-052, TASK-053, TASK-054, TASK-059, TASK-060
POST /auth/refresh¶
< Backward: RF-021, G-014.3, ASR-003, ADR-028
Autenticação: Requerida (via cookie refreshToken, não via Access Token)
Request: Corpo vazio — o Refresh Token é lido do cookie httpOnly.
Response 200:
Novo Access Token (e, conforme rotação adotada, novo Refresh Token) é setado via cookie.
Response 401:
> Forward: TASK-071
POST /user/reactivate¶
< Backward: RF-020, G-014.2.3, ASR-007, ADR-011, UC-018, US-035
Autenticação: Não requerida — mas exige e-mail + senha novamente como prova de identidade (não reaproveita sessão, pois nenhuma foi criada em /auth/login)
Request:
Response 200:
{
"status": "success",
"user": { "id": "uuid", "name": "Maria Silva", "email": "maria@exemplo.com" }
}
Conta alterada para Ativa; sessão gerada normalmente (mesmos cookies de /auth/login).
Response 401:
Response 400 (recusa de reativação — UC-018, fluxo 3a):
> Forward: TASK-059, TASK-060
GET /auth/sessions¶
< Backward: RF-021, G-014.3, UC-017, US-033, ADR-027
Autenticação: Requerida
Response 200:
[
{
"id": "uuid-sessao-A",
"userAgent": "Chrome no Windows",
"createdAt": "2026-07-20T10:00:00Z",
"isCurrent": true
},
{
"id": "uuid-sessao-B",
"userAgent": "Safari no iPhone",
"createdAt": "2026-07-22T09:00:00Z",
"isCurrent": false
}
]
O campo isCurrent (ADR-027) evita que o frontend precise decodificar o token para identificar a sessão corrente antes de permitir revogação em massa.
> Forward: TASK-055, TASK-056
DELETE /auth/sessions/{id}¶
< Backward: RF-021, G-014.3.1, UC-017, US-034
Autenticação: Requerida
Path params: id — UUID da sessão a revogar
Response 204: (sem corpo)
Response 404:
Response 403 (tentativa de revogar sessão de outro usuário):
> Forward: TASK-057, TASK-058
DELETE /auth/sessions¶
< Backward: RF-021, G-014.3.2, UC-017, US-034, ADR-027
Autenticação: Requerida
Request: Corpo vazio. Revoga todas as sessões exceto a sessão corrente (identificada pelo cookie da própria requisição), reutilizando revokeAllSessions(userId, exceptSessionId) (ADR-007).
Response 204: (sem corpo)
> Forward: TASK-081
Configurações / Conta¶
GET /user/me¶
< Backward: RF-016, G-013.1, UC-020
Autenticação: Requerida
Response 200:
{
"id": "uuid",
"name": "Maria Silva",
"email": "maria@exemplo.com",
"status": "ATIVA",
"createdAt": "2026-01-10T08:00:00Z"
}
> Forward: TASK-082, TASK-049
PUT /user/account¶
< Backward: RF-016, G-013.1, G-013.2, UC-020, US-038
Autenticação: Requerida
Request:
Response 200:
{
"id": "uuid",
"name": "Maria S. Silva",
"email": "maria.nova@exemplo.com",
"updatedAt": "2026-07-24T12:00:00Z"
}
Response 409:
> Forward: TASK-048, TASK-049
PUT /user/password¶
< Backward: RF-024, G-014.6, UC-021, US-039, US-040
Autenticação: Requerida
Request:
Response 200:
Efeito colateral (RF-024): revoga todas as demais sessões ativas, preservando a corrente (via revokeAllSessions(userId, exceptSessionId) — ADR-007).
Response 401:
Response 400:
> Forward: TASK-064, TASK-065, TASK-066
POST /user/deactivate¶
< Backward: RF-022, G-014.4.1, UC-022, US-041
Autenticação: Requerida
Request: Corpo vazio.
Response 200:
Todas as sessões (incluindo a corrente) são revogadas imediatamente (RF-021); cookies do cliente devem ser limpos no redirecionamento ao login público.
> Forward: TASK-067, TASK-068
DELETE /user/account¶
< Backward: RF-023, G-014.4.2, UC-022, US-042, ADR-010
Autenticação: Requerida
Request:
Response 204: (sem corpo) — deleção em cascata transacional de todos os Cadernos, Itens, Sub-itens e Sessões (ADR-010).
Response 400:
> Forward: TASK-069, TASK-070
Cadernos¶
POST /notebooks¶
< Backward: RF-001, G-001.1, UC-001, US-001
Autenticação: Requerida
Request:
Response 201:
Response 400:
> Forward: TASK-001, TASK-002
GET /notebooks¶
< Backward: RF-001, UC-001, US-002
Autenticação: Requerida
Response 200:
[
{ "id": "uuid-1", "name": "Trabalho", "createdAt": "2026-07-20T09:00:00Z" },
{ "id": "uuid-2", "name": "Pessoal", "createdAt": "2026-07-21T09:00:00Z" }
]
> Forward: TASK-003
DELETE /notebooks/{id}¶
< Backward: RF-011, G-008, G-008.1, ADR-010, ADR-020
Autenticação: Requerida
Path params: id — UUID do caderno
Response 200 (retorna a contagem afetada para feedback de UI):
Todos os itens do caderno têm notebookId setado para null (retorno à Inbox) em transação — nunca cascade automático (ADR-010, ADR-020).
Response 404:
> Forward: TASK-072, TASK-073
Inbox¶
POST /inbox¶
< Backward: RF-004, G-002, UC-002, US-003
Autenticação: Requerida
Request:
Response 201:
{
"id": "uuid",
"type": "TODO",
"title": "Ligar para o dentista",
"notebookId": null,
"isCompleted": false,
"createdAt": "2026-07-24T12:00:00Z"
}
Todo item capturado na Inbox nasce implicitamente como TODO (SCHEDULE sempre exige data/hora e não faz sentido em captura rápida sem classificação).
> Forward: TASK-004, TASK-005
GET /inbox¶
< Backward: RF-004, UC-002, US-004
Autenticação: Requerida
Response 200:
Equivalente a GET /items?notebookId=null, exposto como rota dedicada por clareza semântica do módulo Inbox.
> Forward: TASK-006
PATCH /items/{id}/classify¶
< Backward: RF-002, G-001.2, UC-003, US-005, US-006
Autenticação: Requerida
Path params: id — UUID do item na Inbox
Request:
Response 200:
Response 404:
> Forward: TASK-007, TASK-008, TASK-009
Itens¶
POST /items¶
< Backward: RF-005, RF-006, G-003, G-003.1, G-003.2, UC-004, US-007, US-008, US-009
Autenticação: Requerida
Request (TODO):
{
"type": "TODO",
"title": "Finalizar relatório",
"notebookId": "uuid-do-caderno",
"priority": 2,
"dueDate": "2026-07-30T00:00:00Z",
"scheduleId": null,
"recurrence": null
}
Request (SCHEDULE):
{
"type": "SCHEDULE",
"title": "Consulta médica",
"notebookId": "uuid-do-caderno",
"startAt": "2026-07-25T14:00:00Z",
"endAt": "2026-07-25T15:00:00Z",
"recurrence": { "frequency": "WEEKLY", "endDate": null }
}
Response 201:
{
"id": "uuid",
"type": "TODO",
"title": "Finalizar relatório",
"notebookId": "uuid-do-caderno",
"priority": 2,
"status": "ATIVO",
"isCompleted": false,
"dueDate": "2026-07-30T00:00:00Z",
"createdAt": "2026-07-24T12:00:00Z"
}
Response 400:
{ "erro": "scheduleId deve referenciar um item do tipo SCHEDULE", "codigo": "SCHEDULE_ID_MUST_REFERENCE_SCHEDULE" }
> Forward: TASK-010, TASK-011, TASK-012, TASK-013, TASK-014, TASK-027, TASK-028
GET /items/{id}¶
< Backward: RF-005, RF-006, ADR-004
Autenticação: Requerida
Path params: id — UUID do item
Response 200: (mesmo formato de POST /items, incluindo subItems quando type = TODO)
{
"id": "uuid",
"type": "TODO",
"title": "Finalizar relatório",
"notebookId": "uuid-do-caderno",
"priority": 2,
"status": "ATIVO",
"isCompleted": false,
"dueDate": "2026-07-30T00:00:00Z",
"subItems": [
{ "id": "uuid-sub-1", "title": "Revisar dados", "isCompleted": true }
]
}
Response 404:
> Forward: TASK-074
GET /items¶
< Backward: RF-012, G-009, UC-014, US-028, US-029
Autenticação: Requerida
Query params:
sort—manual(default) |priority|dueDate|createdAt|notebooknotebookId— filtra por cadernostatus—ATIVO|ARQUIVADO
Response 200:
{
"sort": "priority",
"items": [
{ "id": "uuid-1", "title": "Tarefa crítica", "priority": 1, "dueDate": "2026-07-25T00:00:00Z" },
{ "id": "uuid-2", "title": "Tarefa sem prioridade", "priority": null, "dueDate": null }
]
}
Quando sort não é informado ou é omitido, o backend aplica a combinação padrão (prioridade > data limite > data de criação) — RF-012.
> Forward: TASK-045, TASK-047
PATCH /items/{id}¶
< Backward: RF-006, RF-007, RF-008, ADR-004, ADR-012
Autenticação: Requerida
Path params: id — UUID do item
Request (campos parciais aceitos):
{
"title": "Finalizar relatório trimestral",
"priority": 1,
"dueDate": "2026-08-01T00:00:00Z",
"recurrence": { "frequency": "MONTHLY", "endDate": null }
}
Response 200: (item atualizado, mesmo formato de GET /items/{id})
Response 400:
Este endpoint não altera status, isCompleted ou snoozedUntil — essas transições possuem endpoints dedicados (/complete, /archive, /snooze) por serem transições de domínio validadas na entidade rica Item (ADR-012).
> Forward: TASK-075, TASK-027, TASK-028
PATCH /items/{id}/complete¶
< Backward: RF-010, G-007, G-007.1, ADR-024
Autenticação: Requerida
Path params: id — UUID do item (apenas type = TODO)
Request:
Response 200:
Conforme ADR-024, marcar como concluído não altera status (permanece ATIVO); apenas o arquivamento manual (RF-010) transiciona para ARQUIVADO.
Response 400 (tentativa em SCHEDULE):
> Forward: TASK-076
PATCH /items/{id}/archive¶
< Backward: RF-010, G-007.2, UC-008, US-016, ADR-012, ADR-024
Autenticação: Requerida
Path params: id — UUID do item
Request: Corpo vazio.
Response 200:
Response 400 (item ainda não concluído — pré-condição de domínio, ADR-012):
> Forward: TASK-025, TASK-026
PATCH /items/{id}/snooze¶
< Backward: RF-009, G-006, UC-010, US-019, US-020
Autenticação: Requerida
Path params: id — UUID do item ativo
Request (atalho rápido):
Valores aceitos de shortcut: TOMORROW (08:00 do dia seguinte), IN_3_DAYS, NEXT_MONDAY.
Request (data manual):
Response 200:
Response 400:
> Forward: TASK-030, TASK-031, TASK-032
POST /items/{id}/duplication¶
< Backward: RF-015, G-012, UC-006, US-012, US-013
Autenticação: Requerida
Path params: id — UUID do item original
Request:
titlePrefix é opcional; se omitido, o título é duplicado sem prefixo.
Response 201:
{
"id": "uuid-novo",
"title": "Cópia de Finalizar relatório",
"notebookId": "uuid-do-caderno-original",
"priority": 2,
"status": "ATIVO",
"isCompleted": false,
"dueDate": null,
"scheduleId": null
}
Não copia isCompleted (nasce false), sub-itens nem scheduleId (RF-015).
> Forward: TASK-018, TASK-019, TASK-020
PATCH /items/reorder¶
< Backward: RF-012, G-009, UC-014, US-028, ADR-026
Autenticação: Requerida
Request:
Conforme ADR-026, a reordenação manual é enviada como lote (array ordenado completo do escopo afetado), não como atualização de posição individual — evita inconsistências de concorrência entre múltiplos PATCH de posição isolados.
Response 200:
Response 400:
{ "erro": "Lista de IDs não corresponde aos itens do escopo informado", "codigo": "REORDER_MISMATCH" }
> Forward: TASK-079, TASK-046
DELETE /items/{id}¶
< Backward: RF-011, G-007.3, G-008, G-008.2, UC-007, US-014, US-015, ADR-025, ADR-021
Autenticação: Requerida
Path params: id — UUID do item
Query params: confirm (boolean, opcional — obrigatório apenas se o item possuir sub-itens, ver ADR-025)
Response 204: (sem corpo — item e, se houver, seus sub-itens removidos fisicamente da base, ADR-021)
Response 409 (item possui sub-itens e confirm não foi enviado — ver ADR-025):
{
"erro": "Item possui sub-itens vinculados; reenvie com confirm=true",
"codigo": "ITEM_HAS_SUBITEMS_CONFIRM_REQUIRED",
"subItemsCount": 3
}
> Forward: TASK-021, TASK-022, TASK-023, TASK-024
Sub-itens¶
POST /items/{todoId}/subitems¶
< Backward: RF-003, G-001.3, UC-005, US-010, US-011
Autenticação: Requerida
Path params: todoId — UUID do item pai (deve ser type = TODO)
Request:
Response 201:
{ "id": "uuid-sub", "itemId": "uuid-todo", "title": "Revisar dados financeiros", "isCompleted": false }
Response 400 (tentativa em SCHEDULE):
{ "erro": "Sub-itens só podem ser vinculados a itens do tipo TODO", "codigo": "SUBITEM_PARENT_NOT_TODO" }
> Forward: TASK-015, TASK-016
PATCH /items/{todoId}/subitems/{subItemId}¶
< Backward: RF-003, G-001.3, UC-005, US-011, ASR-013 (Arquitetura)
Autenticação: Requerida
Path params: todoId, subItemId
Request:
Response 200:
A conclusão afeta exclusivamente o escopo daquele sub-item — sem propagação a outros TODOs (US-011).
Response 404:
> Forward: TASK-077, TASK-016, TASK-017
DELETE /items/{todoId}/subitems/{subItemId}¶
< Backward: RF-003, G-001.3, ADR-021
Autenticação: Requerida
Path params: todoId, subItemId
Response 204: (sem corpo)
Response 404:
> Forward: TASK-078
Calendário¶
GET /calendar/daily¶
< Backward: RF-014, G-011.1, G-011.3, UC-011, US-021, US-023
Autenticação: Requerida
Query params: date (ISO 8601, obrigatório)
Response 200:
{
"date": "2026-07-25",
"items": [
{ "id": "uuid-1", "type": "SCHEDULE", "title": "Consulta médica", "startAt": "2026-07-25T14:00:00Z", "endAt": "2026-07-25T15:00:00Z" },
{ "id": "uuid-2", "type": "TODO", "title": "Entregar relatório", "dueDate": "2026-07-25T00:00:00Z" }
]
}
Regras de visibilidade centralizadas em CalendarVisibilityService (ADR-015): SCHEDULEs sempre aparecem; TODOs aparecem apenas com horário ou dueDate.
> Forward: TASK-033, TASK-034, TASK-037
GET /calendar/weekly¶
< Backward: RF-014, G-011.1, UC-011, US-022, US-023
Autenticação: Requerida
Query params: weekStart (ISO 8601, obrigatório — segunda-feira de referência)
Response 200:
{
"weekStart": "2026-07-20",
"days": [
{ "date": "2026-07-20", "items": [] },
{ "date": "2026-07-21", "items": [ { "id": "uuid-1", "type": "SCHEDULE", "title": "Reunião", "startAt": "2026-07-21T10:00:00Z", "endAt": "2026-07-21T11:00:00Z" } ] }
]
}
> Forward: TASK-035, TASK-036, TASK-037
GET /calendar/monthly¶
< Backward: RF-014, G-011.1, UC-011, US-022, US-023
Autenticação: Requerida
Query params: month (formato YYYY-MM, obrigatório)
Response 200:
{
"month": "2026-07",
"days": [
{ "date": "2026-07-01", "itemCount": 2 },
{ "date": "2026-07-02", "itemCount": 0 }
]
}
Visão mensal retorna contagem agregada por dia (grade); detalhamento por item fica a cargo da visão Diária/Agenda ao selecionar um dia específico.
> Forward: TASK-035, TASK-036, TASK-037
GET /calendar/agenda¶
< Backward: RF-014, G-011.1, UC-011, US-022, US-023
Autenticação: Requerida
Query params: from (ISO 8601, obrigatório), limit (default 20)
Response 200:
{
"items": [
{ "id": "uuid-1", "type": "SCHEDULE", "title": "Consulta médica", "startAt": "2026-07-25T14:00:00Z" },
{ "id": "uuid-2", "type": "TODO", "title": "Entregar relatório", "dueDate": "2026-07-26T00:00:00Z" }
]
}
Lista puramente cronológica, ordenada por startAt/dueDate ascendente.
> Forward: TASK-035, TASK-036, TASK-037
Planner Diário¶
GET /planner/daily¶
< Backward: RF-014, G-011.2, UC-012, US-024, US-025
Autenticação: Requerida
Query params: date (ISO 8601, obrigatório)
Response 200:
{
"date": "2026-07-25",
"items": [
{ "id": "uuid-1", "title": "Entregar relatório", "dueDate": "2026-07-25T00:00:00Z", "priority": 1 },
{ "id": "uuid-2", "title": "Ler artigo", "dueDate": null, "priority": null }
]
}
Inclui TODOs do dia selecionado e TODOs sem qualquer data associada (RF-014); SCHEDULEs nunca retornados nesta rota (validado em CalendarVisibilityService, ADR-015).
> Forward: TASK-038, TASK-039, TASK-040
Busca¶
GET /search¶
< Backward: RF-013, G-010, UC-013, US-026, US-027
Autenticação: Requerida
Query params:
q— termo de busca (obrigatório, mínimo 1 caractere)status—ATIVO|ARQUIVADO(opcional)notebookId— filtra por caderno (opcional)priority—1–4(opcional)from,to— intervalo de período pordueDate(opcional)
Response 200:
{
"query": "relatório",
"results": [
{ "id": "uuid-1", "title": "Finalizar relatório trimestral", "priority": 1, "dueDate": "2026-07-25T00:00:00Z" }
]
}
Restrito a itens type = TODO (RF-013) via ILIKE + índice trigram (ADR-016); nunca retorna Cadernos ou SCHEDULEs.
> Forward: TASK-041, TASK-042, TASK-043, TASK-044