ModularFit
Tudo que precisa existir no ModularFit, agrupado por tipo, com a ficha tecnica de cada artefato.
ModularFit: Inventário de Artefatos
| Campo | Valor |
|---|---|
| Produto | ModularFit |
| Documento base | DRS do ModularFit |
| Companheiros | Roadmap de Implementação · Jornadas dos Atores · Plano de Testes |
| Estágio | Rascunho para validação |
| Data | 2026-09-04 |
Este documento é o registro de completude do ModularFit: tudo que precisa existir para o sistema funcionar, agrupado por tipo, com a ficha técnica de cada item. Cada cartão responde quatro coisas: para que serve, com o que se relaciona, onde fica e como deve ser. A quarta é a que permite construir sem perguntar; um artefato só listado, sem ficha, é inventário incompleto.
Como usar
- Marque o artefato quando ele existir no sistema real e a ficha estiver cumprida, não quando a tarefa do roadmap for iniciada.
- Fichas extensas (formulários, planos, matriz de permissão, catálogo de telas) vivem nos apêndices do DRS; o cartão aponta para lá em vez de repetir.
- Cada cartão aponta o requisito e a tarefa do roadmap que o criam. Se a tarefa está fechada e o artefato não confere, algo ficou pelo caminho.
Tipos de artefato neste projeto
| Tipo | Código | Quantos | Onde vivem |
|---|---|---|---|
| Entidade | ART-ENT | 9 cartões cobrindo 39 tabelas | Banco de dados |
| Formulário | ART-FORM | 15 cartões cobrindo 16 formulários | Telas de captura |
| Tela | ART-SCR | 5 cartões cobrindo 38 das 40 rotas do catálogo de telas | Aplicação |
| Menu e navegação | ART-NAV | 1 | Aplicação |
| Papel e permissão | ART-ACS | 13 | Políticas de acesso |
| Auditoria | ART-AUD | 1 | Banco de dados |
| Máquina de estados | ART-SM | 4 | Regras de domínio |
| Automação | ART-WF | 19 cartões, sendo 17 de automação, 1 de semente de contas e 1 de rotina de operação | Servidor de aplicação |
| Rotina agendada | ART-JOB | 7 | Agendador |
| Notificação | ART-NOT | 1 cartão cobrindo 12 tipos | Central de notificações |
| Mensagem de e-mail | ART-MSG | 3 | Envio transacional |
| Plano e oferta | ART-PROD | 1 cartão cobrindo 3 planos | Administração de planos |
| Parâmetro de configuração | ART-CFG | 3 cartões: o catálogo de parâmetros (38 fichas desde {AUD-10}, 48 antes), o ponto único que os protege e os modelos de e-mail | Administração |
| Painel e relatório | ART-DASH | 7 | Aplicação |
| Métrica | ART-KPI | 1 cartão cobrindo 9 métricas | Relatórios e painéis |
| Serviço externo | ART-INT | 4 | Servidor de aplicação |
| Segredo de configuração | ART-ENVV | 1 cartão cobrindo 12 variáveis | Ambiente do servidor |
| Serviço de infraestrutura | ART-INFRA | 1 cartão cobrindo 2 processos e 6 papéis | Hospedagem |
| Asset de marca | ART-MEDIA | 1 cartão cobrindo 5 assets | Repositório de mídia |
Atualização de 2026-09-30, Inspeção: cards {AUD-11} e {AUD-10}. Um cartão novo,{ART-CFG-03}(modelos de e-mail editáveis), aberto, e Notas nos cartões{ART-ENT-05},{ART-ACS-09},{ART-SCR-03},{ART-CFG-01}e{ART-MSG-01}a{ART-MSG-03}. O documento passa de 96 para 97 cartões, 32 marcados, nenhuma marcação alterada. Na tabela de tipos acima, as telas passam a 40 rotas no catálogo do DRS, a quadragésima é/admin/emails, e 38 delas estão em cartão, conta: 37 mais/admin/emailsigual 38, mais/redefinire/confirmarsem cartão igual 40; o tipo parâmetro passa a três cartões, e a contagem de fichas do catálogo vive em{ART-CFG-01}.
Atualização de 2026-09-30, Inspeção: drifts do gate de {F4-03}. Um cartão novo,{ART-FORM-15}(Plano alimentar), aberto, e Notas ou correções de ficha nos cartões{ART-ENT-05},{ART-ACS-01},{ART-ACS-05},{ART-ACS-07},{ART-SCR-01},{ART-WF-06}e{ART-CFG-01}. O documento passa de 97 para 98 cartões, 32 marcados, nenhuma marcação alterada. Na tabela de tipos acima, o formulário passa a 15 cartões cobrindo 16 formulários, conta: 14 cartões mais{ART-FORM-15}igual a 15, e 15 formulários mais o de plano alimentar igual a 16.
Atualização de 2026-09-30, Inspeção: drifts do gate de {AUD-10}. Notas nos cartões{ART-CFG-03}(endereço proibido no assunto, forma da entidade com versão vigente derivada,rotulo,faixaeparametro_legado_id, prévia para os dois papéis, ortografia) e{ART-CFG-01}(a trilha das alterações antigas de assunto continua legível). Nenhum cartão novo, nenhuma marcação alterada.
Atualização de 2026-09-30, Inspeção: drifts do gate de {AUD-11}. Notas nos cartões{ART-AUD-02}(cada entidade sensível declara o seu leitor, no campoleitorUnico, e o leitor de módulo chamaregistrarSeAdministrativo),{ART-ACS-09}(a restrição por especialidade governa também a escrita da meta) e{ART-CFG-01}(onde vivem os textos de consentimento). Nenhum cartão novo, 98 cartões, 32 marcados, nenhuma marcação alterada.
Atualização de 2026-09-30, fechamento de {AUD-11}. Notas de fechamento nos cartões{ART-ACS-09}(consentimento por entidade 2 de 10, sete categorias),{ART-AUD-02}(leitor único 2 de 10,leitorUniconas dez entidades) e{ART-ENT-05}(3 de 5 tabelas, inalterado, agora sob a categoria nutrição), em produção no merge6490072(migrações0046e0047). Nenhum cartão novo e nenhuma marcação alterada: continuam 98 cartões e 33 marcados, medidos na contagem de cartões do endpoint de estado antes e depois.
Atualização de 2026-09-30, fechamento de {AUD-09}. A capacidade "criar ficha de treino" (com duplicar, editar, desativar, reativar, atender e recusar) passa a ser aplicada por especialidade no banco, em produção (merged760b2d, migração0045). Um cartão marcado,{ART-FORM-14}(Meta nutricional), entregue por {F4-02} e provado em produção, e Notas nos cartões{ART-ACS-03}e{ART-ACS-05}. O documento continua com 98 cartões e passa de 32 para 33 marcados (32 mais {ART-FORM-14} igual 33), sem cartão novo.
Atualização de 2026-09-30, fechamento de {AUD-10}. Modelos de e-mail editáveis entregues e em produção (merge17b62d6, migrações0048e0049,https://fit.modulareasy.com,/api/estadona versão17b62d6). Um cartão marcado,{ART-CFG-03}(11 de 11 modelos, conforme o gate), e Fechamentos nos cartões{ART-CFG-01}(os 11 assuntos migrados, catálogo de 48 para 38 fichas,mfit.parametrode 44 para 33),{ART-SCR-03}(/admin/emails, placar de8 de 11para9 de 11) e{ART-MSG-01}a{ART-MSG-03}(texto editável). O documento continua com 98 cartões e passa de 33 para 34 marcados (33 mais{ART-CFG-03}), medidos na contagem de cartões do texto. Nenhum cartão novo.
Atualização de 2026-09-30, fechamento de {AUD-12}. Textos de consentimento editáveis e versionados entregues (merge4e5ed26, migrações0050e0051). Fechamento no cartão{ART-CFG-01}(consentimento_textoscom o consumidor no ponto único, Estado 27 + 0 + 11 = 38, verificador 51 de 98, C 54, universo 152, texto de consentimento em código 7 para 0) e no cartão{ART-SCR-03}(/admin/textoscom o grupo Consentimentos, placar9 de 11inalterado). Nenhuma marcação alterada: continuam 98 cartões e 34 marcados, medidos na contagem de cartões do endpoint de estado antes e depois;{ART-CFG-01}segue aberto por causa dos 11 parâmetros sem consumidor.
Atualização de 2026-09-30, fechamento de {F4-03}. Plano alimentar entregue e em produção (merge2f5c560, migração0052,https://fit.modulareasy.com,/api/estadona versão2f5c560). Três cartões marcados,{ART-ENT-05}(5 de 5 tabelas),{ART-ACS-05}(papel Nutricionista, com o plano alimentar que faltava) e{ART-FORM-15}(formulário Plano alimentar), e Fechamentos nos cartões{ART-ACS-07}(fronteira de dado clínico 3 de 13, leitor único 3 de 10, consentimento por entidade 3 de 10, capacidade por especialidade 12 de 12) e{ART-SCR-01}(/nutricao/planos, placar de9 de 15para10 de 15). O documento continua com 98 cartões e passa de 34 para 37 marcados (34 mais{ART-ENT-05},{ART-ACS-05}e{ART-FORM-15}), medidos na contagem de cartões do endpoint de estado antes e depois. Nenhum cartão novo.
Atualização de 2026-09-30, Inspeção: drifts do gate de {F4-04}. Nota no cartão{ART-ENT-05}(a funçãomfit.comparacao_com_meta, migração 0053, como regra única da comparação do consumo com a meta). Nenhum cartão novo e nenhuma marcação alterada: continuam 98 cartões e 37 marcados, medidos na contagem de cartões antes e depois.
Atualização de 2026-09-30, fechamento de {F4-04}. Painel diário de consumo entregue e em produção (mergea6624e9, migração0053,https://fit.modulareasy.com). Fechamentos nos cartões{ART-ENT-05}(a funçãomfit.comparacao_com_meta, regra única da comparação; placar inalterado em 5 de 5 tabelas, funções do schema de 57 para 58),{ART-FORM-14}(a meta passa a ser comparada com o consumo, eGETePOST /api/metasganham o campopainel) e{ART-SCR-01}(/nutricaocompleta, placar inalterado em10 de 15). O documento continua com 98 cartões e 37 marcados, medidos na contagem de cartões do endpoint de estado antes e depois: nenhum artefato novo nasce e nenhum muda de marca, porque{ART-ENT-05}e{ART-FORM-14}já estavam marcados e{ART-SCR-01}segue[ ]. Nenhum cartão novo.
Atualização de 2026-09-30, Inspeção: drifts do gate de {F4-05}. Notas nos cartões{ART-CFG-01}(a ficha denutricao_meta_tolerancia_pct, a entregar em {F4-05} na migração0054: catálogo de 38 para 39 fichas,mfit.parametrode 33 para 34, Estado 27 + 0 + 11 + 1 a entregar = 39) e{ART-DASH-03}(a regra de meta atingida mora emmfit.meta_atingida, e {F7-08} a consome). A regra do acompanhamento está em RF-DIET-005 do DRS, e a tolerância em L.2. Nenhum cartão novo, 98 cartões, 37 marcados, nenhuma marcação alterada, medidos na contagem de cartões do texto antes e depois.
Atualização de 2026-10-01, fechamento de {F4-05}. Acompanhamento nutricional entregue e em produção (mergef609a9c, migrações0054e0055,https://fit.modulareasy.com). Fechamentos nos cartões{ART-CFG-01}(o parâmetronutricao_meta_tolerancia_pctganha o consumidor no ponto único: catálogo de 38 para 39 fichas,mfit.parametrode 33 para 34, Estado 28 com consumidor + 0 + 11 sem consumidor = 39),{ART-ENT-05}(a funçãomfit.meta_atingida, funções do schema de 58 para 59, placar inalterado em 5 de 5 tabelas),{ART-SCR-01}(/nutricao/acompanhamentoé estado de/nutricao, placar inalterado) e{ART-DASH-03}(a regra e a agregação que o painel consome estão entregues; o painel segue[ ]em {F7-08}). O documento continua com 98 cartões e 37 marcados, medidos na contagem de cartões do texto antes e depois: nenhum artefato muda de marca, porque{ART-ENT-05}já estava marcado e os outros três seguem abertos. Verificador de parâmetros: 51 de 98, C 56, universo 154. Nenhum cartão novo.
Atualização de 2026-10-01, Inspeção: drifts do gate de {F5-01}. Notas e correção de ficha nos cartões{ART-FORM-04}(a ficha dos 46 campos, quem preenche qual seção, anamnese sem edição de conteúdo),{ART-ENT-06}(ficha deanamnesecorrigida:datasemcriado_em, maisdesativado_emedesativado_por) e{ART-CFG-01}(as fichas dos dois tetos de texto da anamnese, a entregar em {F5-01} na migração0056, sem marcar entrega: catálogo de 39 para 41 fichas,mfit.parametrode 34 para 36, Estado 28 + 0 + 11 + 2 a entregar = 41). A decisão de produto está no DRS (RF-SAUD-001, RN-009, L.2 e Apêndice de formulários). Nenhum cartão novo e nenhuma marcação alterada: continuam 98 cartões e 37 marcados, medidos na contagem de cartões do texto antes e depois.
Atualização de 2026-10-01, fechamento de {F5-01}. Anamnese datada entregue e em produção (merge9cb16f3, repositóriowladimirdjr/modularfit, migração0056,https://fit.modulareasy.com(/api/estadona versão9cb16f3)). Fechamentos nos cartões{ART-FORM-04}(formulário e lista entregues, cartão passa a[x]),{ART-ENT-06}(a tabelaanamneseexiste,1 de 9, cartão segue[ ]),{ART-SCR-01}(/saudeentregue,11 de 15, cartão segue[ ]) e{ART-CFG-01}(as duas fichas dos tetos de texto ganham o consumidor no ponto único: catálogo de 39 para 41 fichas,mfit.parametrode 34 para 36, Estado 30 com consumidor + 0 + 11 sem consumidor = 41). O documento continua com 98 cartões e passa de 37 para 38 marcados (37 mais{ART-FORM-04}), medidos na contagem de cartões do texto antes e depois. Verificador de parâmetros: 51 de 98, C 57, universo 155. As rotas/api/anamneses*e o contrato de 46 campos estão descritos nos cartões acima. Nenhum cartão novo.
Atualização de 2026-10-01, Inspeção: drifts do gate de {F5-02}. Notas e correção de ficha nos cartões{ART-FORM-05}(a ficha dos campos da avaliação física, sem edição de conteúdo, regra da comparação),{ART-ENT-06}(ficha deavaliacao_fisicacorrigida: saicalculos derivados, entramespecialidade_autor,dobras_pontos,dobras_mm,desativado_emedesativado_por; migração0057) e{ART-CFG-01}(as fichas dos dois tetos de texto da avaliação e a listaponto_dobra_cutanea, a entregar em {F5-02} na migração0057, sem marcar entrega: catálogo de 41 para 43 fichas,mfit.parametrode 36 para 38, Estado 30 + 0 + 11 + 2 a entregar = 43, listas fechadas com consumidor de sete para oito no fechamento). A decisão de produto está no DRS (RF-SAUD-002, RN-009, L.2, E.1 e Apêndice de formulários). Nenhum cartão novo e nenhuma marcação alterada: continuam 98 cartões e 38 marcados, medidos na contagem de cartões do texto antes e depois.
Atualização de 2026-10-06, Inspeção: drifts do gate de {F5-03}. Nota no cartão {ART-FORM-05} (o desenho do bloco de cálculos: detalhe e comparação com a lista de fora, zonas fora da comparação, "não calculado", arredondamento meio para cima e constantes de literatura como exceção C nomeada no verificador de parâmetros), sem marcar entrega. As Notas de RF-SAUD-002, RF-SAUD-003 e RN-004 estão no DRS. Nenhum cartão novo e nenhuma marcação alterada: continuam 98 cartões e 39 marcados, medidos na contagem de cartões do texto antes e depois.
Atualização de 2026-10-06, fechamento de {F5-02}. Avaliação física entregue e em produção (merge3ab8395, repositóriowladimirdjr/modularfit, migrações0057e0058aplicadas em produção em 06/10,https://fit.modulareasy.com(/api/estadona versão87ae8e0, a mesma árvore do merge; o deploy damainem3ab8395segue em curso)). Fechamentos nos cartões{ART-FORM-05}(formulário, detalhe e comparação entregues, cartão passa a[x]),{ART-ENT-06}(a tabelaavaliacao_fisicaexiste,2 de 9, cartão segue[ ]),{ART-SCR-01}(as telas/saude/avaliacoes,/saude/avaliacoes/novae/saude/avaliacoes/:idsão estados da casca de/saude, sem décima sexta tela: placar11 de 15inalterado) e{ART-CFG-01}(as duas fichas dos tetos de texto da avaliação ganham o consumidor no ponto único e a oitava lista,ponto_dobra_cutanea, entra em produção: catálogo de 41 para 43 fichas,mfit.parametrode 36 para 38, Estado 32 com consumidor + 0 + 11 sem consumidor = 43). A migração0058(CHECK estrito desecoesda anamnese, aprovada pelo Fiscal sem card) não muda ficha nenhuma: troca só a forma do CHECK da tabelaanamnesejá descrita em{ART-ENT-06}. O documento continua com 98 cartões e passa de 38 para 39 marcados (38 mais{ART-FORM-05}), medidos na contagem de cartões do texto antes e depois. Verificador de parâmetros: 51 de 98, C 58, universo 156, 8 listas. Nenhum cartão novo.
Atualização de 2026-10-06, fechamento de {F5-03}. Cálculos derivados da avaliação entregues e em produção (merge08b35ed, repositóriowladimirdjr/modularfit, sem migração,https://fit.modulareasy.com(a mesma árvore já provada em produção como208a883; o deploy damainem08b35edsegue em curso); gates plan, review e qa verdes). Fechamento no cartão{ART-FORM-05}(o bloco de cálculos, no detalhe e na comparação, em produção, sem coluna e sem migração; o cartão já estava[x]desde {F5-02}). Nenhuma ficha de configuração muda: as constantes de literatura (220 menos a idade, o índice de massa corporal, a relação cintura quadril e as cinco zonas) não são parâmetro, e o verificador de parâmetros passa de universo 156 para 157 e de exceção C 58 para 59, com51 de 98inalterado;mfit.parametrosegue em 38 linhas e as listas fechadas em 8. O documento continua com 98 cartões e 39 marcados, medidos na contagem de cartões do texto antes e depois. Nenhum cartão novo.
Atualização de 2026-10-06, fechamento de {AUD-13}. Corpo de requisição inválido responde 400 em todas as rotas, entregue e em produção (merge1c32c5e, repositóriowladimirdjr/modularfit, sem migração,https://fit.modulareasy.com(a mesma árvore já provada em produção comoecef515; o deploy damainem1c32c5esegue em curso); gates plan, review e qa verdes). Nenhuma ficha de configuração muda e nenhum cartão do Inventário é tocado: o ponto únicoserver/src/http/corpoJson.tsnão cria artefato novo de catálogo, e o verificadorverificar:corpo(52 = 37 JSON + 1 multipart + 14 sem corpo; tabela 38 = 38; 13 decoys) entra ao lado dos demais verificadores. O documento continua com 98 cartões e 39 marcados, medidos na contagem de cartões do texto antes e depois. Nenhum cartão novo.
Atualização de 2026-10-06, Inspeção: drifts do gate de {F5-04}. Notas nos cartões{ART-ENT-06}(a ficha deexamecorrigida e a migração0059),{ART-FORM-07}(o exame não se edita, a data, os tetos, o tipo pelos bytes),{ART-INT-02}(limite de envio, desativar sem apagar o objeto, diretório vazio),{ART-ACS-08}(desativação do exame),{ART-ACS-10}(ramo de cota de anexos) e{ART-CFG-01}(três tetos de texto, a listatipo_examee a aritmética do catálogo), todas a entregar em {F5-04}, sem marcar entrega. Nenhum cartão novo e nenhuma marcação alterada: continuam 98 cartões e 39 marcados, medidos na contagem de cartões do texto antes e depois.
Atualização de 2026-10-06, fechamento de {F5-04}. Exames com anexo em repositório privado entregues e em produção (mergeb078e76, repositóriowladimirdjr/modularfit, migração0059aplicada em produção em 06/10,https://fit.modulareasy.com(a mesma árvore já provada em produção comobde96b3; o deploy damainemb078e76segue em curso); gates plan, db, review e qa verdes). Fechamentos nos cartões{ART-FORM-07}(formulário, lista e detalhe entregues, cartão passa a[x]),{ART-ENT-06}(a tabelaexameexiste,3 de 9, cartão segue[ ]),{ART-INT-02}(escrita no repositório privado entregue,2 de 2repositórios com escrita, cartão segue[ ]por {F5-09} e {F5-08}),{ART-ACS-08}(desativação do exame),{ART-ACS-10}(ramo de cota de anexos) e{ART-CFG-01}(as três fichas dos tetos de texto e a listatipo_exameganham o consumidor: catálogo de 43 para 46 fichas,mfit.parametrode 38 para 41, listas fechadas de 8 para 9, Estado 35 com consumidor + 0 + 11 sem consumidor = 46). O documento continua com 98 cartões e passa de 39 para 40 marcados (39 mais{ART-FORM-07}), medidos na contagem de cartões do texto antes e depois. Nenhum cartão novo.
Atualização de 2026-10-06, Inspeção: drifts do gate de {F5-05}. Notas nos cartões {ART-FORM-08} (o cartão cobre dois formulários e {F5-05} entrega só a prescrição, sem marcar; duração estruturada, aviso do receituário como texto versionado) e {ART-CFG-01} (a ficha deprescricao_texto_longo_max_caracteres, a entregar em {F5-05}; o catálogo de 46 para 47 fichas emfit.parametrode 41 para 42 linhas, sem marcar entrega). Nenhum cartão novo e nenhuma marcação alterada: continuam 98 cartões e 40 marcados, medidos na contagem de cartões do texto antes e depois.
Atualização de 2026-10-06, fechamento de {F5-05}. Prescrições com aviso de não substituição do receituário entregues e em produção (mergede718a6, repositóriowladimirdjr/modularfit, migrações0060e0061aplicadas em produção em 07/10 (UTC; noite de 06/10 em Brasília),https://fit.modulareasy.com(a mesma árvore já provada em produção como9510270; o deploy damainemde718a6segue em curso); gates plan, db, review e qa verdes). Fechamentos nos cartões{ART-ENT-06}(a tabelaprescricaoexiste,4 de 9, cartão segue[ ]),{ART-FORM-08}(a metade da prescrição entregue, cartão segue[ ]e só {F5-06} o marca) e{ART-CFG-01}(a fichaprescricao_texto_longo_max_caracteresganha o consumidor: catálogo de 46 para 47 fichas,mfit.parametrode 41 para 42 linhas, Estado 36 com consumidor + 0 + 11 sem consumidor = 47, cartão segue[ ]). Nenhum cartão muda de marca e nenhum nasce: continuam 98 cartões e 40 marcados, medidos na contagem de cartões do texto antes e depois.
Atualização de 2026-10-06, Inspeção: drifts do gate de {F5-06}. Notas nos cartões {ART-ENT-06} (a ficha desessao_reabilitacaocorrigida, migração0062; tabelas deste cartão de 4 para 5 de 9 na entrega, sem marcar), {ART-FORM-08} (a sessão de reabilitação é a metade que fecha o cartão, a entregar em {F5-06}, sem marcar) e {ART-CFG-01} (a ficha dereabilitacao_texto_longo_max_caracterese a listaregiao_corporal, a entregar em {F5-06}; o catálogo de 47 para 48 fichas,mfit.parametrode 42 para 43 linhas e as listas fechadas de 9 para 10, sem marcar entrega). Nenhum cartão novo e nenhuma marcação alterada: continuam 98 cartões e 40 marcados, medidos na contagem de cartões do texto antes e depois.
Entidades
Para que serve: guardar conta, perfil por papel, consentimento e trilha de auditoria.
Nota (R-5, {F1-18}): mfit.texto_versionado, criada em {F1-18}, é configuração, não identidade: a ficha dela é {ART-CFG-01}, e ela não entra nesta ficha.
Nota (onda AUD, {AUD-04} e {AUD-05}, 2026-09-15): esta ficha passa de 6 para 7 tabelas, e a sétima é sessao_personificacao. Duas mudanças acompanham: (a) o tipo do papel em usuario ganha o valor super_administrador, sem remover nenhum valor existente, e os valores passam a ser quatro (aluno, profissional, administrador, super_administrador); (b) auditoria ganha o papel do autor e o par personificador e personificado, este último preenchido apenas nas entradas geradas sob personificação. sessao_personificacao (id, personificador_id, personificado_id, iniciada_em, terminada_em anulável enquanto a sessão dura, motivo_fim entre saída e expiração) é da classe apenas acrescida no que importa: a linha nasce no início e recebe um único UPDATE, o do fim, nunca mais; índices em (personificador_id, iniciada_em) e (personificado_id, iniciada_em); leitura servida apenas ao Super Administrador, pela mesma política que serve auditoria. Ela guarda a SÉRIE, uma linha por personificação, e não o estado corrente: saber quem personificou quem em maio é exatamente o que a trilha existe para responder. Medição feita em 15/09/2026, antes da migração: o banco tinha 3 contas com papel de administrador, todas de topo, 1 de aluno e nenhuma de profissional; logo a migração de dados de {AUD-04} toca 3 linhas e nenhuma outra. As sete tabelas desta ficha passam a ser usuario, perfil_aluno, perfil_profissional, consentimento, aceite_termos, auditoria e sessao_personificacao.
Relacionado com: RF-CORE-001 a 012; tarefas F1-03 a F1-12, F1-18 e F1-19; ART-ACS, ART-AUD.
Onde fica: banco de dados, esquema principal.
Especificação: usuario (id, nome, email único, senha derivada, papel entre aluno, profissional, administrador e super administrador, status, bloqueado_pela_administracao, bloqueado_em, bloqueado_por, email_confirmado_em, criado_em), sendo o bloqueio administrativo independente do status_acesso do plano em perfil_aluno: o bloqueio nega a entrada de qualquer papel com mensagem própria, o status de acesso restringe o uso do aluno sem impedir a entrada; perfil_aluno (id, usuario_id chave estrangeira única, identificador_publico único e curto, nascimento, sexo, altura, telefone, foto, plano_id, status_acesso); perfil_profissional (id, usuario_id único, especialidade entre as quatro, registro, uf, registro_verificado, biografia, foto); consentimento (id, aluno_id, categoria entre as seis, versao_texto, finalidade, concedido_em, revogado_em, restrito_a_especialidades, sendo esta coluna um array de mfit.especialidade_profissional, NULL significando sem restrição conforme RN-003 e array vazio proibido por restrição de tabela, porque restringir a ninguém é revogação disfarçada e disfarçada não deixa data na trilha); aceite_termos (id, usuario_id, versao_termos, versao_aviso_nao_clinico, aceito_em); auditoria (id, autor_id, autor_papel, acao, entidade, entidade_id, campo, aluno_id anulável, valor_anterior, valor_novo, momento, personificador_id e personificado_id anuláveis, preenchidos apenas nas entradas geradas sob personificação; anonimização por exclusão de conta, RN-008, zera autor_id, aluno_id, personificador_id e personificado_id mantendo o restante da linha); sessao_personificacao (id, personificador_id, personificado_id, iniciada_em, terminada_em anulável, motivo_fim entre saída e expiração). Índices: usuario.email, perfil_aluno.identificador_publico, índice único parcial consentimento(aluno_id, categoria) WHERE revogado_em IS NULL (garante a linha ativa única e serve a consulta de toda escrita de categoria sensível), mais o índice não único consentimento(aluno_id, categoria) para o histórico, que o parcial não enxerga, aceite_termos(usuario_id, aceito_em), auditoria(entidade, entidade_id, momento), auditoria(autor_id, momento), sessao_personificacao(personificador_id, iniciada_em), sessao_personificacao(personificado_id, iniciada_em). Integridade: consentimento sem duplicidade ativa por aluno e categoria, garantida pelo índice único parcial acima, e reconceder cria registro novo sem apagar o anterior; DELETE revogado de mfit_app (o histórico nunca é apagado pela aplicação) e UPDATE mantido, porque a revogação é um UPDATE, por isso consentimento não entra na classe de tabela apenas acrescida, cujo critério é a linha nunca mudar; aceite_termos apenas acrescida, um registro por aceite, sem sobrescrever aceites anteriores quando a versão do texto muda, por privilégio UPDATE/DELETE revogado de mfit_app; auditoria apenas acrescida por esse mesmo mecanismo, privilégio UPDATE/DELETE revogado do papel de aplicação mfit_app, que serve os três papéis de produto e portanto os nega sem exceção. O dono do esquema (mfit_admin) não é papel de produto, não atende requisição nenhuma e atravessa por desenho: é por ele que roda a única exceção prevista à imutabilidade, a anonimização de RN-008 (zerar autor_id e aluno_id mantendo o restante da linha), executada pela rotina de retenção da Fase 8. Escopo: usuario e perfis por dono, com a leitura de terceiro reduzida ao perfil público de D.2 (nome, foto e, para profissional, especialidade e registro); aceite_termos legível apenas pelo titular e pelo administrador, nunca por profissional vinculado; auditoria legível apenas pelo administrador, por política de RLS de SELECT restrita ao papel administrador, com a inserção mantida livre para os gatilhos e para o leitor único de acesso administrativo.
Fechamento [2026-09-29] de {AUD-05}: a sétima tabela, sessao_personificacao, está em produção (merge 3dabc30, https://fit.modulareasy.com, migrações 0034, 0035 e 0036, gates plan, qa e review verdes), medida no catálogo do banco: a tabela existe, com quatro índices (chave primária, um por personificador, um por personificado e o único parcial que impede duas personificações ativas do mesmo operador), e auditoria tem as colunas personificador_id e personificado_id. Placar da ficha: 7 de 7, ficha fechada; o 6 de 7 anterior era a ausência desta tabela.
Estado: usuario, tentativa_entrada e sessao provisionadas em F1-03; perfil_aluno, plano_plataforma (com o Gratuito) e aceite_termos provisionadas em F1-04; perfil_profissional provisionada em F1-05; foto e edição em F1-06/F5. Revogação de UPDATE/DELETE de mfit_app em auditoria e aceite_termos e RLS de leitura da auditoria restrita ao Administrador no ar desde F1-11; consentimento provisionada em produção desde F1-12 (migração 0012). RLS ligada em usuario, perfil_aluno e perfil_profissional, com a leitura de terceiro passando a ser servida pela leitura reduzida de {ART-ACS-11}, desde F1-19 (2026-09-13).
Para que serve: governar quem acessa quem e registrar plano e cobrança.
Relacionado com: RF-VINC-001 a 005, RF-PLAN-001 a 004, RF-COBR-001 a 004; tarefas F1-04 (nascimento de plano_plataforma), F1-13 (tela de administração do catálogo), F2-05 a F2-09, F8-01 a F8-04.
Onde fica: banco de dados, esquema principal.
Especificação: vinculo (id, profissional_id, aluno_id, especialidade, estado entre pendente, ativo, recusado, cancelado e inativo, criado_em, encerrado_em, encerrado_por); plano_plataforma (id, nome único, descricao, valor_referencia numérico anulável, sendo nulo igual a "a definir pela administração", recorrencia em lista fechada entre nenhuma, mensal e anual, seis colunas tipadas de limite, uma por dimensão do Apêndice, cada uma inteira não negativa ou nula, sendo nula igual a ilimitado, padrao booleano, no máximo um verdadeiro por índice único parcial, apontando o plano atribuído ao cadastro do aluno novo, ativo); acordo_cobranca (id, vinculo_id único ativo, valor, moeda, recorrencia entre mensal, quinzenal e avulsa, dia_vencimento, inicio, termino, observacoes); competencia_cobranca (id, acordo_id, periodo, valor, vencimento, status entre em aberto, vencida, paga e isenta, data_pagamento, observacao). Índices: vinculo(aluno_id, estado), vinculo(profissional_id, estado), competencia_cobranca(acordo_id, periodo) único. Integridade: no máximo um vinculo em estado ativo ou pendente por par aluno e profissional, garantido por índice único parcial em (aluno_id, profissional_id) para esses dois estados; não existe restrição por aluno e especialidade, ausência medida pelo critério (e) do décimo sexto verificador (ops/verifica-vinculo.mjs, núcleo em verificarVinculos.ts), por universo de catálogo (pg_index, pg_constraint, pg_policy, pg_trigger de mfit.vinculo) mais varredura de código dos caminhos de escrita, com decoy e placar positivo ({F2-08}), porque o aluno pode ter vários profissionais ativos da mesma especialidade (RF-VINC-004) e o único teto é a dimensão de vínculos do plano; a contagem de vínculos ativos por aluno tem teto no plano, garantido por WITH CHECK nas duas políticas de escrita ({F1-15}, ART-ACS-10); o teto vale na entrada em ativo, nunca em pendente, recusado, cancelado ou inativo; a contagem exclui a própria linha por id, para que reescrever uma linha já ativa nunca seja negada por ela mesma; a unicidade do par acima é uma recusa diferente do teto de limite, distinguida pelo código de erro; competencia_cobranca única por acordo e período, o que garante a rotina agendada idempotente.
Estado: PARCIAL. Tabela vinculo e índices entregues em {F1-08}. Fechamento [2026-09-14] de {F2-05}: merge 7eaa87b em produção (https://fit.modulareasy.com), migração 0021_convite_de_vinculo.sql; política vinculo_leitura passa de pode_ler_aluno(aluno_id) para "meus vínculos" (profissional dono da linha, aluno titular ou Administrador), com a perda declarada e única, o profissional com vínculo ativo deixa de ler vínculos do aluno com terceiros; função definer mfit.usuario_por_identificador_publico resolve o identificador por igualdade exata; gatilho AFTER INSERT ON mfit.vinculo WHEN (NEW.estado = 'pendente') enfileira a notificação de convite ao aluno na origem. Transição de entrada (inexistente) para pendente servida; as cinco restantes seguem em {F2-06}..{F2-09}. plano_plataforma nasce em F1-04 com a linha do plano Gratuito, em documento estruturado; plano_plataforma fecha em {F1-13}, que substitui o documento pelas seis colunas tipadas, converte a recorrência em enum, torna o valor de referência anulável, cria a coluna padrao e semeia Essencial e Completo com os limites do Apêndice. Ficha PARCIAL: acordo_cobranca e competencia_cobranca continuam abertas para F8-01 a F8-04. Fechamento [2026-09-14] de {F2-06}: merge 9b994b0 em produção (https://fit.modulareasy.com), migração 0022_aceite_e_recusa_do_vinculo.sql; duas transições novas servidas por UPDATE condicional dentro de SAVEPOINT (pendente para ativo, pendente para recusado), guardadas por aluno_id = claims.sub AND estado = 'pendente' no próprio WHERE. Transições de entrada servidas: (inexistente) para pendente ({F2-05}), pendente para ativo e pendente para recusado ({F2-06}); as três restantes (pendente para cancelado, ativo para inativo, inativo para pendente) seguem em {F2-07}. Fechamento [2026-09-14] de {F2-07}: as três transições restantes servidas: pendente para cancelado (rota nova POST /api/vinculos/:id/cancelar), ativo para inativo (POST /api/vinculos/:id/desativar consertado) e inativo para pendente (reconvite, linha nova). encerrado_em e encerrado_por gravados nos dois casos de encerramento (aluno e profissional), provados no arnês. Ficha continua PARCIAL: acordo_cobranca e competencia_cobranca seguem abertas para F8-01 a F8-04. Ficha continua PARCIAL: acordo_cobranca e competencia_cobranca seguem abertas para F8-01 a F8-04. Fechamento [2026-09-14] de {F2-08}: ausência de guarda por especialidade deixa de ser afirmação de documento e passa a medição do critério (e) do décimo sexto verificador: placar 0 de 15 objetos de mfit.vinculo usam especialidade como guarda (1 restrição, 3 índices, 4 políticas, 7 gatilhos) e 0 de 5 caminhos de escrita aplicam guarda por especialidade; placar positivo na mesma transação, 4 de 4 especialidades do catálogo aceitam vínculo ativo simultâneo no mesmo aluno, 2 vínculos ativos de personal_trainer no mesmo aluno, 5 vínculos ativos no total. Nenhuma migração, nenhum índice, nenhuma política e nenhum gatilho novos. Fechamento [2026-09-14] de {F2-09}: a leitura global do Administrador, já permitida por política desde {F2-05} (terceira disjunção de vinculo_leitura, mfit.papel_atual() = 'administrador'), ganha rota (GET /api/admin/vinculos) e tela (/admin/vinculos); nenhuma política, nenhum gatilho e nenhuma coluna novos. Ficha continua PARCIAL: acordo_cobranca e competencia_cobranca seguem abertas para F8-01 a F8-04.
Para que serve: ser a única fonte de exercício para ficha e para proposta gerada.
Relacionado com: RF-EXER-001 a 005; tarefas F2-01 a F2-04 e F8-12; ART-FORM-02, ART-WF-15.
Onde fica: banco de dados, tabela global sem coluna de dono.
Especificação: exercicio (id, nome, grupo_muscular, equipamento, instrucoes, erros_comuns, dicas, imagem_url, video_url, imagem_largura, imagem_altura, series_padrao, reps_padrao, descanso_padrao, dificuldade, categoria, ativo, criado_por, atualizado_por, atualizado_em), com erros_comuns e dicas em texto longo, um item por linha, exibidos como blocos próprios na tela do exercício e na execução, e ocultos quando vazios. imagem_largura e imagem_altura são inteiras positivas, ambas nulas ou ambas preenchidas, medidas no servidor na ingestão a partir dos bytes do arquivo, para o front declarar aspect-ratio antes de a imagem carregar (deslocamento zero); nulas quando a imagem é endereço externo, caso em que o retângulo reservado usa a proporção padrão do mockup. Ordem de escrita: objeto no disco primeiro, linha depois, e o objeto antigo é removido apenas após o commit, para que a falha possível seja arquivo órfão e nunca linha apontando para objeto ausente. Os três enums (grupo_muscular com dez valores, dificuldade com três, categoria com dois) são canônicos, minúsculos e sem acento; o rótulo acentuado de cada valor vive num catálogo único no código, nunca escrito à mão na tela. Chave natural (grupo_muscular, lower(btrim(nome))), sem unaccent (a extensão existe mas não é IMMUTABLE, e o DRS não pede insensibilidade a acento). Índices: exercicio(grupo_muscular, dificuldade) para o filtro combinado; índice textual GIN por trigrama (pg_trgm) sobre lower(nome), para busca por pedaço de palavra. Restrição: nome único por grupo_muscular. Escopo: leitura para todo usuário autenticado, escrita apenas para administrador. imagem_url e video_url nascem como coluna aqui, ainda sem tela: são servidas por ART-FORM-02 quando F2-02 entregar a mídia.
Estado: tabela, políticas, auditoria, rotas e telas entregues em F2-01; mídia (incluindo as duas colunas de dimensão) entregue em F2-02; prévia assistida em F8-12. Filtros combináveis e contador entregues em F2-03, sem índice novo: exercicio_grupo_dificuldade_idx (nascido em F2-01) já serve os dois filtros do H1 e os quatro filtros mais a busca por Bitmap Index Scan, medido por EXPLAIN ANALYZE em 5.000 linhas sintéticas (44 vezes o volume real de 113), dentro de transação desfeita: Execution Time 0,242 ms com grupo mais dificuldade, 0,144 ms com os quatro filtros mais o LIKE do nome; índice por categoria ou equipamento isolado recusado por medição, não por gosto.
Para que serve: guardar a prescrição, a execução e as preferências de treino.
Relacionado com: RF-TREI-001 a 010; tarefas F3-01 a F3-10.
Onde fica: banco de dados, esquema principal.
Especificação: ficha_treino (id, aluno_id, autor_id, titulo, descricao, status ativo ou inativo, ficha_origem_id, criado_em, atualizado_por, atualizado_em); ficha_item (id, ficha_id, exercicio_id, ordem, series, reps, descanso, carga_sugerida, observacao de até 280 caracteres, exibida junto do exercício durante a execução); sessao_treino (id, aluno_id, ficha_id, inicio, fim, duracao_segundos, volume_kg, status entre em andamento, concluida e abandonada, exercicio_atual_ordem, ultimo_registro_em, observacao da sessão), com no máximo uma sessão em andamento por aluno, garantida por índice único parcial em aluno_id para o status em andamento, e a série gravada a cada registro, de modo que a retomada leia do banco e não da memória da tela; sessao_serie (id, sessao_id, exercicio_id, numero_serie, carga_kg, repeticoes, duracao_segundos, observacao, pulado), aceitando série de carga (carga e repetições preenchidas, duração vazia) ou série por tempo (duração preenchida, carga e repetições podendo ficar vazias), sem exigir os dois pares ao mesmo tempo e sem gravar zero no lugar de vazio; preferencia_treino (id, aluno_id único, objetivos, nivel, equipamentos, dias, duracao_min, limitacoes, observacoes, criado_em, atualizado_em), uma linha por aluno: objetivos é conjunto não vazio do catálogo fechado de oito objetivos e nivel é valor único do catálogo fechado de três níveis, os dois obrigatórios conforme o Apêndice de catálogo de formulários; equipamentos é conjunto, possivelmente vazio, do catálogo fechado de vinte e seis equipamentos; dias é conjunto, possivelmente vazio, de dia da semana de segunda a domingo, guardado na ordem em que o Apêndice o escreve, de modo que o critério de exibição e o de ordenação sejam o mesmo; duracao_min é anulável, de 20 a 120 e múltipla de 5, nunca zero, pela regra terminal de RN-004; limitacoes e observacoes são anuláveis, até 2000 caracteres cada. Conjunto vazio é vazio, nunca nulo disfarçado e nunca elemento de preenchimento, e a ausência de escolha é um fato, não um desconhecido. atualizado_por não existe: só o titular escreve, então a coluna gravaria sempre o mesmo valor de aluno_id, e a pergunta de quem alterou e quando já tem dono na trilha imutável de RF-CORE-009; solicitacao_ficha (id, aluno_id, profissional_id, motivo escrito pelo aluno, obrigatório e não vazio, com teto de mil caracteres; ficha_alvo_id anulável, preenchida quando o pedido é de ajuste de uma ficha existente e nula quando o pedido é de ficha nova; ficha_id anulável, a ficha que atendeu o pedido, preenchida apenas no estado atendida; motivo_recusa anulável, exigido apenas no estado recusada e garantido pela guarda de transição, nunca por NOT NULL na coluna, que quebraria os dois estados legítimos em que ele é nulo; estado entre aberta, atendida e recusada; criado_em; resolvido_em, preenchido nos dois estados terminais). As duas colunas de ficha respondem perguntas diferentes e por isso são duas: ficha_alvo_id é a ficha de que o aluno reclamou e ficha_id é a ficha que atendeu, e no atendimento por criação elas nem são a mesma; fundir as duas apagaria a pergunta exatamente no instante em que a resposta chegasse. Coerência entre estado e colunas garantida por restrição de verificação, nunca por disciplina da rota: atendida exige ficha_id e resolvido_em preenchidos, recusada exige motivo_recusa e resolvido_em preenchidos, aberta exige os três nulos. Índices: ficha_treino(aluno_id, status), sessao_treino(aluno_id, inicio), sessao_serie(sessao_id), sessao_serie(exercicio_id, sessao_id) para a progressão de carga, solicitacao_ficha(profissional_id, estado) para a lista de pedidos do profissional solicitacao_ficha(aluno_id, estado) para o acompanhamento do aluno e preferencia_treino(aluno_id) único, que é o que materializa o aluno_id único declarado acima e serve a toda consulta desta tabela, sempre por aluno. Integridade: ficha_item.ordem única por ficha; sessao_serie.numero_serie única por sessão e exercício; o volume da sessão soma apenas as séries com carga e repetições preenchidas, ignorando as séries por tempo, conforme RN-004.
Nota de decisão declarada (gate {F3-01}, 2026-09-14): a desativação de ficha_treino usa a coluna status que a própria ficha já declara (ativo e inativo, as duas únicas transições que E.3 prevê) e a tabela NÃO ganha desativado_em nem desativado_por. A pergunta estava aberta desde {F1-10}, que exige do card dono uma declaração e proíbe decidir por analogia. Três motivos medidos: um par de colunas ao lado de status criaria duas fontes para o mesmo fato, e o dia em que uma linha tivesse status ativo com desativado_em preenchido nenhum verificador perceberia, com a dimensão fichas_ativas contando uma coisa e a lista de trabalho filtrando outra; quem desativou e quando já tem dono, que é a trilha imutável de RF-CORE-009, gravada pelo gatilho genérico de remoção sem a tabela precisar de coluna nenhuma, na mesma forma de três argumentos já usada por vinculo; e a própria lista única de entidades prevê declarar qual é a coluna de desativação, conferindo por catálogo que a coluna declarada existe, nunca que ela se chama desativado_em. Isto é decisão declarada, não entrega: as duas tabelas nascem em {F3-01} e o placar deste cartão segue 0 de 6 até lá. plano_alimentar tem a mesma pergunta aberta e NÃO é decidida aqui: o card dono dela é {F4-03}, com o mesmo dever de declarar.
Nota (gate {F3-02}, 2026-09-14): {F3-02} não cria tabela, migração, política, gatilho, função nem índice. O aluno titular já passa, conjunção por conjunção, pela política de inserção que {F3-01} escreveu, e o único guarda que o recusava era uma linha da camada de aplicação. O placar deste cartão fica exatamente onde {F3-01} o deixou, 2 de 6 tabelas, e a última migração em produção continua 0025. Placar que não muda também se declara, senão o leitor supõe que ninguém olhou.
Fechamento [2026-09-14]: confirmado inalterado. {F3-02} entrou em produção (3d25e27) sem tocar tabela, migração, política, gatilho, função nem índice. Placar continua 2 de 6 tabelas, última migração em produção continua 0025.
Nota (gate {F3-03}, 2026-09-14): {F3-03} não cria tabela, coluna, índice nem GRANT, e por isso o placar deste cartão fica onde {F3-01} o deixou, 2 de 6 tabelas. Ele cria uma migração, que é outra coisa: 0026_edicao_da_ficha.sql altera duas políticas de UPDATE que já existem, acrescenta a política de DELETE que faltava em ficha_item, recria a restrição de ordem única como adiável dentro da transação e instala os gatilhos de auditoria das duas tabelas. solicitacao_ficha, sessao_treino, sessao_serie e preferencia_treino não nascem aqui, e a última migração em produção passa de 0025 para 0026 só no fechamento. Decisão declarada sobre a escrita: a edição acontece por uma rota só, PATCH /api/fichas/:id, numa transação só, e a lista de itens é reconciliada por identificador, nunca por posição e nunca por apagar tudo e reinserir: item conhecido com campos diferentes recebe UPDATE, que é a única forma de a trilha ter valor anterior e valor novo, que é o que o H1 cobra; item conhecido sem diferença nenhuma não é escrito; item sem identificador recebe INSERT; item que existia e não veio no corpo recebe DELETE; e item cujo identificador não pertence a esta ficha é recusado antes de o banco ser tocado, para que o erro não conte a existência de outra ficha. A rota nunca escreve status: desativar e reativar têm rotas próprias, porque estado e conteúdo mudando na mesma instrução apagariam a alteração de conteúdo da trilha. ficha_item.ordem continua única por ficha; o que muda é que a restrição passa a ser adiável dentro da transação, para que reordenar não colida no meio do caminho e a trilha não registre uma ordem intermediária que nunca existiu. Placar que não muda também se declara.
Fechamento [2026-09-14]: confirmado em produção (merge 76bc9cd, migração 0026_edicao_da_ficha.sql aplicada, última em produção passa de 0025 para 0026). A decisão de escrita descrita acima está implementada: PATCH /api/fichas/:id numa transação, item conhecido com diferença recebe UPDATE, sem identificador recebe INSERT, ausente no corpo recebe DELETE, identificador alheio é recusado antes do banco; status fora da rota, com desativar e reativar próprios; ficha_item.ordem única e agora DEFERRABLE. Placar continua 2 de 6 tabelas, nenhuma tabela nova.
Nota (gate {F3-04}, Drifts 2 e 3, 2026-09-14): a especificação de solicitacao_ficha acima foi reconciliada nesta data, e a reconciliação é da FICHA da tabela, nunca do requisito: RF-TREI-004 sempre disse "uma ficha nova ou o ajuste de uma existente", e quem estava incompleto era esta ficha, que tinha uma coluna de ficha para dois significados. Três colunas entram, cada uma com dono declarado: ficha_alvo_id, porque o pedido de ajuste precisa dizer qual ficha o aluno quer mudar e sem ela a lista do profissional mostraria o pedido sem o alvo; motivo_recusa, porque {ART-SM-03} exige motivo obrigatório na recusa e motivo já tem dono, que é o texto do aluno cobrado pelo H1, de modo que reaproveitá-lo apagaria o pedido no ato de recusá-lo; e criado_em e resolvido_em, que a irmã ficha_treino deste mesmo cartão já tem por escrito e sem as quais nem a lista ordena nem a tela exibe a data da resolução. O placar deste cartão não muda aqui, continua 2 de 6 tabelas, porque nada é criado antes de o código existir; quando {F3-04} entregar, solicitacao_ficha nasce e o placar passa a 3 de 6, e para aí: sessao_treino, sessao_serie e preferencia_treino são de {F3-05}, {F3-08} e {F3-10}. Placar que não muda também se declara.
Fechamento [2026-09-14]: solicitacao_ficha em produção (migração 0027_solicitacao_de_ficha.sql, merge 8f0f9fd), com as colunas reconciliadas (ficha_alvo_id, ficha_id, motivo_recusa, criado_em, resolvido_em) e os dois índices por papel. Placar passa de 2 de 6 para 3 de 6 tabelas; sessao_treino, sessao_serie e preferencia_treino seguem pendentes, donos {F3-05}, {F3-08} e {F3-10}.
Nota (gate {F3-08}, Drift 7, 2026-09-15): a ficha de preferencia_treino acima foi reconciliada nesta data, e a reconciliação é da FICHA, nunca do requisito. Três lacunas medidas e fechadas: objetivos, equipamentos e dias não declaravam tipo nenhum, e quem fosse codar escolheria entre conjunto, texto separado por vírgula e tabela filha em silêncio; não havia coluna de auditoria, e sem atualizado_em a leitura do valor vigente que M.3 exige não tem como se provar; e a cláusula de índices nomeava seis índices, nenhum desta tabela. Uma contradição também se resolve: E.2 dizia um para muitos e {ART-ENT-04} diz aluno_id único, dois artefatos publicados dizendo coisas incompatíveis sobre a mesma tabela, e o diagrama do DRS foi corrigido para um para um, porque o cartão e o H1 (os valores aparecem preenchidos ao reabrir a tela, no singular) mandam uma linha por aluno. Daí decorre a declaração de histórico, que se escreve porque toda entidade de registro a deve: preferência não guarda série, guarda o valor vigente, e o passado não se perde, porque a trilha imutável de RF-CORE-009 grava valor anterior e valor novo a cada alteração pelo gatilho genérico; tela de histórico de preferências, se o dono a quiser, é card novo. Este cartão fecha [x] em 6 de 6 tabelas quando {F3-08} entregar: preferencia_treino é a sexta e última. E uma atribuição errada, publicada na Nota do gate {F3-04}, se corrige de passagem: sessao_serie é de {F3-05}, não de {F3-10}; a frase que diz "donos {F3-05}, {F3-08} e {F3-10}" ordena as três tabelas de modo a sugerir o contrário, e índice que atribui errado também faz placar mentir. Fechamento [2026-09-15]: preferencia_treino em produção (migração 0029_preferencia_treino.sql, merge ce1787b, https://fit.modulareasy.com). Placar fecha em 6 de 6 tabelas, a sexta e última. Nota (gate {F3-09}, Drift 7, 2026-09-15): a coluna ficha_origem_id de ficha_treino, já escrita por extenso nesta Especificação, ganha caminho de escrita em {F3-09}, e nenhuma tabela nasce: o placar deste cartão não se move por este card. A dívida deixada por declarar na migração que criou a coluna, com {F3-09} nominado dono por escrito, fecha aqui: a referência passa a ser anulada quando a ficha de origem é excluída em definitivo. As alternativas de recusa fariam a primeira cópia criada em produção revogar na prática o direito de exclusão em definitivo que RF-CORE-008 e RN-008 dão ao Administrador sobre a origem, e o sintoma chegaria como erro de banco sem mensagem de produto; a alternativa em cascata apagaria as fichas que os alunos construíram a partir dela, que são registros de outra autoria e outro titular, contradizendo de frente a consequência escrita de ADR-006. Anular perde a referência, que é o único fato que deixa de ter onde apontar, e não perde a cópia nem a história: o momento da duplicação fica na trilha imutável de RF-CORE-009 gravada pelo gatilho de criação, e a própria anulação gera entrada de auditoria pelo gatilho de alteração, de modo que a pergunta de onde esta ficha veio continua respondível depois de a origem sumir. Duas ausências declaradas, porque ausência não declarada vira suspeita: sem índice em ficha_origem_id, porque consulta nenhuma do produto filtra por ela e a leitura vai sempre da cópia para a origem por chave primária, e o índice nasce com a consulta de cópias de uma ficha se ela vier a existir, em card novo; e sem restrição de verificação impedindo a ficha de apontar para si mesma, porque é inalcançável por construção, já que o identificador da cópia é gerado no próprio comando de inserção e não há caminho de atualização que escreva a coluna. Placar que não muda também se declara, senão o leitor supõe que ninguém olhou.
Fechamento [2026-09-15]: {F3-09} em produção (merge e931e3b, migração 0030_duplicacao_da_ficha.sql aplicada, última em produção passa de 0029 para 0030, https://fit.modulareasy.com). A dívida do ON DELETE de ficha_origem_id, deixada por declarar em 0025 e nominada a este card na Nota acima, fecha em produção: ON DELETE SET NULL confirmado (confdeltype = 'n', gate de db-ops). Placar não se move, continua 6 de 6 tabelas.
Nota (gate {F3-05}, Drifts 2, 6 e 11, 2026-09-14): três declarações sobre as duas tabelas da execução, e nenhuma delas muda o placar deste cartão, que continua 3 de 6 tabelas até o fechamento. Primeira, autoria. sessao_treino não tem autor_id e não passa a ter: a sessão é sempre executada pelo próprio aluno titular, a Matriz Ator por Capacidade dá a capacidade de executar e retomar sessão de treino ao Aluno e a nega aos cinco demais papéis, e a lista de autoria de RN-009 não a inclui. Não existe terceiro a autorar uma execução, e a especificação acima sempre esteve certa. A consequência é do lado do verificador, que enumera o universo de autoria por catálogo (toda tabela com coluna autor_id) e por isso nunca alcançaria esta tabela: a declaração antecipada de autoria de terceiro que vive no código desde {F2-07} é corrigida em {F3-05}, com a aritmética e o motivo do eixo reescritos, e não o contrário. Sem essa correção o nome da tabela ficaria pendente para sempre num placar que nenhum card poderia fechar. Segunda, persistência. A série gravada a cada registro, que esta ficha já exige, é obrigação de {F3-05} por construção da tabela, e o "O que implementar" de {F3-10} foi reconciliado nesta data para deixar de reivindicá-la. Terceira, tempo sob tensão. O cálculo derivado de RN-004, soma do tempo de execução das séries registradas por tempo, não ganha coluna aqui e não tem ponto de exibição: o dado bruto existe em sessao_serie.duracao_segundos, linha a linha, e o total é derivável a qualquer momento por quem tiver onde mostrá-lo. Criar coluna agora seria guardar número que ninguém lê, e inventar tela seria escopo nascido num gate. Se o cálculo precisar de dono, isso é card novo no roadmap, nunca coluna silenciosa aqui. Ausência declarada, no molde das de {ART-CFG-01} e {ART-ACS-08}.
Nota (gate {F3-06}, 2026-09-15): o descanso real decorrido entre séries não ganha coluna, não ganha ponto de exibição e não entra em RN-004; o alvo prescrito continua em ficha_item.descanso e o decorrido é estado efêmero de tela. Se um dia precisar de dono, é card novo no roadmap, nunca coluna silenciosa aqui. O placar deste cartão fica em 5 de 6 tabelas, o valor que {F3-05} deixa: {F3-06} não cria tabela, coluna, índice, restrição, política, gatilho nem função. A sexta, preferencia_treino, continua em {F3-08}.
Decisão declarada (gate {F3-05}, D-8, 2026-09-14): o encerramento da sessão decide pelo resultado, não pelo que a tela pediu, e a decisão vive num ponto único no banco: um gatilho de BEFORE UPDATE OF status em sessao_treino, disparado quando o status sai de em andamento, conta as séries registradas naquele instante e naquela transação e grava concluida se houver ao menos uma, abandonada se não houver. A rota pede "encerrar" e nunca manda um estado: E.3 não dá essa escolha ao ator, e deixar a rota escolher daria ao cliente o poder de gravar concluída numa sessão vazia, o que transformaria status num campo que assume o valor que a tela mandou, isto é, enfeite. No mesmo gatilho e na mesma transação são gravados fim, duracao_segundos (do relógio do servidor, a partir de inicio, nunca do cronômetro da tela, que é desenho) e volume_kg pela fórmula de RN-004 escrita uma vez, somando apenas as séries com carga e repetições preenchidas e ignorando as séries por tempo, sem erro e sem contar zero no lugar de vazio; sessão sem nenhuma série de carga tem volume zero porque não há o que somar, não porque alguém escreveu zero. ultimo_registro_em também é do gatilho, tanto no UPDATE da sessão quanto no INSERT e no UPDATE da série, por gatilho próprio na tabela filha, e a rota nunca escreve essa coluna: se escrevesse, um caminho novo de registro nasceria mudo e a retomada de {F3-10} leria uma verdade velha. Por que no banco e não na aplicação: a fórmula de RN-004 terá três leitores ({F3-05} no encerramento, {F3-07} no histórico e na progressão, {F7-05} no gráfico) e dois escritores de sessão (a rota de hoje e a retomada de {F3-10}); no gatilho ela é exaustiva por construção, inclusive para o caminho que ainda não existe, e na aplicação seria exaustiva por disciplina, que falha em silêncio, porque volume errado não levanta erro. É o mesmo raciocínio que já pôs a notificação no gatilho da origem. Consequência: não existe janela em que uma sessão esteja concluída sem volume, e por isso a cláusula de duração maior que zero do H1 de RF-TREI-005 é provável.
Nota (gate {F3-10}, Drift 1, 2026-09-29): o gatilho distingue os dois eventos de E.3 que saem de em andamento: encerrar, decidido pelo resultado (contagem de séries), e prazo decorrido, cujo resultado é a própria guarda de tempo, avaliada no relógio do banco pelo escritor único (D-2); prazo decorrido leva a abandonada com qualquer número de séries.
Nota (gate {F3-10}, Drift 4, 2026-09-29): o evento prazo decorrido de E.3 tem executor, e nenhum deles é um {ART-JOB} nem um {ART-WF}. Quatro pontos preguiçosos de escrita (iniciar, registrar série, atualizar posição e encerrar, todos do aluno titular) passam a abandonada a sessão vencida de quem volta; a leitura por predicado garante que esse aluno nunca veja a sessão vencida como em andamento; e uma rotina de operação de hora em hora, uma linha de crontab e NÃO um {ART-JOB}, cobre quem nunca volta. A janela aberta é de até uma hora e vale só para leitores terceiros, porque o próprio aluno nunca a vê.
Fechamento [2026-09-15]: sessao_treino e sessao_serie em produção (migração 0028_execucao_da_sessao.sql, merge 80c103e), com as colunas, os índices e as integridades desta ficha, sem autor_id em sessao_treino (Drift 2). Placar passa de 3 de 6 para 5 de 6 tabelas; preferencia_treino segue pendente, dono {F3-08}.
Fechamento [2026-09-29] de {F3-10}: em produção (migração 0042_abandono_da_sessao_por_prazo.sql, merge 047f3bc): a decisão declarada acima passa a distinguir os dois eventos de E.3 que saem de em andamento. Encerrar continua decidido pelo resultado (com série, concluída; sem série, abandonada); prazo decorrido leva a abandonada com qualquer número de séries, porque a guarda de tempo já foi avaliada no relógio do banco pelo escritor único. fim, duracao_segundos e volume_kg continuam calculados no mesmo gatilho para os dois eventos. A migração só reescreve a função do gatilho e comentários: nenhuma tabela, coluna, índice, política, gatilho ou concessão nasce, e o placar deste cartão permanece 6 de 6.
Para que serve: guardar o que o aluno come, as metas e o plano prescrito.
Relacionado com: RF-DIET-001 a 005; tarefas F4-01 a F4-05.
Onde fica: banco de dados, esquema principal.
Especificação: refeicao (id, aluno_id, tipo, nome, data, horario, observacoes, criado_em, desativado_em, desativado_por); refeicao_alimento (id, refeicao_id, ordem, nome, quantidade_g, calorias, proteina_g, carboidrato_g, gordura_g); meta_nutricional (id, aluno_id, calorias, proteina_g, carboidrato_g, gordura_g, autor_id, vigente_desde, definida_em), com autor_id e vigente_desde nulos juntos e só juntos na vigência padrão (uma por aluno); plano_alimentar (id, aluno_id, autor_id, titulo, descricao, status, criado_em, atualizado_por, atualizado_em), com status texto ativo ou inativo (E.3); plano_refeicao (id, plano_id, ordem, nome, horario, notas, alimentos), com alimentos em documento [{nome, quantidade, calorias}] validado no banco e unicidade (plano_id, ordem). Índices: refeicao(aluno_id, data), refeicao_alimento(refeicao_id), meta_nutricional(aluno_id, vigente_desde, definida_em), plano_alimentar(aluno_id, status), plano_refeicao(plano_id). Regra: a meta do dia D é a de maior vigente_desde menor ou igual a D, a vigência padrão valendo antes de todas, e no empate a de maior definida_em, o que preserva o histórico sem recalcular o passado.
Nota (gate {F4-01}, Drift 2, 2026-09-29): reconciliação da FICHA, nunca do requisito. A especificação de refeicao trazia criado_por, sem desativado_em e desativado_por; E.1 e a lista única de entidades removíveis de RF-CORE-008 dizem o contrário, e criado_por seria sempre igual a aluno_id, porque só o titular escreve (o Super Administrador escreve personificando, e a trilha guarda o par). A ficha acima já está corrigida: criado_por sai, criado_em, desativado_em e desativado_por entram, refeicao_alimento ganha ordem e o índice refeicao_alimento(refeicao_id). O placar deste cartão (0 de 5 tabelas) só muda no fechamento de {F4-01}, quando as duas tabelas existirem em produção.
Fechamento [2026-09-30] de {F4-01}: placar 2 de 5 tabelas. refeicao e refeicao_alimento estão em produção (migração 0043) com as colunas da ficha acima, o índice refeicao(aluno_id, data) e a unicidade (refeicao_id, ordem) na filha; desativação por desativado_em e desativado_por, sem rota de exclusão definitiva (só o Super Administrador, no banco). Faltam meta_nutricional ({F4-02}) e plano_alimentar com plano_refeicao ({F4-03}). O cartão permanece [ ].
Nota (gate {F4-02}, Drift 5, 2026-09-29): reconciliação da FICHA, nunca do requisito. A ficha de meta_nutricional não ordenava duas metas do mesmo dia (o H1 de RF-DIET-002 troca a meta duas vezes, tipicamente no MESMO dia, e vigente_desde sozinho não diz qual é a mais recente) e não tinha forma para a vigência padrão do aluno novo, que não tem data certa porque o fuso do aluno é desconhecido no cadastro. A ficha acima já está corrigida: entra definida_em; autor_id e vigente_desde são NULOS juntos e só juntos na vigência padrão (uma por aluno); a regra passa a dizer que a meta do dia D é a de maior vigente_desde menor ou igual a D, a vigência padrão valendo antes de todas, e no empate a de maior definida_em; o índice passa a (aluno_id, vigente_desde, definida_em). O placar deste cartão (2 de 5 tabelas) só muda no fechamento de {F4-02}, medido no dia.
Fechamento [2026-09-30] de {F4-02}: placar 3 de 5 tabelas. meta_nutricional está em produção (migração 0044, https://fit.modulareasy.com) com as colunas da ficha acima já corrigida (definida_em incluída; autor_id e vigente_desde nulos juntos e só juntos na vigência padrão, uma por aluno) e o índice (aluno_id, vigente_desde, definida_em); só de acréscimo, com UPDATE e DELETE pela aplicação negados (42501). A regra da ficha está provada: a meta do dia D é a de maior vigente_desde menor ou igual a D, a vigência padrão valendo antes de todas, e no empate a de maior definida_em, calculada no ponto único mfit.meta_vigente(aluno, data). Falta plano_alimentar com plano_refeicao ({F4-03}). O cartão permanece [ ].
Nota (Inspeção, {AUD-11}, 2026-09-30): as cinco tabelas deste cartão são dado da categoria nutrição de RF-CORE-010, a sétima: refeicao, meta_nutricional e plano_alimentar decidem acesso com mfit.tem_consentimento(aluno_id, 'nutricao') na escrita e mfit.consentimento_visivel(aluno_id, 'nutricao') na leitura, e refeicao_alimento e plano_refeicao seguem a linha pai. A vigência padrão de meta_nutricional passa a nascer no primeiro consentimento de nutrição, não na criação do aluno, e a de aluno sem consentimento sai na migração de {AUD-11}. Placar deste cartão inalterado, 3 de 5 tabelas.
Fechamento [2026-09-30] de {AUD-11}: placar inalterado, 3 de 5 tabelas: nenhuma tabela nasce neste card, as três que existem (refeicao, refeicao_alimento, meta_nutricional) passam a estar sob a categoria nutrição em produção (migrações 0046 e 0047). A vigência padrão de meta_nutricional agora nasce no primeiro consentimento de nutrição do aluno, e a de aluno sem consentimento foi removida pela migração (era cópia de metas_padrao, conforme o gate de db); nenhuma linha com autor foi tocada. Faltam plano_alimentar com plano_refeicao ({F4-03}, migração 0048), que já nascem sob a categoria. O cartão permanece [ ].
Nota (gate {F4-03}, Drift 2, 2026-09-30): reconciliação da FICHA, nunca do requisito. A ficha de plano_alimentar e de plano_refeicao não trazia o que RF-CORE-009 exige (quem alterou por último e quando), não desempatava dois horários iguais e não dizia a forma dos alimentos. A ficha acima já está corrigida: plano_alimentar ganha criado_em, atualizado_por e atualizado_em, com status ativo ou inativo (E.3) e índice (aluno_id, status); plano_refeicao ganha ordem, e alimentos passa a documento [{nome, quantidade, calorias}] validado no banco (Cenário 1 do Drift 1 do mesmo gate, com calorias), com unicidade (plano_id, ordem), índice (plano_id) e exibição por horario e depois ordem. plano_alimentar usa o status existente como coluna de desativação, no molde de ficha_treino; quem desativou e quando fica na trilha. O placar deste cartão (3 de 5 tabelas) só muda no fechamento de {F4-03}, medido no dia.
Nota de correção (Inspeção, gate {F4-03}, Drift 9, 2026-09-30): a migração do plano alimentar é a 0052 ({F4-03}); o fechamento de {AUD-11} acima, que numera a migração de {F4-03} como 0048, fica corrigido (a 0048 é de {AUD-10}). A categoria nutricao existe desde a 0046 ({AUD-11}).
Fechamento [2026-09-30] de {F4-03}: placar 5 de 5 tabelas. plano_alimentar e plano_refeicao estão em produção (migração 0052, https://fit.modulareasy.com) com as colunas da ficha acima já corrigida: status texto ativo ou inativo (E.3) e índice (aluno_id, status) no plano; ordem, alimentos em documento [{nome, quantidade, calorias}] validado no banco, unicidade (plano_id, ordem) e índice (plano_id) na filha. Titular e autor imutáveis por privilégio de coluna; a filha herda o consentimento de nutrição do plano pai; a soma de calorias por refeição e por plano é do banco, sem coluna de total. Medido em produção na conferência de fechamento: as cinco tabelas de nutrição existem e mfit.parametro tem 33 linhas. Remover refeição ao editar grava na trilha refeicao_removida com o conteúdo anterior. O cartão passa a [x].
Nota (gate {F4-04}, Drift 2, 2026-09-30): mfit.comparacao_com_meta, migração 0053, é a regra única da comparação do consumo com a meta; {F4-05} a consome e define por cima dela o que é meta atingida. A razão: se a tela calculasse o percentual e o acompanhamento calculasse em SQL, um dia que a tela mostra "100 por cento" poderia não contar como atingido. Placar do cartão inalterado, 5 de 5 tabelas (a função não é tabela).
Fechamento [2026-09-30] de {F4-04}: placar inalterado, 5 de 5 tabelas: nenhuma tabela nasce neste card. O que nasce é a função mfit.comparacao_com_meta(consumido, meta) (migração 0053, https://fit.modulareasy.com, merge a6624e9), função pura e IMMUTABLE, sem SECURITY DEFINER, com EXECUTE para o papel da aplicação: devolve restante com uma casa e percentual inteiro, meio para cima e sem teto, e nulo nos dois quando a meta é nula, zero ou negativa, ou o consumido é nulo. É a regra única da comparação do consumo com a meta, e {F4-05} a consome. Medido: funções do schema de 57 para 58 (só a nova), políticas 77 e parâmetros 33, inalterados; a 0053 não cria tabela, política, gatilho, privilégio de tabela nem parâmetro. A soma do dia continua sobre refeicao e refeicao_alimento, pelo leitor único de refeição, só com refeições ativas.
Fechamento [2026-10-01] de {F4-05}: placar inalterado, 5 de 5 tabelas: nenhuma tabela nasce. Nasce a função mfit.meta_atingida(consumido, meta, tolerância) (migração 0054, função pura, IMMUTABLE, sem SECURITY DEFINER, consome mfit.comparacao_com_meta), que decide o dia com meta atingida de RF-DIET-005; funções do schema de 58 para 59, políticas 77 e gatilhos inalterados. A tolerância chega como argumento e a função nunca lê mfit.parametro. NULL não é falso: meta ausente, zero ou negativa devolve nulo. A migração 0055 é só de COMMENT.
Para que serve: guardar a vida clínica e a evolução física do aluno.
Relacionado com: RF-SAUD-001 a 010, RF-INTE-001, RF-INTE-003 a 005; tarefas F5-01 a F5-10, F8-09, F8-13 a F8-15.
Onde fica: banco de dados, esquema principal, com anexos no repositório privado.
Especificação: anamnese (id, aluno_id, autor_id, especialidade_autor anulável, data, tronco em documento estruturado, secoes preenchidas na ocasião em documento estruturado, explicacao_gerada, explicacao_gerada_em, desativado_em, desativado_por) com vários registros por aluno, um por ocasião de coleta, sem restrição de unicidade por aluno, e nenhuma atualização de registro anterior no fluxo de nova coleta; avaliacao_fisica (id, aluno_id, autor_id, especialidade_autor anulável, data, secoes em documento estruturado, dobras_pontos, dobras_mm, desativado_em, desativado_por); medida_corporal (id, aluno_id, autor_id, data, treze colunas numéricas, observacao); foto_progresso (id, aluno_id, data, arquivo_chave, categoria entre frente, lado direito, lado esquerdo e costas, observacao); exame (id, aluno_id, autor_id, tipo, nome, data, resumo, observacoes, anexo_chave, explicacao_gerada, explicacao_gerada_em); prescricao (id, aluno_id, autor_id, diagnostico, medicamentos, posologia, duracao, data, observacoes, explicacao_gerada); sessao_reabilitacao (id, aluno_id, autor_id, regiao, tratamento_realizado, exercicios_realizados, notas_amplitude, notas_progresso, plano_proxima_sessao, dor_antes, dor_depois, duracao_min, data, explicacao_gerada, explicacao_gerada_em); atividade_externa (id, aluno_id, conta_integracao_id opcional, origem nomeando o serviço ou o registro manual, identificador_externo, tipo, data, duracao_min, calorias, passos, distancia_m, fc_media, fc_maxima, chave_deduplicacao); conta_integracao (id, aluno_id, servico entre os habilitados, identificador_conta_no_servico, credencial cifrada, escopos, conectado_em, ultima_sincronizacao, estado entre conectada, precisa_reautorizar e desconectada). Índices: cada tabela de saúde por (aluno_id, data); foto_progresso(aluno_id, categoria, data) para a comparação dentro da categoria; conta_integracao(aluno_id, servico) único enquanto conectada. Restrições: dor_antes e dor_depois entre zero e dez; atividade_externa.chave_deduplicacao única por aluno, composta por origem mais identificador da atividade no serviço, o que garante que nem reimportar o mesmo arquivo nem repetir a sincronização duplicam registro; toda escrita nas seis categorias sensíveis verifica o consentimento correspondente. Escopo: conta_integracao responde apenas ao titular e ao administrador, nunca a profissional vinculado, e a credencial cifrada não é servida a ninguém, nem ao titular.
Nota (Inspeção, gate {F5-01}, Drifts 4 e 5, 2026-10-01): a ficha de anamnese acima foi corrigida, sem mudar o placar do cartão (continua [ ]; nenhuma das nove tabelas existe até {F5-01}, que cria a primeira na migração 0056). data é o momento da coleta, com padrão do banco e nunca informada pelo cliente, e é o único campo de data, porque criado_em repetia o mesmo fato; entram desativado_em e desativado_por (a desativação de RN-008 e de E.1), ambos nulos até a desativação e preenchidos juntos; especialidade_autor é nula quando o autor é o próprio aluno. Índice (aluno_id, data decrescente). Atualização: o banco concede atualização somente em desativado_em e desativado_por; nenhum campo de conteúdo (tronco, secoes, data, autor_id, especialidade_autor) aceita atualização, e as colunas da explicação nascem sem permissão de atualização até {F5-10}. O tronco e as seções são documentos estruturados cujas chaves e tipos são a ficha do Apêndice: Catálogo de formulários do DRS, e secoes aceita apenas as quatro chaves de especialidade.
Fechamento [2026-10-01] de {F5-01}: a primeira das nove tabelas existe: mfit.anamnese em produção (migração 0056, merge 9cb16f3), com a ficha corrigida pelo gate (id, aluno_id, autor_id, especialidade_autor anulável, data, tronco, secoes, explicacao_gerada, explicacao_gerada_em, desativado_em, desativado_por; índice (aluno_id, data decrescente)), quatro políticas e quatro gatilhos, sem função nova. Atualização concedida somente em desativado_em e desativado_por; as colunas da explicação nascem sem permissão de atualização, para {F5-10}. Placar de tabelas deste cartão: 1 de 9 (aritmética: 1 entregue mais 8 pendentes igual 9). Tabelas do schema de 31 para 32, políticas de 77 para 81, funções inalteradas em 59, parâmetros de 34 para 36, listas em 7. O cartão continua [ ].
Nota (Inspeção, gate {F5-02}, Drifts 3, 5, 6 e 8, 2026-10-01): a ficha de avaliacao_fisica acima foi corrigida, sem mudar o placar do cartão (continua [ ]; só anamnese existe até {F5-02}, que cria a segunda na migração 0057). Sai calculos derivados: o cálculo é feito na leitura e nunca guardado (RN-004, "calculados, não digitados"; precedente da refeição: total guardado é cópia que envelhece). Entram especialidade_autor (nula quando o autor é o próprio aluno), dobras_pontos e dobras_mm (duas colunas paralelas, uma entrada por ponto de dobra, validadas contra a lista ponto_dobra_cutanea) e desativado_em e desativado_por (a desativação de RN-008 e de E.1). data é o momento do registro, com padrão do banco, nunca informada pelo cliente e travada na política (data = now()). secoes aceita apenas as seis chaves de seção. Índice (aluno_id, data decrescente). Atualização: o banco concede atualização somente em desativado_em e desativado_por; nenhum campo de conteúdo aceita atualização (a avaliação não se edita, Nota de RN-009 no DRS). Leitor único: o de avaliacao_fisica passa a ser o módulo avaliacao/avaliacao.ts, que lê, lista, grava e desativa e chama o registro de leitura administrativa em toda leitura, no molde da anamnese. Aritmética prevista no fechamento, a medir e não a projetar: tabelas deste cartão de 1 para 2 de 9 (1 entregue mais 1 igual 2, restando 7); tabelas do schema de 32 para 33; políticas de 81 para 85; funções em 59; parâmetros de 36 para 38; listas de 7 para 8. O cartão continua [ ].
Fechamento [2026-10-06] de {F5-02}: a segunda das nove tabelas existe: mfit.avaliacao_fisica em produção (migração 0057, merge 3ab8395), com a ficha corrigida pelo gate (id, aluno_id, autor_id, especialidade_autor anulável, data, secoes, dobras_pontos, dobras_mm, desativado_em, desativado_por; índice (aluno_id, data decrescente)), sem coluna de cálculo, quatro políticas, cinco gatilhos e sete CHECKs, sem função nova. Atualização concedida somente em desativado_em e desativado_por; data é travada pela política (data = now()). Placar de tabelas deste cartão: 2 de 9 (aritmética: 2 entregues mais 7 pendentes igual 9). Tabelas do schema de 32 para 33, políticas de 81 para 85, funções inalteradas em 59, parâmetros de 36 para 38, listas de 7 para 8. A migração 0058 troca o CHECK anamnese_secoes_formato da tabela anamnese pela forma estrita, sem mudar a ficha. O cartão continua [ ].
Nota (Inspeção, gate {F5-04}, Drifts 3, 7, 10 e 11, 2026-10-06): a ficha de exame acima foi corrigida, sem mudar o placar do cartão (continua [ ]; só anamnese e avaliacao_fisica existem até {F5-04}, que cria a terceira na migração 0059). Colunas: id, aluno_id, autor_id, especialidade_autor (nula quando o autor é o próprio aluno), tipo, nome, data_exame (informada pelo usuário, não futura), resumo, observacoes, anexo_chave, anexo_bytes e anexo_formato (os três juntos ou nenhum), criado_em (gravado pelo banco e exigido igual a agora na política de inserção), desativado_em e desativado_por (a desativação de RN-008). As colunas explicacao_gerada e explicacao_gerada_em da ficha acima não constam da lista de colunas decidida para a 0059; o dono delas é {F5-10}. Políticas: leitura por pode_ler_aluno(aluno_id, autor_id, false, 'exame') em conjunção com consentimento_visivel; inserção com tem_consentimento e vínculo ativo de Médico (literal) ou titular; atualização: o banco concede somente em desativado_em e desativado_por, e nenhum campo de conteúdo aceita atualização (o exame não se edita, Nota de RN-009 no DRS); exclusão só do Super Administrador; cinco gatilhos (um de lista e quatro de auditoria) e nenhuma função nova. Desativar não apaga o objeto: o exame desativado segue legível ao titular e ao Super Administrador e o anexo segue na cota ({ART-ACS-10}); o objeto só é apagado na exclusão definitiva (hoje só a limpeza, sem rota de exclusão clínica, precedente da anamnese), e quem garante é o verificador de órfãos disco contra banco no repositório privado. Leitor único: exames/exames.ts, que chama o registro de leitura administrativa em toda leitura; o detalhe com anexo grava UMA trilha administrativa, a da emissão do endereço, e a lista não traz endereço. Aritmética prevista no fechamento, a medir e não a projetar: tabelas deste cartão de 2 para 3 de 9 (2 entregues mais 1 igual 3, restando 6); tabelas do schema de 33 para 34; funções inalteradas em 59; parâmetros de 38 para 41; listas de 8 para 9. O cartão continua [ ].
Fechamento [2026-10-06] de {F5-04}: a terceira das nove tabelas existe: mfit.exame em produção (migração 0059, merge b078e76), com a ficha corrigida pelo gate (id, aluno_id, autor_id, especialidade_autor anulável, tipo, nome, data_exame, resumo, observacoes, anexo_chave, anexo_bytes e anexo_formato juntos ou nenhum, criado_em, desativado_em e desativado_por; índice (aluno_id, data_exame decrescente)), quatro políticas, cinco gatilhos (um de lista e quatro de auditoria) e seis CHECKs, nenhuma função nova. Atualização concedida somente em desativado_em e desativado_por; exclusão só do Super Administrador. As colunas da explicação não nasceram: o dono delas é {F5-10}. Placar de tabelas deste cartão: 3 de 9 (aritmética: 3 entregues mais 6 pendentes igual 9). Tabelas do schema de 33 para 34, políticas de 85 para 89, funções inalteradas em 59, parâmetros de 38 para 41, listas de 8 para 9. O cartão continua [ ].
Fechamento [2026-10-06] de {F5-05}: a quarta das nove tabelas existe: mfit.prescricao em produção (migrações 0060 e 0061, merge de718a6), com a ficha corrigida pelo gate (id, aluno_id, autor_id, especialidade_autor sempre medico, diagnostico, medicamentos, posologia, duracao_quantidade de 1 a 999, duracao_unidade em dias, semanas ou meses, uso_continuo obrigatório e sem valor padrão, data_prescricao, observacoes opcional, criado_em, desativado_em e desativado_por; 15 colunas e 8 restrições, entre elas a de coerência: uso contínuo sem quantidade nem unidade, e o contrário com as duas; índice (aluno_id, data_prescricao decrescente)), quatro políticas, quatro gatilhos de auditoria (nenhum de lista), nenhuma função nova. A coluna duracao em texto da ficha acima foi substituída pelas três colunas estruturadas, e a coluna data por data_prescricao. Inserção só do Médico com vínculo ativo na especialidade e consentimento; atualização concedida somente em desativado_em e desativado_por; exclusão só do Super Administrador. A coluna da explicação não nasceu: o dono dela é {F5-10}. Placar de tabelas deste cartão: 4 de 9 (aritmética: 4 entregues mais 5 pendentes igual 9). Tabelas do schema de 34 para 35, políticas de 89 para 93, funções inalteradas em 59, parâmetros de 41 para 42, listas inalteradas em 9. O cartão continua [ ].
Nota (Inspeção, gate {F5-06}, Drifts 1, 2, 4 e 6 e migração 0062, 2026-10-06): a ficha de sessao_reabilitacao acima foi corrigida, sem mudar o placar do cartão (continua [ ]; só anamnese, avaliacao_fisica, exame e prescricao existem até {F5-06}, que cria a quinta na migração 0062, a única do card: a categoria e o ponto sessao_reabilitacao já existem desde as migrações 0012 e 0050, e nenhum valor de enumeração é acrescentado). Colunas: id, aluno_id, autor_id, especialidade_autor (nula quando o autor é o próprio aluno, ou fisioterapeuta), regiao (item da lista regiao_corporal), tratamento_realizado, exercicios_realizados, notas_amplitude, notas_progresso, plano_proxima_sessao, observacoes, dor_antes e dor_depois (inteiros de 0 a 10, restrição espelhada no banco), duracao_min (de 1 a 300, restrição espelhada no banco), a data da sessão (informada, não futura), criado_em (gravado pelo banco e exigido igual a agora na política), desativado_em e desativado_por. As colunas explicacao_gerada e explicacao_gerada_em da ficha acima não constam da lista de colunas decidida para a 0062; o dono delas é {F5-10}. Políticas: leitura por pode_ler_aluno(aluno_id, autor_id, false, 'sessao_reabilitacao') em conjunção com consentimento_visivel; inserção no molde do exame (0059), com tem_consentimento, para o aluno sobre si (especialidade do autor nula) ou para o Fisioterapeuta com vínculo ativo de fisioterapeuta (literal); atualização: o banco concede somente em desativado_em e desativado_por, e nenhum campo de conteúdo aceita atualização (a sessão não se edita, Nota de RN-009 no DRS); exclusão só do Super Administrador; gatilhos de auditoria e nenhuma função nova. Leitor único: reabilitacao/reabilitacao.ts, que chama o registro de leitura administrativa em toda leitura; a variação de dor (depois menos antes) é calculada na leitura por função pura, nunca guardada. Aritmética prevista no fechamento, a medir e não a projetar: tabelas deste cartão de 4 para 5 de 9 (4 entregues mais 1 igual 5, restando 4); tabelas do schema de 35 para 36; funções inalteradas em 59; parâmetros de 42 para 43; listas de 9 para 10. O cartão continua [ ].
Para que serve: guardar conversas, mensagens e notificações.
Relacionado com: RF-COMU-001 a 006; tarefas F6-01 a F6-06.
Onde fica: banco de dados, esquema principal.
Especificação: conversa (id, tipo entre aluno_profissional, entre_profissionais e grupo_aluno, aluno_contexto_id); conversa_participante (id, conversa_id, usuario_id, entrou_em, saiu_em); mensagem (id, conversa_id, autor_id, texto, mencoes, momento, lida_por); notificacao (id, destinatario_id, tipo, origem_entidade, origem_id, texto, destino_rota, agrupador, criada_em, lida_em, limpa_em). Índices: mensagem(conversa_id, momento), notificacao(destinatario_id, limpa_em, criada_em), conversa_participante(usuario_id). Regra: uma conversa por par e por aluno de contexto; participante com saiu_em preenchido lê o histórico até aquela data e não recebe mensagem nova.
Para que serve: guardar as conquistas concedidas ao aluno.
Relacionado com: RF-ENGA-004; tarefa F7-04.
Onde fica: banco de dados, esquema principal.
Especificação: conquista_aluno (id, aluno_id, conquista_codigo, concedida_em). Restrição: par aluno_id e conquista_codigo único, o que impede concessão repetida. A lista de conquistas e os critérios são configuração, não código (Apêndice de conquistas do DRS).
Para que serve: guardar o conteúdo de ajuda do sistema por módulo e por papel, versionado.
Relacionado com: RF-AJUD-001 a 003; tarefas F9-01 a F9-03; ART-SCR-05, ART-FORM-10.
Onde fica: banco de dados, tabelas globais sem coluna de aluno nem de profissional.
Especificação: guia_modulo (id, modulo entre os treze códigos do bloco C.1, papel entre os seis do bloco B.1, titulo, estado entre sem_guia, rascunho e publicado, versao_publicada_id, atualizado_por, atualizado_em); guia_versao (id, guia_id, numero, conteudo com os sete blocos em documento estruturado, autor_id, origem entre escrita e gerada_revisada, publicada_em). Restrições: par modulo e papel único em guia_modulo; par guia_id e numero único em guia_versao; numero sempre crescente, e restaurar uma versão anterior cria uma versão nova em vez de reabrir a antiga. Índices: guia_modulo(papel, estado), guia_versao(guia_id, numero). Escopo: leitura da versão publicada para todo usuário autenticado do papel correspondente; escrita apenas para o administrador; rascunho invisível ao leitor. Auditoria: criação, edição, publicação, despublicação e restauração.
Formulários
Para que serve: criar a conta do profissional com o registro do conselho no formato certo.
Relacionado com: RF-CORE-003; tarefa F1-05.
Onde fica: tela de cadastro, caminho /cadastrar.
Especificação: ficha completa no Apêndice de catálogo de formulários do DRS, seção Cadastro de profissional. Contém a tabela de campos, as quatro máscaras, a ação no envio, as mensagens e o idioma.
Para que serve: cadastrar e editar o exercício global.
Relacionado com: RF-EXER-001, RF-EXER-002; tarefas F2-01 e F2-02.
Onde fica: administração de exercícios, caminho /admin/exercicios.
Especificação: ficha completa no Apêndice de catálogo de formulários do DRS, seção Exercício do catálogo, com os treze campos, as listas fechadas e os limites de arquivo. imagem aceita arquivo enviado ou endereço, as duas formas moram na mesma coluna, distinguidas pelo prefixo; video é só endereço.
Estado: 13 de 13 campos servidos, ficha fechada, aritmética 11 ({F2-01}) mais 2 ({F2-02}) igual 13. A ficha do Apêndice tem treze linhas.
Para que serve: capturar o que orienta a prescrição e a geração assistida.
Relacionado com: RF-TREI-008, RF-IAGE-001; tarefas F3-08 e F8-06.
Onde fica: tela de preferências do aluno.
Especificação: ficha completa no Apêndice de catálogo de formulários do DRS, seção Preferências de treino do aluno, com os sete campos, a obrigatoriedade declarada por campo (objetivos e nível sim, os outros cinco não), as oito opções de objetivo, os três níveis, a lista fechada de vinte e seis equipamentos, os dias de segunda a domingo, a duração de 20 a 120 minutos com passo de 5 e o teto de 2000 caracteres de cada um dos dois textos.
Estado: 7 de 7 campos servidos, ficha fechada. A ficha do Apêndice tem sete linhas, e os sete são de um card só, {F3-08}, que os serve de uma vez, porque o formulário salva inteiro num botão só.
Nota (gate {F3-08}, Drift 8, 2026-09-15): este cartão não tinha campo Estado, logo não tinha universo declarado contra o qual fechar, e seria marcado [x] sem ninguém poder conferir contra o quê. O universo nasce aqui, sete campos, no molde literal de {ART-FORM-02}, e o cartão fecha campo a campo, com a obrigatoriedade, as listas fechadas e os limites conferidos contra o Apêndice, item por item, incluindo os três rótulos com barra da lista de equipamentos. A metade que não é de {F3-08} é a leitura das preferências pela geração assistida, que o próprio campo "Relacionado com" já nomeia em {F8-06}, e ela continua com o dono dela: servir os sete campos ao aluno e ao profissional vinculado fecha este cartão, e ler para gerar treino não é campo deste formulário.
Fechamento [2026-09-15]: os sete campos em produção (merge ce1787b, https://fit.modulareasy.com), conferidos contra o Apêndice, obrigatoriedade, listas fechadas e limites inclusos. Cartão fecha 7 de 7.
Para que serve: montar o histórico do aluno uma única vez, acrescido por especialidade.
Relacionado com: RF-SAUD-001, ADR-007, RF-CORE-012; tarefa F5-01, F1-18.
Onde fica: aba de saúde do aluno.
Especificação: ficha completa no Apêndice de catálogo de formulários do DRS, seção Anamnese, com o tronco comum e as quatro seções por especialidade. Cada envio cria um registro datado, com autor e especialidade do autor, e não altera nenhum registro anterior; o tronco de uma anamnese nova abre pré-preenchido pela anterior do aluno, editável, com a indicação da data de origem. A tela lista as anamneses do aluno da mais recente para a mais antiga e permite abrir qualquer uma em leitura. Pré-condição: consentimento da categoria anamnese. A tela nasce com <AvisoNaoClinico ponto="telas_clinicas" /> no topo (R-9, {F1-18}).
Nota (Inspeção, gate {F5-01}, Drifts 1, 3 e 4, 2026-10-01): a ficha dos 46 campos, com tipo, obrigatoriedade e teto, está no Apêndice: Catálogo de formulários do DRS, na Nota do Drift 1: tronco com 20 campos e quatro seções de 5, 5, 8 e 8; todos opcionais, mas o envio exige ao menos um campo preenchido (422 anamnese_vazia); texto curto e texto longo com os tetos de anamnese_texto_curto_max_caracteres e anamnese_texto_longo_max_caracteres ({ART-CFG-01}). Quem preenche o quê: o profissional preenche o tronco e somente a seção da própria especialidade, e somente com vínculo ativo nela; o aluno preenche o tronco e as seções das especialidades com as quais não tem vínculo ativo; ao abrir uma anamnese, todas as seções gravadas aparecem. Sem edição: a anamnese não se edita, a correção é nova coleta, e o autor e o Super Administrador só a desativam; a tela não tem ação de editar. O cartão continua [ ].
Fechamento [2026-10-01] de {F5-01}: formulário e lista da anamnese em produção (merge 9cb16f3, repositório wladimirdjr/modularfit, migração 0056, https://fit.modulareasy.com (/api/estado na versão 9cb16f3)), em /saude (aba Anamneses), /saude/anamneses/nova e /saude/anamneses/:id. Os 46 campos (tronco de 20 mais as seções de 5, 5, 8 e 8) seguem o contrato único do servidor com espelho na web provado por teste; todos opcionais, o envio exige ao menos um campo (422 anamnese_vazia), texto curto e longo com os tetos editáveis (200 e 2000), números com vírgula aceita e as faixas de plausibilidade (o qa recusou idade 121, altura 49, peso com duas casas e sexo inválido, e aceitou dor de 0 a 10). Cada envio cria um registro datado, com autor e especialidade vindos da sessão; o tronco abre pré-preenchido pela anamnese ativa mais recente, com a indicação da data de origem; a tela lista da mais recente para a mais antiga, o formulário mostra só as seções da própria especialidade (o aluno, as das especialidades sem vínculo) e a leitura mostra todas as seções gravadas, com "não informado" visível no campo vazio. A anamnese não se edita: a tela não tem ação de editar, e o autor ou o Super só desativam, com confirmação, no detalhe (divergência declarada: não há botão no cartão da lista). O aviso não clínico fica no topo da casca. Pré-condição de consentimento provada em produção. O cartão passa a [x].
Para que serve: registrar as medições e testes e alimentar os cálculos derivados.
Relacionado com: RF-SAUD-002, RF-SAUD-003; tarefas F5-02 e F5-03.
Onde fica: aba de saúde do aluno.
Especificação: ficha completa no Apêndice de catálogo de formulários do DRS, seção Avaliação física, com as seis seções e o bloco de cálculos, que é calculado e nunca digitado. Quem preenche: as quatro especialidades com vínculo ativo e o próprio aluno; a seção de antropometria não é restrita a especialidade nenhuma.
Nota (Inspeção, gate {F5-02}, Drifts 1, 3, 4 e 7, 2026-10-01): a ficha dos campos, com tipo, faixa e teto, está no Apêndice: Catálogo de formulários do DRS, na Nota do Drift 1: anamnese resumida com 8 campos, cardiovascular com 6 (entra idade_anos, insumo da frequência cardíaca máxima de RN-004), antropometria com 6 mais um campo por ponto de dobra ativo, neuromuscular com até 10 testes de força, aeróbico com 6 e biotipo com 2; todos opcionais, mas o envio exige ao menos um campo (422 avaliacao_vazia); texto curto e texto longo com os tetos de avaliacao_texto_curto_max_caracteres e avaliacao_texto_longo_max_caracteres ({ART-CFG-01}). Quem preenche não muda. Sem edição: a avaliação não se edita, a correção é nova avaliação, e o autor e o Super Administrador só a desativam; a tela não tem ação de editar. Comparação: bloco do detalhe, pela regra da Nota de RF-SAUD-002 (contra a ativa anterior ou outra ativa escolhida; métrica de teste só com o mesmo teste; ausente nunca vale zero). O mockup traz campos que a ficha não tem (peitoral, braço direito e esquerdo, preensão manual, FC final, objetivo e nível): o DRS vence, e perímetro extra é medida corporal ({F5-07}). O cartão continua [ ].
Nota (Inspeção, gate {F5-03}, Drifts 1 a 5, 2026-10-06): o bloco de cálculos desta ficha ganha o desenho, sem mudar a ficha dos campos. Detalhe da avaliação: bloco "Cálculos" com índice de massa corporal, relação cintura quadril e frequência cardíaca máxima, cada um com valor, unidade e a fórmula usada ("peso / altura² (m)", "cintura / quadril" e "220 menos a idade"), e as cinco zonas de intensidade em tabela que empilha em tela estreita; sem classificação de índice de massa corporal, porque o produto não é clínico. Comparação: seção "Cálculos" ao fim, com índice de massa corporal (uma casa, kg/m²), relação cintura quadril (duas casas) e frequência cardíaca máxima (zero casas, bpm); as zonas não entram; as linhas antigas mantêm ordem e chave. Lista de avaliações: não exibe cálculo. Cálculo sem insumo: o número some e a linha diz "não calculado: informe a altura" (e a forma equivalente para cintura, quadril e idade), nunca zero. Arredondamento: meio para cima sobre a representação decimal; divisor zero ou ausente não calcula. Constantes: 220 menos a idade, o índice de massa corporal, a relação cintura quadril e as cinco zonas são constantes de literatura com fonte citada (Fox, 1971; Quetelet e OMS; OMS, 2008; ACSM) e não parâmetro: mudar é mudar RN-004, e o verificador de parâmetros as conhece como exceção C nomeada. Nada dele é gravado. O cartão continua [ ].
Fechamento [2026-10-06] de {F5-02}: formulário, detalhe e comparação da avaliação física em produção (merge 3ab8395, repositório wladimirdjr/modularfit, migrações 0057 e 0058 aplicadas em produção em 06/10, https://fit.modulareasy.com (/api/estado na versão 87ae8e0, a mesma árvore do merge; o deploy da main em 3ab8395 segue em curso)), em /saude/avaliacoes (aba Avaliações da casca de /saude), /saude/avaliacoes/nova e /saude/avaliacoes/:id. As seis seções (anamnese resumida, cardiovascular, antropometria, neuromuscular, aeróbico e biotipo) seguem o contrato único do servidor com espelho na web provado por teste; todas opcionais, o envio exige ao menos um campo (422 avaliacao_vazia), texto curto e longo com os tetos editáveis (200 e 2000), números com vírgula aceita e faixas de plausibilidade (o qa recusou idade 121 e peso 501), as quatro dobras cutâneas em milímetros pela lista de pontos vinda da configuração, o teste de flexibilidade, o teste de resistência e o tempo aeróbico em minutos e segundos (mm:ss). Cada envio cria um registro datado, com autor e especialidade vindos da sessão (o aluno grava com especialidade nula) e o Nutricionista vinculado registra a antropometria completa sem recusa. A avaliação não se edita: a tela não tem ação de editar, e o autor ou o Super só desativam, com confirmação, no detalhe. Comparação: bloco do detalhe, contra a ativa anterior ou outra ativa escolhida em "Comparar com" (as opções se distinguem por autor, ordem no dia e a medida); variação com sinal e unidade, "não informado" e "sem variação" onde falta dado, métrica de teste só com o mesmo teste. O aviso não clínico fica no topo da casca. Pré-condição de consentimento provada em produção. O cartão passa a [x].
Fechamento [2026-10-06] de {F5-03}: o bloco de cálculos desta ficha está em produção (merge 08b35ed, repositório wladimirdjr/modularfit, sem migração, https://fit.modulareasy.com (a mesma árvore já provada em produção como 208a883; o deploy da main em 08b35ed segue em curso)), como a Nota de {F5-03} desenhou: no detalhe da avaliação, o bloco "Cálculos" com índice de massa corporal (uma casa, kg/m²), relação cintura quadril (duas casas) e frequência cardíaca máxima (zero casas, bpm), cada um com valor, unidade e fórmula, e as cinco zonas de intensidade em tabela que empilha em tela estreita; na comparação, a seção "Cálculos" ao fim com as três métricas e as zonas fora; a lista não exibe cálculo. Sem insumo o número some e a linha diz "Não calculado: informe ...", nunca zero. Arredondamento meio para cima sobre a representação decimal, provado com 48 kg e 160 cm (18,8). Nada é gravado: nenhuma coluna e nenhuma migração. Prova: H1 de {TA-40} em produção (24,7, 0,90, 190 e as zonas 95 a 114 até 171 a 190). O cartão segue [x].
Para que serve: registrar a evolução física datada.
Relacionado com: RF-SAUD-007; tarefa F5-07.
Onde fica: tela de evolução.
Especificação: treze campos numéricos com data mais um campo de observação de até 500 caracteres, todos opcionais e ao menos um dos treze obrigatório para salvar. Ficha no Apêndice de catálogo de formulários do DRS, seção Medida corporal. Ação no envio: cria o registro, atualiza o gráfico e calcula a variação contra a medição anterior. Mensagens: erro quando nenhum campo foi preenchido; aviso quando a data é futura.
Para que serve: guardar o exame com o arquivo no repositório privado.
Relacionado com: RF-SAUD-004, RF-SAUD-009, RF-CORE-012; tarefas F5-04 e F5-09, F1-18.
Onde fica: aba de saúde do aluno.
Especificação: ficha completa no Apêndice de catálogo de formulários do DRS, seção Exame, com os seis campos, a lista editável de tipos e o limite de vinte megabytes. A tela nasce com <AvisoNaoClinico ponto="telas_clinicas" /> no topo (R-9, {F1-18}).
Nota (Inspeção, gate {F5-04}, Drifts 2, 5, 7, 8, 9 e 11, 2026-10-06): a ficha dos seis campos está no Apêndice: Catálogo de formulários do DRS, na Nota do exame, e {ART-CFG-01} traz os parâmetros. Sem edição: o exame não se edita, a correção é novo exame, e o autor e o Super Administrador só o desativam; a tela não oferece edição. Data: informada pelo usuário e não futura, com a folga de fuso já existente no servidor; o momento do registro é do banco. Tetos: nome (mínimo de 3 caracteres, regra fixa, e teto de exame_nome_max_caracteres), resumo (exame_resumo_max_caracteres) e observações (exame_observacoes_max_caracteres), todos editáveis; a mensagem do campo diz o teto vigente. Tipo: a lista tipo_exame (Laboratorial, Imagem, Cardiológico, Funcional e Outro). Anexo: o tipo vem dos bytes e da extensão declarada, os dois na lista de extensões aceitas e da mesma família (jpg é jpeg); documento por %PDF-; texto só se for UTF-8 válido, sem byte nulo e sem controle além de tabulação e quebra de linha; um arquivo de extensão aceita e conteúdo de outro formato é recusado com a mensagem do campo; um arquivo de exatamente o limite é aceito; a cota do plano é decidida antes de gravar o objeto. Aviso aos Médicos: não é desta tela nem de {F5-04}; é {F6-05}. O cartão continua [ ].
Fechamento [2026-10-06] de {F5-04}: formulário, lista e detalhe do exame estão em produção (merge b078e76, repositório wladimirdjr/modularfit, migração 0059, https://fit.modulareasy.com (a mesma árvore já provada em produção como bde96b3; o deploy da main em b078e76 segue em curso)), como a Nota de {F5-04} desenhou, dentro da casca de /saude (aba Exames, com <AvisoNaoClinico ponto="telas_clinicas" /> no topo, sem rota clínica fora da casca): os seis campos (tipo da lista tipo_exame, nome, data, resumo, observações e anexo), mensagem do campo com o teto vigente, "Não informado" e "Sem anexo" nos vazios, barra de envio, confirmação ao desativar e anexo aberto em nova aba por endereço assinado, emitido só no detalhe. Sem edição: nenhuma tela ou rota altera conteúdo, o autor e o Super Administrador só desativam. Data do usuário, não futura além da folga de fuso, e o momento do registro gravado pelo banco. Anexo pelos bytes e pela extensão declarada, 20 MiB exatos aceitos e 20 MiB mais um byte recusados com a mensagem do campo. Prova: H1 de {TA-41} em produção, e 72 combinações de largura, tema e tela sem rolagem horizontal. Lacuna: o formulário mostra "20 MB e o limite é 20 MB" para 20 MiB mais um byte (P3 do qa). O aviso aos Médicos segue em {F6-05}. O cartão passa a [x].
Para que serve: registrar conduta médica e atendimento de fisioterapia.
Relacionado com: RF-SAUD-005, RF-SAUD-006; tarefas F5-05 e F5-06.
Onde fica: abas clínica e de reabilitação do aluno.
Especificação: fichas completas no Apêndice de catálogo de formulários do DRS, seções Prescrição e Sessão de reabilitação, incluindo a escala de dor de zero a dez, os campos de tratamento realizado, exercícios realizados, notas de amplitude de movimento, notas de progresso e plano da próxima sessão, o aviso obrigatório de não substituição do receituário e, no topo das duas telas, <AvisoNaoClinico ponto="telas_clinicas" /> (RF-CORE-012, R-9, {F1-18}).
Nota (Inspeção, gate {F5-05}, Drifts 4, 7 e 8, 2026-10-06): este cartão cobre DOIS formulários e {F5-05} entrega só a metade da prescrição: o cartão NÃO é marcado em {F5-05}, e {F5-06} (sessão de reabilitação) o fecha. A ficha da prescrição no Apêndice do DRS ganha a Nota do gate de {F5-05}: duração estruturada (quantidade inteira maior que zero mais unidade em dias, semanas ou meses, ou uso contínuo; a unidade é constante estrutural com restrição no banco, não lista editável), tetos de texto, data não futura e o aviso do receituário como texto versionado (aviso_receituario, ponto prescricao, publicado em /admin/textos), exibido pelo componente AvisoDoReceituario na lista, no formulário e no detalhe. O <AvisoNaoClinico ponto="telas_clinicas" /> do topo é o da casca de /saude, e o aviso do receituário não é um quarto ponto de RF-CORE-012. O cartão continua [ ].
Fechamento parcial [2026-10-06] de {F5-05}: a metade da prescrição está em produção (merge de718a6), dentro da casca de /saude (aba Prescrições, com <AvisoNaoClinico ponto="telas_clinicas" /> no topo): lista em três grupos (vigentes, encerradas e desativadas, com "Vigente até", "Encerrada em" ou "Uso contínuo"), formulário (diagnóstico, medicamentos, posologia e observações, data que abre em hoje de São Paulo, escolha explícita de uso contínuo sem seleção inicial, quantidade e unidade só quando não é contínuo) e detalhe com data e autor e a confirmação nominal ao desativar. O aviso do receituário é o texto versionado aviso_receituario, exibido pelo componente AvisoDoReceituario na lista, no formulário e no detalhe, editável em /admin/textos. Sem edição: só se desativa. O cartão continua [ ] porque a sessão de reabilitação segue com {F5-06}.
Nota (Inspeção, gate {F5-06}, Drifts 1, 2, 4, 5 e 6, 2026-10-06): {F5-06} entrega a metade da sessão de reabilitação e fecha este cartão (a entregar, sem marcar nesta publicação). A ficha da sessão no Apêndice do DRS ganha a Nota do gate de {F5-06}: região como item da lista editável regiao_corporal; dor de 0 a 10 como constante estrutural e duração de 1 a 300 minutos como constante técnica, as duas com restrição espelhada no banco; data não futura com a folga de fuso espelhada; um só teto de texto longo (reabilitacao_texto_longo_max_caracteres) para os seis campos longos; quem grava é o Fisioterapeuta vinculado ou o Aluno para si; detalhe sem campo opcional vazio e sem "Não informado". O <AvisoNaoClinico ponto="telas_clinicas" /> do topo é o da casca de /saude, e a aba nasce dentro dela. O cartão continua [ ].
Para que serve: capturar o que o aluno comeu com os macronutrientes.
Relacionado com: RF-DIET-001; tarefa F4-01.
Onde fica: tela de nutrição do dia.
Especificação: ficha completa no Apêndice de catálogo de formulários do DRS, seção Refeição registrada, com os campos da refeição e os seis campos por alimento. Ação no envio: cria a refeição, soma os totais e recalcula o dia contra a meta vigente.
Nota (gate {F4-01}, Drift 4, 2026-09-29): {F4-01} soma a refeição (RN-004); a comparação do dia com a meta vigente é de {F4-02} e {F4-04}. A ação no envio descrita na Especificação acima se lê nesse recorte: neste card o envio cria a refeição com os alimentos e devolve os totais somados da própria refeição.
Fechamento [2026-09-30] de {F4-01}: o formulário está em produção em /nutricao/refeicoes/nova (estado de /nutricao, não tela nova), com os campos da refeição (tipo lido da lista fechada tipo_refeicao de oito itens, nome, data, horário e observações) e os seis campos por alimento, cada linha de alimento com a ação de remover. Os tetos de caracteres de nome e de observações vêm de refeicao_nome_max_caracteres e refeicao_observacoes_max_caracteres e mudam sem reiniciar. Validação provada pelo qa: tipo inexistente ou desativado, valores negativos, quantidade zero, mais de duas casas, teto de numeric(7,1) e ausência de alimento respondem 422, e o formulário nomeia o campo com erro. O envio soma a refeição no servidor e a tela mostra os totais que o servidor devolveu.
Para que serve: registrar a foto na pose certa, para que a comparação mostre evolução e não troca de ângulo.
Relacionado com: RF-SAUD-008, RF-SAUD-009; tarefas F5-08 e F5-09.
Onde fica: tela de evolução, galeria de fotos.
Especificação: ficha completa no Apêndice de catálogo de formulários do DRS, seção Foto de progresso, com arquivo até 10 megabytes no repositório privado, data não futura, categoria obrigatória (frente, lado direito, lado esquerdo, costas, lista editável pela administração) e observação opcional. Ação no envio: guarda a imagem no repositório privado e acrescenta à galeria daquela categoria. Pré-condição: consentimento da categoria foto de progresso. Regra da comparação: só entre fotos da mesma categoria; categoria com uma única foto exibe comparação indisponível, sem erro.
Para que serve: cada usuário editar os próprios dados de perfil, com campos que variam por papel.
Relacionado com: RF-CORE-004, RF-CORE-009, ADR-004; tarefa F1-06; ART-SCR-01, ART-AUD-01.
Onde fica: tela de perfil, caminho /perfil.
Especificação: ficha completa no Apêndice de catálogo de formulários do DRS, seção Perfil do usuário, com os campos por papel, o e-mail em leitura, a foto ainda não disponível (Fase 5) e a regra de que trocar o registro profissional zera o registro verificado.
Estado: entregue em F1-06.
Para que serve: escrever e publicar o conteúdo de ajuda de um par módulo e papel.
Relacionado com: RF-AJUD-002, RF-AJUD-003; tarefas F9-02 e F9-03.
Onde fica: administração do guia, caminho /admin/guia.
Especificação: campos: módulo (seleção, obrigatório, os treze códigos do bloco C.1 do DRS); papel (seleção, obrigatório, os seis do bloco B.1); título (texto, obrigatório, 3 a 120 caracteres); os sete blocos do guia (texto longo com formatação, todos obrigatórios para publicar, conforme o Apêndice do catálogo do guia da plataforma no DRS); origem (escrita ou gerada e revisada, preenchida pelo sistema). Ações: salvar rascunho, gerar conteúdo assistido, publicar, despublicar e restaurar versão. Regra de publicação: publicar exige os sete blocos preenchidos e cria versão numerada com data e autor; salvar rascunho não altera o que o leitor enxerga. Mensagens: bloco vazio impede a publicação nomeando qual falta; publicação bem-sucedida informa o número da versão criada. Pré-condição: papel Administrador. Idioma: português do Brasil.
Para que serve: prescrever um exercício dentro da ficha com o que o aluno precisa para executá-lo, na ordem em que ele vai executar.
Relacionado com: RF-TREI-001, RF-TREI-002, RF-TREI-003, RF-EXER-001, RF-EXER-004, RN-009; tarefas F3-01, F3-02, F3-03 e F3-09; ART-ENT-04 (tabela ficha_item), ART-SCR-01 (a tela /fichas/nova), ART-FORM-02 (o exercício do catálogo, de onde o item vem).
Onde fica: tela de criação e de edição da ficha, caminho /fichas/nova, e leitura do item no detalhe da ficha e na execução da sessão.
Especificação: ficha completa no Apêndice de catálogo de formulários do DRS, seção Item da ficha de treino, com os sete campos, os tipos, a obrigatoriedade e a validação de cada um: exercício vindo do catálogo global por seleção, nunca texto livre (RF-EXER-001); séries de 1 a 20; repetições em texto livre, que aceita faixa, tempo ou por lado, e por isso sem formato imposto, porque impor formato aqui recusaria prescrição legítima; descanso de 0 a 600 segundos; carga sugerida opcional, em quilogramas com uma casa decimal; observação opcional de até 280 caracteres; e ordem única por ficha. A observação do item aparece junto do exercício durante a execução da sessão, para quem executa ler sem abrir outra tela, e o item sem observação não reserva espaço para ela.
Estado: entregue em {F3-01}, https://fit.modulareasy.com, merge 17bd22e. Aritmética dos cartões de formulário nesta data: 12 cartões existentes ({ART-FORM-01} a {ART-FORM-12}) mais este igual a 13 cartões, cobrindo 14 formulários, porque {ART-FORM-08} cobre dois (prescrição e sessão de reabilitação). Fechamento [2026-09-14]: os sete campos, os tipos, a obrigatoriedade e a validação estão na tela /fichas/nova exatamente como a Especificação descreve; a observação do item aparece no detalhe da ficha (/treinos/:id) e o item sem observação não reserva espaço para ela, provado no arnês e na tela real. A metade que acontece na execução ({F3-05}) fica com {TA-24}, não com este formulário, que fecha campo a campo aqui. Nota (gate {F3-01}, Drift 3, 2026-09-14): a ficha deste formulário já existia no Apêndice do DRS desde a publicação inicial; o que faltava era o cartão onde marcá-la entregue, e era por isso que o artefato central de {F3-01} não tinha onde ser conferido campo a campo. A tabela de tipos de artefato declarava 11 e foi medida e corrigida nesta mesma republicação: contava errado antes mesmo deste cartão nascer, e índice que conta errado é a primeira coisa que faz um placar mentir.
Nota (gate {F3-02}, 2026-09-14): o formulário é o MESMO, campo a campo: os sete campos do item, os tipos, a obrigatoriedade e a validação não mudam quando quem cria é o próprio aluno. O que muda é o entorno da tela, porque o titular passa a ser implícito para o aluno e o seletor não aparece para ele, e isso não é campo deste formulário. Placar inalterado, 13 de 13 campos.
Fechamento [2026-09-14]: confirmado inalterado. Em produção (3d25e27), os sete campos do item continuam idênticos para os dois papéis. Placar continua 13 de 13 campos.
Nota (gate {F3-03}, Drift 8, 2026-09-14): o formulário é o MESMO, campo a campo, na criação e na edição: os sete campos do item, os tipos, a obrigatoriedade e a validação não mudam, e o componente que desenha o item continua sendo um só, consumido também pela execução. O campo "Onde fica" deste cartão já dizia "tela de criação e de edição da ficha, caminho /fichas/nova", e é {F3-03} que torna a segunda metade dessa frase verdadeira, pelo caminho /fichas/:id/editar, que é estado da mesma tela e não uma tela nova. Nenhum segundo formulário com os mesmos sete campos nasce, pela mesma razão já escrita para a criação não se dividir por papel. Placar inalterado, 13 de 13 campos.
Fechamento [2026-09-14]: a edição está em produção (76bc9cd) pelo caminho /fichas/:id/editar, com os sete campos, os tipos, a obrigatoriedade e a validação idênticos aos da criação, provado no arnês e na tela real. Placar continua 13 de 13 campos.
Para que serve: definir a meta diária de calorias e macronutrientes do aluno, com vigência datada, contra a qual o dia é comparado.
Relacionado com: RF-DIET-002; tarefa F4-02; ART-FORM-09, ART-SCR-01 (a tela /nutricao), ART-ACS (capacidade "Definir meta nutricional", da Matriz Ator por Capacidade).
Onde fica: tela de nutrição, caminho /nutricao, no estado de metas: bloco "Metas do dia" com a ação Editar metas, que abre este formulário com confirmação. Não é rota nova, e sim estado de /nutricao, conforme a Nota de ART-SCR-01 ({F4-02}, Drift 4).
Especificação: ficha completa no Apêndice de catálogo de formulários do DRS, seção Meta nutricional. Campos: calorias (número, obrigatório, maior que zero); proteína, carboidrato e gordura em gramas (números, obrigatórios, maior ou igual a zero); todos com uma casa decimal. Ação no envio: cria uma vigência nova a partir do dia corrente de quem salva, sem alterar nem apagar as anteriores, o que preserva o histórico de metas e faz a alteração valer no cálculo seguinte, sem recalcular o passado. Quem pode: o aluno titular e o Nutricionista com vínculo ativo com o aluno; os demais papéis profissionais e o Administrador não definem meta.
Nota (ficha criada em 2026-09-30, a pedido da Inspeção): o formulário foi entregue em produção por {F4-02} (merge b569460) e existia no Apêndice do DRS, mas não tinha cartão onde ser conferido campo a campo. Aritmética dos cartões de formulário nesta data: 13 cartões existentes ({ART-FORM-01} a {ART-FORM-13}) mais este igual a 14 cartões, cobrindo 15 formulários, porque {ART-FORM-08} cobre dois (prescrição e sessão de reabilitação). A marca de entregue segue o fluxo do loop e não é posta aqui.
Fechamento [2026-09-30] de {F4-02}, conferido na atualização de {AUD-09}: o formulário está alcançável em produção: a rota /nutricao/metas responde 200 no build servido, e o qa de {F4-02} provou o formulário em produção (gate de qa modularfit-F4-02). Cartão marcado [x].
Fechamento [2026-09-30] de {F4-04}: a meta deste formulário passa a ser comparada com o consumo do dia em /nutricao, no bloco "Metas do dia". O formulário não muda; GET e POST /api/metas devolvem agora também o campo painel (os quatro cartões e o total do dia), e os consumidores (DefinirMetas e o formulário de plano alimentar) o ignoram, provados na regressão do qa. Meta de macronutriente igual a zero é válida no formulário e o painel a trata como "Sem meta definida", nunca como zero.
Para que serve: prescrever ao aluno um plano de alimentação em refeições estruturadas, cada uma com horário e lista de alimentos com quantidade e calorias, que é a base do que o aluno deve comer e da soma contra as metas vigentes.
Relacionado com: RF-DIET-003, RF-CORE-007, RF-CORE-008, RF-CORE-009, RN-009; tarefa F4-03; ART-FORM-14 (a meta nutricional, contra a qual a soma do plano é lida), ART-ENT-05 (tabelas plano_alimentar e plano_refeicao), ART-SCR-01 (a tela /nutricao/planos), ART-ACS-05 (capacidade "Criar plano alimentar", da Matriz Ator por Capacidade).
Onde fica: tela de planos alimentares, caminho /nutricao/planos, nos estados /nutricao/planos/novo e /nutricao/planos/:id/editar (formulário único de criação e de edição). Não é rota nova, e sim estado de /nutricao/planos, conforme a Nota de ART-SCR-01 (gate {F4-03}, Drift 4).
Especificação: ficha completa no Apêndice de catálogo de formulários do DRS, seção Plano alimentar. Campos do plano: título (texto, obrigatório) e descrição (texto longo, opcional). Campos de cada refeição, pelo menos uma: nome (texto, obrigatório), horário (HH:MM, obrigatório) e notas (texto longo, opcional). Campos de cada alimento, pelo menos um por refeição: nome (texto, obrigatório), quantidade (TEXTO, obrigatório, porque a prática usa "2 un", "200 ml", "1 col." e "à vontade") e calorias (número, obrigatório, maior ou igual a zero, uma casa decimal). Limites de texto pelos dois parâmetros de nutrição já existentes (nome e observações), editáveis pela administração. Ação no envio: cria o plano ativo, sujeito ao limite de planos alimentares ativos do titular, e o banco soma as calorias por refeição e por plano. Quem pode: o Nutricionista com vínculo ativo com o aluno, ou o próprio aluno quando não tem Nutricionista com vínculo ativo; os demais papéis profissionais e o Administrador não criam plano alimentar.
Nota (ficha criada em 2026-09-30, gate {F4-03}, Drift 1, a pedido da Inspeção): o formulário não existia no Apêndice do DRS, e sem ele o artefato central de {F4-03} não tinha onde ser conferido campo a campo. Decisão ratificada, Cenário 1: calorias de cada alimento obrigatórias, porque só assim o plano salvo carrega a soma que o mockup mostra e que RF-IAGE-002 cobra. Aritmética dos cartões de formulário nesta data: 14 cartões existentes ({ART-FORM-01} a {ART-FORM-14}) mais este igual a 15 cartões, cobrindo 16 formulários, porque {ART-FORM-08} cobre dois (prescrição e sessão de reabilitação). A marca de entregue segue o fluxo do loop e não é posta aqui.
Fechamento [2026-09-30] de {F4-03}: o formulário está em produção (https://fit.modulareasy.com, migração 0052) em /nutricao/planos/novo e /nutricao/planos/:id/editar, com os campos da ficha acima: plano com título e descrição, pelo menos uma refeição com nome, horário e notas, e pelo menos um alimento por refeição com nome, quantidade em texto e calorias (a vírgula é aceita). A soma gravada é a do banco; a prévia ao lado das metas vigentes é calculada na interface e não é gravada. Provado pelo qa: o Nutricionista de vínculo ativo e o aluno sem Nutricionista ativo criam; o Administrador recebe 403 nomeado; o segundo plano ativo do plano Gratuito é recusado com a mensagem do limite. O cartão passa a [x].
Telas e navegação
Para que serve: dar ao aluno o caminho completo de treinar, comer, medir e acompanhar.
Relacionado com: RF-PAIN-001, RF-TREI-010, RF-ENGA-006, RF-CORE-004, RF-CORE-009, módulos trei, diet, saud, enga, plan, cobr; tarefas F1-06, F1-16, F3-05, F3-10, F4-01, F4-04, F5-07, F7-06, F7-15.
Onde fica: aplicação, caminhos /painel, /treinos, /treinos/sessao, /treinos/historico, /treinos/preferencias, /fichas/nova, /nutricao, /nutricao/planos, /evolucao, /saude, /exercicios, /integracoes, /plano, /cobranca, /perfil.
Especificação: linhas correspondentes do Apêndice de catálogo de telas do DRS, com rota, papéis, elementos, estados e responsividade. Regras próprias deste grupo: desenho primeiro para o celular, com todos os blocos empilhados em 375 pixels de largura sem rolagem horizontal; caminho de volta pela própria interface em toda tela; e, no painel, o bloco de treino em primeiro lugar e no maior destaque, com o atalho de retomar acima da ação de iniciar quando houver sessão em andamento, porque o núcleo do produto é o treino de musculação. A tela /perfil é contada aqui mas serve aos três papéis (Aluno, Profissional, Administrador), com os campos e blocos do formulário Perfil do usuário (Apêndice de catálogo de formulários) variando por papel.
Regra própria de /plano: a tela é de leitura, sem escrita, sem upgrade e sem cobrança; o consumo vem da função única mfit.consumo_do_aluno; dimensão sem tabela é exibida como não medida, nunca como zero; a dimensão ilimitada não tem barra nem alerta; e o consumo nunca é limitado ao valor máximo.
Estado: 8 de 15 entregues. /perfil em {F1-06}, /plano em {F1-16}, /exercicios em {F2-01}, /treinos e /fichas/nova em {F3-01}, /treinos/sessao em {F3-05}, /treinos/historico em {F3-07}, /treinos/preferencias em {F3-08}; /painel não conta, painel marcador de {F1-03} cujo próprio cabeçalho declara que o painel real é da Fase 7, mesmo critério que {ART-SCR-03} já usa para não contar /admin; as seis restantes (/nutricao, /nutricao/planos, /evolucao, /saude, /integracoes, /cobranca) continuam nos cards donos. 8 + 1 marcador + 6 pendentes = 15. Duas notas: (a) /exercicios/:id (página 21b do mockup) é detalhe da mesma tela, não uma décima quarta; (b) a tela serve os três papéis (o Apêndice de telas diz todos), e por isso não conta de novo em {ART-SCR-02}. Nota (R-10, {F2-04}): medido em 14/09/2026, /exercicios ainda não tinha ponto de entrada por interface em nenhum painel, só se alcançava digitando a URL; o painel do aluno, o do profissional e o da administração ganham um link Exercícios cada, no mesmo padrão dos botões já existentes, e é {F2-04} quem entrega esses três pontos de entrada, não uma tela nova. Fechamento [2026-09-14]: os três pontos de entrada estão em produção (merge 98db15a, https://fit.modulareasy.com), com o link Exercícios visível nos painéis do aluno, do profissional e do administrador. Placar de telas inalterado, 3 de 13, porque a tela /exercicios já contava desde {F2-01}; o que fechou agora foi o caminho de chegada até ela. Nota (R-9, {F2-02}): {F2-02} não entrega tela nova, apenas enriquece /exercicios e /exercicios/:id com mídia; o placar continua 3 de 13. Nota (gate {F2-06}, 2026-09-14): {F2-06} acrescenta o bloco Vínculos dentro de /perfil (convites recebidos e vínculos ativos do aluno), sem rota nova; o placar continua 3 de 13. Nota (gate {F2-07}, 2026-09-14): {F2-07} acrescenta as ações Encerrar (em /perfil e em /alunos) e Cancelar (em /alunos), sem rota nova; o placar continua 3 de 13. Nota (gate {F3-01}, Drift 2, 2026-09-14): o universo deste cartão passa de 13 para 14 telas. A tela de criação de ficha, /fichas/nova, ganhou linha no Apêndice de catálogo de telas do DRS nesta mesma republicação e é contada UMA vez, aqui, embora sirva ao Aluno e ao Profissional: é o mesmo tratamento de /perfil, contado uma vez neste cartão embora sirva aos três papéis, e por isso ela NÃO conta de novo em {ART-SCR-02}. O detalhe /treinos/:id é detalhe da tela /treinos, não uma décima quinta, no mesmo precedente de /exercicios/:id já escrito acima. Nova aritmética: 3 entregues mais 1 marcador (/painel) mais 10 pendentes igual a 14. Nenhuma entrega muda aqui, só o universo; quando {F3-01} entregar, o placar passa a ser 5 de 14 (as 3 de hoje mais /treinos e /fichas/nova), nunca 4 de 13. Fechamento [2026-09-14]: /treinos (lista do aluno, entrega mínima) e /fichas/nova (criação, servindo Aluno e Profissional) estão em produção (merge 17bd22e, https://fit.modulareasy.com). Placar sobe de 3 de 14 para 5 de 14. /treinos/:id é detalhe da tela /treinos, não conta como décima quinta, mesmo tratamento já dado a /exercicios/:id. Ressalva nomeada: a ação de executar a sessão, na lista e no detalhe, é {F3-05}, ainda não entregue; a ausência é ausência, sem botão desabilitado.
Nota (gate {F3-02}, 2026-09-14): {F3-02} não entrega tela nova. Ele abre ao Aluno a tela /fichas/nova e ao Profissional a tela /treinos, as duas já contadas aqui e as duas já declaradas no Apêndice de catálogo de telas do DRS com os papéis Aluno, Profissional. Placar de telas inalterado, 5 de 14. O que nasce são caminhos de chegada, o link Criar ficha no painel do aluno e na lista de treinos, e não rotas: mesmo tratamento já dado em {F2-04}, quando os três pontos de entrada de /exercicios fecharam sem mover o placar.
Fechamento [2026-09-14]: confirmado inalterado. Em produção (3d25e27): /fichas/nova e /treinos continuam sendo as mesmas rotas, agora com o ramo do aluno; os três caminhos de chegada (painel, topo e vazio de /treinos) nasceram como caminhos de interface, não como tela nova. Placar continua 5 de 14.
Nota (gate {F3-03}, Drift 8, 2026-09-14): o universo deste cartão continua em 14 telas e o placar continua 5 de 14. A edição da ficha é ESTADO da tela /fichas/nova, já contada desde {F3-01}, alcançada pelo caminho /fichas/:id/editar, no mesmo precedente de /exercicios/:id e de /treinos/:id: ela não é uma décima quinta tela, e o Apêndice de catálogo de telas do DRS recebeu a Nota que declara isso nesta mesma republicação. As ações de desativar e de reativar a ficha aparecem na lista e no detalhe já contados, sem rota nova. Placar que não muda também se declara.
Fechamento [2026-09-14]: confirmado inalterado. Em produção (76bc9cd): /fichas/:id/editar é estado de /fichas/nova, sem rota nova; desativar e reativar aparecem na lista e no detalhe já contados. Placar continua 5 de 14.
Nota (gate {F3-04}, 2026-09-14): nenhuma rota nova nasce. Pedir ficha nova e acompanhar os próprios pedidos são conteúdo de /treinos, e pedir ajuste é ação de /treinos/:id, que é detalhe de /treinos e não uma décima quinta tela, no precedente já escrito acima para /exercicios/:id. /fichas/nova ganha apenas um estado, o de atender uma solicitação, alcançado por consulta na própria rota, no mesmo precedente do estado de edição. Placar inalterado, 5 de 14.
Nota (gate {F4-01}, Drift 3, 2026-09-29): {F4-01} entrega /nutricao em versão MÍNIMA (navegador de data, lista das refeições do dia com os quatro totais de cada uma, a ação Registrar refeição, a ação Desativar e o vazio do dia), no mesmo tratamento que {F3-01} deu a /treinos; o formulário de refeição, /nutricao/refeicoes/nova, é ESTADO de /nutricao e não uma décima sexta tela (mesmo critério de /fichas/:id/editar). {F4-04} completa a tela com os quatro cartões contra a meta e o total do dia. A tarefa F4-01 entra no Relacionado deste cartão; o placar 8 de 15 só muda no fechamento de {F4-01}, para 9 de 15, medido no dia e nunca projetado aqui.
Nota (gate {F3-05}, Drift 10, 2026-09-14): este é o primeiro card da Fase 3 que acrescenta rota ao catálogo, e o placar só se move no fechamento, medido no dia: 5 de 14 passa a 6 de 14 com /treinos/sessao. Ela é linha própria do Apêndice de catálogo de telas do DRS, com papéis, elementos e estados declarados, e este cartão já a relaciona nominalmente ao card {F3-05}; por isso ela não recebe o tratamento de /treinos/:id e de /fichas/:id/editar, que os gates de {F3-01} e de {F3-03} declararam detalhe e estado de outra tela. Decisão de desenho que vem junto: /treinos/sessao é declarada antes de /treinos/:id no arranjo de rotas, porque o padrão de identificador casa com o literal sessao em qualquer roteador que resolva por ordem de declaração, e a prova é pela URL real, abrindo a execução e não o detalhe de uma ficha chamada "sessao".
Fechamento [2026-09-15]: /treinos/sessao em produção (merge 80c103e, https://fit.modulareasy.com), declarada antes de /treinos/:id no arranjo de rotas, provado pela URL real abrindo a execução. Placar sobe de 5 de 14 para 6 de 14.
Nota (gate {F3-07}, 2026-09-15): /treinos/historico é a segunda rota que a Fase 3 acrescenta ao placar, e ele só se move no fechamento, medido no dia: 6 de 14 passa a 7 de 14. Ela é linha própria do Apêndice de catálogo de telas do DRS, com rota, papéis, elementos e estados declarados, e por isso não recebe o tratamento de /treinos/:id e de /fichas/:id/editar, que os gates de {F3-01} e de {F3-03} declararam detalhe e estado de outra tela. Ela serve os dois papéis (o Apêndice declara Aluno, Profissional) e por isso não conta de novo em {ART-SCR-02}, que continua 1 de 4: o profissional chega à mesma rota com o aluno na consulta, no precedente literal de /perfil, de /treinos e de /fichas/nova. A rota é declarada antes de /treinos/:id no arranjo, pelo mesmo motivo já escrito para /treinos/sessao: o roteador resolve por ordem de declaração. Os dois pontos de entrada nascem juntos, o botão Histórico no cabeçalho de /treinos, desenhado desde o início e nunca construído, e o link Ver histórico no resumo da execução, que desfaz o beco sem saída hoje declarado por comentário datado no código. A janela de retenção do histórico visível do plano é aplicada nesta leitura, e a dimensão, que não tinha card dono em nenhuma das oito fases, passa a ter {F3-07} como dono declarado; os dois cenários e a decisão estão em {Q3} do Questionário.
Fechamento [2026-09-15]: /treinos/historico em produção (merge c331286, https://fit.modulareasy.com). Placar sobe de 6 de 15 para 7 de 15.
Nota (gate {F3-08}, 2026-09-15): o universo deste cartão passa de 14 para 15 telas. A tela de preferências de treino, /treinos/preferencias, ganhou linha própria no Apêndice de catálogo de telas do DRS nesta mesma republicação: ela não existia em catálogo nenhum, embora o H1 de RF-TREI-008 comece por "Dado um aluno na tela de preferências" e {ART-FORM-03} já declarasse que o formulário fica nela. É linha própria, e não detalhe nem estado de /treinos, porque os sete campos são outros sete, com formulário próprio, ficha própria e navegação própria, ao contrário de /treinos/:id, de /exercicios/:id e de /fichas/:id/editar. Ela serve os dois papéis (o Apêndice declara Aluno e Profissional) e por isso é contada uma vez, aqui, e não conta de novo em {ART-SCR-02}, que continua 1 de 4: o profissional chega à mesma rota com o aluno na consulta, em somente leitura, no precedente literal de /perfil, de /treinos, de /fichas/nova e de /treinos/historico. Nova aritmética, conferida somando: 6 entregues mais 1 marcador (/painel) mais 8 pendentes igual a 15. Nenhuma entrega muda nesta data, só o universo. Duas consequências de placar, e as duas se escrevem para ninguém supor: o fechamento de {F3-07} vale 7 de 15, e a Nota dele acima diz 7 de 14 porque foi escrita antes desta mudança de universo, divergência de data e não de contagem; e o fechamento de {F3-08} vale 8 de 15, medido no dia, nunca projetado. A rota é declarada antes de /treinos/:id no arranjo, pelo mesmo motivo já escrito para /treinos/sessao e para /treinos/historico: o roteador resolve por ordem de declaração.
Fechamento [2026-09-15]: /treinos/preferencias em produção (merge ce1787b, https://fit.modulareasy.com), tela única servindo os dois papéis (edição do aluno, leitura somente do profissional vinculado). Placar sobe de 7 de 15 para 8 de 15.
Fechamento [2026-09-30] de {F4-01}: /nutricao em produção (merge 5e36145, https://fit.modulareasy.com), em versão mínima, no tratamento que {F3-01} deu a /treinos: navegador de data, refeições do dia com os quatro totais de cada uma, Registrar refeição, Desativar e o vazio do dia. /nutricao/refeicoes/nova é estado da mesma tela, sem rota contada à parte. Placar sobe de 8 de 15 para 9 de 15; {F4-04} completa a tela com os quatro cartões contra a meta e o total do dia. Para o Administrador nenhuma das duas rotas existe: ambas redirecionam a /admin, e o painel dele não mostra Nutrição. Nota (gate {F4-02}, Drift 4, 2026-09-29): {F4-02} abre /nutricao?aluno=<id> ao Profissional (leitura do dia pela API que {F4-01} já serve, sem Registrar refeição e sem Desativar) e entrega o bloco "Metas do dia" nas duas pontas, com Editar metas quando o servidor disser que pode, e o histórico de metas. /nutricao/metas é ESTADO de /nutricao, não uma décima sexta tela (mesmo critério de /nutricao/refeicoes/nova e de /fichas/:id/editar), e a tela continua contada uma vez só aqui, e não em {ART-SCR-02}, que continua 1 de 4, no precedente de /perfil, /treinos e /fichas/nova. A COMPARAÇÃO (consumido, restante, percentual) continua de {F4-04}, que lê a meta do dia do MESMO ponto único, mfit.meta_vigente; nenhum segundo leitor. O placar 9 de 15 não se move nesta Nota.
Fechamento [2026-09-30] de {F4-02}: em produção (merge b569460, https://fit.modulareasy.com), /nutricao ganha o bloco "Metas do dia" (os quatro valores da meta, o autor e o histórico de metas) e o formulário "Meta nutricional" (Editar metas, com confirmação, ficha em {ART-FORM-14}) para o aluno titular e para o Nutricionista de vínculo ativo. /nutricao?aluno=<id> abre ao Profissional de vínculo ativo, em leitura, sem Registrar refeição e sem Desativar; quando o servidor nega a leitura, a tela mostra o cartão "Sem permissão para ver estes dados" com "Voltar à carteira", nunca erro cru nem lista vazia. O Administrador é redirecionado a /admin (a API segue com 403 nomeado). /alunos ganha o link Nutrição no vínculo de Nutricionista. Nenhuma rota nova entra na contagem: o placar 9 de 15 segue inalterado, e a comparação do consumo com a meta continua de {F4-04}. Nota (gate {F4-03}, Drift 4, 2026-09-30): /nutricao/planos já é contada neste cartão e já é linha do Apêndice de catálogo de telas do DRS; {F4-03} a entrega com ESTADOS /nutricao/planos/:id, /nutricao/planos/novo e /nutricao/planos/:id/editar (formulário único), no precedente de /fichas/nova e de /fichas/:id/editar, e nenhum dos três é décima sexta tela. A rota /planos/novo do mockup não entra no catálogo, porque colidiria de leitura com /plano; o Profissional chega ao formulário vindo de /alunos, com o aluno na consulta. O placar 9 de 15 só muda no fechamento de {F4-03}, para 10 de 15, medido no dia e nunca projetado aqui. Fechamento [2026-09-30] de {F4-03}: /nutricao/planos em produção (merge 2f5c560, https://fit.modulareasy.com), para o aluno e para o Profissional vinculado (com ?aluno= vindo de /alunos), com os estados /nutricao/planos/:id, /nutricao/planos/novo e /nutricao/planos/:id/editar e sem rota nova contada à parte. Placar sobe de 9 de 15 para 10 de 15. Para o Administrador a API segue com 403 nomeado nas seis rotas. As cinco restantes (/nutricao completa por {F4-04}, /evolucao, /saude, /integracoes, /cobranca) continuam nos cards donos; o cartão permanece [ ]. Fechamento [2026-09-30] de {F4-04}: /nutricao completa em produção (merge a6624e9, https://fit.modulareasy.com): o bloco "Metas do dia" ganha no topo os quatro cartões contra a meta e o total do dia, no desenho da tela 11 do mockup, e o Profissional vinculado com a categoria de nutrição visível os vê em /nutricao?aluno=, sem Registrar nem Desativar. Sem rota nova: a tela já contava desde {F4-01}, por isso o placar fica inalterado, 10 de 15 (placar que não muda também se declara). As cinco restantes (/evolucao, /saude, /integracoes, /cobranca e o painel marcador /painel) continuam nos cards donos; o cartão permanece [ ]. Fechamento [2026-10-01] de {F4-05}: /nutricao/acompanhamento?aluno= em produção (merge f609a9c, https://fit.modulareasy.com) como ESTADO de /nutricao, no precedente de /nutricao/metas: sem linha nova no catálogo de telas e sem décima sexta tela. Placar inalterado, o declarado no fechamento de {F4-04}. A tarefa F4-05 entra no Relacionado deste cartão. O Aluno não ganha tela de acompanhamento: a rota o redireciona para /painel. Os links do topo das dezesseis telas passam a um componente único com área de toque de 2,75rem em 375 de largura, destino e texto iguais. Fechamento [2026-10-01] de {F5-01}: /saude em produção (merge 9cb16f3, repositório wladimirdjr/modularfit, migração 0056, https://fit.modulareasy.com (/api/estado na versão 9cb16f3)), com os estados /saude/anamneses/nova e /saude/anamneses/:id (sem décima sexta tela), para o aluno e para o Profissional vinculado (com ?aluno=); o Administrador volta a /admin. A casca traz o aviso de natureza não clínica no topo e serve as quatro telas clínicas por abas, de modo que as abas de exame, prescrição e reabilitação nascem dentro dela. Placar sobe de 10 de 15 para 11 de 15 (aritmética: 11 entregues mais 1 marcador /painel mais 3 pendentes, /evolucao, /integracoes e /cobranca, igual 15). Entradas por interface: link "Saúde" no painel do aluno e na linha ativa de /alunos. O cartão continua [ ]. Fechamento [2026-10-06] de {F5-02}: /saude/avaliacoes, /saude/avaliacoes/nova e /saude/avaliacoes/:id em produção (merge 3ab8395, repositório wladimirdjr/modularfit, migrações 0057 e 0058 aplicadas em produção em 06/10, https://fit.modulareasy.com (/api/estado na versão 87ae8e0, a mesma árvore do merge; o deploy da main em 3ab8395 segue em curso)) como ESTADOS da casca de /saude, no precedente das telas da anamnese: aba Avaliações dentro da casca, com o aviso não clínico no topo. Sem linha nova no catálogo de telas e sem décima sexta tela: o placar fica inalterado, 11 de 15 (placar que não muda também se declara), e as três pendentes (/evolucao, /integracoes e /cobranca), mais o painel marcador /painel, seguem nos cards donos (11 entregues mais 1 marcador mais 3 pendentes igual 15). O cartão continua [ ].
Para que serve: dar ao profissional a carteira e o detalhe do aluno com as abas da especialidade.
Relacionado com: RF-PAIN-002 a 006; tarefas F7-07 a F7-11.
Onde fica: aplicação, caminhos /pro/painel, /alunos, /alunos/:id, /conversas.
Especificação: linhas correspondentes do Apêndice de catálogo de telas do DRS. Regra própria: o painel de entrada e a ordem das abas do detalhe variam pela especialidade (treino, clínico, reabilitação, nutrição), e nenhuma aba oferece ação que a matriz de capacidade nega ao papel.
Estado: 1 de 4 entregues. /alunos mínima em {F2-05} (ação Vincular aluno por identificador, com leitura reduzida do aluno antes do envio, mais a lista de convites enviados pendentes, sem KPIs, filtros, abas nem tabela de ativos); /pro/painel, /alunos/:id e /conversas continuam nos cards donos (F7-07 a F7-11). Nota (gate {F3-01}, Drift 2, 2026-09-14): o universo deste cartão continua em 4 telas. A tela de criação de ficha, /fichas/nova, serve ao Profissional e ao Aluno e é contada uma vez só, em {ART-SCR-01}, pelo precedente de /perfil; contá-la aqui também faria os cinco cartões somarem mais rotas do que o catálogo de telas tem. Placar inalterado, 1 de 4.
Nota (gate {F3-02}, 2026-09-14): o profissional passa a ler as fichas do aluno pela tela /treinos, com o aluno na consulta, e essa tela é contada uma vez só, em {ART-SCR-01}, pelo mesmo precedente de /perfil e de /fichas/nova. Nenhuma rota nova nasce aqui e a tela de detalhe do aluno continua na Fase 7. Placar inalterado, 1 de 4.
Fechamento [2026-09-14]: confirmado inalterado. Em produção (3d25e27): o link Treinos nasceu na linha do aluno em /alunos, levando a /treinos?aluno=<id>, sem rota nova. Placar continua 1 de 4.
Nota (gate {F3-03}, 2026-09-14): nenhuma rota nova nasce aqui e nenhuma tela de administração de fichas nasce: o Administrador, a quem RN-009 dá a edição, chega à ficha pela mesma /treinos com o aluno na consulta que {F3-02} abriu. A edição é estado de /fichas/nova, contada uma vez só em {ART-SCR-01}, pelo precedente de /perfil. Placar inalterado, 1 de 4.
Fechamento [2026-09-14]: confirmado inalterado. Em produção (76bc9cd), nenhuma rota nova nasce para o Administrador. Placar continua 1 de 4.
Nota (gate {F3-04}, 2026-09-14): /pro/painel ganha um bloco mínimo de solicitações abertas, com título, aluno, trecho do motivo, tipo de pedido, data e as duas ações de resolver; isso é conteúdo da tela, não entrega da tela, que tem cinco indicadores, carteira, alerta de inativo e bloco por especialidade e continua em {F7-07}, no precedente literal da /alunos mínima de {F2-05}. Nenhuma rota nova nasce. Placar inalterado, 1 de 4.
Nota (gate {F3-05}, 2026-09-14): nenhuma tela do profissional nasce, muda ou é alcançada aqui, e o placar continua 1 de 4. A execução da sessão é do aluno titular e de mais ninguém: nem o profissional vinculado nem o Administrador executam, retomam ou registram série, e a Matriz Ator por Capacidade nega a capacidade aos cinco papéis não titulares. O que o profissional passa a ver do treino executado é o histórico, cujo card dono é {F3-07}. Placar que não muda também se declara.
Fechamento [2026-09-15]: confirmado inalterado. Em produção (80c103e), nenhuma tela do profissional nasceu, mudou ou foi alcançada. Placar continua 1 de 4.
Nota (gate {F3-08}, 2026-09-15): nenhuma tela do profissional nasce aqui. /treinos/preferencias serve os dois papéis mas é contada uma vez só, em {ART-SCR-01}, pelo precedente já firmado de /perfil, /treinos, /fichas/nova e /treinos/historico; o profissional vinculado chega à mesma rota com o aluno na consulta, em somente leitura. Placar inalterado, 1 de 4. Fechamento [2026-09-15]: confirmado inalterado. Em produção (ce1787b), nenhuma tela do profissional nasceu. Placar continua 1 de 4.
Para que serve: operar catálogo, contas, vínculos, planos, relatórios e auditoria.
Relacionado com: RF-EXER-001, RF-VINC-005, RF-PLAN-001, RF-PAIN-007 a 009, RF-CORE-007; tarefas F1-13, F1-14, F2-01, F2-09, F7-12 a F7-14.
Onde fica: aplicação, caminhos /admin, /admin/usuarios, /admin/exercicios, /admin/vinculos, /admin/planos, /admin/relatorios, /admin/auditoria, /admin/textos, /admin/parametros, /admin/listas, /admin/emails.
Especificação: linhas correspondentes do Apêndice de catálogo de telas do DRS. Regra própria: toda ação destrutiva pede confirmação nominal do registro e gera entrada de auditoria. Regra própria de /admin/planos: o botão "Atribuir plano a aluno" e o painel de atribuição foram entregues em {F1-14}, com o seletor de aluno, o seletor de plano ativo, o status de acesso e a confirmação nominal. A nota da página 34 do mockup diz "vale na próxima sessão, fica na auditoria"; medido no sistema, plano e status não vivem no token de sessão e são lidos do banco a cada requisição, então a atribuição vale na próxima requisição do aluno, sem nova sessão; o painel exibe "Vale imediatamente, na próxima ação do aluno. Fica na auditoria.", e é este texto que vale, não o do desenho.
Fechamento [2026-09-29] de {AUD-05}: o placar sobe de 5 de 8 para 6 de 8: /admin/usuarios está no ar (https://fit.modulareasy.com/admin/usuarios), mínima, com a busca por nome e e-mail e a única ação Personificar, visível ao Super Administrador, com confirmação nominal. A ressalva nominal da nota de escopo se mantém: ela só fecha como tela de gestão de usuários em {F7-14}. Falta /admin/relatorios ({F7-12}), com /admin fora da contagem.
Fechamento [2026-09-29] de {AUD-06}: o universo do cartão passa de 8 para 9 telas e o placar sobe de 6 de 8 para 7 de 9: /admin/parametros está no ar (https://fit.modulareasy.com/admin/parametros), renderizada a partir do catálogo (28 linhas em 12 grupos mais a seção dos quatro parâmetros tabulares), com escrita do Super Administrador, leitura do Administrador sem botão de gravar, valor recusado fora da faixa com a mensagem do servidor e confirmação nominal. Aritmética: 6 entregues mais /admin/parametros igual 7; pendente /admin/relatorios ({F7-12}); mais o marcador /admin fora da contagem: 7 + 1 + 1 = 9.
Nota (onda AUD, {AUD-07}, 2026-09-29): /admin/listas entra neste cartão, escrita do Super Administrador e leitura do Administrador, na mesma coluna de /admin/planos e /admin/parametros. O universo passa de 9 para 10 telas e o placar vigente passa de 7 de 9 para 7 de 10, com /admin/listas pendente até {AUD-07} entregar. Aritmética: 7 entregues mais /admin/relatorios pendente mais /admin/listas pendente mais o marcador /admin fora da contagem: 7 + 1 + 1 + 1 = 10.
Fechamento [2026-09-29] de {AUD-07}: o placar vigente sobe de 7 de 10 para 8 de 10: /admin/listas está no ar (https://fit.modulareasy.com/admin/listas), com as seis listas em blocos, escrita do Super Administrador (acrescentar item, renomear, reordenar, desativar e reativar, com confirmação nominal ao desativar), leitura do Administrador sem nenhum controle de edição, e cada alteração na trilha de /admin/auditoria com lista, rótulo e valor antes e depois; profissional e aluno não alcançam a tela. Aritmética: 7 entregues mais /admin/listas igual 8; pendente /admin/relatorios ({F7-12}); mais o marcador /admin fora da contagem: 8 + 1 + 1 = 10. O cartão segue aberto por causa de /admin/relatorios.
Nota (Inspeção, {AUD-10}, 2026-09-30): /admin/emails entra neste cartão, escrita do Super Administrador e leitura do Administrador, na mesma coluna de /admin/planos, /admin/parametros e /admin/listas. O universo passa de 10 para 11 telas e o placar vigente passa de 8 de 10 para 8 de 11, com /admin/emails pendente até {AUD-10} entregar. Aritmética: 8 entregues mais /admin/relatorios pendente mais /admin/emails pendente mais o marcador /admin fora da contagem: 8 + 1 + 1 + 1 = 11. Especificação da tela: linha /admin/emails do Apêndice de catálogo de telas do DRS e cartão {ART-CFG-03}.
Fechamento [2026-09-30] de {AUD-10}: o placar vigente sobe de 8 de 11 para 9 de 11: /admin/emails está no ar (https://fit.modulareasy.com/admin/emails, merge 17b62d6, migrações 0048 e 0049, https://fit.modulareasy.com, /api/estado na versão 17b62d6), com a lista dos onze modelos, as variáveis de cada um, a pré-visualização, o editor com confirmação nominal, o histórico e a restauração, escrita do Super Administrador e leitura do Administrador sem controle de gravar; Profissional e Aluno não alcançam a tela. Verificada nos dois temas e nas larguras de 400 e 1280, sem rolagem lateral. Aritmética: 8 entregues mais /admin/emails igual 9; pendente /admin/relatorios ({F7-12}); mais o marcador /admin fora da contagem: 9 + 1 + 1 = 11. O cartão segue aberto por causa de /admin/relatorios.
Fechamento [2026-09-30] de {AUD-12}: placar vigente inalterado, 9 de 11: /admin/textos já contava como entregue em {F1-18} e não conta duas vezes. A tela ganha o terceiro grupo, Consentimentos, com os sete textos de consentimento (texto, finalidade, versão e rótulo), publicação com confirmação nominal, escrita do Super Administrador e do Administrador (a permissão é a que a tela já tinha; nenhuma capacidade nova, divergência de B.1 em 22), verificada nos dois temas e nas larguras de 400 e 1280, sem rolagem lateral. Aritmética: 9 entregues mais /admin/relatorios ({F7-12}) mais o marcador /admin fora da contagem: 9 + 1 + 1 = 11. O cartão segue aberto por causa de /admin/relatorios.
Estado: 5 de 8 entregues (leitura histórica, anterior aos fechamentos de {AUD-05} e {AUD-06} acima; o placar vigente é 7 de 9). /admin/auditoria em {F1-11}; /admin/planos em {F1-13} e {F1-14} (painel de atribuição incluído); /admin/textos em {F1-18}; /admin/exercicios em {F2-01}; /admin/vinculos em {F2-09}; /admin segue como painel marcador de {F1-03}; /admin/usuarios e /admin/relatorios continuam nos cards donos ({F7-14}, {F7-12}). Aritmética: /admin/auditoria ({F1-11}) + /admin/planos ({F1-13}/{F1-14}) + /admin/textos ({F1-18}) + /admin/exercicios ({F2-01}) + /admin/vinculos ({F2-09}) = 5 de 8; os dois pendentes somam com o marcador /admin fora da contagem de telas entregues, como já era. O estado previa-ia da página 32 do mockup não é deste card, é {F8-12}. Nota (R-9, {F2-02}): {F2-02} não entrega tela nova, apenas enriquece /admin/exercicios com os dois campos de mídia; o placar continua 4 de 8. Nota (gate {F2-09}, 2026-09-14, ressalva nominal): a linha /admin/vinculos do Apêndice de telas foi reconciliada nesta data para o que a máquina sustenta: lista global com profissional, aluno, especialidade, estado e data; os quatro filtros; e desativar, cancelar convite e excluir em definitivo, com confirmação nominal. Fica a ressalva, e ela é nominal: a Descrição de RF-VINC-005 ainda nomeia "ativar", e a tela NÃO serve essa ação, porque E.3 não tem evento de ativação pelo Administrador e o único caminho até ativo é o aceite do aluno (RF-VINC-002). O requisito não foi editado; "Ativar" e "Novo vínculo" (tela 33 do mockup) continuam sem card dono, com decisão de produto a confirmar com o dono. Fechamento [2026-09-14]: o placar sobe de 4 de 8 para 5 de 8 com esta ressalva mantida, nominal; os dois pendentes são /admin/usuarios ({F7-14}) e /admin/relatorios ({F7-12}), com /admin seguindo fora da contagem como painel marcador. Nota de escopo (onda AUD, {AUD-05}, 2026-09-15): a rota /admin/usuarios deixa de esperar inteira por {F7-14}. Ela nasce MÍNIMA em {AUD-05}, com a busca por nome e e-mail reusando a rota de busca de alunos que já existe, a linha do usuário encontrado e UMA única ação, Personificar, visível apenas ao Super Administrador e com confirmação nominal. Criar conta, editar cadastro, promover ou rebaixar papel, bloquear e desbloquear conta e excluir em definitivo continuam sendo {F7-14}, sem exceção. Consequência no placar, e ela fica escrita para ninguém a descobrir depois: quando {AUD-05} entregar, este cartão passa de 5 de 8 para 6 de 8, com a ressalva nominal de que a tela nasceu com uma ação só e só fecha como tela de gestão de usuários em {F7-14}. Até lá o placar continua 5 de 8, porque placar mede o que está no ar, não o que foi decidido.
Para que serve: página inicial pública, entrada, cadastro, recuperação de senha e gestão de consentimentos.
Relacionado com: RF-CORE-001, 002, 003, 005, 010, 011, RF-INTE-002; tarefas F1-03 a F1-07, F1-12, F1-17, F8-09.
Onde fica: aplicação, caminhos /, /entrar, /cadastrar, /recuperar e /privacidade.
Especificação: linhas correspondentes do Apêndice de catálogo de telas do DRS. Regras próprias: a página inicial responde sem sessão, apresenta o produto, nomeia os cinco papéis de público com o que cada um faz na plataforma, oferece as chamadas entrar e criar conta, não exibe dado de usuário nem valor de plano, e leva ao painel quem já tem sessão; a tela de privacidade lista as seis categorias com estado, data de concessão, restrição por especialidade e as ações conceder e revogar. O botão "Exportar meus dados" pertence a RF-INTE-002 ({F8-09}) e não é renderizado até existir destino: affordance sem destino é beco, e ausência se declara, não se explica em rótulo. A página inicial não nomeia plano nenhum, nem nome nem preço, porque o catálogo é editável pela administração (ADR-012) e um nome escrito na tela envelheceria calado; nenhum link de ferramenta de desenvolvimento (/api/estado, /estilo) sai de página pública; e os quatro rótulos de especialidade da página inicial espelham a fonte única do servidor (CATALOGO_ESPECIALIDADES.rotulo), com verificador próprio que reprova a divergência.
Estado: 5 de 5 entregues. Entrar em {F1-03} com os quatro estados; Cadastro em {F1-04} (duas etapas, cinco estados) e {F1-05} (etapa do profissional); /recuperar já no ar desde {F1-07}; /privacidade em {F1-12}; / pública em {F1-17}. Aritmética: /entrar ({F1-03}) + /cadastrar ({F1-04} e {F1-05}) + /recuperar ({F1-07}) + /privacidade ({F1-12}) + / (este card) = 5 de 5. Ressalva: este total fecha o universo de cinco telas que esta própria ficha declara, não "todas as telas públicas do produto". /redefinir e /confirmar estão em produção desde {F1-07} e constam no Apêndice de catálogo de telas do DRS, mas não têm ficha de tela em nenhum dos cinco cartões {ART-SCR-0x}, hoje só existem como modelo de e-mail (fichas de confirmação de cadastro e de redefinição de senha). Ampliar o universo para sete telas não é feito aqui: mexeria na aritmética dos 32 que {ART-SCR-05} carrega e colide com a divergência "30 rotas x trinta e três rotas" aberta desde R-11(a) de {F1-16}; os dois seguem no mesmo bilhete ao mds-architect.
Para que serve: ler a ajuda do sistema por módulo e por papel, e mantê-la.
Relacionado com: RF-AJUD-001 a 003; tarefas F9-01 a F9-03; ART-ENT-09, ART-FORM-10.
Onde fica: aplicação, caminhos /guia, /guia/:modulo e /admin/guia. O catálogo de telas do DRS tem, depois da reconciliação de 2026-09-29 ({AUD-06}), 40 linhas: 38 rotas mais a central de notificações, que fica no topo de toda tela e é coberta por ART-NAV-01, e a faixa de personificação, também de topo e também não rota. Os cinco cartões deste grupo somam 36 rotas, sem sobreposição entre eles: 15 em {ART-SCR-01}, 4 em {ART-SCR-02}, 9 em {ART-SCR-03}, 5 em {ART-SCR-04} e 3 em {ART-SCR-05}. As duas rotas restantes, /redefinir e /confirmar, estão no catálogo do DRS e em produção desde {F1-07} e seguem sem ficha em nenhum dos cinco cartões, pendência nominal já registrada em {ART-SCR-04}: 36 mais 2 igual a 38. Atualização (onda AUD, {AUD-07}, 2026-09-29): com /admin/listas, o catálogo de telas do DRS passa a 41 linhas: 39 rotas mais as duas de topo (39 mais 2 igual a 41). Os cinco cartões deste grupo somam 37 rotas (15 em {ART-SCR-01}, 4 em {ART-SCR-02}, 10 em {ART-SCR-03}, 5 em {ART-SCR-04} e 3 em {ART-SCR-05}), e as duas restantes, /redefinir e /confirmar, seguem sem ficha: 37 mais 2 igual a 39. Os dois números anteriores desta linha (30 rotas, e 32 telas somadas) foram medidos de novo nesta data e estavam defasados, e a explicação que os acompanhava, de que /painel apareceria no cartão do aluno e no do profissional, não corresponde aos cartões, porque {ART-SCR-02} não lista /painel. /perfil é contado uma vez, no cartão do aluno, embora sirva também ao Profissional e ao Administrador, e /fichas/nova segue a mesma regra.
Especificação: linhas correspondentes do Apêndice de catálogo de telas do DRS. Regras próprias: a lista traz apenas os módulos com guia publicado para o papel de quem lê; a página do módulo exibe os sete blocos na ordem do apêndice, mais o número da versão e a data de publicação; a administração exibe a matriz módulo por papel com o estado de cada par, o histórico de versões e as ações de edição, geração assistida, publicação e restauração; nenhum rascunho é alcançável por quem não é Administrador.
Para que serve: cada papel enxergar apenas o que pode operar.
Relacionado com: Apêndice de matriz de capacidade; tarefa F1-02.
Onde fica: navegação principal da aplicação.
Especificação: Guia da plataforma é a primeira entrada do menu dos seis papéis, acima de qualquer outra. Depois dela, Aluno: Painel, Treinos, Nutrição, Evolução, Saúde, Conversas, Integrações, Plano, Cobrança, Privacidade. Profissional: Painel, Alunos, Exercícios, Conversas, Cobrança, Perfil. Administrador: Painel, Usuários, Exercícios, Vínculos, Planos, Relatórios, Auditoria, Guia, Textos, sendo a entrada Guia a da administração do conteúdo e a entrada Textos a de {F1-18}. Todos: sino de notificações no topo. Condição de exibição: papel do usuário e, no Aluno, status de acesso, que quando inativo reduz o menu a Perfil, Plano e leitura do histórico. Ordem fixa e ícone com rótulo em toda entrada.
Papéis, permissão e auditoria
Para que serve: definir o que o aluno pode sobre os próprios dados.
Relacionado com: RF-CORE-006, RF-CORE-008; tarefas F1-08 e F1-10.
Onde fica: políticas de acesso do banco e verificação de rota.
Especificação: recorte do Apêndice de matriz de capacidade do DRS, coluna Aluno. O que o distingue: é o único que executa e retoma sessão de treino, envia foto de progresso e conecta serviço de atividade, é dono de todo o próprio dado e pode registrar em qualquer categoria clínica na ausência de profissional. Não convida vínculo, não exclui em definitivo e não vê relatório do sistema. Escopo de visibilidade: apenas os próprios registros.
Nota (gate {F4-03}, Drift 3, 2026-09-30): "pode registrar em qualquer categoria clínica na ausência de profissional" passa, para o plano alimentar, a ser respondido no banco por mfit.aluno_tem_vinculo_ativo_na_especialidade(aluno, 'nutricionista'): o aluno cria o próprio plano alimentar somente enquanto não tem Nutricionista com vínculo ativo, e volta a poder criar quando esse vínculo se encerra; o plano que criou antes continua dele e editável por ele. Segundo auxiliar de capacidade, ratificado pela Inspeção; o motivo está na Nota de {ART-ACS-07}.
Para que serve: definir o alcance do profissional de treino.
Relacionado com: RF-VINC-002, RF-TREI-001, RF-SAUD-002; tarefas F2-06, F3-01, F5-02.
Onde fica: políticas de acesso do banco.
Especificação: recorte da matriz do DRS, coluna Personal. O que o distingue das demais especialidades: cria ficha de treino e registra avaliação física; não prescreve medicamento, não define meta nutricional e não registra exame, que é do Médico e do próprio aluno (RF-SAUD-004). Escopo: apenas alunos com vínculo ativo, mais os registros que ele mesmo criou em vínculos encerrados.
Para que serve: definir o alcance do profissional de medicina.
Relacionado com: RF-SAUD-004, RF-SAUD-005; tarefas F5-04 e F5-05.
Onde fica: políticas de acesso do banco.
Especificação: recorte da matriz do DRS, coluna Médico. O que o distingue: é o único papel profissional que registra prescrição e o único que registra exame, capacidade que divide apenas com o próprio aluno. Não cria ficha de treino nem define meta nutricional. Escopo igual ao dos demais profissionais.
Nota (gate {AUD-09}, 2026-09-30): "não cria ficha de treino" deixa de ser só texto de matriz e passa a ser aplicado no banco e na rota (migração 0045, merge d760b2d, em produção): Médico e Nutricionista recebem 403 nomeado em criar, duplicar, editar, desativar, reativar, atender e recusar ficha de treino (0 de 7, 14 de 14 negações provadas, cada uma com o par positivo de Personal Trainer e Fisioterapeuta 7 de 7), com a leitura preservada. O verificador de capacidade por especialidade passa de 1 de 7 para 7 de 7, reusando o auxiliar único de capacidade de {F4-02}. A ficha antiga de um deles só é alterada pela administração (RN-009); contagem em produção antes da migração: zero fichas e zero pedidos. O cartão permanece [ ] porque as demais capacidades do papel ainda pertencem a fases abertas.
Para que serve: definir o alcance do profissional de fisioterapia.
Relacionado com: RF-SAUD-006, RF-TREI-001; tarefas F5-06 e F3-01.
Onde fica: políticas de acesso do banco.
Especificação: recorte da matriz do DRS, coluna Fisio. O que o distingue: registra sessão de reabilitação e também cria ficha de treino, por prescrever exercício terapêutico. Não prescreve medicamento nem define meta nutricional.
Para que serve: definir o alcance do profissional de nutrição.
Relacionado com: RF-DIET-002, RF-DIET-003, RF-SAUD-002; tarefas F4-02, F4-03 e F5-02.
Onde fica: políticas de acesso do banco.
Especificação: recorte da matriz do DRS, coluna Nutri. O que o distingue: é o único papel profissional que define meta nutricional e cria plano alimentar. Registra avaliação física como as demais especialidades, por a antropometria ser prática central dele. Não cria ficha de treino, não prescreve medicamento e não registra exame.
Nota (gate {AUD-09}, 2026-09-30): a parte "não cria ficha de treino" desta ficha está aplicada no banco e na rota desde a migração 0045 (merge d760b2d, em produção), nos mesmos termos da Nota de {ART-ACS-03}: 403 nomeado, leitura preservada, verificador de capacidade por especialidade de 1 de 7 para 7 de 7. O cartão permanece [ ] porque o plano alimentar ({F4-03}) ainda falta.
Nota (gate {F4-02}, Drift 6, 2026-09-29): "define meta nutricional" é a primeira capacidade da Matriz aplicada POR ESPECIALIDADE no banco, e nasce em {F4-02}, na migração 0044. Antes dela nenhuma política nem rota do produto distinguia especialidade (medido no gate de {F4-02}, M-3). O auxiliar novo, mfit.tem_vinculo_ativo_na_especialidade(p_aluno, p_especialidade), responde uma pergunta de CAPACIDADE (existe vínculo ativo do usuário atual com o aluno naquela especialidade), não de leitura: o auxiliar único de leitura, {ART-ACS-07}, continua um só. O servidor pergunta o mesmo auxiliar para dizer se a tela oferece Editar metas, sem cópia em TypeScript. O formulário de meta entra no Apêndice de formulários do DRS na mesma republicação.
Fechamento [2026-09-30] de {F4-02}: a capacidade "define meta nutricional" está em produção (migração 0044, https://fit.modulareasy.com) e é a primeira da Matriz aplicada por especialidade no banco: mfit.tem_vinculo_ativo_na_especialidade(p_aluno, p_especialidade) decide, e o servidor pergunta o mesmo auxiliar para a tela oferecer Editar metas. Provado pelo qa: Nutricionista de vínculo ativo grava (201); Personal, Médico e Fisio vinculados leem (200) e não editam (403, 0 linhas); Nutricionista sem vínculo ativo ou ex-vinculado: GET 404, POST 403. Falta o plano alimentar ({F4-03}), por isso o cartão permanece [ ]. Fora do card e declarado: Médico e Nutricionista ainda criam ficha de treino até {AUD-09}, que reusa este auxiliar.
Nota (gate {F4-03}, Drift 3, 2026-09-30): "cria plano alimentar" é a segunda capacidade da Matriz aplicada POR ESPECIALIDADE no banco e usa os DOIS auxiliares de capacidade: para o Nutricionista, mfit.tem_vinculo_ativo_na_especialidade (pergunta sobre o ATOR, {F4-02}); para o aluno sem Nutricionista, mfit.aluno_tem_vinculo_ativo_na_especialidade (pergunta sobre o TITULAR, {F4-03}). Ratificação da Inspeção: a regra de {AUD-09}, "nunca um segundo auxiliar", vale para a pergunta de capacidade do ator, que continua uma só; a pergunta sobre o titular é outra e tem o seu auxiliar. Nutricionista de vínculo encerrado e aluno com Nutricionista ativo não criam plano. O cartão permanece [ ].
Fechamento [2026-09-30] de {F4-03}: a capacidade "cria plano alimentar" está em produção (migração 0052, https://fit.modulareasy.com) e é a segunda da Matriz aplicada por especialidade no banco, com os dois auxiliares da Nota acima. Provado pelo qa: o Nutricionista de vínculo ativo cria plano; o aluno sem Nutricionista ativo cria o próprio (201, autor "eu mesmo"); o aluno com Nutricionista ativo recebe 403 nomeado e 0 linhas; a edição por aluno, Personal e outro Nutricionista é negada; o Administrador recebe 403 nomeado nas seis rotas. Verificador de capacidade por especialidade de 7 de 7 para 12 de 12. Com {F4-02} e {AUD-09} o recorte do papel fecha: o cartão passa a [x].
Para que serve: operar a plataforma inteira, atravessando o isolamento de forma auditável, e deter as sete capacidades de governança que nenhum outro papel alcança.
Relacionado com: RF-CORE-007, RF-CORE-008, RF-CORE-009, RF-CORE-014, RF-PLAN-001, RF-PLAN-002, RF-PAIN-009, RN-010, ADR-017; tarefas F1-09, F1-10, F7-14, AUD-04 e AUD-05; ART-ACS-12 (o papel irmão), ART-ACS-13 (personificação), ART-WF-18 (semente das contas de topo).
Onde fica: políticas de acesso do banco, com política de exceção própria, e guarda de rota nas dez rotas de administração.
Especificação: recorte da matriz do DRS, coluna Super Admin, com escopo total em 41 das 48 capacidades e N nas sete restantes (três do titular: executar e retomar sessão, registrar preferências de treino, e consultar o próprio plano, os limites e o consumo; e quatro por ausência de requisito, já explicadas no Apêndice: criar ficha de treino, duplicar ficha de terceiro, solicitar ficha de treino ao profissional, e atender ou recusar solicitação de ficha). O que o distingue do Administrador são vinte e duas capacidades, e só elas: quatorze da fronteira de dado clínico, detalhadas em {ART-ACS-12}, e oito de governança, que são: atribuir plano e status de acesso (RF-PLAN-002); manter o catálogo de planos e os limites operacionais (RF-PLAN-001); bloquear e desbloquear conta pela administração (RF-PAIN-009); promover ou rebaixar papel e criar conta de Administrador (RF-PAIN-009); personificar usuário, com registro (RF-CORE-014); excluir em definitivo (RF-CORE-008); consultar a trilha de auditoria (RF-CORE-009); e manter o catálogo de parâmetros de operação (RF-PAIN-011). Valor do papel no tipo mfit.papel_usuario: super_administrador. Contas que o detêm: exatamente as três de topo da plataforma (RN-010), promovidas pela migração de {AUD-04}; qualquer quarta conta exige ato deliberado registrado na auditoria. Toda leitura dele em categoria sensível gera entrada de auditoria de acesso administrativo, igual à do Administrador. Teste mecânico da escada: 41 contra 19, diferença de 22, que se decompõe em 8 de governança mais 14 de dado clínico, dez por classificação e quatro por conteúdo, sem sobra; diferença de uma ou duas reprovaria o desenho, por significar dois nomes para o mesmo papel.
Para que serve: dar à operação do dia a dia o alcance necessário para manter o catálogo, o guia e o atendimento, sem entregar a governança da plataforma e sem lhe dar dado de saúde de aluno nenhum.
Relacionado com: RF-EXER-001, RF-AJUD-002, RF-PAIN-008, RF-PAIN-009, RF-CORE-007 (que declara a fronteira de dado), RF-CORE-010, D.2, D.6, ADR-017; tarefa AUD-04; ART-ACS-06 (o papel acima dele na escada), ART-ACS-07 (o auxiliar que passa a distinguir os dois).
Onde fica: políticas de acesso do banco (inclusive as das entidades clínicas, que passam a negar este papel), auxiliar único de decisão de acesso e guarda de rota das sete rotas de administração comuns.
Especificação: recorte da matriz do DRS, coluna Admin, com escopo total em 20 das 47 capacidades. Valor do papel no tipo mfit.papel_usuario: administrador, valor que já existe e cujo significado muda com {AUD-04}. O que ele ALCANÇA: manter o catálogo global de exercícios e acionar a geração de mídia demonstrativa; manter e publicar o guia da plataforma; ler os relatórios agregados do sistema; criar, buscar e editar cadastro de aluno e de profissional e marcar registro profissional como verificado; gerir vínculos globalmente para resolver caso de suporte; e atravessar o isolamento para ler e operar o dado NÃO CLÍNICO de qualquer aluno (perfil, vínculo, ficha de treino e itens, sessão de treino e séries, solicitação de ficha, preferência de treino, acordo e competência de cobrança e aceite de termos), sempre com entrada de auditoria de acesso administrativo.
O que ele NÃO alcança, e são duas listas fechadas. Primeira, as oito capacidades privativas de governança listadas em {ART-ACS-06}. Segunda, a fronteira de dado clínico, quatorze capacidades em que ele é N, em dois grupos. Dez por classificação: preencher anamnese, registrar avaliação física, registrar medida corporal, enviar foto de progresso, registrar exame, registrar prescrição, registrar sessão de reabilitação, registrar refeição, definir meta nutricional e criar plano alimentar. Quatro por conteúdo, que não são categorias de saúde mas transportam o dado delas: conversar com vinculado, conversar entre profissionais do mesmo aluno, conectar e desconectar serviço de atividade (e ler a atividade importada) e acionar geração assistida de treino, dieta e explicação. Ler preferências de treino fica fora da fronteira, por RN-001. A negação alcança leitura e escrita, e por isso mora na política de acesso por linha das entidades correspondentes, não só na guarda de rota: o auxiliar único de decisão de acesso ({ART-ACS-07}) passa a distinguir os dois papéis de administração, liberando o Super Administrador em toda entidade e o Administrador apenas nas nove não clínicas. 8 mais 14 igual a 22, que é exatamente 41 menos 19, e é esse fechamento que o card TA-92 mede. Motivo: menor privilégio sobre dado de saúde; o chamado que precisa do dado clínico sobe ao Super Administrador, que lê sob consentimento (RF-CORE-007) ou personifica com registro (RF-CORE-014).
Telas: as sete rotas de administração comuns mais /admin/planos em leitura; /admin/auditoria responde negativa a ele; e as telas de saúde, dieta, evolução, conversas e integrações de atividade de aluno respondem negativa a ele em qualquer unidade (B.5), restando-lhe as próprias notificações. Contas que o detêm hoje: nenhuma; o papel nasce vazio em {AUD-04} e se povoa quando um Super Administrador promover alguém.
Nota (gate {F4-01}, Drift 1, 2026-09-29): o mecanismo que faz o auxiliar único distinguir os dois papéis por entidade ({ART-ACS-07}) nasce em {F4-01}, com refeicao, a primeira entidade da fronteira; cada card dono de entidade da fronteira passa o nome da própria entidade como quarto argumento do auxiliar nas suas políticas. A negação de leitura e de escrita descrita na Especificação acima passa a ter efeito por entidade à medida que cada card dono a entrega, e nenhuma delas é contada como entregue antes do fechamento do card dono.
Fechamento [2026-09-30] de {F4-01}: a primeira entidade da fronteira nega este papel em produção. refeicao responde 403 nomeado ao Administrador na leitura própria, na leitura de aluno indicado, na criação e na desativação, sem lista vazia disfarçada de resultado; PATCH, PUT e DELETE não têm rota (404). O painel dele não mostra Nutrição, e /nutricao e /nutricao/refeicoes/nova o redirecionam a /admin. O par positivo, o titular no mesmo alvo, devolve 200. Fronteira: 1 de 13 entidades servidas; as doze restantes seguem com os cards donos.
Para que serve: permitir que o Super Administrador enxergue o sistema como um usuário determinado, para resolver um chamado de suporte, sem que isso aconteça sem rastro nem amplie o alcance de quem personifica.
Relacionado com: RF-CORE-014, RF-CORE-010, D.2, D.5; tarefa AUD-05; ART-ENT-01 (tabela sessao_personificacao e as colunas novas de auditoria), ART-AUD-01 (trilha); a faixa vive no topo de toda tela e não pertence a cartão de tela nenhum, pelo mesmo critério da central de notificações.
Onde fica: servidor de aplicação (início, saída e expiração da sessão personificada), banco de dados (tabela sessao_personificacao e par nas entradas de auditoria) e a faixa no topo de toda tela.
Especificação: início por ação explícita com confirmação nominal a partir de /admin/usuarios, negada a todo papel diferente de Super Administrador e negada quando o alvo é Super Administrador. A sessão personificada decide acesso pelo usuário personificado: o auxiliar único de decisão de acesso ({ART-ACS-07}) recebe o identificador do personificado, nunca o do personificador, e por isso categoria sensível não consentida pelo titular continua bloqueada. Duração máxima de trinta minutos, parâmetro de configuração ({ART-CFG-01}), com dois desfechos, saída explícita e expiração, cada um gravando a entrada de fim com o motivo. Registro: uma linha em sessao_personificacao por personificação (personificador, personificado, início, fim, motivo do fim), apenas acrescida, e o par personificador e personificado carimbado em toda entrada de auditoria gerada no período. Autoria: o registro escrito sob personificação tem como autor o usuário personificado; quem estava por trás vive na trilha, nunca no registro. Interface: faixa permanente no topo de toda tela com nome e papel do personificado, tempo restante e ação de sair, com estado próprio próximo da expiração. Sair da personificação devolve a sessão do Super Administrador sem exigir entrada nova.
Estado: materializado em produção em 2026-09-29 (merge 3dabc30, https://fit.modulareasy.com, migrações 0034, 0035 e 0036, gates plan, qa e review verdes). Provado pelo qa: início a partir de /admin/usuarios, faixa em 44 de 44 telas do aluno, autoria sob personificação gravada como o alvo, negação por 403 para Administrador, profissional, aluno, alvo Super Administrador e o próprio operador, saída sem tela de entrada em 8 de 8 combinações, expiração com o motivo certo. As negações de senha e e-mail não têm rota para provar hoje.
Para que serve: decidir, num só lugar, se quem pergunta pode ler a linha de um aluno, para que toda política de tabela de dado de aluno chame o mesmo auxiliar, e exista um só lugar a auditar.
Nota (onda AUD, {AUD-04}, 2026-09-15): este auxiliar passa a receber também a ENTIDADE consultada, porque o alcance dos dois papéis de administração deixa de ser igual: o Super Administrador é liberado em toda entidade de dado de aluno, e o Administrador apenas nas não clínicas, recebendo negação nas entidades das quatorze capacidades da fronteira de B.1 (RF-CORE-007), que incluem conversa, mensagem, conta de integração e atividade externa, e não apenas as categorias de saúde. O ponto único a auditar continua sendo um só, que é exatamente a razão de a distinção entrar aqui e não ser espalhada por política de tabela; a lista de entidades clínicas vive num lugar só, ao lado dele.
Nota de fronteira (R-6, {F1-19}): o universo deste verificador é a coluna aluno_id das dezoito entidades de E.1. usuario, perfil_aluno e perfil_profissional ficam de fora dele: têm titular por usuario_id e não por aluno_id, e a leitura de terceiro nelas é o quarto placar de {ART-ACS-11}, nunca este auxiliar (usá-lo ali entregaria telefone e e-mail ao vinculado). mfit.plano_plataforma está confirmada desde {F1-13}, com USING (true) intencional e motivo escrito no banco (não é dado de aluno, é informação de produto igual para todos); não é pendência deste verificador nem do quarto placar.
Relacionado com: RF-CORE-006, D.2, ADR-003 e ADR-013; tarefa F1-08; ART-ENT-02 (tabela vinculo, de que o auxiliar depende); ART-ACS-11 (o quarto placar, que cobre usuario, perfil_aluno, perfil_profissional e a confirmação de plano_plataforma).
Onde fica: banco de dados, função mfit.pode_ler_aluno, chamada pela política de leitura de cada tabela de dado de aluno.
Especificação: assinatura mfit.pode_ler_aluno(p_aluno_id uuid, p_autor_id uuid default null, p_restrito boolean default false) returns boolean. Quatro condições avaliadas nesta ordem: primeiro o papel Administrador, que sempre recebe verdadeiro; depois a ausência de claim de sessão, que sempre recebe falso; depois o titular (usuario_atual() = p_aluno_id), que sempre recebe verdadeiro, inclusive na classe restrita; depois, se p_restrito for verdadeiro, falso para qualquer outro (é a classe restrita, que só titular e Administrador leem); por fim, para os demais casos, verdadeiro quando existe vínculo do autor da chamada com o aluno em estado ativo, ou quando p_autor_id corresponde ao autor da chamada (o profissional que foi autor do registro, mesmo com vínculo já encerrado). Classe restrita: conta_integracao e aceite_termos, chamadas com p_restrito = true. Declaração: SECURITY DEFINER com SET search_path = mfit, pg_catalog fixo na própria função, nunca herdado da sessão, e STABLE, não VOLATILE nem IMMUTABLE, para o planejador reaproveitar o resultado dentro da mesma consulta. Gabarito de uso por tabela nova, publicado em db/migrations/GABARITO-ACESSO-ALUNO.md: aluno direto (USING (mfit.pode_ler_aluno(aluno_id, autor_id))), aluno indireto (mesma chamada com subconsulta que resolve o titular pela chave estrangeira) e classe restrita (USING (mfit.pode_ler_aluno(<titular>, NULL, true))), sempre com ENABLE ROW LEVEL SECURITY e política de escrita explícita junto da de leitura. Verificador ops/verifica-acesso-aluno.mjs: reprova toda tabela do esquema mfit com coluna aluno_id sem relrowsecurity verdadeira e sem política que chame o auxiliar; confere nominalmente as dezoito entidades de E.1, reportando cobertas e pendentes; reprova política USING (true) ou concedida a PUBLIC; e imprime a aritmética cobertas + pendentes = 18.
Estado: entregue em F1-08. O auxiliar, a tabela vinculo, o gabarito e o verificador nasceram em {F1-08}, cobrindo hoje aceite_termos; as dezessete entidades restantes de E.1 recebem a política pelo gabarito no card que as cria, até fechar na Fase 8. Nota ({F2-05}): {F2-05} PROVA a condição 2 desta função no caminho de vínculo pendente, sem alterá-la, o décimo sexto verificador mede pendente 0 linha e ativo 1 linha como controle positivo e negativo do mesmo auxiliar. Nota ({F2-06}): o aceite PROVA a condição 2 no caminho oposto, vínculo passando a ativo: com a sessão do profissional, mfit.pode_ler_aluno devolve verdadeiro e a leitura de mfit.consentimento do aluno passa de zero para as linhas concedidas, controle positivo do arnês do H1; a recusa prova a mesma condição negada, pode_ler_aluno falso e zero linhas. Placar pendente 0, recusado 0, ativo 1 (décimo sexto verificador). Nota ({F2-07}): {F2-07} PROVA a condição 3 desta função pela primeira vez no produto (autor com vínculo já encerrado continua lendo), sem alterá-la: com o vínculo em inativo, mfit.pode_ler_aluno com p_autor_id do próprio profissional devolve verdadeiro para as três fichas que ele escreveu, e devolve falso para a quarta ficha de autoria alheia (controle negativo). Placar pendente 0, recusado 0, inativo 0, ativo 1 (décimo sexto verificador). Função inalterada. Nota (gate {F3-01}, Drift 7, 2026-09-14): o universo do critério (a) deste verificador é a lista das tabelas do esquema que têm a coluna aluno_id, e por isso ele NÃO enxerga a tabela que guarda dado de aluno por chave estrangeira para uma tabela pai, sem coluna própria de titular. O gabarito chama essa forma de aluno indireto e nomeia seis tabelas nela (mensagem, acordo_cobranca, ficha_item, sessao_serie, plano_refeicao, refeicao_alimento); nenhuma delas entra no universo de hoje, e o critério (b), que percorre a lista única de entidades de E.1, também não as alcança, porque essa lista é das entidades com titular direto. Consequência medida, não suposta: uma tabela de forma indireta nascendo sem segurança por linha, ou com segurança por linha e sem política, passaria em todos os verificadores, na suíte inteira e nos gates, sem erro e sem aviso, exatamente como a guarda por especialidade passava antes de {F2-08} e como o segundo chamador da leitura reduzida passava antes de {F2-09}. ficha_item é a primeira das seis a nascer, em {F3-01}, e é nesse card que o critério novo entra, com três exigências: lista nominal e fechada das seis tabelas de forma indireta, com o card dono de cada uma e trava síncrona de cardinalidade que recusa carregar o módulo se a lista mudar de tamanho sem alguém atualizar o número; as mesmas exigências do critério (a) aplicadas a elas (segurança por linha habilitada, política de leitura chamando mfit.pode_ler_aluno pela subconsulta que resolve o titular no pai, política de escrita explícita, nada de USING (true) nem concessão a PUBLIC); e a exigência própria da forma indireta, que o gabarito escreve e nenhum critério mede hoje, um índice na chave estrangeira usada pela subconsulta. Obrigatório também o lado negativo, no molde do critério (e) de {F2-08}: trechos fabricados que o critério tem de REPROVAR (tabela de forma indireta sem segurança por linha; com segurança por linha e sem política; com política USING (true); sem índice na chave estrangeira) e trechos que ele tem de ACEITAR. Critério que nunca reprovou nada não é verificador, é enfeite. Placar previsto quando {F3-01} entregar, separado dos demais e nunca somado a eles: 1 servida (ficha_item, {F3-01}) mais 5 pendentes igual a 6. Nada disto move o placar cobertas mais pendentes igual a 18 do critério (a), que segue com o universo próprio.
Nota (gate {F3-03}, Drift 2, 2026-09-14): nasce ao lado deste auxiliar um segundo, de escopo próprio e nome próprio, mfit.pode_editar_por_autoria(p_autor_id uuid), que responde a pergunta de RN-009, "quem edita a linha que tem autor", e não a pergunta deste cartão, "quem lê a linha de um aluno". Ele existe porque a política de UPDATE escrita em 0025 compara o autor com o usuário da sessão de forma crua e por isso recusa o Administrador, a quem RN-009 dá a edição em letra: o requisito está certo e quem diverge é o banco, então a correção é a migração 0026 e nunca o texto de RN-009. Ele entra apenas nas políticas de UPDATE das duas tabelas da ficha e no USING da política de DELETE de ficha_item; no WITH CHECK do INSERT a igualdade crua permanece literal e intocada, porque lá a pergunta é outra, "a autoria nasce de quem escreve", e o Administrador não cria ficha. Ele não substitui mfit.pode_ler_aluno nem mfit.autor_com_acesso_ativo, que continuam nas mesmas conjunções e na mesma ordem: uma conjunção, uma pergunta, e um falso fundido não diz qual negou. É função, e não condição colada em cada política, porque a regra alcança dez entidades com autor de terceiro na lista única e só uma existe hoje: as nove restantes herdam a regra inteira pelo gabarito, e condição colada produz nove oportunidades de colar metade dela. O GABARITO-ACESSO-ALUNO.md ganha no mesmo passo a seção "Autoria por LINHA tem DUAS exceções", ligada às duas que já existem. Placar deste cartão inalterado, cobertas mais pendentes igual a 18, porque o universo aqui é a leitura por titular e nada nele muda.
Fechamento [2026-09-14]: mfit.pode_editar_por_autoria em produção (migração 0026, merge 76bc9cd), liberando o Administrador nas políticas de UPDATE das duas tabelas e no USING do DELETE de ficha_item, sem tocar mfit.pode_ler_aluno nem mfit.autor_com_acesso_ativo. Placar deste cartão continua inalterado, cobertas mais pendentes igual a 18.
Nota (gate {F3-04}, Drift 9, 2026-09-14): mfit.solicitacao_ficha nasce com coluna aluno_id e por isso entra no universo do critério (a) deste verificador, que enumera por catálogo, e passa a ser medida por ele sem ninguém precisar lembrar. E ainda assim o placar cobertas mais pendentes igual a 18 NÃO muda, e o motivo se escreve antes de alguém estranhar: as dezoito são as dezesseis entidades de dado de aluno nomeadas por RF-CORE-006 mais as duas de classe restrita, e a solicitação não está entre as dezesseis por critério de produto, não por esquecimento, porque ela não é um registro do acompanhamento do aluno, é uma mensagem com estado entre duas pessoas. ficha_item, sessao_serie, plano_refeicao e refeicao_alimento ficam de fora da mesma lista pelo mesmo tipo de critério, e ficha_item já nasceu assim em {F3-01}. A tabela é coberta por construção pelo critério que varre o catálogo, e não contada na lista nominal: as duas coisas convivem, e quem olhar o placar depois deste card deve ler este parágrafo antes de supor que alguém esqueceu uma linha. Placar que não muda também se declara.
Nota (gate {F4-01}, Drift 1, 2026-09-29): a distinção por entidade declarada na Nota de {AUD-04} acima não existia no banco quando {F4-01} foi medido: mfit.pode_ler_aluno tinha três argumentos e devolvia verdadeiro ao papel de administração na primeira condição, em toda entidade, e nenhuma entidade clínica existia para revelar o furo (o caso {TA-90} media 0 de 28). {F4-01} cria refeicao, a primeira entidade da fronteira, e por isso o mecanismo nasce ali, na migração 0043. Assinatura de quatro argumentos: mfit.pode_ler_aluno(uuid, uuid, boolean, text), sem valores padrão, sendo o quarto o nome da entidade consultada; a versão de três argumentos continua existindo e delega à de quatro com NULL::text, de modo que nenhuma política existente muda de comportamento e um só corpo decide. Corpo: o Super Administrador recebe verdadeiro em toda entidade; o Administrador recebe NOT mfit.entidade_da_fronteira_clinica(p_entidade); dali em diante valem as condições de sempre. A primeira condição da Especificação abaixo (o papel Administrador sempre recebe verdadeiro) passa a valer só fora da fronteira; a Especificação registra o estado entregue em {F1-08} e não se reescreve. A lista clínica vive ao lado do auxiliar, numa função fechada mfit.entidade_da_fronteira_clinica(p_entidade text), com as treze entidades de E.1 que a fronteira alcança: refeicao, meta_nutricional, plano_alimentar, medida_corporal, foto_progresso, anamnese, avaliacao_fisica, exame, prescricao, sessao_reabilitacao (as dez por classificação que têm entidade em E.1) e mensagem, atividade_externa, conta_integracao (três das quatro por conteúdo; a conversa entre profissionais e a geração assistida não têm entidade própria em E.1 e ficam com os cards donos {F6-01} e {F8-05}). O placar de {ART-ACS-11} e o de {TA-90} só se movem no fechamento, medidos no dia.
Fechamento [2026-09-30] de {F4-01}: o mecanismo está em produção (migração 0043, https://fit.modulareasy.com): mfit.pode_ler_aluno(uuid, uuid, boolean, text) com quatro argumentos e mfit.entidade_da_fronteira_clinica com as treze entidades da nota acima; a versão de três argumentos delega e nenhuma política existente mudou de comportamento (caminho antigo reconferido pelo qa em todos os papéis). refeicao e refeicao_alimento são as primeiras a chamar o auxiliar com o quarto argumento. Medido em produção: o Administrador lê 0 das 4 refeições e o INSERT é negado (42501), o titular lê as 4 refeições e os 9 alimentos, e o controle com três argumentos devolve verdadeiro para o mesmo alvo, o que prova que o quarto argumento é quem nega. Fronteira de dado clínico: 1 de 13 entidades servidas; {TA-90} sobe de 0 de 28 para 2 de 28.
Gabarito de uso, linha nova (gate {F4-01}, Drift 1, 2026-09-29): entidade da fronteira de dado clínico, USING (mfit.pode_ler_aluno(<titular>, NULL, false, '<entidade>')), com o nome da própria entidade como quarto argumento (na filha, o nome da mãe); a política de escrita repete o predicado do titular com o mesmo quarto argumento. Tabela da fronteira com três argumentos entrega o dado ao Administrador em silêncio, e é isso que o critério novo do verificador reprova.
Nota (gate {F3-05}, 2026-09-14): sessao_treino e sessao_serie nascem em {F3-05} e entram no universo deste auxiliar pelo critério que já existe, sem ninguém precisar lembrar: a primeira tem coluna aluno_id e recebe a política de leitura chamando mfit.pode_ler_aluno; a segunda não tem titular próprio e é alcançada pela sessão mãe, na forma indireta já usada por ficha_item. O total de dezoito não muda, e o motivo se escreve antes de alguém estranhar: as dezoito são as dezesseis entidades de dado de aluno nomeadas por RF-CORE-006 mais as duas de classe restrita, e sessao_treino já está entre as dezesseis desde que E.1 foi escrita. O que sobe é a contagem de servidas, e ela sobe no fechamento, medida no dia, nunca projetada aqui.
Fechamento [2026-09-15]: sessao_treino e sessao_serie em produção (migração 0028, merge 80c103e), cobertas pelo auxiliar: a primeira por política de leitura chamando mfit.pode_ler_aluno, a segunda pela forma indireta já usada por ficha_item. Placar de E.1 sobe de 4 servidas + 17 pendentes = 21 para 5 servidas + 16 pendentes = 21. Placar do critério (a), cobertas mais pendentes igual a 18, continua inalterado. Nota (gate {F4-02}, Drift 1, 2026-09-29): a lista única de entidades de E.1 em server/src/acesso/verificarPoliticas.ts marcava meta_nutricional como sem autor de terceiro (temAutorDeTerceiro: false), e a entrada estava errada desde {F2-07}: RF-DIET-002 dá a escrita ao Nutricionista vinculado, E.1 tem autor e a ficha de {ART-ENT-05} tem autor_id. Com o valor errado o critério (e) do verificador nunca olharia esta tabela, e a autoria na leitura (condição 3) e a negação de escrita do vínculo encerrado ficariam sem verificador. Só a lista única muda (passa a true, e a trava CARDS_AUTORIA_PENDENTES sobe de 10 para 11); nenhum requisito muda, e a correção de código é de {F4-02}. Nota (gate {F4-02}, Drift 3, 2026-09-29): o critério (e) do mesmo verificador lia errado a forma de quatro argumentos de mfit.pode_ler_aluno, que nasceu em {F4-01}: qualquer vírgula contava como "passa autor_id". O defeito só aparece agora porque meta_nutricional é a primeira tabela da fronteira clínica COM autor. Sem o conserto, a política de inserção correta reprovaria (NULL no segundo argumento visto como autor) e uma política de leitura errada passaria. A regra corrigida: o critério lê o SEGUNDO argumento literal, "com autor" é pode_ler_aluno(<coluna_titular>, autor_id e nada mais, e NULL no segundo argumento é "sem autor". Prova exigida: decoy nos dois sentidos (leitura com NULL reprova, inserção com autor_id reprova), controle (a forma certa passa) e os casos de três argumentos que já passavam continuando a passar. Nenhum requisito muda e a especificação do auxiliar acima não muda; a correção é do verificador, em {F4-02}. Fechamento [2026-09-30] de {F4-02}: meta_nutricional em produção (migração 0044, https://fit.modulareasy.com) é a segunda entidade da fronteira de dado clínico servida, 2 de 13, e a primeira com autor: as políticas chamam mfit.pode_ler_aluno com o quarto argumento 'meta_nutricional'. Medido pelo qa: o Administrador recebe 403 nomeado e lê 0 das 3 linhas existentes no banco, o INSERT dele é negado (42501), e o par positivo do titular lê as 3 e insere. O cartão continua [x], sem mudança de escopo. Nota de gabarito (gate {F4-03}, Drift 3, 2026-09-30): o gabarito de acesso passa a ter DUAS perguntas de capacidade por especialidade, cada uma com o seu auxiliar, e nenhuma delas é o auxiliar de leitura deste cartão, que continua um só. mfit.tem_vinculo_ativo_na_especialidade(p_aluno, p_especialidade) ({F4-02}) pergunta sobre o ATOR: o usuário atual, como profissional, tem vínculo ativo com o aluno naquela especialidade? mfit.aluno_tem_vinculo_ativo_na_especialidade(p_aluno, p_especialidade) ({F4-03}, migração 0046) pergunta sobre o TITULAR: o aluno tem, hoje, vínculo ativo com profissional daquela especialidade? O segundo é STABLE SECURITY DEFINER, responde somente a quem já lê o aluno e devolve false a quem não lê, nunca um oráculo, e é a mesma pergunta que RF-SAUD-001 fará em {F5-01} ("quando não há profissional daquela especialidade vinculado"). Ratificação da Inspeção: a ordem de {AUD-09} dizia "nunca um segundo auxiliar", e essa regra vale para a pergunta de capacidade do ATOR, que continua uma só; a cláusula "ou o próprio aluno na ausência de um" de RF-DIET-003 pergunta sobre o titular, e o auxiliar do ator não a responde. Alternativa recusada: um EXISTS colado na política e copiado no servidor, que dá duas cópias da mesma pergunta. Nota de correção (Inspeção, gate {F4-03}, Drift 9, 2026-09-30): na Nota de gabarito acima, a migração de mfit.aluno_tem_vinculo_ativo_na_especialidade ({F4-03}) é a 0052, e não a 0046. A 0046 é da categoria nutricao ({AUD-11}), que existe desde então. Fechamento [2026-09-30] de {F4-03}: plano_alimentar e plano_refeicao em produção (migração 0052, https://fit.modulareasy.com) chamam mfit.pode_ler_aluno com o quarto argumento 'plano_alimentar' em toda política das duas tabelas (a filha passa o nome da mãe). Fronteira de dado clínico: 3 de 13 entidades servidas. Medido pelo qa: o Administrador recebe 403 nomeado nas seis rotas, lê 0 das 7 linhas existentes no banco e tem a escrita recusada, com os pares positivos (titular lê, Nutricionista insere e atualiza). Placares: leitor único 3 de 10, consentimento por entidade 3 de 10, capacidade por especialidade 12 de 12. O verificador ganha a fronteira à esquerda do nome do auxiliar de capacidade (o auxiliar do titular deixa de ser lido como o do ator) e a exceção nominal FILHAS_COM_EXCLUSAO_NA_EDICAO para plano_refeicao, ratificada pelo Fiscal, com a forma exata do DELETE exigida. O cartão continua [x], sem mudança de escopo.
Para que serve: ser o mecanismo único de remoção de dado de aluno, para que toda entidade nasça já com exclusão privativa do Super Administrador e desativação para os demais, sem depender de alguém lembrar.
Relacionado com: RF-CORE-008, RN-008; tarefas {F1-10} e {AUD-04}; ART-ACS-06 (o papel Super Administrador que a política exige).
Onde fica: banco de dados, política FOR DELETE por tabela mais o gatilho genérico de auditoria de remoção; campo removível na lista única de entidades em server/src/acesso/verificarPoliticas.ts.
Especificação: política CREATE POLICY ... FOR DELETE TO mfit_app USING (mfit.e_super_administrador()) em cada uma das onze entidades de RF-CORE-008, por chamada à função de papel e nunca por comparação com literal; nenhum REVOKE DELETE de mfit_app (o privilégio é do role, a política decide por papel). Desativação: estado = 'inativo' em vinculo (já existente); desativado_em timestamptz anulável mais desativado_por uuid referenciando usuario(id) nas oito entidades sem coluna própria; status existente em ficha_treino e plano_alimentar, com a decisão de reaproveitar ou ganhar as duas colunas tomada pelo card dono. Toda exclusão e toda desativação gera entrada de auditoria (excluir em AFTER DELETE, desativar em AFTER UPDATE quando a coluna de desativação muda), sem conteúdo da linha na trilha. DELETE negado por política não lança erro, então a rota confere rowCount e traduz zero em negação explícita. Verificador por critério, nunca por lista escrita à mão: reprova tabela de dado de aluno sem política FOR DELETE, política que não exija o papel de Super Administrador, qualquer comparação com literal de papel dentro de política, função ou gatilho, ausência do gatilho de remoção nas entidades que já existem, e ausência da coluna de desativação declarada. Placar impresso: N servidas + (11-N) pendentes = 11, cada pendente nomeada com o card dono.
Estado: entregue em F1-10: política vinculo_exclusao, mfit.auditar_remocao() e os dois gatilhos (excluir/desativar) em vinculo (migração 0010), seção Remoção em db/migrations/GABARITO-ACESSO-ALUNO.md, campo removível na lista única de entidades em server/src/acesso/verificarPoliticas.ts, verificador por critério com prova negativa, rotas mínimas de vínculo traduzindo zero linhas afetadas em negação explícita. Cobre 1 de 11; as dez restantes recebem política, coluna de desativação e gatilho pelo gabarito no card que as cria, até fechar na Fase 8, quando TA-08 fecha junto.
Nota (gate {F3-03}, Drifts 3 e 9, 2026-09-14): duas declarações, e nenhuma delas muda o placar deste cartão. Primeira: remover um item de uma ficha NÃO é remoção de entidade de RF-CORE-008, é edição do conteúdo da prescrição, com a trilha guardando o que saiu; ficha_item não tem titular próprio e não pertence às onze entidades removíveis, então a política de exclusão de item que {F3-03} cria em 0026 segue a regra de autoria do card e não a regra de exclusão privativa do Administrador. Sem esta declaração, a leitura ingênua de RN-008 tornaria o autor incapaz de tirar um exercício da própria ficha, invertendo ADR-006 no card que existe para sustentá-lo. A política de exclusão da ficha inteira fica intocada, privativa do Administrador, e nenhuma tela a oferece. Segunda: a desativação da ficha ganha caminho de escrita em {F3-03}, por rotas próprias de desativar e de reativar, no molde literal das rotas de vínculo, nunca por um campo de formulário de edição; ela existia no banco desde {F3-01} (coluna de estado, política, gatilho e contagem) e não tinha uma única porta, o que deixava o aluno no teto do plano sem nenhuma ação disponível. O placar de remoção deste cartão fica inalterado; o que se move com {F3-03} é o caso de teste {TA-08}, de 1 de 11 para 2 de 11, sem fechar.
Fechamento [2026-09-14]: as duas declarações confirmadas em produção (76bc9cd): a política de exclusão de ficha_item segue a regra de autoria, não a de RF-CORE-008, e a ficha inteira continua exclusão privativa do Administrador; desativar e reativar ganham rota própria. Placar deste cartão continua inalterado; {TA-08} sobe para 2 de 11, sem fechar.
Nota (gate {F3-04}, Drift 11, 2026-09-14): o placar de remoção deste cartão fica inalterado, e o motivo se escreve. mfit.solicitacao_ficha nasce com política de exclusão privativa do Administrador, exatamente como o gabarito manda, mas não é uma das onze entidades de RF-CORE-008: ela recebe a política por CRITÉRIO, porque o verificador varre toda tabela de dado de aluno do esquema, e não por pertencer à lista das onze. Somar uma coisa na outra faria o denominador crescer toda vez que uma tabela nova nascesse, e o placar deixaria de medir o que RF-CORE-008 enumera. O aluno e o profissional não excluem a solicitação; o que a resolve é transição de estado, que preserva a trilha, e apagar o pedido no ato de respondê-lo seria perder exatamente o texto que explica o que o aluno queria.
Nota (gate {F3-05}, 2026-09-14): o placar de remoção deste cartão fica inalterado, e o motivo se escreve. Nem sessao_treino nem sessao_serie estão entre as onze entidades que o H1 de RF-CORE-008 enumera (ficha, plano alimentar, refeição, medida, exame, prescrição, sessão de reabilitação, anamnese, avaliação, foto e vínculo): a sessão de treino é execução registrada, não prescrição, e a série é linha dela. As duas recebem a política de exclusão privativa do Administrador pelo gabarito, por critério, porque o verificador varre toda tabela de dado de aluno do esquema, e não por pertencerem à lista das onze. Somar uma coisa na outra faria o denominador crescer a cada tabela nova, e o placar deixaria de medir o que RF-CORE-008 enumera. O aluno não exclui sessão nem série: o que ele faz é encerrar, e encerrar é transição de estado.
Fechamento [2026-09-15]: confirmado em produção (migração 0028, merge 80c103e). sessao_treino e sessao_serie nasceram com a política de exclusão privativa do Administrador, por critério, não por pertencerem às onze de RF-CORE-008. Placar de remoção deste cartão continua inalterado. Nota (onda AUD, {AUD-04}, 2026-09-15): o literal que estas políticas exigem muda com {AUD-04}, e o placar deste cartão não. Onde as notas de fechamento datadas acima dizem exclusão privativa do Administrador, leia-se o papel que era o topo da escada até esta republicação: a partir de {AUD-04} a exclusão em definitivo é privativa do Super Administrador (RF-CORE-008 e RN-008), as políticas passam a chamar mfit.e_super_administrador() e nenhuma comparação com literal de papel sobrevive dentro de política, função ou gatilho. As notas acima não se reescrevem porque registram o que estava em produção na data delas; o que manda daqui para a frente é a Especificação. Nota (Inspeção, gate {F5-04}, Drift 3, 2026-10-06): para o exame, desativar não apaga o anexo: o objeto continua no repositório privado, legível ao titular e ao Super Administrador, e só sai na exclusão definitiva (hoje só a limpeza, sem rota de exclusão clínica, precedente da anamnese). O exame entra na lista de entidades removíveis com desativado_em e desativado_por e a política FOR DELETE do Super Administrador, na migração 0059 de {F5-04}. Ficha em {ART-ENT-06} e em {ART-INT-02}. O cartão continua [x]. Fechamento [2026-10-06] de {F5-04}: a desativação do exame está em produção como a Nota descreveu: a política FOR DELETE do Super Administrador e as colunas desativado_em e desativado_por na mfit.exame (migração 0059, merge b078e76); o autor e o Super Administrador desativam (200), a segunda vez dá 409, o titular que não é o autor, o Personal e o Médico sobre o exame do aluno recebem 403, e PATCH, PUT e DELETE não existem como rota (404). O objeto do anexo segue no disco e abre depois de desativar, provado. O cartão continua [x].
Para que serve: impedir, na camada de dados, a escrita de categoria sensível sem consentimento ativo do titular, e retirar a categoria revogada da visibilidade do profissional.
Relacionado com: RF-CORE-010, RN-001, RN-003, ADR-010; tarefa {F1-12}; ART-ENT-01 (tabela consentimento), ART-SM-04 (a máquina de estados), ART-WF-10 (a revogação), ART-AUD-01 (a auditoria de concessão e revogação), ART-ACS-07 (o auxiliar de acesso, ao lado do qual este entra na leitura, nunca no lugar dele).
Onde fica: banco de dados, funções mfit.tem_consentimento e mfit.consentimento_visivel, chamadas pela política de cada tabela sensível; rotas GET/POST/DELETE /api/consentimentos.
Especificação: assinaturas mfit.tem_consentimento(p_aluno_id uuid, p_categoria mfit.categoria_sensivel) returns boolean e mfit.consentimento_visivel(p_aluno_id uuid, p_categoria mfit.categoria_sensivel) returns boolean, ambas STABLE, SECURITY DEFINER, SET search_path = mfit, pg_catalog fixo na própria declaração. tem_consentimento: existe linha de consentimento daquela categoria, daquele aluno, com revogado_em IS NULL; entra em conjunção no WITH CHECK das políticas de INSERT e de UPDATE de cada tabela sensível. consentimento_visivel: decide se o leitor enxerga a categoria, nesta ordem, papel administrador sempre verdadeiro, titular sempre verdadeiro, sem consentimento ativo falso, restrito_a_especialidades nulo verdadeiro (padrão de RN-003, todas as especialidades vinculadas), senão verdadeiro apenas se a especialidade do leitor estiver no array; entra em conjunção no USING da política de SELECT de cada tabela sensível, ao lado de mfit.pode_ler_aluno, nunca no lugar dela. O que estas funções NÃO decidem: acesso (isso é mfit.pode_ler_aluno), auditoria de leitura (isso é leituraSensivel.ts), plano e limite (isso é {F1-15}). Campo categoriaConsentimento na lista única ENTIDADES_E1, não nulo exatamente nas seis entidades marcadas sensivel: true. Rotas: GET devolve as seis categorias sempre, cada uma com estado; POST carimba versao_texto e finalidade do ponto único de configuração, nunca do corpo da requisição, e traduz concessão repetida em 409 com a linha ativa; DELETE é a revogação, confere rowCount e traduz zero em negação explícita. Verificador por catálogo, dois critérios: (g) toda entidade sensivel: true que exista tem política FOR INSERT/FOR UPDATE cujo WITH CHECK chama mfit.tem_consentimento com o literal de categoriaConsentimento, e política FOR SELECT cujo USING chama mfit.consentimento_visivel além de mfit.pode_ler_aluno; (h) bijeção entre categoriaConsentimento e os seis valores do enum mfit.categoria_sensivel lidos de pg_enum. Placar impresso: servidas + pendentes = 6, nunca misturado com os placares de leitura (19), remoção (11), sensível (6) nem imutabilidade (2).
Estado: entregue em F1-12: mecanismo, auxiliares, gabarito e verificador no ar cobrindo 0 de 6 entidades sensíveis; cada uma nasce já servida no card dela (Fase 5). Nota ({F2-06}): o aceite exercita mfit.consentimento como PROVA do H1 (categoria já concedida via /privacidade antes do aceite), sem tocar as duas funções: a cláusula "categorias consentidas" do RF-VINC-002 se prova hoje por mfit.consentimento e mfit.pode_ler_aluno (ART-ACS-07), porque nenhuma das seis entidades sensíveis existe ainda. Placar de entidades sensíveis inalterado, 0 de 6.
Nota (Inspeção, {AUD-11}, 2026-09-30): o tipo mfit.categoria_sensivel passa de seis para sete valores, com nutricao; o mecanismo e as duas funções não mudam, e as entidades que decidem acesso por categoria passam de seis para dez tabelas (as seis de saúde, medida_corporal na categoria avaliação física, e refeicao, meta_nutricional e plano_alimentar). Placar por entidade coberta: hoje 0 de 10; sobe para 2 de 10 quando {AUD-11} entregar (refeicao e meta_nutricional) e para 3 de 10 com {F4-03}. O universo do leitor único de {ART-AUD-02} cresce da mesma forma.
Nota (Inspeção, {AUD-11}, drift 7, 2026-09-30): a ficha põe mfit.consentimento_visivel só no USING da política de leitura. Para meta_nutricional ele entra também no WITH CHECK da inserção, em conjunção com mfit.tem_consentimento, porque o profissional fora da restrição escolhida pelo aluno que gravasse sem poder ler quebraria a regra de vigência "nunca atrás" e escreveria o que não pode ler (RN-003, RF-CORE-010). Vale para plano_alimentar em {F4-03}; refeicao não é afetada, porque só o titular a escreve. As funções não mudam.
Fechamento [2026-09-30] de {AUD-11}: placar por entidade coberta 2 de 10 (8 pendentes: plano_alimentar em {F4-03}, medida_corporal em {F5-07} e as seis de saúde na Fase 5). refeicao e meta_nutricional estão em produção (migrações 0046 e 0047, https://fit.modulareasy.com) com mfit.consentimento_visivel(aluno_id, 'nutricao') na leitura e mfit.tem_consentimento(aluno_id, 'nutricao') na escrita (na inserção de meta_nutricional, as duas, conforme a Nota do drift 7), e refeicao_alimento com a mesma conjunção pela linha mãe. O tipo mfit.categoria_sensivel tem 7 valores. A Especificação acima, escrita para seis, lê-se com sete: GET /api/consentimentos devolve as sete categorias sempre, e o critério (h) passa de bijeção a igualdade de conjuntos (toda categoria do enum reivindicada por ao menos uma entidade, nenhuma fora dele), de modo que duas entidades podem reivindicar a mesma categoria: 7 = 7. A meta padrão nasce na concessão de nutrição, pelo ponto único concederConsentimento, e a função de semente recusa (42501) sem consentimento. As duas funções tem_consentimento e consentimento_visivel não mudaram. O cartão permanece [x].
Para que serve: ser a única porta pela qual um usuário enxerga o perfil de outro, entregando exatamente os quatro campos públicos de D.2 e nenhum outro, na camada de dados, sem depender de a interface esconder campo nenhum.
Relacionado com: RF-CORE-004, RF-CORE-006, D.2, ADR-003, ADR-013; tarefa {F1-19}; ART-ENT-01 (tabelas usuario, perfil_aluno e perfil_profissional, de onde ela lê); ART-ACS-07 (fronteira declarada na Nota dela, R-6).
Onde fica: banco de dados, tipo composto mfit.perfil_publico_reduzido e função mfit.perfil_publico(p_usuario_id uuid); ponto único no servidor server/src/acesso/perfilPublico.ts; rota GET /api/perfil/:usuarioId.
Especificação: tipo composto mfit.perfil_publico_reduzido com exatamente quatro atributos, nominais e fechados: nome text, foto_caminho text, especialidade mfit.especialidade_profissional (nula quando o outro não é profissional) e registro text (nula quando o outro não é profissional); nunca um quinto atributo, nunca papel no retorno. Função mfit.perfil_publico(p_usuario_id uuid) returns mfit.perfil_publico_reduzido, language sql stable security definer set search_path = mfit, pg_catalog, resolve a foto pela tabela de perfil do papel do titular por dentro da própria função; não decide acesso (não pergunta vínculo, não audita), decide só o recorte. RLS ligada em mfit.usuario, mfit.perfil_aluno e mfit.perfil_profissional: política de SELECT só para o titular (usuario_atual()/usuario_id = usuario_atual()) e para o Administrador (papel_atual() = 'administrador'), nunca para o vinculado; sem política de INSERT em usuario (o único INSERT passa por mfit.criar_usuario, função definer); WITH CHECK de perfil_aluno com AND mfit.autor_com_acesso_ativo() fora dos parênteses da expressão de titular; perfil_profissional sem essa conjunção, por não ter escrita de aluno; REVOKE DELETE ON mfit.usuario, mfit.perfil_aluno, mfit.perfil_profissional FROM mfit_app nas três, para que a exclusão negada seja erro de permissão e não zero linhas. Nove caminhos sem claim de sessão, tratados por dois mecanismos: promoção de claim (set_config dentro da transação, depois de a identidade ser provada pelo consumo do token de uso único) na redefinição de senha e na confirmação de e-mail; cinco funções SECURITY DEFINER estreitas para os demais, cada uma devolvendo só as colunas do caminho que serve, nunca aceitando nome nem fazendo LIKE: mfit.credencial_por_email (entrada), mfit.conta_ativa_por_email (pedido de recuperação), mfit.nome_do_usuario (abertura de link de redefinição e rotina de e-mail, os dois caminhos), mfit.papel_do_usuario (renovação de sessão) e mfit.criar_usuario (cadastro, resolve a armadilha do RETURNING da política de SELECT). Rota GET /api/perfil/:usuarioId: alvo é o próprio solicitante devolve perfil completo; solicitante Administrador devolve perfil completo do alvo com registro de auditoria (acesso_administrativo, mesma transação da leitura, entidade = perfil_aluno ou perfil_profissional, campo/valor_anterior/valor_novo nulos); qualquer outro autenticado devolve a leitura reduzida, sem vínculo exigido; a chave de consulta é o identificador interno, nunca identificador_publico. Quarto placar em ops/verifica-acesso-aluno.mjs, núcleo server/src/acesso/verificarPerfilPublico.ts, quatro critérios: (a) RLS e política por linha nas quatro tabelas da lista TABELAS_DO_PERFIL (usuario, perfil_aluno, perfil_profissional, plano_plataforma confirmada), nenhuma citando mfit.pode_ler_aluno; (b) o tipo composto com exatamente os quatro atributos, por igualdade de conjunto nominal, nunca por ausência dos oito; (c) varredura estática de server/src proibindo SELECT direto nas três tabelas fora de uma lista autorizada e nominal; (d) os oito campos privados de D.2 (telefone, nascimento, sexo, altura_cm, identificador_publico, plano, status_acesso, email), mais senha_hash e biografia, ausentes da resposta HTTP real. Placar impresso: 4 tabelas do perfil = 3 ligadas em {F1-19} + 1 confirmada em {F1-13}; 4 campos públicos + 8 campos privados nominados negados; 9 caminhos sem claim = 6 por função definer + 2 por promoção de claim + 1 por política existente.
Estado: entregue em {F1-19} (2026-09-13): tipo composto, função de leitura reduzida, cinco funções definer estreitas, dez políticas nas três tabelas, três REVOKE DELETE, rota GET /api/perfil/:usuarioId com o ramo do Administrador auditado, quarto placar do verificador, oitava seção do gabarito ("Perfil público reduzido"). Não fecha {TA-06} (nota em {TA-06}, R-3): o placar N de 36 do isolamento de dados de aluno não se move, porque usuario, perfil_aluno e perfil_profissional não estão entre as dezoito entidades de E.1. Nota ({F2-05}): a sexta função SECURITY DEFINER estreita, mfit.usuario_por_identificador_publico, nasceu em {F2-05}; ela roda COM claim de sessão (o profissional autenticado), então o placar 9 caminhos sem claim desta ficha não se move. Nota (gate {F2-09}, Drift 3, 2026-09-14): o comentário desta função no banco e o do módulo no servidor afirmam ponto único, mas nenhum critério mede isso: o critério (c) do quarto placar varre server/src por citação das três tabelas do perfil, nunca por chamada da função, então um segundo chamador passaria calado por todos os verificadores, pela suíte inteira e pelos três gates. {F2-09} precisa do segundo chamador (a listagem global resolve as duas pontas de cada linha por junção lateral com mfit.perfil_publico, numa consulta só, sem citar nenhuma das três tabelas, em vez de resolver uma ponta por chamada dentro de um laço), e por isso a afirmação deixa de ser caneta e passa a ser medida, em duas peças: (1) critério novo no quarto placar varrendo server/src por chamada de mfit.perfil_publico, com lista nominal autorizada de DOIS arquivos (o ponto único do servidor e a listagem administrativa de vínculos), excluindo os arnês e o próprio verificador, com lado positivo obrigatório, um trecho fabricado que ele tem de reprovar e um que tem de aceitar; (2) o comentário da função reescrito na migração seguinte, dizendo o que passa a ser verdade, que o ponto único da FORMA HTTP continua sendo o módulo do servidor e que existe um segundo chamador, em SQL, na listagem administrativa, nominal e medido pelo critério novo. O que não muda: campo privado não cabe no tipo de retorno de quatro atributos, então o segundo chamador não amplia o que D.2 permite ver; o que ele amplia é o número de lugares que montam a forma reduzida, e é disso que o critério novo passa a cuidar. O placar 9 caminhos sem claim continua inalterado, porque a listagem roda com claim de sessão do Administrador. Fechamento [2026-09-14]: o segundo chamador está em produção (server/src/rotas/admin/vinculos.ts), a lista nominal autorizada do critério novo tem exatamente dois arquivos, e o COMMENT ON FUNCTION mfit.perfil_publico(uuid) foi reescrito na migração 0024_gestao_global_de_vinculos.sql, dizendo o que passa a ser verdade: ponto único da forma HTTP continua em acesso/perfilPublico.ts, e existe um segundo chamador, em SQL, na listagem administrativa. A afirmação de ponto único deixou de ser caneta. Nota de decisão declarada (gate {F3-01}, 2026-09-14): {F3-01} traz o TERCEIRO chamador de mfit.perfil_publico, porque a lista de fichas do aluno e o detalhe da ficha exibem o nome do autor, e a regra da casa proíbe SELECT próprio nas três tabelas do perfil. A lista nominal autorizada do critério (d) passa de dois para três arquivos, e a trava síncrona de cardinalidade passa de 2 para 3 no mesmo commit, junto do comentário da função reescrito para dizer o que passa a ser verdade. A trava recusar carregar com três entradas até alguém atualizar o número é o comportamento desejado, não um obstáculo: ampliar a lista é uma DECISÃO, nunca um efeito colateral. O que não muda: o tipo de retorno tem exatamente quatro atributos, então campo privado de D.2 não cabe nele e o terceiro chamador não amplia o que se pode ver, só o número de lugares que montam a forma reduzida. O placar 9 caminhos sem claim segue inalterado, porque as duas telas rodam com claim de sessão. Fechamento [2026-09-14]: o terceiro chamador está em produção (server/src/fichas/fichas.ts, merge 17bd22e), a lista nominal autorizada do critério (d) tem exatamente três arquivos, a trava síncrona recusa carregar com número diferente de 3, e o COMMENT ON FUNCTION mfit.perfil_publico(uuid) foi reescrito na migração 0025_ficha_de_treino.sql. Placar impresso pelo qa: chamadores nominais 3 de 3. Nenhum campo privado no retorno, LEFT preservado (autor que não resolva aparece com nome nulo, nunca some da lista).
Nota (gate {F3-02}, 2026-09-14): {F3-02} consome a leitura reduzida pelos chamadores que já existem e não acrescenta um quarto. Quem lê o nome do autor da ficha continua sendo o módulo de fichas, pela mesma junção lateral escrita em {F3-01}, e a obrigação da Nota R-4 do roadmap (consumir a leitura reduzida, nunca um SELECT próprio) é cumprida sem tocar em nada. A lista nominal de chamadores autorizados continua em três.
Fechamento [2026-09-14]: confirmado inalterado. Em produção (3d25e27), nenhum quarto chamador nasceu. Lista nominal continua em três.
Para que serve: decidir, na camada de dados, se a escrita de um vínculo em estado ativo respeita o limite do plano do aluno titular, e traduzir a recusa numa mensagem que nomeia o limite e o plano que o amplia.
Relacionado com: RF-PLAN-003, RF-VINC-002 a 004, L.1, ADR-012, ADR-013; tarefa {F1-15}; ART-ACS-07 (o auxiliar de acesso, ao lado do qual este entra na conjunção, nunca fundido), ART-ACS-09 (o auxiliar de consentimento, mesma disciplina de auxiliar único por pergunta), ART-SM-01 (a máquina de estados que a guarda governa), ART-ENT-02 (a tabela vinculo de que o auxiliar depende).
Onde fica: banco de dados, quatro funções empilhadas mais uma de apoio, chamadas pelas políticas de escrita de mfit.vinculo e pela rota GET /api/meu-plano; servidor de aplicação, tradutor único server/src/planos/negacaoDeEscrita.ts.
Especificação: quatro funções empilhadas, cada uma com um trabalho só, mais uma de apoio: mfit.limite_do_aluno(aluno_id, dimensao) lê o limite do plano, existente desde {F1-13}; mfit.dentro_do_limite(aluno_id, dimensao, contagem) compara contagem contra limite, nulo é ilimitado, existente desde {F1-13}; mfit.consumo_do_aluno(aluno_id, dimensao, ignorar_id) conta, com SECURITY DEFINER, existente desde {F1-16}; mfit.dentro_do_limite_do_aluno(aluno_id, dimensao, ignorar_id) decide, devolvendo verdadeiro antes de chamar consumo_do_aluno quando a dimensão é ilimitada, e chamando as outras três para as demais decisões. A contagem saiu do decisor para consumo_do_aluno em {F1-16} porque a tela do plano precisa do número e o decisor devolve um booleano, e duplicar o CASE na rota seria o defeito que a Nota do card manda evitar; consumo_do_aluno não decide acesso nenhum e nunca entra num WITH CHECK diretamente, quem entra na política continua sendo dentro_do_limite_do_aluno. Mais mfit.plano_que_amplia(aluno_id, dimensao), que devolve o primeiro plano ativo cuja coluna da dimensão é maior que o limite atual ou nula, por ordem de limite crescente com nulo por último, depois valor de referência crescente com nulo por último, depois nome. A conjunção de limite entra só no WITH CHECK das duas políticas de escrita de mfit.vinculo, guardada por estado = 'ativo', nunca em pendente, recusado, cancelado ou inativo, e excluindo a própria linha por id. Nunca se funde com mfit.pode_ler_aluno, mfit.tem_consentimento nem mfit.autor_com_acesso_ativo: cada auxiliar responde uma pergunta só, acesso, consentimento ou limite, e um auxiliar fundido devolveria um "falso" que não diz qual pergunta negou. O tradutor único negacaoDeEscrita.ts transforma o erro de permissão do banco em resposta nomeada, perguntando acesso antes de limite (ordem de RF-PLAN-003), envolto em SAVEPOINT porque o erro aborta a transação da requisição. Gabarito: seção "Limite de plano por dimensão" em db/migrations/GABARITO-ACESSO-ALUNO.md, aplicada por toda tabela que materializa uma dimensão ao nascer, acrescentando o ramo dela ao CASE de dentro_do_limite_do_aluno; dimensão sem ramo levanta exceção, nunca aprova em silêncio. Placar impresso: 1 servida + 3 pendentes de tabela + 1 pendente de forma + 1 fora do universo de escrita = 6, as seis dimensões de L.1.
Nota ({F2-06}): o aceite entra como segundo caminho de escrita a acionar este auxiliar dentro de SAVEPOINT, ao lado do de {F2-05}; a recusa passa pelo mesmo tradutor mas nunca aciona a conjunção de limite, porque a guarda estado <> 'ativo' da política a exclui por construção, controle negativo provado no arnês do H1 de {F2-06}. Placar de dimensões inalterado, 6.
Nota (Inspeção, gate {F5-04}, Drift 10, 2026-10-06): a dimensão de espaço de armazenamento de anexos ganha o ramo no CASE de mfit.consumo_do_aluno em {F5-04}, a entregar: a soma de anexo_bytes dos exames do aluno, em megabytes arredondados para cima (a foto de progresso entra em {F5-08}); o exame desativado segue na soma, porque o objeto continua no repositório. A política de inserção do exame usa a forma genérica, consumo anterior menor que o limite, como as demais dimensões; a soma com o anexo novo é decidida pelo servidor ANTES de gravar o objeto, com a mensagem de limite existente, porque a política não conhece os bytes de um arquivo que ainda não foi gravado. mfit.dentro_do_limite_do_aluno não muda e nenhum auxiliar novo nasce. A tela /plano passa a exibir a dimensão sozinha, sem linha de código de front. O cartão continua [x].
Fechamento [2026-10-06] de {F5-04}: o ramo anexos_megabytes está em mfit.consumo_do_aluno em produção (migração 0059, merge b078e76): soma de anexo_bytes de toda linha do titular, ativa ou desativada, em megabytes arredondados para cima; os três ramos antigos, a assinatura e a mensagem do ELSE ficaram idênticos (provado no aborto da migração). A política do exame usa a forma genérica e o servidor decide a soma com o anexo novo antes de gravar o objeto. Provado em produção no plano Gratuito (100 megabytes): cinco envios de 20 MiB fecham 100 de 100, o sexto recebe 409 com a mensagem de limite, e o exame desativado segue na cota (21 megabytes antes e depois). Lacuna declarada: a soma com o anexo novo arredonda duas vezes e pode recusar um arquivo que caberia por até 1 megabyte (desvio 4 declarado, aceitável; documentar na tela do plano). mfit.dentro_do_limite_do_aluno não mudou e nenhum auxiliar nasceu. O cartão continua [x].
Para que serve: responder quem alterou o quê, quando e a partir de qual valor.
Relacionado com: RF-CORE-009, RF-CORE-007, RF-CORE-004, D.5; tarefas F1-06, F1-09 e F1-11.
Onde fica: tabela auditoria e tela /admin/auditoria.
Especificação: eventos registrados, nominalmente: criação, alteração, desativação e exclusão em cada uma das dezesseis entidades de dado de aluno; mudança de papel, de especialidade, de plano, de status de acesso, de bloqueio administrativo e de estado de vínculo; concessão e revogação de consentimento; aceite dos termos com a versão; conexão e desconexão de serviço de atividade, sem jamais registrar a credencial; baixa e estorno de competência de cobrança; acesso administrativo a categoria sensível; entrada e falha de autenticação; exportação de dados do titular. Campos de cada evento: autor, papel do autor, ação, entidade, identificador, aluno quando houver, campo, valor anterior, valor novo, endereço de origem, momento e, quando a escrita aconteceu sob personificação, o par personificador e personificado. Eventos acrescentados em 2026-09-15: início e fim de personificação (RF-CORE-014), este último com o motivo do fim. Imutabilidade: tabela apenas acrescida, sem permissão de atualização nem de remoção para nenhum papel. Retenção: cinco anos. Quem consulta: apenas o Super Administrador; o Administrador produz entradas e não lê a trilha (RF-CORE-009). Filtros: autor, entidade, aluno, tipo de ação e período. O que "sem permissão de atualização nem de remoção para nenhum papel" significa na implementação: os três papéis do produto são servidos por um único papel de banco (mfit_app), portanto a revogação é feita nele e a negação alcança os três sem exceção; o dono do esquema (mfit_admin), que não é papel de produto e não atende requisição nenhuma, atravessa por desenho, e é por ele que a rotina de retenção de cinco anos da Fase 8 vai poder expurgar.
Fechamento [2026-09-29] de {AUD-05}: as duas classes de evento novas, personificar_inicio e personificar_fim, existem no tipo de ação em produção e gravam nos dois desfechos, com o par personificador e personificado; a tela /admin/auditoria as rotula e mostra o par. Placar de classes de evento: de seis para oito. Continua aberta a lista nominal restante da ficha.
Estado: entregues em F1-11: REVOKE UPDATE, DELETE em mfit_app nas duas tabelas (auditoria e aceite_termos), RLS de leitura restrita ao Administrador em auditoria mantendo a inserção livre, rota e tela /admin/auditoria com os filtros autor, entidade e período mais o destaque de acesso administrativo, e o verificador por catálogo com prova negativa. O registro automático de alteração nas três tabelas de perfil (usuario, perfil_aluno, perfil_profissional), com autor, campo, valor anterior e valor novo, nasce em F1-06 (RF-CORE-004). Continua aberta: a lista nominal de eventos registrados da ficha (criação em cada entidade, consentimento, cobrança, integração, entrada e falha de autenticação, exportação), nenhum desses nasce em F1-11. Placar: cinco classes de evento gravando hoje (alteração, desativação, exclusão, acesso administrativo, concessão e revogação de consentimento), as demais nos cards donos. Concessão e revogação de consentimento entregues em {F1-12}: a revogação usa mfit.auditar_remocao() de {F1-10} sem alteração (ação desativar, transição de revogado_em deixando de ser nulo); a concessão usa mfit.auditar_criacao(), genérica, que nasce em {F1-12} e é aplicada hoje a uma única tabela (consentimento). A ação criar das dezesseis entidades de dado de aluno de RF-CORE-006 continua 0 servidas + 16 pendentes = 16, nos cards donos; consentimento não pertence a esse universo e por isso não entra naquele placar. plano_plataforma também não pertence a esse universo, por não ser dado de aluno; entra como entidade administrativa própria, servida por {F1-13}, com aritmética separada: criação por mfit.auditar_criacao() sem argumento, e alteração por mfit.auditar_alteracao() generalizada, cobrindo hoje 1 de 1 entidade administrativa (plano_plataforma). Desativação não tem gatilho próprio: é uma alteração da coluna ativo e já aparece na trilha com valor anterior e valor novo, mais informação do que uma linha desativar sem campo. Fechamento [2026-09-14] de {F2-06}: gatilho auditar_transicao_vinculo, AFTER UPDATE OF estado ... WHEN (OLD.estado IS DISTINCT FROM NEW.estado AND NEW.estado <> 'inativo'), grava a transição de vínculo como alterar, sem valor de enum novo, campo = 'estado', valor_anterior e valor_novo corretos, aluno_id preenchido; controle negativo provado, o encerramento continua gerando uma linha só (desativar), nunca duas. Placar de classes de evento sobe para seis (soma mudança de estado de vínculo às cinco já gravando: alteração, desativação, exclusão, acesso administrativo, concessão e revogação de consentimento). Fechamento [2026-09-14] de {F2-07}: nenhum gatilho de auditoria novo. O encerramento (ativo para inativo) continua caindo na classe desativar de {F1-10}; o cancelamento (pendente para cancelado) cai na classe alterar de {F2-06}, mesmo critério da transição do aluno. Controle provado no arnês: encerrar gera uma linha (desativar), cancelar gera uma (alterar), nunca duas nem zero. Placar de classes de evento inalterado em seis; nenhum valor de enum novo. Nota (gate {F2-09}, 2026-09-14): desativar, cancelar e excluir pelo Administrador caem nas mesmas classes já gravando desde {F1-10}/{F2-06}; nenhum gatilho novo, nenhum valor de enum novo. A leitura da listagem global não gera trilha (mesmo critério de {ART-AUD-02}: mfit.vinculo não é uma das seis entidades sensíveis de RN-001). Placar de classes de evento inalterado em seis.
Nota (gate {F3-03}, Drift 6, 2026-09-14): correção de fato publicado, com o registro anterior preservado inteiro. A Nota do gate {F3-01} acima afirma que a criação da ficha cai em criar e que a trilha grava autor e momento pelo gatilho genérico, e a Nota do gate {F3-02} repete que a criação de ficha já audita pela classe que {F3-01} usou. Medido no banco em 14/09/2026, tabela por tabela pelo catálogo: não existe gatilho de auditoria de criação nem de alteração em mfit.ficha_treino nem em mfit.ficha_item. As duas frases descreviam a intenção do card e não o estado do banco, e o placar da classe criar escrito acima (0 servidas + 16 pendentes = 16) sempre esteve certo e contradizia as duas, que é a assinatura clássica de frase escrita a partir da intenção e não da medição. A consequência não é cosmética: hoje, quem perguntar quem criou uma ficha e quando depende da coluna da própria linha, que some no dia em que o Administrador excluir a ficha em definitivo, porque a linha de exclusão não carrega conteúdo por decisão de {F1-10}. A correção é no banco, não no texto: {F3-03} instala em 0026 os gatilhos de criação e de alteração das duas tabelas, com guarda que impede a linha dobrada quando a mudança é de estado. Enquanto a migração não estiver em produção as duas frases acima valem lidas como intenção, e o placar da classe criar permanece 0 servidas + 16 pendentes = 16; no fechamento de {F3-03} ele passa a 1 servida + 15 pendentes = 16, nunca antes de o gatilho existir. Registro honesto, e ele proíbe uma afirmação: a função genérica de alteração não grava o titular, e o comentário da própria coluna declara isso desde {F1-09}; portanto o filtro por aluno de /admin/auditoria não alcança as linhas de alteração, nem as desta ficha. Isto NÃO se conserta em {F3-03}, porque a função é compartilhada por cinco gatilhos em produção e mudar a assinatura dela aqui alteraria em silêncio a trilha de outras cinco entidades, que é regressão com gates verdes. Fica como pendência nominal sem card dono, e nenhum documento desta família pode afirmar que a edição da ficha é filtrável por aluno na trilha. Critério de verificador novo declarado por {F3-03}: quem pode ser alterado e quem audita alteração, com universo por catálogo (toda tabela com política de alteração, hoje nove) e exceções por lista nominal fechada de duas (vinculo, pelo gatilho de transição, e consentimento, pelo gatilho de remoção na revogação), com trava de cardinalidade que recusa carregar se a lista crescer sem decisão. Placar hoje 5 servidas + 2 declaradas + 2 pendentes = 9; ao fim de {F3-03}, 7 servidas + 2 declaradas = 9 de 9. Placar de classes de evento inalterado em seis.
Fechamento [2026-09-14] de {F3-03}: confirmado em produção (migração 0026, merge 76bc9cd). Os gatilhos de criação e de alteração de mfit.ficha_treino e mfit.ficha_item existem, com guarda contra linha dobrada na transição de estado. Placar da classe criar das dezesseis entidades de RF-CORE-006 passa de 0 servidas + 16 pendentes para 1 servida + 15 pendentes = 16. Critério de tabela alterável com auditoria de alteração fecha 7 servidas + 2 declaradas = 9 de 9. A divergência apontada na Nota do Drift 6 está corrigida em {F3-03}: as frases dos gates {F3-01} e {F3-02} agora correspondem ao banco. Placar de classes de evento inalterado em seis.
Nota (gate {F3-01}, 2026-09-14): nenhuma classe de evento nova. A criação da ficha cai em criar e a desativação (status para inativo) cai em desativar, ambas já existentes desde {F1-10}; a trilha grava autor e momento pelo gatilho genérico, sem coluna nova na tabela (D-1). Placar de classes de evento inalterado em seis. Nota (gate {F3-02}, 2026-09-14): nenhuma classe de evento nasce aqui. A criação de ficha já audita pela classe que {F3-01} usou, e a autoria do aluno é escrita pela mesma rota, com o mesmo registro. Placar inalterado, seis classes.
Fechamento [2026-09-14]: confirmado inalterado. Em produção (3d25e27), a criação de ficha pelo aluno audita pela mesma classe já existente. Placar continua seis classes.
Nota (gate {F3-04}, 2026-09-14): mfit.solicitacao_ficha nasce em {F3-04} com os três gatilhos genéricos de trilha (criação, alteração e remoção), sem nenhuma função de gatilho nova e sem nenhuma classe de evento nova: as classes continuam seis, e as três genéricas que já servem as tabelas em produção não são tocadas. Ela entra sozinha no critério de alteração auditada que {F3-03} instalou, que enumera por catálogo toda tabela do esquema com política de atualização, e por isso o universo daquele critério passa de nove para dez tabelas; o placar só se move no fechamento de {F3-04}, medido no dia, nunca projetado aqui. Este é o primeiro card em que aquele critério varre uma tabela que nasceu depois dele, e é a prova de que ele é exaustivo por construção. O placar da classe de criação das dezesseis entidades de RF-CORE-006 NÃO muda, porque a solicitação não é uma das dezesseis, pelo mesmo critério já escrito em {ART-ACS-07}. Registro honesto, herdado de {F3-03} e que continua valendo: a função genérica de alteração não grava o titular, então o filtro por aluno da tela de auditoria não alcança as linhas de alteração, também as desta tabela; continua pendência nominal sem card dono, e nenhum documento desta família afirma que a solicitação é filtrável por aluno na trilha.
Fechamento [2026-09-14]: os três gatilhos genéricos de trilha em produção em solicitacao_ficha (migração 0027, merge 8f0f9fd), sem função nova e sem classe de evento nova. O critério de alteração auditada fecha em 10 de 10 tabelas (nove mais esta). O placar da classe criar das dezesseis entidades de RF-CORE-006 continua inalterado, a solicitação não é uma das dezesseis.
Nota (gate {F3-05}, 2026-09-14): sessao_treino e sessao_serie nascem com os gatilhos genéricos de trilha, sem nenhuma função de gatilho nova e sem nenhuma classe de evento nova: as classes continuam seis, e as genéricas que já servem as tabelas em produção não são tocadas. As duas entram no critério de alteração auditada que {F3-03} instalou, que enumera por catálogo toda tabela do esquema com política de atualização, e por isso o universo daquele critério passa de dez para doze tabelas. O placar da classe criar das dezesseis entidades de RF-CORE-006 também se move, porque sessao_treino é uma das dezesseis. Os dois placares só se movem no fechamento, medidos no dia, nunca projetados aqui.
Fechamento [2026-09-15]: os gatilhos genéricos de trilha em produção em sessao_treino e sessao_serie (migração 0028, merge 80c103e), sem função nova e sem classe de evento nova. O critério de alteração auditada fecha em 12 de 12 tabelas (dez mais estas duas). O placar da classe criar das dezesseis entidades de RF-CORE-006 sobe, sessao_treino entra como uma das dezesseis. Placar de classes de evento inalterado em seis.
Nota (gate {AUD-03}, 2026-09-15): o comando ops/limpar-contas-de-teste grava, na mesma transação da remoção, uma entrada excluir por conta removida, origem ops/limpar-contas-de-teste; a ação excluir já existe no enum de auditoria desde a migração 0010, então nenhuma classe de evento nasce aqui. Duas entradas gravadas na execução real (contas inspecao-qa-20260906 e inspecao-visual-20260907; as demais nomeadas no card já não existiam). Placar de classes de evento inalterado em seis.
Para que serve: ser o único caminho pelo qual qualquer rota do servidor lê uma das seis entidades sensíveis de RN-001, registrando o acesso administrativo cross-unidade na mesma transação da leitura.
Relacionado com: RF-CORE-007, D.5, ADR-013; tarefa F1-09; ART-ENT-01 (coluna aluno_id da trilha), ART-AUD-01 (a trilha).
Onde fica: servidor de aplicação, server/src/acesso/leituraSensivel.ts, chamado por toda rota que sirva uma das seis entidades sensíveis.
Especificação: assinatura lerRegistroSensivel({ client, claims, entidade, id }): Promise<Registro | null>. Condição que dispara o registro: claims.papel === 'administrador' e claims.sub diferente do titular da linha lida; titular, profissional vinculado e profissional autor não geram entrada. Garantia de transação única: o registro e a leitura ocorrem na mesma transação já aberta por sessaoAtual; se a inserção da auditoria falhar, a leitura não é servida (rollback). Coluna a coluna da linha gravada: autor_id recebe claims.sub, autor_papel recebe claims.papel, acao recebe acesso_administrativo, entidade recebe o nome da tabela, entidade_id recebe o id do registro lido, aluno_id recebe o titular do registro, campo, valor_anterior e valor_novo ficam nulos (leitura não copia conteúdo clínico para a trilha), origem vem de current_setting('mfit.origem'), momento vem de now(). Arquivo: a emissão de endereço assinado de foto_progresso passa pelo mesmo leitor, e o registro acontece na emissão, não no download. O que ele NÃO decide: acesso (isso é mfit.pode_ler_aluno), consentimento, escrita, listagem. Verificador ops/verifica-leitura-sensivel.mjs: reprova toda ocorrência do nome de tabela sensível em SQL fora deste arquivo; confere nominalmente as seis entidades de RN-001, cobertas ou pendentes por card dono; reprova entrada acesso_administrativo com aluno_id nulo ou emissão de endereço assinado de arquivo sensível fora do leitor; imprime a aritmética servidas + pendentes = 6.
Estado: entregue em F1-09. O leitor, a marcação sensivel e o verificador nascem em {F1-09}, cobrindo hoje 0 das 6 entidades sensíveis (nenhuma existe ainda); cada uma nasce já servida pelo leitor no card dela (Fase 5), até fechar em 6 de 6.
Nota (Inspeção, {AUD-11}, drift 1, 2026-09-30): o universo deste leitor passa de seis para dez entidades sensíveis (as seis de saúde, medida_corporal, refeicao, meta_nutricional e plano_alimentar), e as duas frases da ficha ficam ampliadas. Onde fica passa a ser server/src/acesso/leituraSensivel.ts, ou o ponto único do módulo declarado em leitorUnico, que chama registrarSeAdministrativo. Especificação: cada entidade sensível declara o seu leitor, no campo leitorUnico (caminho relativo a server/src) da lista única ENTIDADES_E1, não nulo exatamente nas entidades sensíveis: acesso/leituraSensivel.ts para as seis de saúde, para medida_corporal e, provisoriamente, para plano_alimentar ({F4-03} declara o seu); refeicoes/refeicoes.ts para refeicao e metas/metas.ts para meta_nutricional. Todo leitor declarado que não seja acesso/leituraSensivel.ts chama registrarSeAdministrativo( com o nome da entidade, de modo que a auditoria de leitura administrativa (RF-CORE-007) segue na mesma transação da leitura. O verificador ops/verifica-leitura-sensivel.mjs troca a regra "toda ocorrência do nome de tabela sensível fora deste arquivo reprova" por duas: (a) ocorrência de mfit.<tabela> em arquivo .ts de produção fora do leitorUnico DAQUELA entidade reprova; (a2) leitor declarado que não seja leituraSensivel.ts e não contenha registrarSeAdministrativo( e o nome da entidade reprova. Arquivos .test.ts saem do universo (fixture não serve leitura a usuário), o que se compensa com o critério positivo (a2) e com decoy (mfit.refeicao em arquivo de produção fora do leitor reprova; leitor declarado sem a chamada reprova). Motivo: sem esta declaração, marcar refeicao e meta_nutricional como sensíveis reprovaria os dois pontos únicos de módulo de {F4-01} e {F4-02} e cerca de oitenta linhas de fixture. Placar impresso pelo verificador, sem número escrito à mão: servidas + pendentes = 10, hoje 0 de 10, e 2 de 10 quando {AUD-11} entregar (refeicao e meta_nutricional); e, dos leitores de módulo, 2 de 2 com registrarSeAdministrativo. Isenção dos testes (gate modularfit-AUD-11, Drift 1, 2026-09-30): arquivos .test.ts ficam isentos do critério (a) do leitor único, e a isenção vale para as dez entidades sensíveis, não só para as duas de nutrição. Texto do gate: "Arquivos *.test.ts saem do universo (fixture não serve leitura a usuário)". Motivo medido no gate (M-8 e M-9): o critério (a) de {F1-09} reprovava toda ocorrência de mfit.<tabela sensível> em qualquer .ts de server/src, testes inclusos, fora de acesso/leituraSensivel.ts; as ocorrências de mfit.refeicao e mfit.meta_nutricional são 9 nos pontos únicos refeicoes.ts e metas.ts mais cerca de oitenta em 16 arquivos .test.ts, e a fixture de teste semeia e confere dado, não serve leitura a usuário. A isenção cobre somente o critério (a): o critério (a2) segue valendo para todo leitor declarado, e a compensação do gate (R-5) é o critério positivo (a2) mais o decoy (mfit.refeicao em arquivo de produção fora do leitor reprova; leitor declarado sem a chamada reprova).
Fechamento [2026-09-30] de {AUD-11}: placar do leitor único 2 de 10 servidas (2 servidas mais 8 pendentes igual 10): refeicao por refeicoes/refeicoes.ts e meta_nutricional por metas/metas.ts, cada uma chamando registrarSeAdministrativo com o nome da entidade (critério (a2), 2 de 2 leitores de módulo). O campo leitorUnico está nas 10 entidades sensíveis e nulo nas demais, com as travas de carga 10, 10 e leitorUnico igual a sensível, entidade a entidade. Os arquivos *.test.ts saíram do universo do critério (a), compensados por (a2) e por decoys nos dois sentidos. Em produção o Super lê as duas entidades com 200 e a trilha grava a entrada na mesma leitura (+4 entradas), e o Administrador segue com 403 nomeado. O cartão permanece [x].
Nota de conjunto (onda AUD, {AUD-04}, 2026-09-15; atualizada em 2026-09-29 por {AUD-06}, que acrescenta /admin/parametros, escrita do Super Administrador e leitura do Administrador, e leva as rotas de administração de nove para dez: 7 mais 1 mais 2 igual a 10): as nove rotas de administração deixam de servir um papel só. Sete servem aos dois papéis (/admin, /admin/usuarios, /admin/exercicios, /admin/vinculos, /admin/relatorios, /admin/guia e /admin/textos), uma serve apenas ao Super Administrador (/admin/auditoria) e uma tem escrita do Super Administrador e leitura do Administrador (/admin/planos): 7 mais 1 mais 1 igual a 9, fechando o universo. Nenhuma rota nova nasce, e por isso nenhum placar de tela se move. A faixa de personificação de {ART-ACS-13} é cromática do topo de toda tela, como a central de notificações, e também não é rota. O que muda em cada cartão de tela é a coluna de papéis, reconciliada no Apêndice de catálogo de telas do DRS na mesma republicação. Exceção nominal (onda AUD, {AUD-05}, 2026-09-15): a frase acima, sobre nenhum placar de tela se mover, foi escrita para {AUD-04} e continua valendo letra por letra para ele. Ela NÃO alcança {AUD-05}: decidido o ponto de entrada da personificação, a rota /admin/usuarios nasce mínima naquele card, com uma única ação, e o placar de {ART-SCR-03} sobe de 5 de 8 para 6 de 8 quando {AUD-05} entregar. Esta é a única exceção da onda e ela é nominal: nenhum outro cartão de tela se move, e a faixa de personificação continua sem pertencer a cartão de tela nenhum.
Nota de conjunto (onda AUD, {AUD-07}, 2026-09-29): /admin/listas acrescenta uma rota sobre o que {AUD-06} publicou, escrita do Super Administrador e leitura do Administrador, e leva as rotas de administração de dez para onze: sete servem aos dois papéis, uma serve apenas ao Super Administrador (/admin/auditoria) e três têm escrita do Super Administrador e leitura do Administrador (/admin/planos, /admin/parametros e /admin/listas): 7 mais 1 mais 3 igual a 11. O catálogo de telas do DRS passa a 41 linhas e 39 rotas (a nota de {AUD-06} dizia 40 e 38). A seção B.1 do DRS continua em oito capacidades privativas, porque manter as listas e manter o catálogo de parâmetros de operação (RF-PAIN-011) são a mesma capacidade, e a Matriz Ator por Capacidade não ganha linha.
Máquinas de estado
Para que serve: governar quando o profissional passa a enxergar e deixa de enxergar o aluno.
Relacionado com: RF-VINC-001 a 004; tarefas F2-05 a F2-08.
Onde fica: coluna vinculo.estado e as regras de transição no servidor.
Especificação: tabela de transições do bloco E.3 do DRS. Estado inicial pendente; terminais recusado, cancelado e inativo; transições proibidas: pendente direto para inativo e ativo de volta para pendente. Guarda de entrada em pendente: não existir vínculo ativo nem pendente entre aquele profissional e aquele aluno. Guarda de entrada em ativo: limite de vínculos do plano do aluno não excedido, guarda que passa a existir na camada de dados em {F1-15}, no WITH CHECK das duas políticas de escrita de mfit.vinculo (ART-ACS-10); {F2-06} não a reimplementa no servidor, a máquina de estados dele confia na política e chama o tradutor único de {F1-15} para produzir a mensagem, sem uma segunda verificação no tratador. A especialidade não é guarda de transição nenhuma. Efeito colateral de cada transição: notificação conforme a lista nominal do bloco M.1 do DRS (nem toda transição notifica as duas partes; o cancelamento notifica só o aluno), e revogação imediata do acesso corrente quando sai de ativo.
Estado: medido em 14/09/2026 (gate {F2-07}). O caminho de escrita que leva ativo a inativo já existe desde {F1-10} (desativarVinculo, em server/src/rotas/vinculo.ts), mas hoje não respeita esta tabela: o UPDATE é WHERE id = $1 AND estado <> 'inativo', então um vínculo pendente vira inativo com 204, produzindo a transição proibida pendente para inativo direto. A validação da tabela de transições como lista única, por gatilho BEFORE UPDATE na origem, nasce em {F2-07}; até aqui o único controle era o WHERE de cada rota, isto é, exaustividade por disciplina, não por construção. O caminho de cancelamento (pendente para cancelado) também nasce em {F2-07}, hoje inexistente. Fechamento [2026-09-14] de {F2-06}: as duas transições do aluno passam a servida: true (pendente para ativo, pendente para recusado), guardadas pela política de {F1-15}/{ART-ACS-10} sem segunda verificação no tratador, como esta ficha já previa. Placar do décimo sexto verificador (ops/verifica-vinculo.mjs): 4 de 6 transições servidas (a prova de reconvite rodou), mais o lado negativo nomeado, as duas transições proibidas de E.3 e o caminho de escrita medido que as alcança hoje (POST /api/vinculos/:id/desativar), dono {F2-07}. pendente para cancelado, ativo para inativo e a validação da tabela inteira por gatilho BEFORE UPDATE continuam em {F2-07}. Fechamento [2026-09-14] de {F2-07}: gatilho mfit.validar_transicao_vinculo() (BEFORE UPDATE OF estado ... WHEN (OLD.estado IS DISTINCT FROM NEW.estado)) valida a tabela de E.3 como lista única na origem, nunca mais só pelo WHERE das rotas; pendente para cancelado (rota nova /cancelar) e ativo para inativo (/desativar consertado) passam a servida: true. Aritmética das seis transições de E.3: quatro por UPDATE servidas (pendente para ativo, pendente para recusado, pendente para cancelado, ativo para inativo) mais o reconvite inativo para pendente (linha nova, INSERT, não UPDATE) mais a entrada (inexistente) para pendente (o convite, INSERT) fecham 6 de 6. As duas proibidas (pendente para inativo direto, ativo para pendente) são recusadas na origem pelo gatilho, P0001, controle negativo provado no arnês encerramento.test.ts. Placar do décimo sexto verificador: 6 de 6 transições servidas, 6 de 6 transições notificando por construção (gatilhos 0021, 0022, 0023). Nota (gate {F2-08}, 2026-09-14): placar de transições inalterado, 6 de 6, este card não serve transição nenhuma; acrescenta a prova de que a especialidade não é guarda de transição nenhuma, critério (e) do mesmo verificador, universo de catálogo em mfit.vinculo. Nota (gate {F2-09}, 2026-09-14): placar de transições inalterado, 6 de 6, este card não serve transição nenhuma; prova, no arnês, que o filtro de listagem por especialidade não altera acesso (o vínculo escondido pelo filtro continua ativo e continua dando acesso), reforçando a mesma distinção entre filtro e guarda. Nota (gate {F3-01}, 2026-09-14): placar de transições inalterado, 6 de 6, este card não toca mfit.vinculo nem transição nenhuma; a ficha de treino é entidade nova, com máquina de estados própria e menor (ativo/inativo, D-1), sem gatilho BEFORE UPDATE de validação, porque E.3 não lhe atribui transição proibida nenhuma.
Nota (gate {F3-02}, 2026-09-14): nenhuma transição de vínculo é criada, alterada ou exercitada de forma nova. Este card entrega justamente o caminho que NÃO depende de vínculo (ADR-002, o aluno sem profissional monta a própria ficha), e o vínculo que o caso de teste cria depois usa as transições já fechadas em {F2-07}. Placar inalterado, 6 de 6.
Fechamento [2026-09-14]: confirmado inalterado. Em produção (3d25e27), nenhuma transição de vínculo nova. Placar continua 6 de 6.
Nota (gate {F3-03}, 2026-09-14): nenhuma transição de vínculo é criada, alterada ou exercitada de forma nova. O estado que {F3-03} passa a escrever é o da ficha (ativo e inativo), que é outro autômato, declarado em E.3 e coberto pelo cartão da própria entidade; o vínculo entra apenas como condição de leitura, pelas conjunções já escritas, e o segundo profissional vinculado ao mesmo aluno continua sendo recusado ao tentar editar a ficha do colega, que é a conjunção de {F2-08} preservada e provada por controle negativo. Placar inalterado, 6 de 6.
Fechamento [2026-09-14]: confirmado inalterado. Em produção (76bc9cd), nenhuma transição de vínculo nova; o autômato da ficha (ativo/inativo) ganha rotas de desativar e reativar. Placar continua 6 de 6.
Para que serve: manter o extrato do aluno e o total em aberto corretos.
Relacionado com: RF-COBR-002, RF-COBR-003; tarefas F8-02 e F8-03.
Onde fica: coluna competencia_cobranca.status.
Especificação: tabela de transições do bloco E.3 do DRS. Inicial em aberto; terminais paga e isenta; vencida é intermediário e reversível. O estorno de paga para em aberto exige registro na auditoria. Nenhuma transição altera o valor da competência.
Para que serve: distinguir treino em curso, concluído e abandonado, e o ciclo do pedido do aluno.
Relacionado com: RF-TREI-004, RF-TREI-005, RF-TREI-010; tarefas F3-04, F3-05 e F3-10.
Onde fica: colunas sessao_treino.status e solicitacao_ficha.estado.
Especificação: sessão: em andamento na abertura, com no máximo uma em andamento por aluno; retomável enquanto em andamento, carregando as séries do banco; concluída quando o aluno encerra com ao menos uma série registrada; abandonada quando encerra sem série, ou quando fica sem registro novo por mais tempo que o parâmetro sessao_abandono_horas, com valor inicial de vinte e quatro horas. Abandonada é terminal e não é oferecida para retomada. Apenas a concluída conta para sequência, calendário, conquistas e progressão. Solicitação: aberta na criação; atendida quando o autor vincula a ficha criada; recusada com motivo obrigatório. Solicitação atendida ou recusada não volta a aberta.
Nota (gate {F3-04}, Drift 4, 2026-09-14): a metade da solicitação deste cartão fecha em {F3-04} e a metade da sessão continua em {F3-05} e {F3-10}, e por isso o cartão continua [ ] com motivo escrito, no molde exato da Nota de {TA-24}, nunca [x] por metade e nunca [ ] mudo. A prosa da solicitação escrita aqui foi transcrita para o bloco E.3 do DRS nesta data, em tabela de origem, evento, destino e guarda, no mesmo formato das outras três máquinas de estado daquele bloco, sem acrescentar nada: este cartão não é editado porque já dizia tudo. O motivo de a tabela existir lá é que a guarda de transição do banco se escreve TRANSCREVENDO a tabela publicada, e não interpretando prosa de outro artefato; a diferença aparece no dia em que alguém perguntar por que uma transição é proibida e a resposta precisar ser um documento, não uma opinião. A obrigatoriedade do motivo da recusa vive na guarda de transição, nunca em coluna não nula, porque a coluna é legitimamente nula em aberta e em atendida.
Nota (gate {F3-05}, 2026-09-14): a metade da sessão deste cartão anda aqui e não fecha, e por isso ele continua [ ] com motivo escrito, no molde exato da Nota que {F3-04} deixou para a metade da solicitação. {F3-05} entrega a abertura em andamento com no máximo uma por aluno, garantida por índice único parcial; o encerramento decidindo entre concluída e abandonada pela contagem de séries registradas, num ponto único; e as transições proibidas recusadas pelo banco, nomeando origem e destino. Continuam em {F3-10} a retomada oferecida enquanto em andamento e a passagem automática a abandonada por falta de registro além do parâmetro sessao_abandono_horas, que {F3-05} não lê e não escreve. A regra de que apenas a concluída conta para sequência, calendário, conquistas e progressão é consumida por {F3-07} e por {F7-02} a {F7-05}, e nenhuma delas nasce aqui.
Fechamento [2026-09-15]: em produção (migração 0028, merge 80c103e), 3 de 5 transições de E.3 servidas por caminho alcançável: abrir em andamento com a guarda de sessão única; encerrar com série registrada para concluída; encerrar sem série para abandonada. As duas pendentes, retomar e a passagem automática por prazo, seguem nomeadas para {F3-10}. Este cartão continua [ ], porque a metade da sessão anda aqui e só fecha com {F3-10}, no mesmo molde da Nota que {F3-04} deixou para a solicitação.
Nota (gate {F3-10}, Drift 1, 2026-09-29): o gatilho distingue os dois eventos de E.3 que saem de em andamento: encerrar, decidido pelo resultado (contagem de séries), e prazo decorrido, cujo resultado é a própria guarda de tempo, avaliada no relógio do banco pelo escritor único (D-2); prazo decorrido leva a abandonada com qualquer número de séries.
Nota (gate {F3-10}, Drift 4, 2026-09-29): o evento prazo decorrido de E.3 tem executor, e nenhum deles é um {ART-JOB} nem um {ART-WF}. Quatro pontos preguiçosos de escrita (iniciar, registrar série, atualizar posição e encerrar, todos do aluno titular) passam a abandonada a sessão vencida de quem volta; a leitura por predicado garante que esse aluno nunca veja a sessão vencida como em andamento; e uma rotina de operação de hora em hora, uma linha de crontab e NÃO um {ART-JOB}, cobre quem nunca volta. A janela aberta é de até uma hora e vale só para leitores terceiros, porque o próprio aluno nunca a vê.
Fechamento [2026-09-29] de {F3-10}: em produção (migração 0042, merge 047f3bc), 5 de 5 transições de E.3 servidas por caminho alcançável: às três de {F3-05} somam-se retomar (atalho nas duas telas e leitura por predicado em GET /api/sessoes/atual, que responde 204 à sessão vencida sem escrever) e prazo decorrido (escrita preguiçosa nos quatro caminhos do titular mais a rotina horária de operação, sempre pelo escritor único da passagem a abandonada). A sessão com séries que passou do prazo termina abandonada e as séries deixam de contar; provado em produção pelo qa (34 critérios, 0 reprovações, P2 declarados no card). As duas metades do cartão, solicitação ({F3-04}) e sessão, estão fechadas: este cartão passa a [x].
Para que serve: governar a escrita de dado sensível e o acesso do aluno inativo.
Relacionado com: RF-CORE-010, RF-PLAN-002; tarefas F1-12 e F1-14.
Onde fica: tabela consentimento e coluna perfil_aluno.status_acesso.
Especificação: consentimento por categoria: ausente na origem, concedido com data e versão, revogado com data; concedido é a única condição que libera escrita, e revogar também retira a categoria da visibilidade dos profissionais. Reconceder cria um registro novo, sem apagar o anterior. Acesso do aluno: ativo libera tudo que o plano permite; inativo libera apenas perfil, plano e leitura do próprio histórico, com toda escrita negada; a transição é manual e exclusiva do administrador.
Estado: a metade do consentimento entregue em {F1-12}: os três estados implementados, "reconceder cria um registro novo, sem apagar o anterior" garantido por construção (unicidade parcial mais gatilho que só aceita a transição de revogado_em de nulo para preenchido, nunca de volta), "só concedido libera escrita" garantido pelo WITH CHECK, "revogar retira a categoria da visibilidade dos profissionais" garantido pela conjunção no USING. A metade do acesso do aluno (perfil_aluno.status_acesso, ativo e inativo) foi entregue em {F1-14}: a conjunção de acesso entra em consentimento_insercao e em consentimento_revogacao só dentro do WITH CHECK, nunca no USING, e o aluno inativo continua lendo os próprios consentimentos, e o profissional vinculado continua enxergando exatamente o que enxergava, porque nenhuma leitura foi tocada.
Automações
Para que serve: avisar o aluno de que alguém quer acompanhá-lo.
Relacionado com: RF-VINC-001; tarefa F2-05.
Onde fica: servidor de aplicação, ao criar o vínculo.
Especificação: gatilho, criação de vinculo com estado pendente. Condição, o aluno existe e está ativo. Passos, sem espera: criar notificação do tipo convite para o aluno com destino à tela de vínculos. Saída, notificação criada. Anti-duplicação, um convite pendente por par profissional e aluno; um segundo convite reaproveita o pendente. Falha, o vínculo é criado mesmo se a notificação falhar, e a falha é registrada.
Para que serve: avisar o profissional do aceite ou da recusa.
Relacionado com: RF-VINC-002; tarefa F2-06.
Onde fica: servidor de aplicação, na transição de estado do vínculo.
Especificação: gatilho, vinculo sai de pendente. Ramificação: aceito gera notificação de aceite e abre o acesso; recusado gera notificação de recusa e não abre nada. Saída, notificação ao profissional. Idempotência, a transição só ocorre uma vez a partir de pendente.
Para que serve: revogar o acesso corrente e avisar os dois lados.
Relacionado com: RF-VINC-003; tarefa F2-07.
Onde fica: servidor de aplicação.
Especificação: gatilho, vinculo passa a inativo. Passos: registrar quem encerrou e quando; revogar o acesso corrente do profissional; marcar a saída dele nas conversas daquele aluno; notificar as duas partes. Saída, acesso negado na consulta seguinte e histórico preservado. Falha, se a notificação falhar a revogação permanece.
Para que serve: alimentar engajamento e progressão a partir do treino executado.
Relacionado com: RF-TREI-005, RF-ENGA-002 a 005; tarefas F3-05, F7-02 a F7-05.
Onde fica: servidor de aplicação, ao encerrar a sessão.
Especificação: gatilho, sessao_treino passa a concluída. Condição, ao menos uma série registrada. Passos, sem espera: calcular duração e volume; atualizar a sequência de dias; marcar o dia no calendário; cumprir a progressão dos exercícios executados, que não é recalculada aqui nem gravada em lugar nenhum, porque é derivada na leitura, em ponto único, a partir das sessões concluídas, e o encerramento a cumpre por construção, ao fazer a sessão entrar no universo da derivação; avaliar os oito critérios de conquista. Ramificação, critério atingido e conquista ainda não concedida gera a concessão e a notificação. Idempotência, a concessão é impedida pela unicidade de aluno e conquista, e a sessão só transita uma vez para concluída.
Nota (gate {F3-05}, 2026-09-14): dos cinco passos deste fluxo, {F3-05} entrega dois, e o cartão continua [ ]. Entregues: calcular a duração e calcular o volume ao encerrar, no mesmo ponto único que decide o desfecho, com o volume somando apenas as séries que têm carga e repetições preenchidas e ignorando as séries por tempo, conforme RN-004. Pendentes, com dono nominal: atualizar a sequência de dias e marcar o dia no calendário são {F7-02} e {F7-03}; recalcular a progressão dos exercícios executados é RF-TREI-007 e {F3-07}; avaliar os oito critérios de conquista é {F7-04} e {F7-05}. A condição e a idempotência da especificação valem desde já: a sessão só transita uma vez para concluída, e o encerramento sem nenhuma série registrada leva a abandonada, nunca a concluída. Ausência é ausência: o que tem outro dono não nasce aqui como aviso na tela.
Fechamento [2026-09-15]: em produção (migração 0028, merge 80c103e), dois dos cinco passos entregues: calcular a duração e calcular o volume ao encerrar, no ponto único do gatilho, conforme RN-004. Os três restantes seguem pendentes com dono nominal: sequência e calendário são {F7-02} e {F7-03}; progressão de carga é {F3-07}; conquistas são {F7-04} e {F7-05}. Este cartão continua [ ].
Nota (gate {F3-07}, 2026-09-15): o passo 4 deste fluxo muda de forma, não de dono. "Recalcular a progressão", num fluxo disparado pelo encerramento e sem espera, é verbo de escrita, e não existe onde escrever: {ART-ENT-04} declara seis tabelas de treino, nominalmente, e nenhuma delas é de progressão. A progressão passa a ser derivada na leitura, em ponto único, a partir das sessões concluídas, e o encerramento a cumpre por construção, ao fazer a sessão entrar no universo da derivação, de modo que não há agregado a atualizar e, portanto, não há caminho novo que possa esquecer de atualizá-lo. Alternativa recusada, e a condição em que ela volta: agregado materializado, que criaria uma sétima tabela ou colunas novas contradizendo a especificação publicada de {ART-ENT-04}; ela só volta a ser examinada se a cláusula da tabela de riscos do DRS (crescimento do histórico de séries, com agregados pré-calculados nos painéis) for medida e exigir pré-cálculo, e nesse dia é card novo, nunca este. Aritmética: com {F3-07} entregue este cartão passa de 2 de 5 para 3 de 5 passos e continua [ ]; os dois restantes seguem com dono nominal, sequência de dias e calendário em {F7-02} e {F7-03}, conquistas em {F7-04} e {F7-05}. RN-004, {ART-ENT-04} e a especificação de entidades do DRS não são editadas: as três estão certas, e quem estava com o verbo errado era a Especificação deste fluxo.
Fechamento [2026-09-15]: em produção (merge c331286), a progressão passa a ser derivada na leitura por server/src/sessoes/progressao.ts, cumprindo o passo por construção. Placar sobe de 2 de 5 para 3 de 5 passos; cartão continua [ ], os dois restantes com dono nominal, sequência e calendário em {F7-02} e {F7-03}, conquistas em {F7-04} e {F7-05}.
Para que serve: fazer o pedido do aluno chegar e voltar.
Relacionado com: RF-TREI-004; tarefa F3-04.
Onde fica: servidor de aplicação.
Especificação: gatilho um, criação de solicitacao_ficha, notifica o profissional. Gatilho dois, ficha criada vinculada à solicitação, muda o estado para atendida e notifica o aluno com o destino da ficha. Gatilho três, recusa, exige motivo e notifica o aluno. Idempotência, uma solicitação só é atendida uma vez.
Nota (gate {F3-04}, Drift 10, 2026-09-14): o gatilho dois deste fluxo pendura no FATO, não no caminho. A especificação o escreve como "ficha criada vinculada à solicitação", e a jornada do Personal descreve o atendimento como "cria a ficha nova ou altera a que é dele vinculando a solicitação": são dois caminhos publicados, e se o aviso pendurasse na criação de ficha o segundo caminho notificaria ninguém. Leitura declarada, sem o cartão mudar de texto: o gatilho dois observa a transição da própria solicitação, o momento em que a ficha passa a estar vinculada e o estado vai a atendida, cobrindo por construção os dois caminhos publicados e qualquer terceiro que nasça depois. É o que ele sempre quis dizer. Os três avisos deste fluxo nascem em {F3-04} por gatilho na origem, em fila de correio eletrônico, no molde literal dos três avisos de vínculo que já estão em produção, com chave de evento garantindo que repetir o mesmo fato não gera segunda mensagem; a central de notificações com sino e contagem é outro artefato, {ART-NOT-01}, e continua em {F6-05}.
Fechamento [2026-09-14]: os três avisos em produção (migração 0027, merge 8f0f9fd), em fila de correio eletrônico por gatilho na origem, chave de evento garantindo que repetir o mesmo fato não gera segunda mensagem: criação do pedido notifica o profissional destinatário; a transição da solicitação para atendida (por criação ou por alteração da ficha) notifica o aluno com a ficha; a recusa notifica o aluno com o motivo. Fecha [x].
Para que serve: o aluno saber que a prescrição mudou.
Relacionado com: RF-TREI-001, RF-DIET-003; tarefas F4-03 e F6-05.
Onde fica: servidor de aplicação.
Especificação: gatilho, criação ou alteração de ficha_treino ou plano_alimentar por autor diferente do aluno. Passos: notificar o aluno com o destino do registro. Anti-duplicação, alterações do mesmo registro pelo mesmo autor em uma janela de dez minutos geram uma única notificação agrupada.
Nota (gate {F3-03}, Drift 10, 2026-09-14): o campo "Relacionado com" apontava para {F3-01}, que fechou em 14/09/2026 sem entregar notificação nenhuma, e cartão que aponta para card já fechado nunca mais é cobrado por ninguém, que é a forma mais silenciosa de um requisito morrer. Medido e reconciliado: a metade de treino deste gatilho tem duas condições, criada e alterada; a condição criada existe desde {F3-01} e a condição alterada passa a existir a partir de {F3-03}, que é o primeiro card em que uma ficha pode mudar. Nenhum dos dois entrega a notificação, e {F3-03} não a entrega de propósito: o H1 dele não a pede, {TA-26} não a pede, e a anti-duplicação por janela é desenho próprio, com parâmetro de operação próprio. O dono nominal passa a ser {F6-05}, ainda em aberto, que é onde a central de notificações nasce, ao lado de {F4-03} para a metade de plano alimentar. Se a intenção do produto for que esta notificação nasça junto da prescrição, e não junto da central, isso é decisão do dono do projeto e vira card próprio na Fase 3 ou na Fase 4, nunca correção silenciosa deste campo.
Nota (gate {F4-03}, Drift 6, 2026-09-30): {F4-03} cria o FATO que este gatilho observa: plano alimentar com autor diferente do titular, com criado_em e atualizado_em. A notificação ao aluno continua em {F6-05}, no precedente da Nota de {F3-03} acima: o H1 de RF-DIET-003 não a pede, {TA-35} não a pede, e a anti-duplicação por janela é desenho da central de notificações. O cartão permanece [ ].
Para que serve: avisar quem precisa saber que existe exame, prescrição ou sessão nova.
Relacionado com: RF-SAUD-004 a 006; tarefas F5-04 a F5-06.
Onde fica: servidor de aplicação.
Especificação: gatilho, criação de exame, prescricao ou sessao_reabilitacao. Passos: notificar o aluno e todos os profissionais com vínculo ativo da especialidade correspondente, que podem ser mais de um (RF-VINC-004), respeitando a restrição de visibilidade por categoria do aluno. Anti-duplicação, uma notificação por destinatário, nunca uma por especialidade. Ramificação, se a categoria estiver restrita a outras especialidades, apenas o aluno é notificado.
Para que serve: entregar a mensagem e notificar sem inundar.
Relacionado com: RF-COMU-001, 005, 006; tarefas F6-01, F6-05, F6-06.
Onde fica: servidor de aplicação e canal de tempo real.
Especificação: gatilho, criação de mensagem. Passos: publicar no canal de tempo real da conversa; criar ou incrementar a notificação agrupada por conversa para cada participante que não é o autor e não está com a conversa aberta. Anti-duplicação, o agrupador é o identificador da conversa, então mensagens seguidas incrementam o contador em vez de criar linhas novas. Saída, mensagem visível ao destinatário em até três segundos.
Para que serve: chamar alguém especificamente sem depender de ele ler tudo.
Relacionado com: RF-COMU-003; tarefa F6-03.
Onde fica: servidor de aplicação.
Especificação: gatilho, mensagem com menção em conversa de grupo. Passos: além da notificação agrupada da conversa, criar uma notificação dirigida do tipo menção para cada mencionado, não agrupada. Condição, o mencionado é participante ativo do grupo.
Para que serve: tornar a revogação efetiva na hora.
Relacionado com: RF-CORE-010; tarefa F1-12.
Onde fica: servidor de aplicação.
Especificação: gatilho, revogação de consentimento de uma categoria. Passos: gravar a data de revogação; bloquear escrita nova naquela categoria; remover a categoria da visibilidade de todos os profissionais vinculados; registrar na auditoria. Saída, a próxima consulta de profissional àquela categoria retorna vazia e a próxima escrita é bloqueada.
Estado: os quatro passos implementados como mecanismo e provados contra tabela de ensaio em {F1-12}; o efeito sobre dado real aparece quando cada uma das seis entidades sensíveis existir. Placar: mecanismo no ar, 0 de 6 categorias com tabela.
Para que serve: fazer valer o limite novo e o corte de acesso.
Relacionado com: RF-PLAN-002, RF-PLAN-003; tarefas F1-14 e F1-15.
Onde fica: servidor de aplicação.
Especificação: gatilho, alteração de perfil_aluno.plano_id ou de status_acesso pelo administrador. Passos: invalidar o cache de limites do aluno; notificar o aluno; registrar na auditoria. Saída, a próxima requisição do aluno já opera com o plano novo, nunca "a sessão seguinte": o prazo real é a próxima requisição, sem nova sessão nem reinício. A partir de {F1-15}, essa saída passa a ter efeito observável: até então nenhuma escrita consultava limite nenhum e a frase era verdadeira por vacuidade. Regra, reduzir o plano não apaga registro existente, apenas impede criar novo acima do limite.
Estado: 2 de 3 passos, entregues em {F1-14}. Invalidar o cache de limites do aluno está atendido por construção, mfit.limite_do_aluno lê do banco a cada chamada e não existe cache para invalidar; registrar na auditoria está atendido pelo gatilho de perfil_aluno desde {F1-06}, sem coluna nova. Notificar o aluno depende da central de notificações, {F6-05}, Fase 6, e continua pendente.
Para que serve: produzir a prévia sem gravar nada e sem estourar o limite do plano.
Relacionado com: RF-IAGE-001 a 003, RF-SAUD-010, RF-EXER-005, RF-AJUD-003, M.2; tarefas F8-05 a F8-08, F5-10, F8-12 e F9-03.
Onde fica: camada interna de geração assistida.
Especificação: vale para os cinco pontos de geração de M.2, cada um com a sua forma de revisão humana. Gatilho, acionamento pelo usuário. Condição, uso mensal do aluno abaixo do limite do plano. Passos: montar o contexto com preferências, última avaliação, últimas medidas, histórico e catálogo; chamar o provedor com tempo limite de sessenta segundos; validar que todo exercício ou alimento retornado existe e é permitido; devolver a prévia em memória. Ramificação, item inválido é descartado e o pedido é repetido uma vez. Saída, prévia editável, nenhum registro criado. Falha, mensagem de indisponibilidade e composição manual disponível. Contagem, o uso só é debitado quando a geração retorna resultado válido. Nota (gate {F3-08}, Drift 13, 2026-09-15): o passo de montar o contexto com preferências precisa de uma correspondência declarada entre a lista fechada de vinte e seis equipamentos do aluno (RF-TREI-008, Apêndice de catálogo de formulários) e o equipamento do exercício do catálogo, que é texto livre por decisão já tomada e em produção, com o filtro montando as opções a partir do próprio dado. Essa correspondência não existe hoje em artefato nenhum e não nasce em {F3-08}, que só coleta a preferência: o dono é o card da geração assistida, {F8-05}, porque é o H1 de RF-IAGE-001 que cobra usar somente exercícios compatíveis com esses equipamentos. Se ela exigir mudar a forma de um dos dois lados, é card novo com a decisão escrita, nunca uma tradução improvisada dentro da geração.
Para que serve: trazer o registro do aplicativo de saúde sem duplicar.
Relacionado com: RF-INTE-001; tarefa F8-09.
Onde fica: servidor de aplicação.
Especificação: gatilho, envio do arquivo de exportação pelo aluno. Passos: interpretar o arquivo; para cada atividade, montar a chave de deduplicação com aluno, origem, tipo e momento de início; inserir ignorando as chaves já existentes; devolver o número de criadas e de ignoradas. Idempotência, garantida pela unicidade da chave. Falha, arquivo ilegível retorna erro sem criar registro parcial.
Para que serve: ligar a conta do aluno num serviço de relógio ou de atividade sem que a credencial passe pelo navegador.
Relacionado com: RF-INTE-003, ADR-011, F.2; tarefa F8-13.
Onde fica: servidor de aplicação e tela de integrações.
Especificação: gatilho, o aluno escolhe um serviço habilitado. Passos: gerar o pedido de autorização com os escopos mínimos (atividades, passos e frequência cardíaca) e um identificador de estado de uso único; redirecionar ao site do serviço; ao retorno, conferir o identificador de estado, trocar o código pela credencial no servidor, cifrar e guardar em conta_integracao, registrar escopos e data, e disparar a primeira sincronização. Ramificação, autorização recusada ou identificador de estado inválido não cria conta e devolve mensagem à tela. Desconexão: descartar a credencial, marcar a conta como desconectada e manter as atividades já importadas. Anti-duplicação, uma conta conectada por par aluno e serviço. Falha, credencial recusada pelo serviço marca a conta como precisando reautorizar e notifica o aluno. Segurança, a credencial nunca é enviada ao navegador nem exibida em tela, e não entra em registro de log.
Para que serve: atender o direito de portabilidade.
Relacionado com: RF-INTE-002, D.6; tarefa F8-09.
Onde fica: servidor de aplicação.
Especificação: gatilho, pedido do aluno ou do administrador. Passos: montar um arquivo estruturado por categoria; incluir os anexos; empacotar; disponibilizar por endereço assinado com validade de vinte e quatro horas; registrar na auditoria. Saída, cada categoria com o mesmo número de registros da base. Falha, pedido incompleto não é entregue pela metade, é refeito.
Para que serve: cobrir de mídia os exercícios do catálogo sem sobrescrever nada por engano.
Relacionado com: RF-EXER-005, M.2; tarefa F8-12.
Onde fica: servidor de aplicação, acionado pela administração de exercícios.
Especificação: gatilho um, acionamento por exercício. Gatilho dois, acionamento em lote, cujo conjunto é exatamente os exercícios ativos sem imagem_url no momento do acionamento, contado e exibido antes de começar. Passos: montar o contexto com nome, grupo muscular, equipamento e instruções; chamar a camada interna; guardar o resultado como prévia associada ao exercício na própria tela de administração, sem tabela própria e sem tocar no campo de mídia do exercício, como na prévia de RF-IAGE-003; apresentar aprovar e rejeitar por exercício. Aprovar grava a mídia no exercício e registra na auditoria; rejeitar descarta a prévia e o exercício volta a constar entre os sem mídia. Anti-pico, lotes de vinte e cinco exercícios com pausa entre lotes. Idempotência, exercício que já tem mídia não entra no lote; reexecutar o lote alcança apenas os que continuam sem mídia. Falha, item que falha na geração fica sem prévia e é reportado nominalmente, sem interromper os demais.
Para que serve: trazer os 113 exercícios do protótipo para o catálogo global sem redigitação manual.
Relacionado com: RF-EXER-001; tarefa F2-01; ART-ENT-03.
Onde fica: script de operação (ops/importar-exercicios.mjs), acionado manualmente.
Especificação: gatilho, acionamento manual pela operação. Condição, arquivo docs/seed/exercicios.csv presente e cabeçalho conferido contra o mapeamento de colunas conhecido. Passos: ler o CSV, normalizar os valores de grupo muscular, dificuldade e categoria para os enums canônicos, casar pela chave natural (grupo_muscular, lower(btrim(nome))), inserir ou atualizar. Idempotência, por essa chave natural, reexecutar não duplica. Falha, arquivo ausente ou coluna desconhecida no cabeçalho aborta sem escrever nada e reporta nominalmente qual falta. Saída, placar N de M importados, K atualizados, J recusados (cada recusa com o motivo). Modo --ensaio é o padrão, que só conta e relata; escrever exige --aplicar. Etapa de mídia (R, {F2-02}): quando docs/seed/midia/ existir, casa o arquivo de mídia pela coluna do CSV, mede e valida pelo mesmo critério de bytes do card de mídia, copia para o repositório público com nome por hash e preenche imagem_url, imagem_largura e imagem_altura; escreve como mfit_app com claim de administrador, pelas mesmas políticas. A pasta hoje não existe (medido); o relatório abre em 0 de N exercícios com imagem, N lido do banco, nunca de constante no script.
Estado: importador entregue e idempotente em {F2-01}. Etapa de mídia entregue em {F2-02}; placar honesto 0 de N exercícios com imagem, porque docs/seed/midia/ do dono ainda não existe (pendência dele, mesma natureza, não bloqueia o card).
Fechamento [2026-09-14]: docs/seed/exercicios.csv do dono chegou (114 linhas, cabeçalho mais 113 exercícios do protótipo), commit 53cb783 na branch feat/semente-exercicios. Executado ops/importar-exercicios.mjs --ensaio (idempotente, sem escrever) e depois --aplicar em produção: placar 113 de 113 importados, 0 atualizados, 0 recusados. Medido direto no banco de produção após a carga: 113 linhas ativas em mfit.exercicio pela chave natural do importador. Etapa de mídia continua 0 de 0, docs/seed/midia/ do dono ainda ausente, pendência dele, mesma natureza, não bloqueia o card. Placar da semente sobe de 0 de 113 para 113 de 113.
Para que serve: garantir que as três contas de operação da plataforma existam, com o papel de topo e a senha no padrão, em qualquer ambiente que suba do zero.
Relacionado com: RN-010, RF-PAIN-009, ART-ACS-06; tarefa AUD-04.
Onde fica: comando de operação do servidor de aplicação, executado na instalação e reexecutável a qualquer momento.
Especificação: cria ou reconcilia exatamente três contas, uma por operador da plataforma, todas com papel super_administrador e status ativo. A senha de cada uma segue o padrão de operação (nome do operador, produto, ano e sufixo fixo) e não exige troca na primeira entrada. Idempotência, e ela se prova: rodar duas vezes seguidas deixa o mesmo número de contas, não rebaixa papel de conta já promovida e não sobrescreve senha que o operador já tenha trocado, reconhecida por a derivada em banco ser diferente da derivada do padrão. Nenhum endereço de e-mail, nenhuma senha e nenhum valor de padrão aparece neste documento nem em qualquer documento publicado: o registro vive no arquivo de credenciais do projeto, fora do repositório de código. Saída do comando: uma linha por conta dizendo criada, promovida ou inalterada, e a contagem final, que é o observável do H1 de {AUD-04}.
Para que serve: garantir que a entrada de fim chegue à trilha de auditoria também quando o Super Administrador simplesmente vai embora, fechando o navegador sem sair da personificação.
Relacionado com: RF-CORE-014, RF-CORE-009; tarefa AUD-05; ART-ACS-13 (o mecanismo), ART-ENT-01 (tabela sessao_personificacao), ART-AUD-01 (a entrada de fim), ART-CFG-01 (o teto de duração que ela lê).
Onde fica: script de operação do servidor de aplicação, chamado pelo agendador do sistema operacional que já existe. Não é rotina agendada de aplicação e não pertence ao grupo ART-JOB, que é da fase de cobrança: nenhum agendador novo nasce por causa desta ficha.
Especificação: gatilho, o agendador do sistema operacional, de dez em dez minutos. Processa, toda linha de sessao_personificacao sem fim gravado cuja duração já passou do teto configurado. Passos, gravar o fim com o motivo expiração e escrever a entrada de fim na trilha, com o mesmo par personificador e personificado da entrada de início. Idempotência, alcança apenas linha sem fim gravado, e o gatilho de atualização única da tabela recusa a segunda escrita: reexecutar não duplica entrada nem sobrescreve motivo. Falha, a linha que não fechar é relatada nominalmente e as demais seguem, nunca aborta o lote inteiro. Saída, placar N de M personificações fechadas por execução, e zero é resultado legítimo e esperado na maioria das execuções. Janela declarada, e ela é a razão de esta ficha existir com cadência em vez de sob demanda: o fechamento preguiçoso que a aplicação faz em três pontos, a passagem pela camada única de sessão, a renovação e o início de uma personificação nova, cobre todo operador que volta, e esta rotina cobre quem não volta; entre a expiração e a execução seguinte existe uma janela de até dez minutos em que a linha continua aberta, e ela é consequência da cadência, não defeito. Reduzir a janela é mudar a cadência, e a cadência vive no agendador, nunca dentro do código.
Estado: instalado em produção em 2026-09-29 (merge 3dabc30, https://fit.modulareasy.com, migrações 0034, 0035 e 0036, gates plan, qa e review verdes): a rotina ops/fechar-personificacoes-expiradas.mjs está no agendador do sistema operacional do servidor, a cada dez minutos (*/10), com o log em arquivo próprio. O qa rodou o mesmo comando a mão sobre uma linha órfã expirada: fechadas=1, motivo expiração, saída 0.
Rotinas agendadas
Para que serve: manter o extrato em dia sem ação manual.
Relacionado com: RF-COBR-002, RN-007; tarefa F8-10.
Onde fica: agendador do servidor.
Especificação: cadência, diária às três da manhã. Processa, acordos ativos cujo período seguinte já venceu. Passos, criar a competência do período com valor e vencimento pela regra RN-007. Idempotência, chave única por acordo e período. Anti-pico, processa em lotes de quinhentos acordos com pausa entre lotes. Se já rodou, nada é criado. Loga início, fim, criadas e ignoradas.
Para que serve: o profissional enxergar o que passou do prazo.
Relacionado com: RF-COBR-003; tarefa F8-10.
Onde fica: agendador do servidor.
Especificação: cadência, diária às três e quinze. Processa, competências em aberto com vencimento anterior a hoje. Passos, mudar o status para vencida e notificar o profissional uma vez por competência. Idempotência, só atinge status em aberto. Loga a quantidade alterada.
Para que serve: alimentar o alerta no painel do profissional.
Relacionado com: RF-PAIN-006, RN-006; tarefa F8-10.
Onde fica: agendador do servidor.
Especificação: cadência, diária às quatro, depois da sincronização das contas conectadas para não marcar como inativo quem treinou pelo relógio. Processa, alunos com vínculo ativo. Passos, calcular a data da última atividade entre as quatro fontes de RN-006, sessão concluída, refeição, medida e atividade externa, e marcar como inativo quem passou de sete dias. Idempotência, o cálculo é uma função do estado, então repetir produz o mesmo resultado. Anti-pico, processa por lotes de mil alunos.
Para que serve: garantir que nenhum marco atingido ficou sem conceder.
Relacionado com: RF-ENGA-004; tarefa F8-10.
Onde fica: agendador do servidor.
Especificação: cadência, diária às quatro e trinta. Processa, alunos com sessão concluída nas últimas quarenta e oito horas. Passos, reavaliar os oito critérios e conceder o que faltar. Idempotência, garantida pela unicidade de aluno e conquista. Loga as concessões de recuperação, que indicam falha na automação de tempo real.
Para que serve: trazer sozinho o que o aluno registrou no relógio ou no aplicativo do serviço.
Relacionado com: RF-INTE-004, K.1; tarefas F8-14 e F8-10.
Onde fica: agendador do servidor.
Especificação: cadência, a cada seis horas, ajustável pela configuração. Processa, contas no estado conectada, em lotes de cem contas com pausa entre lotes. Passos, para cada conta: buscar atividades, passos e frequência cardíaca desde a última sincronização; montar a chave de deduplicação com origem e identificador da atividade no serviço; inserir apenas as chaves inexistentes; atualizar a data da última sincronização. Idempotência, garantida pela unicidade da chave, então repetir a execução no mesmo período não cria registro novo. Ramificação, credencial expirada ou revogada marca a conta como precisando reautorizar, notifica o aluno e não apaga nada. Anti-pico, o serviço com limite de chamadas é respeitado, e a conta que estourar o limite entra na execução seguinte. Loga início, fim, contas processadas, atividades criadas e ignoradas.
Para que serve: não guardar arquivo enviado que nunca virou registro.
Relacionado com: ADR-009, K.1; tarefa F8-10.
Onde fica: agendador do servidor.
Especificação: cadência, semanal, domingo às duas. Processa, objetos dos dois repositórios sem linha correspondente e com mais de sete dias. Passos, listar, conferir a ausência de referência e remover. Idempotência, o que já foi removido não aparece na listagem seguinte. Segurança, remove por chave explícita, nunca por varredura de prefixo. Loga cada chave removida.
Para que serve: cumprir o prazo de retenção do dado sensível.
Relacionado com: D.6; tarefa F8-10.
Onde fica: agendador do servidor.
Especificação: cadência, mensal, primeiro dia às duas. Processa, dado sensível de aluno cujo último vínculo foi encerrado há mais de cinco anos e que não tem vínculo ativo. Passos, substituir conteúdo identificável por marcador de anonimizado, remover anexos, manter a contagem histórica e registrar na auditoria. Idempotência, registro já anonimizado é ignorado. Loga a quantidade por categoria.
Notificações e mensagens
Para que serve: concentrar o que exige atenção sem inundar o usuário.
Relacionado com: RF-COMU-005, RF-COMU-006; tarefa F6-05.
Onde fica: sino no topo de toda tela.
Especificação: os doze tipos, com destinatário, texto e destino: convite de vínculo (aluno, tela de vínculos); vínculo aceito e vínculo recusado (profissional, carteira); vínculo encerrado (ambos, carteira ou vínculos); solicitação de ficha (profissional, lista de solicitações); ficha ou plano criado ou alterado (aluno, o registro); registro clínico criado (aluno e profissional da especialidade, o registro); mensagem nova (participantes, a conversa, agrupada pelo identificador da conversa); menção (mencionado, a conversa, não agrupada); conquista concedida (aluno, painel); competência vencida (profissional, cobrança); plano ou acesso alterado (aluno, tela de plano); exportação pronta (aluno, tela de privacidade). Canal, sino com contador; entrega em tempo real. Marca como lida ao abrir o destino; limpar todas zera a lista sem apagar o registro de origem. Agrupamento, por agrupador, que incrementa o contador em vez de criar linha nova.
Nota (gate {F3-04}, 2026-09-14): este cartão continua [ ] e sem nenhuma entrega. O aviso de {F3-04} é correio eletrônico por gatilho na origem, no molde dos três avisos de vínculo que já estão em produção, e não a central de notificações: sino, contagem de não lidas, agrupamento e limpar todas continuam em {F6-05}, com a tabela notificacao de {ART-ENT-07}. Nenhuma casca nasce aqui, nem sino sem conteúdo, nem contador zerado.
Nota (gate {F3-05}, 2026-09-14): nenhum tipo de notificação nasce, muda ou é removido, e este cartão continua [ ] e sem entrega. A execução da sessão não avisa ninguém: ela é do aluno titular, acontece na tela dele e termina nela, e nenhum dos doze tipos catalogados tem a sessão como gatilho. Os avisos que o treino executado alimenta, sequência e conquista, são de {F7-02} a {F7-05} e chegam pelos tipos já catalogados. Placar que não muda também se declara.
Fechamento [2026-09-15]: confirmado inalterado. Em produção (80c103e), nenhum tipo de notificação nasceu, mudou ou foi removido. Este cartão continua [ ] e sem entrega.
Para que serve: confirmar o endereço de e-mail informado no cadastro.
Relacionado com: RF-CORE-002, RF-CORE-003; tarefas F1-07 (envio), disparado pela criação de conta em F1-04 e F1-05.
Onde fica: envio transacional.
Especificação: canal, e-mail. Disparado por, criação de conta. Assunto, confirmação de cadastro no ModularFit. Corpo com as variáveis nome e endereço de confirmação. Idioma, português do Brasil. Remetente, endereço institucional do produto. Ação, confirmar o e-mail. Janela, imediato. Sem descadastro, por ser transacional.
Nota (gate {AUD-08}, 2026-09-29): Assunto: valor inicial; editável em email_assunto_<modelo> ({ART-CFG-01}). Prazo: recuperacao_validade_min.
Fechamento [2026-09-29] de {AUD-08}: o assunto deste e-mail é o parâmetro email_assunto_confirmacao_conta, em mfit.parametro (merge fa725bc, migração 0041), editável em /admin/parametros pelo Super Administrador e valendo para o próximo e-mail renderizado, inclusive os já na fila e ainda não enviados. A prova ao vivo do qa do assunto novo saído foi feita no e-mail de recuperação; este segue o mesmo caminho da tabela e do renderizador.
Nota (Inspeção, {AUD-10}, 2026-09-30): assunto e corpo deste e-mail passam a viver no modelo confirmacao_conta de {ART-CFG-03}, editável em /admin/emails, e o parâmetro email_assunto_confirmacao_conta sai de mfit.parametro quando {AUD-10} entregar. As variáveis do corpo são as da linha do modelo no catálogo de variáveis de {ART-CFG-03}.
Fechamento [2026-09-30] de {AUD-10}: assunto e corpo deste e-mail vivem agora no modelo confirmacao_conta (merge 17b62d6, migrações 0048 e 0049, https://fit.modulareasy.com, /api/estado na versão 17b62d6), editável em /admin/emails, e o parâmetro email_assunto_confirmacao_conta saiu de mfit.parametro. Texto idêntico ao de antes na versão 1 (regressão de {TA-96}).
Para que serve: permitir redefinir a senha com segurança.
Relacionado com: RF-CORE-005; tarefa F1-07.
Onde fica: envio transacional.
Especificação: canal, e-mail. Disparado por, pedido de redefinição. Assunto, redefinição de senha. Corpo com as variáveis nome, endereço de uso único e prazo de sessenta minutos. Regra, e-mail não cadastrado não gera envio e a tela exibe a mesma mensagem neutra. Janela, imediato. Uso único, o endereço expira ao ser usado.
Nota (gate {AUD-08}, 2026-09-29): Assunto: valor inicial; editável em email_assunto_<modelo> ({ART-CFG-01}). Prazo: recuperacao_validade_min.
Fechamento [2026-09-29] de {AUD-08}: o assunto deste e-mail é o parâmetro email_assunto_recuperacao_senha, em mfit.parametro (merge fa725bc, migração 0041), editável em /admin/parametros pelo Super Administrador e valendo para o próximo e-mail renderizado, inclusive os já na fila e ainda não enviados. Provado ao vivo pelo qa: com o valor alterado, o e-mail enviado gravou o assunto novo em mfit.email_saida, sem reiniciar a aplicação, e o valor foi restaurado depois (trilha com antes e depois).
Nota (Inspeção, {AUD-10}, 2026-09-30): assunto e corpo deste e-mail passam a viver no modelo recuperacao_senha de {ART-CFG-03}, editável em /admin/emails, e o parâmetro email_assunto_recuperacao_senha sai de mfit.parametro quando {AUD-10} entregar. As variáveis do corpo são as da linha do modelo no catálogo de variáveis de {ART-CFG-03}.
Fechamento [2026-09-30] de {AUD-10}: assunto e corpo deste e-mail vivem agora no modelo recuperacao_senha (merge 17b62d6, migrações 0048 e 0049, https://fit.modulareasy.com, /api/estado na versão 17b62d6), editável em /admin/emails, e o parâmetro email_assunto_recuperacao_senha saiu de mfit.parametro. Provado ao vivo: a versão 2 (de teste) saiu no e-mail real com o marcador e modelo_versao 2, e a versão 3, restauração da 1, devolveu o texto original; o HTML diz "Acesse" no lugar de "Clique" (troca declarada).
Para que serve: entregar a senha inicial ao usuário criado pelo administrador.
Relacionado com: RF-PAIN-009; tarefa F7-14.
Onde fica: envio transacional.
Especificação: canal, e-mail. Disparado por, criação de usuário na administração. Assunto, seu acesso ao ModularFit. Corpo com as variáveis nome, papel, endereço de entrada e instrução de troca de senha no primeiro uso. Janela, imediato.
Nota (gate {AUD-08}, 2026-09-29): Assunto: valor inicial; editável em email_assunto_<modelo> ({ART-CFG-01}). Prazo: recuperacao_validade_min.
Fechamento [2026-09-29] de {AUD-08}: o assunto deste e-mail é o parâmetro email_assunto_acesso_criado, em mfit.parametro (merge fa725bc, migração 0041), editável em /admin/parametros pelo Super Administrador e valendo para o próximo e-mail renderizado, inclusive os já na fila e ainda não enviados. O cartão continua [ ]: o parâmetro existe e o modelo lê o assunto dele, mas o envio disparado pela criação de usuário na administração é de {F7-14}, e o qa não o exercitou.
Nota (Inspeção, {AUD-10}, 2026-09-30): assunto e corpo deste e-mail passam a viver no modelo acesso_criado de {ART-CFG-03}, editável em /admin/emails, e o parâmetro email_assunto_acesso_criado sai de mfit.parametro quando {AUD-10} entregar. As variáveis do corpo são as da linha do modelo no catálogo de variáveis de {ART-CFG-03}.
Fechamento [2026-09-30] de {AUD-10}: assunto e corpo deste e-mail vivem agora no modelo acesso_criado (merge 17b62d6, migrações 0048 e 0049, https://fit.modulareasy.com, /api/estado na versão 17b62d6), editável em /admin/emails, e o parâmetro email_assunto_acesso_criado saiu de mfit.parametro. O envio disparado pela criação de usuário na administração continua de {F7-14} e não foi exercitado em produção, por isso o cartão segue [ ]; o texto editável foi coberto pela semente e pelo arnês, e a descrição do evento perdeu o código interno de card pela migração 0049.
Nota (gate {F2-07}, 2026-09-14): MAPA_MODELO (server/src/email/modelos.ts) tem hoje 8 entradas: as 3 fichadas aqui (ART-MSG-01 a 03) mais convite de vínculo, aceite e recusa (entregues em {F2-05} e {F2-06}) e, entregues por {F2-07}, vinculo_encerrado e convite_cancelado, os dois sem token (finalidade: null), destinatário e caminho resolvidos pelo papel no momento do envio. Os 5 modelos de vínculo não ganham ficha própria de mensagem: vivem na automação que os dispara (ART-WF-01 a 03). A contagem do tipo na tabela do topo permanece 3, cartões de mensagem, não total de modelos em código.
Planos, configuração e métricas
Para que serve: definir o que cada faixa de assinatura do aluno libera.
Relacionado com: RF-PLAN-001 a 004, L.1; tarefas F1-13 a F1-16.
Onde fica: administração de planos, tabela plano_plataforma.
Especificação: ficha completa no Apêndice de catálogo de planos do DRS, com os três planos, as seis dimensões de limite e as regras comuns. Cada dimensão guarda um número ou o valor ilimitado; o plano mais alto nasce ilimitado nas seis, e dimensão ilimitada é aprovada sem contagem e exibida ao aluno com a palavra ilimitado no lugar do máximo. Recorrência mensal; cobrança fora do sistema; atribuição manual pelo administrador; editável por tela, sem publicação nova. Estado, ativo ou descontinuado; descontinuar não altera quem já está no plano.
Estado: 3 de 3 planos existentes, 2 de 3 com preço definido. Os limites das três faixas são os do Apêndice, integrais, semeados em {F1-13}. O preço de Essencial e de Completo continua a definir, decisão comercial de L.1; a tela exibe a ausência em vez de um número inventado, e nenhuma verificação do sistema lê o valor de referência (ADR-005: o sistema não cobra).
Nota (gate {F3-05}, 2026-09-14): nenhuma dimensão de plano nasce aqui e nenhum limite é consumido pela execução da sessão: treinar não é cobrado por cota, e a função única de consumo do aluno não ganha ramo novo. Os três planos e as seis dimensões de limite continuam exatamente como estão, e o placar continua 3 de 3 planos existentes, 2 de 3 com preço definido. Placar que não muda também se declara.
Fechamento [2026-09-15]: confirmado inalterado. Em produção (80c103e), nenhuma dimensão de plano nasceu e mfit.consumo_do_aluno não ganhou ramo novo. Placar continua 3 de 3 planos existentes, 2 de 3 com preço definido.
Para que serve: permitir ajustar regra de negócio sem publicar versão nova.
Relacionado com: L.2, ADR-012; tarefa {AUD-06}.
Onde fica: administração, tela de configuração.
Dono: Estado: 33 de 46 parâmetros com o consumidor no ponto único (os 19 do retrato de {AUD-07} mais as 14 linhas novas de {AUD-08}; em produção são 42 linhas em mfit.parametro mais 4 de forma tabular, igual a 46 fichas), 1 com valor vivo ainda fora do ponto único (consentimento_textos) e 12 sem consumidor: 33 + 1 + 12 = 46. Retrato anterior, de {AUD-07}, preservado abaixo: 19 de 46 parâmetros com o consumidor no ponto único (17 com valor vivo migrado, mais termos_e_aviso_nao_clinico, materializado em {F1-18}, mais listas_fechadas, materializado em {AUD-07}), 1 com valor vivo ainda fora do ponto único (consentimento_textos, restante nominal no placar do verificador) 12 sem consumidor e 14 a entregar em {AUD-08} (as catorze linhas novas da tabela, de senha_minima_caracteres a email_assunto_solicitacao_ficha_recusada): 19 + 1 + 12 + 14 = 46. Aritmética: 32 + 14 de {AUD-08} = 46; mfit.parametro 28 + 14 = 42 linhas (46 menos 4 tabulares). Fechamento [2026-09-29] de {AUD-07} (merge 7b47fa6, migrações 0039 e 0040, https://fit.modulareasy.com): listas_fechadas sai do grupo dos sem consumidor e passa a ter o consumidor no ponto único: seis listas (grupos musculares, dificuldade e categoria do exercício, objetivos, nível e equipamentos das preferências de treino), 52 itens em mfit.lista_fechada_item (10, 3, 2, 8, 3 e 26), editáveis em /admin/listas pelo Super Administrador, valendo no próximo uso, com os seis tipos enum removidos do banco. As quatro listas sem módulo (tipos de refeição {F4-01}, tipos de exame {F5-04}, pontos de dobra {F5-02} e categorias de pose {F5-08}) seguem nascendo na mesma tabela pelo card dono. Placar: 19 de 46, 1 com valor vivo fora do ponto único, 12 sem consumidor e 14 a entregar em {AUD-08}: 19 + 1 + 12 + 14 = 46. Os trechos abaixo que falam em 13 sem consumidor e em listas_fechadas como constantes descrevem o estado anterior a este fechamento. Fechamento [2026-09-29] de {AUD-06} (merge 29380ae, migrações 0037 e 0038, https://fit.modulareasy.com): mfit.parametro tem 28 linhas (as 32 menos os 4 de forma tabular), editáveis em /admin/parametros pelo Super Administrador; 3 delas com editável = false (email_lote_por_ciclo, vinculo_convites_pendentes_teto_linhas e modelo_geracao), em leitura com etiqueta e motivo. Os 13 sem consumidor seguem como estavam, com o módulo dono por fechar. Medição anterior, preservada: 1 de 32 parâmetros materializado. Medido em 2026-09-15, chave por chave, no código: 1 materializado (termos_e_aviso_nao_clinico, {F1-18}), 18 com valor vivo (midia_exercicio_tamanho_max, midia_exercicio_formatos, url_assinada_validade, bloqueio_tentativas, personificacao_duracao_min (5 leitores no servidor: middleware/sessaoAtual.ts, rotas/eu.ts, rotas/sessao.ts, sessao/emitir.ts, ops/fechar-personificacoes-expiradas.mjs), personificacao_aviso_min (valor vivo no web, estadoFaixa.ts; zero leitores no servidor), consentimento_textos, recuperacao_validade_min, recuperacao_por_origem_maximo, recuperacao_intervalo_conta_min, email_rotina_intervalo_seg, email_tentativas_recuo, email_fila_alerta_limite, email_retencao_corpo_horas, email_lote_por_ciclo, vinculo_convites_pendentes_teto_linhas, sessao_acesso_validade_min e sessao_renovacao_validade_dias; as duas de sessão foram acrescentadas ao catálogo por {AUD-06} e as duas de personificação passaram a ter valor vivo em 2026-09-29 com {AUD-05}) e 13 sem consumidor, porque o módulo dono ainda não existe ou o card dono ainda não fechou (metas_padrao, dias_inatividade, sessao_abandono_horas, campos_completude, anexo_tamanho_max (zero leitores medidos em 3dabc30), anexo_extensoes, listas_fechadas, provedores_atividade, sincronizacao_cadencia_horas, conquistas, visibilidade_cruzada, modelo_geracao, retencao_meses). 1 + 18 + 13 = 32, sem parâmetro fora das três listas. O placar anterior, aspas 1 materializado e 27 em config.ts fecha aspas, nunca correspondeu ao código, e a diferença importa: 13 parâmetros não têm consumidor pronto e listas_fechadas vive hoje em sete constantes de server/src/exercicios/catalogo.ts e server/src/preferencias/contratoPreferencias.ts, fora do ponto único. Dono: {AUD-06}. Nota (gate {F2-09}, 2026-09-14): nenhum parâmetro novo (0.2 do gate: limite e teto de paginação da listagem, os cinco estados e o filtro por especialidade são, todos, não configuráveis por desenho); total inalterado em 28. Nota (gate {F3-01}, 2026-09-14): nenhum parâmetro novo; séries de 1 a 20, descanso de 0 a 600 segundos, observação até 280 caracteres e o limite de fichas ativas são valores de validação e de dimensão de plano, não parâmetros editáveis de operação. Total inalterado em 31. Nota (gate {F3-03}, 2026-09-14): nenhum parâmetro novo (0.2 do gate: quem edita e quem desativa a ficha são fixados por RN-009/ADR-006, não configuráveis por desenho; a janela de dez minutos da notificação de prescrição alterada segue sem dono, nasce em card futuro). Total inalterado em 31. Fechamento [2026-09-14]: confirmado em produção (76bc9cd), nenhum parâmetro novo. Total inalterado em 31. Fechamento [2026-09-15]: confirmado em produção (80c103e), nenhum parâmetro novo; sessao_abandono_horas já era um dos 31 e não nasce em {F3-05}, é lido em {F3-10}. Total inalterado em 31. Nota (gate {F3-08}, 2026-09-15): nenhum parâmetro novo; listas_fechadas já é um dos 31 e não é materializado aqui (RF-TREI-008 não tem a Nota que tornaria a tabela obrigatória, no molde de RF-CORE-012 em {F1-18}). Total inalterado em 31.
Fechamento [2026-09-29] de {AUD-08} (merge fa725bc, migração 0041, https://fit.modulareasy.com, /api/estado na versão fa725bc): as catorze linhas de senha_minima_caracteres a email_assunto_solicitacao_ficha_recusada estão em mfit.parametro (42 linhas, e a trava de cardinalidade na carga passa a 42), com consumidor no ponto único, editáveis em /admin/parametros pelo Super Administrador (o Administrador lê e não grava) e valendo no próximo uso, sem deploy. Estado: 33 de 46, 1 com valor vivo fora do ponto único e 12 sem consumidor: 33 + 1 + 12 = 46. A forma texto (assunto de e-mail, uma linha, 3 a 120 caracteres) passa a ser editável, e o retrato dos 42 parâmetros depois da restauração bate com o inicial. Os trechos acima e abaixo que falam em 14 a entregar em {AUD-08} descrevem o estado anterior a este fechamento. O cartão continua [ ] porque restam 12 parâmetros sem consumidor. Fechamento [2026-09-29] de {F3-10} (merge 047f3bc, migração 0042, https://fit.modulareasy.com): sessao_abandono_horas (24, faixa 2 a 72, em horas) passa de sem consumidor para consumidor no ponto único: é lido por parametro() dentro da função que decide, nunca em escopo de módulo, tanto na escrita preguiçosa do servidor quanto na rotina horária de operação, e vale na próxima avaliação da sessão (provado em produção com 24, 2, 4 e 24 sem reiniciar, retrato dos 42 parâmetros igual ao inicial). Nenhuma linha nova em mfit.parametro (continuam 42). A cadência horária da rotina não é parâmetro: é técnica, classificada C no verificador (universo 147). Estado: 34 de 46 com o consumidor no ponto único, 1 com valor vivo fora do ponto único e 11 sem consumidor: 34 + 1 + 11 = 46. Os trechos acima que falam em 33 de 46 e em 12 sem consumidor descrevem o estado anterior a este fechamento. O cartão continua [ ] porque restam 11 parâmetros sem consumidor.
Especificação:
| Parâmetro | Controla | Tipo | Default | Faixa ou opções | Efeito ao mudar |
|---|---|---|---|---|---|
| metas_padrao | metas nutricionais iniciais do aluno novo | conjunto de números | 2000 kcal, 150 g, 250 g, 65 g | 800 a 6000 kcal; 0 a 1000 g cada macro | vale para alunos novos |
| dias_inatividade | prazo do alerta de aluno inativo | número | 7 | 3 a 30 | próximo cálculo diário |
| sessao_abandono_horas | tempo sem registro que passa a sessão em andamento para abandonada | número em horas | 24 | 2 a 72 | próxima avaliação da sessão |
| campos_completude | conjunto de campos do indicador de completude do perfil | lista de campos do perfil | data de nascimento, sexo, altura, peso mais recente, foto | campos do perfil do aluno | imediato, recalcula o percentual de todos |
| anexo_tamanho_max | limite de tamanho do anexo | número em megabytes | 20 | 1 a 50 | imediato |
| anexo_extensoes | extensões aceitas de anexo | lista | documento e imagem | subconjunto não vazio das 13 extensões de server/src/arquivos/tipoConteudo.ts | imediato |
| midia_exercicio_tamanho_max | limite de tamanho da imagem de exercício | número em megabytes | 5 | 1 a 20 | imediato |
| midia_exercicio_formatos | formatos aceitos da imagem de exercício | lista | png, jpg, webp e gif (rótulo medido nos bytes, aspas jpeg fecha aspas é o tipo MIME, nunca o valor gravado) | subconjunto não vazio de png, jpg, webp, gif | imediato |
| url_assinada_validade | validade do endereço assinado | número em minutos | 15 (código grava 900 segundos; conversão no ponto único, {ART-CFG-02}) | 1 a 60 | imediato |
| bloqueio_tentativas | tentativas, janela e tempo de bloqueio | três números | 6, 15 e 30 | 3 a 10, 5 a 60 e 5 a 120 | imediato |
| personificacao_duracao_min | teto de duração de uma sessão de personificação | número em minutos | 30 | 5 a 120 | vale para a próxima personificação iniciada, não encurta as em curso |
| personificacao_aviso_min | minutos restantes em que a faixa de personificação entra no estado de próxima da expiração | número em minutos | 5 | 1 a 30, e sempre menor que personificacao_duracao_min | vale para a próxima personificação iniciada |
| listas_fechadas | sete listas com consumidor (as seis atuais, grupos musculares, dificuldade e categoria do exercício, objetivos, nível e equipamentos das preferências de treino, mais tipos de refeição, entregue em {F4-01}) mais as três com card dono (tipos de exame {F5-04}, pontos de dobra cutânea {F5-02}, categorias de pose {F5-08}); sete listas com consumidor desde o fechamento de {F4-01} (a sétima, tipos de refeição, em produção com oito itens); três nascem nos cards de módulo; a oitava lista com consumidor, ponto_dobra_cutanea (pontos de dobra cutânea, com quatro itens: Tríceps, Suprailíaca, Abdominal e Coxa), entregue em {F5-02} na migração 0057 (oito listas com consumidor em produção desde o fechamento de {F5-02}) | tabelas | conforme apêndices | fora de mfit.parametro, tabela própria (D-15 do gate {AUD-06}); pendente, dono nominal {AUD-07} | imediato nos formulários |
| consentimento_textos | texto, finalidade e versão de cada categoria | tabela | versão inicial | fora de mfit.parametro, tabela própria (D-15 do gate {AUD-06}); entregue em {AUD-12} (merge 4e5ed26, migrações 0050 e 0051), mecanismo mfit.texto_versionado de {F1-18}, sete textos e sete finalidades, editáveis em /admin/textos | versão nova vale para as próximas concessões; quem já consentiu guarda a versão aceita |
| termos_e_aviso_nao_clinico | texto e versão dos termos de uso e do aviso de que a plataforma não é registro clínico | tabela | versão inicial | livre | os quatro pontos de exibição passam a mostrar a versão nova, e os aceites antigos guardam a versão que aceitaram |
| provedores_atividade | serviços de atividade habilitados para conexão | lista | Strava, Fitbit, Garmin, Polar | provedores com adaptador implementado | imediato na tela de integrações; desabilitar não desconecta quem já está conectado |
| sincronizacao_cadencia_horas | intervalo entre sincronizações das contas conectadas | número em horas | 6 | 1 a 24 | próxima execução |
| conquistas | catálogo e critérios | tabela | oito do apêndice | livre | próxima avaliação |
| visibilidade_cruzada | padrão de visibilidade entre especialidades | enumerado | todas as especialidades vinculadas | todas ou apenas a especialidade correspondente | imediato, respeitando a restrição individual do aluno |
| modelo_geracao | modelo em uso na geração assistida | texto | definido na abertura da construção | lista fechada nomeada pelo card dono da geração assistida; até lá, não editável (editável = false), motivo "o catálogo de modelos nasce na Fase 8" | próxima geração |
| retencao_meses | prazo de retenção antes da anonimização | número | 60 | 12 a 120 | próxima execução mensal |
| recuperacao_validade_min | validade do endereço de uso único de recuperação de senha | número em minutos | 60 | 15 a 120 | vale para o próximo endereço gerado |
| recuperacao_por_origem_maximo | teto de pedidos de recuperação por endereço de origem, e a janela | dois números | 5 e 60 | 2 a 20 e 15 a 120 | imediato |
| recuperacao_intervalo_conta_min | intervalo mínimo entre dois e-mails de recuperação para a mesma conta | número em minutos | 5 | 1 a 30 | imediato |
| email_rotina_intervalo_seg | cadência da rotina de envio de e-mail | número em segundos | 30 | 10 a 300 | próximo ciclo |
| email_tentativas_recuo | tentativas máximas de envio de e-mail e o recuo progressivo, base e teto | três números | 6, 60 e 60 (tentativas; base em segundos; teto em minutos, medido em config.ts:174) | 3 a 10; 10 a 600 s; 5 a 1440 min | próxima tentativa |
| email_fila_alerta_limite | tamanho da fila de e-mail que dispara o alerta de acúmulo | número | 50 | 10 a 500 | próximo ciclo |
| email_retencao_corpo_horas | prazo de retenção do corpo renderizado na fila de e-mail | número em horas | 24 | 1 a 168 | próximo expurgo |
| email_lote_por_ciclo | quantidade de e-mails processados por ciclo da rotina | número | 10 | fixo, não editável pela administração | nenhum, parâmetro técnico |
| vinculo_convites_pendentes_teto_linhas | teto de linhas retornado por GET /api/vinculos para aluno e profissional | número | 50 | fixo, não editável pela administração | nenhum, parâmetro técnico; sem paginação nem contagem do universo, medido em {F2-08}, evolução em {F7-07} |
| sessao_acesso_validade_min | validade do token de acesso (cookie de sessão) | número em minutos | 15 | 5 a 60 | vale para a próxima sessão emitida |
| sessao_renovacao_validade_dias | validade do cookie de renovação | número em dias | 30 | 1 a 90 | vale para a próxima sessão emitida |
| senha_minima_caracteres | tamanho mínimo da senha no cadastro e na redefinição | número em caracteres | 8 | 8 a 64 | vale para a próxima senha definida; senha já gravada continua válida |
| cadastro_por_origem_maximo | teto de cadastros por endereço de origem, e a janela | dois números | 10 e 60 | 2 a 100 e 15 a 240 minutos | imediato |
| perfil_biografia_max_caracteres | teto de caracteres da biografia do profissional | número | 1000 | 200 a 5000 | vale para a próxima gravação da biografia; a já gravada acima do teto continua exibida |
| modelos_email | os onze modelos de e-mail transacional, assunto e corpo com variáveis e versões | tabela | a versão 1 de cada modelo, igual ao texto de antes | faixa por modelo como dado: assunto de 3 a 120 caracteres em linha única, corpo de 20 a 5000 | fora de mfit.parametro, tabela própria; vale para o próximo e-mail renderizado, sem reiniciar; ficha completa em {ART-CFG-03} |
| refeicao_nome_max_caracteres | tamanho máximo de nome em nutrição: refeição, alimento e plano alimentar | número em caracteres | 120 | 40 a 280 | vale para o próximo registro; entregue em {F4-01} |
| refeicao_observacoes_max_caracteres | tamanho máximo de observações e notas em nutrição: refeição e plano alimentar | número em caracteres | 1000 | 280 a 5000 | vale para o próximo registro; entregue em {F4-01} |
| nutricao_meta_tolerancia_pct | faixa, para mais e para menos, em torno da meta de calorias em que o dia conta como meta atingida no acompanhamento nutricional (grupo nutrição) | número em porcentagem | 10 | 1 a 50 | vale na próxima leitura do acompanhamento, sem recálculo guardado; entregue em {F4-05} |
| anamnese_texto_curto_max_caracteres | tamanho máximo de um campo de texto curto da anamnese (grupo saúde) | número em caracteres | 200 | 80 a 500 | vale para o próximo registro; a anamnese gravada acima do teto continua exibida; entregue em {F5-01} |
| anamnese_texto_longo_max_caracteres | tamanho máximo de um campo de texto longo da anamnese (grupo saúde) | número em caracteres | 2000 | 500 a 10000 | vale para o próximo registro; a anamnese gravada acima do teto continua exibida; entregue em {F5-01} |
| avaliacao_texto_curto_max_caracteres | tamanho máximo de um campo de texto curto da avaliação física (grupo saúde) | número em caracteres | 200 | 80 a 500 | vale para o próximo registro; a avaliação gravada acima do teto continua exibida; entregue em {F5-02} |
| avaliacao_texto_longo_max_caracteres | tamanho máximo de um campo de texto longo da avaliação física (grupo saúde) | número em caracteres | 2000 | 500 a 10000 | vale para o próximo registro; a avaliação gravada acima do teto continua exibida; entregue em {F5-02} |
| exame_nome_max_caracteres | tamanho máximo do nome de um exame (grupo saúde) | número em caracteres | 160 | 80 a 500; o mínimo de 3 caracteres é regra fixa | vale para o próximo registro; o exame gravado acima do teto continua exibido; a entregar em {F5-04} |
| exame_resumo_max_caracteres | tamanho máximo do resumo dos resultados de um exame (grupo saúde) | número em caracteres | 4000 | 500 a 10000 | vale para o próximo registro; o exame gravado acima do teto continua exibido; a entregar em {F5-04} |
| exame_observacoes_max_caracteres | tamanho máximo das observações de um exame (grupo saúde) | número em caracteres | 2000 | 500 a 10000 | vale para o próximo registro; o exame gravado acima do teto continua exibido; a entregar em {F5-04} |
Nota (R-2, {F2-02}): midia_exercicio_tamanho_max e midia_exercicio_formatos são de mídia de exercício, servida sem sessão pelo repositório público; não confundir com anexo_tamanho_max e anexo_extensoes, que são de anexo sensível do repositório privado, outro limite e outro repositório. Aritmética publicada: 25 existentes + 2 novos de {F2-02} + 1 novo de {F2-08} + 2 de {AUD-05} (personificacao_duracao_min, personificacao_aviso_min) + 2 de {AUD-06} (validades de sessão) = 32, dos quais 1 materializado, 18 com valor vivo e 13 sem consumidor (medido em 2026-09-29, depois de {AUD-05}; anexo_tamanho_max reclassificado por zero leitores em 3dabc30). Nota R-2 recontada em {AUD-06}: 25 + 2 + 1 + 2 de {AUD-05} + 2 de {AUD-06} = 32, porque {AUD-05} contribuiu duas linhas (personificacao_duracao_min e personificacao_aviso_min) e não uma, catalogada esta última na republicação de {AUD-06}.
Nota (gate {AUD-08}, 2026-09-29): email_remetente e ajuda_registro_profissional não são parâmetro: C nomeado no verificador, motivos em L.2.
Quem edita: Super Administrador, exceto email_lote_por_ciclo e vinculo_convites_pendentes_teto_linhas (parâmetros técnicos não editáveis) e modelo_geracao (não editável até a Fase 8, catálogo de modelos ainda sem dono). Auditado: sim, todos os editáveis. Requisitos associados: RF-DIET-002, RF-PAIN-006, RF-TREI-008, RF-TREI-010, RF-ENGA-006, RF-SAUD-004, RF-SAUD-008, RF-SAUD-009, RF-CORE-001, RF-CORE-002, RF-CORE-004, RF-CORE-005, RF-CORE-010, RF-CORE-012, RF-ENGA-004, RF-INTE-003, RF-INTE-004, RN-003, ADR-014, RF-IAGE-001 e D.6. A lista listas_fechadas cobre também as categorias de pose da foto de progresso, os pontos de dobra cutânea da avaliação física e, das preferências de treino do aluno (RF-TREI-008), os objetivos e os equipamentos, que são duas das cinco listas nomeadas no parâmetro. Nota (gate {F3-08}, 2026-09-15): neste card nenhum parâmetro nasce, nenhum é materializado e nenhum é lido, e o total continua em trinta e um. As duas listas fechadas de RF-TREI-008 nascem como tipo enumerado no banco mais um catálogo único de rótulo no código, fonte única, e isso não fecha a porta da administração editável: o precedente de {F1-18} mostra o caminho, a constante virou tabela mantendo a mesma forma de import, e o enumerado de hoje é a semente daquela tabela. Materializar listas_fechadas aqui significaria construir a tabela editável das cinco listas, mais a tela de administração delas, mais a migração das três que pertencem a outros módulos, o que é maior que este card inteiro e que artefato nenhum lhe atribui. A pendência que fica já existia, e este card a nomeia em vez de a criar: 1 de 31 materializado, dono confirmado em {AUD-06}.
Nota ({F1-12}): dois parâmetros já listados aqui têm consumidor novo, e nenhum parâmetro nasce. consentimento_textos já cobre os seis textos, as seis versões e as seis finalidades das categorias de RN-001; eles nascem em server/src/config.ts, o ponto único que o dono a confirmar deste card substitui por tabela editável mantendo a mesma forma de import ({F1-13} não toca este arquivo além de corrigir o comentário que apontava para ele). visibilidade_cruzada: o auxiliar mfit.consentimento_visivel implementa hoje o padrão publicado (todas as especialidades vinculadas) mais a restrição individual do aluno, e passa a ler este parâmetro quando a tabela de configuração do dono a confirmar existir. Nota (gate {F3-02}, 2026-09-14): nenhum parâmetro editável nasce aqui. Quais papéis criam ficha é lista fechada em código, derivada dos Atores de RF-TREI-001 e RF-TREI-002, e parametrizar isso por tela de administração transformaria decisão de privacidade em configuração, o que D.2 e RN-003 não admitem. O limite de fichas ativas por plano já é editável desde {F1-13} e não é tocado. Placar de parâmetros inalterado. Fechamento [2026-09-14]: confirmado inalterado. Em produção (3d25e27), nenhum parâmetro novo. Placar de parâmetros inalterado. Nota (gate {F3-03}, 2026-09-14): nenhum parâmetro novo nasce e nenhum existente é tocado. A janela de anti-duplicação da notificação de prescrição alterada, que seria parâmetro de operação, não é escrita aqui, porque a notificação não é deste card ({ART-WF-06}); o teto de fichas ativas por plano já é editável desde {F1-13} e é apenas consumido pela reativação, pelo mesmo tradutor único de recusa, sem segunda contagem e sem mensagem nova. Placar de parâmetros inalterado. Nota (gate {F3-04}, 2026-09-14): {F3-04} não cria parâmetro de operação nenhum e não mexe em nenhum existente. Em particular, não nasce teto de solicitações abertas por aluno: requisito nenhum o impõe, e inventar um limite numa implementação seria escrever regra de produto sem dono. A defesa contra pedido repetido é a TELA, que mostra ao aluno o pedido aberto no lugar de oferecer a ação de novo, e o banco não impede o pedido repetido, o que se declara aqui para ninguém ler a tela como garantia. Se a garantia for desejada, ela vira card próprio com a regra escrita. Placar inalterado.
Nota (gate {F3-05}, 2026-09-14): nenhum parâmetro de operação nasce aqui e nenhum existente é tocado. sessao_abandono_horas, o único parâmetro que a execução da sessão encosta, já está catalogado, e quem o consome é {F3-10}, na passagem automática a abandonada; {F3-05} não o lê e não o escreve. Placar de parâmetros inalterado, e placar que não muda também se declara.
Nota (gate {F4-01}, Drift 9, 2026-09-29): duas fichas novas, refeicao_nome_max_caracteres e refeicao_observacoes_max_caracteres (grupo Nutrição, valores iniciais 120 e 1000), a entregar em {F4-01}, e a lista tipo_refeicao (oito itens) que passa a ser a sétima lista fechada, também a entregar em {F4-01}. O catálogo sobe de 46 para 48 fichas, sem marcar entrega. Soma do Estado recalculada: 33 com o consumidor no ponto único + 1 com valor vivo fora do ponto único (consentimento_textos) + 12 sem consumidor + 2 a entregar em {F4-01} = 48; nada foi somado a "com consumidor", porque as duas fichas novas só têm consumidor quando {F4-01} fechar. Em mfit.parametro as linhas passam de 42 para 44 no fechamento de {F4-01} (48 menos 4 de forma tabular). Os trechos acima que falam em 46 fichas e em quatro listas sem módulo descrevem o estado anterior a esta reconciliação. O cartão continua [ ]. Fechamento [2026-09-30] de {F4-01}: as duas fichas (refeicao_nome_max_caracteres, 120, faixa 40 a 280, e refeicao_observacoes_max_caracteres, 1000, faixa 280 a 5000) estão em mfit.parametro em produção, que passa de 42 para 44 linhas, e a lista tipo_refeicao (oito itens, 60 no total da tabela de listas) é a sétima lista fechada com consumidor. O consumidor das duas fichas é a rota de refeição, pelo ponto único de leitura, e a mudança vale na chamada seguinte (provado pelo qa, com o valor restaurado ao fim). Soma do Estado recalculada: 35 com o consumidor no ponto único (33 mais as 2 de {F4-01}) + 1 com valor vivo fora do ponto único (consentimento_textos) + 12 sem consumidor = 48. Placar do verificador de parâmetros: 52 pendentes de 98, C 51, universo 149. Nota (gate {F4-02}, Drift 9, 2026-09-29): metas_padrao passa a ter consumidor no ponto único, a ENTREGAR em {F4-02}: semearMetaPadrao lê parametro("metas_padrao") quando o aluno é criado e grava a vigência padrão (nenhuma ficha nova; valor, faixa e efeito "vale para alunos novos" seguem como na linha da tabela acima, e o aluno existente guarda a vigência padrão que recebeu, sem recálculo do passado). Não é entrega: o parâmetro continua contado entre os sem consumidor até o fechamento de {F4-02}, quando o placar ganha mais um com consumidor e menos um sem, medido no dia. Fechamento [2026-09-30] de {F4-02}: metas_padrao passa a ter o consumidor no ponto único: semearMetaPadrao lê parametro("metas_padrao") na criação do aluno e grava a vigência padrão (migração 0044, https://fit.modulareasy.com). Provado pelo qa: o aluno novo nasce com 2000, 150, 250 e 65; mudar o valor em /admin/parametros vale para o aluno seguinte, sem reiniciar; o aluno antigo não é alcançado; o valor foi restaurado e provado por SELECT. Soma do Estado recalculada: 36 com o consumidor no ponto único (35 mais metas_padrao) + 1 com valor vivo fora do ponto único (consentimento_textos) + 11 sem consumidor = 48. Placar do verificador de parâmetros: 52 pendentes de 98, C 53, universo 151. Nota (Inspeção, {AUD-10} e {AUD-11}, 2026-09-30): duas mudanças de catálogo, a entregar, sem marcar entrega. (1) {AUD-10}: as onze fichas email_assunto_<modelo> saem da forma escalar e entra uma ficha de forma tabular, modelos_email (os onze modelos de e-mail, assunto e corpo com variáveis e versões, tabela própria, D-15 do gate {AUD-06}; ficha completa no cartão {ART-CFG-03}). Aritmética do catálogo: 48 fichas menos 11 mais 1 igual 38. Em mfit.parametro: 44 linhas menos 11 igual 33, e a trava de cardinalidade da carga passa a 33. Formas tabulares: 4 (listas_fechadas, consentimento_textos, termos_e_aviso_nao_clinico e conquistas) mais modelos_email igual 5; 33 mais 5 igual 38. Soma do Estado depois de {AUD-10}: 26 com o consumidor no ponto único (36 menos os 11 assuntos igual 25, mais modelos_email, lido pelo renderizador único) + 1 com valor vivo fora do ponto único (consentimento_textos) + 11 sem consumidor = 38. Até {AUD-10} fechar, o Estado vigente continua o de {F4-02}, 36 + 1 + 11 = 48, e as onze linhas email_assunto_ da tabela acima continuam valendo. (2) {AUD-11}: consentimento_textos passa de seis para sete textos, o de nutrição na versão 1, escrito e carregado por {AUD-11}; a ficha continua uma só e o total não muda. O cartão continua [ ]. Nota (Inspeção, gate {AUD-10}, drift 3, 2026-09-30): a trilha das alterações de assunto continua legível. As onze linhas email_assunto_<modelo> saem de mfit.parametro, e as entradas antigas da trilha (entidade igual a parametro) deixariam de ter frase; a ficha modelos_email guarda por modelo o parametro_legado_id (o id da linha removida) e /admin/auditoria resolve por ele a frase "Assunto do e-mail <rótulo>: antigo para novo". As alterações antigas não viram versões do modelo (a versão 1 parte do valor vigente), e o mesmo id permite ao desfazer da migração recriar as onze linhas com o id original. O cartão continua [ ]. Nota (gate {F4-03}, Drift 8, 2026-09-30): nenhuma ficha nova e nenhum parâmetro novo: o catálogo não muda de tamanho. refeicao_nome_max_caracteres e refeicao_observacoes_max_caracteres ganham consumidores no plano alimentar (título do plano, nome da refeição do plano, nome e quantidade do alimento; descrição do plano e notas da refeição do plano), e a descrição das duas linhas da tabela acima passa a nomear o plano alimentar: "tamanho máximo de nome em nutrição: refeição, alimento e plano alimentar" e "tamanho máximo de observações e notas em nutrição: refeição e plano alimentar". Mudar o valor delas passa a valer também para o plano. Valores e faixas ficam como estão. Fechamento [2026-09-30] de {AUD-10} (merge 17b62d6, migrações 0048 e 0049, https://fit.modulareasy.com, /api/estado na versão 17b62d6): as onze fichas email_assunto_<modelo> saíram de mfit.parametro, que passou de 44 para 33 linhas (nenhuma email_assunto_ sobrou, trava de cardinalidade 33), e entrou a ficha de forma tabular modelos_email, com os 11 assuntos migrados para a tabela de modelos (a versão 1 de cada um parte do valor que estava vigente, conferido nos onze). Catálogo: 48 fichas menos 11 mais 1 igual 38 (33 escalares mais 5 tabulares: listas_fechadas, consentimento_textos, termos_e_aviso_nao_clinico, conquistas e modelos_email). Soma do Estado recalculada: 26 com o consumidor no ponto único (36 menos os 11 assuntos, mais modelos_email, lido pelo renderizador único) + 1 com valor vivo fora do ponto único (consentimento_textos) + 11 sem consumidor = 38. Placar do verificador de parâmetros inalterado: 52 pendentes de 98, C 53, universo 151; texto de e-mail em código 11 antes, 0 depois. Os trechos acima que falam em 48 fichas, em 36 + 1 + 11 = 48 e nas onze linhas email_assunto_ descrevem o estado anterior a este fechamento. O cartão continua [ ] porque restam 11 parâmetros sem consumidor. Nota (Inspeção, {AUD-11}, drift 5, 2026-09-30): os textos de consentimento vivem hoje em config.consentimentoCategorias (server/src/config.ts, versão 1.3), não na tabela consentimento_textos. O sétimo texto (nutrição, versão 1) entra ali e em docs/textos/consentimentos.md, e a tabela consentimento_textos segue com dono a confirmar, sem mudar o número de literais do verificador de parâmetros. Os Termos de Uso vigentes e a política de privacidade listam seis categorias; atualizá-los, com nova versão dos Termos por /admin/textos, é decisão do operador e fica fora de {AUD-11}. Nota (Inspeção, {AUD-12}, 2026-09-30): consentimento_textos passa a ter dono nominal, a tarefa {AUD-12}, e deixa de ser "a confirmar" (na linha da tabela acima e nas Notas de {F1-12} e de {AUD-11}, que ficam superadas neste ponto). O mecanismo é o texto versionado que já existe desde {F1-18} (mfit.texto_versionado, tela /admin/textos, só acrescido, vigência por publicado_em), um ponto por categoria, no lugar da constante config.consentimentoCategorias, que deixa de existir. O estado da ficha e o checkbox não mudam: continua pendente, entregue só quando {AUD-12} fechar. Nota (Inspeção, {AUD-12}, drift 2, 2026-09-30): na linha consentimento_textos da tabela acima, o efeito ao mudar, "versão nova exige novo consentimento", está superado: versão nova de texto vale para as próximas concessões; quem já consentiu guarda a versão aceita e o consentimento continua válido. Forçar novo consentimento a cada versão não é deste card; é card próprio se o dono pedir. A semente da tabela são os textos e finalidades carimbados nos consentimentos existentes (versões 1.3 e 1), e a finalidade é publicada como segunda chave, na mesma versão do texto. Fechamento [2026-09-30] de {AUD-12} (merge 4e5ed26, migrações 0050 e 0051, https://fit.modulareasy.com; o qa provou em produção na versão 53c7fd2, mesmo código do merge): consentimento_textos deixa de ser "valor vivo fora do ponto único" e passa a ter o consumidor no ponto único: os sete textos e as sete finalidades vivem em mfit.texto_versionado (14 linhas de semente, md5 igual ao texto carimbado nos consentimentos existentes, versões 1.3 e 1), editáveis em /admin/textos, e a constante config.consentimentoCategorias morreu (texto de consentimento em código 7 antes, 0 depois). Catálogo inalterado em 38 fichas (33 escalares mais 5 tabulares) e mfit.parametro inalterado em 33 linhas. Soma do Estado recalculada: 27 com o consumidor no ponto único (26 mais consentimento_textos) + 0 com valor vivo fora do ponto único + 11 sem consumidor = 38. Placar do verificador de parâmetros: de 52 pendentes de 98 para 51 de 98, C 54, universo 152. Os trechos acima e abaixo que falam em 1 valor vivo fora do ponto único e em consentimento_textos pendente descrevem o estado anterior a este fechamento. O cartão continua [ ] porque restam 11 parâmetros sem consumidor. Nota (Inspeção, gate {AUD-12}, drift 7, 2026-09-30): a finalidade também é texto versionado. A ficha consentimento_textos fala em "texto e versão", e RF-CORE-010 grava a finalidade no consentimento; por isso a finalidade de cada categoria vira uma segunda chave publicada junto com o texto, na mesma versão e na mesma transação, e a especificação da ficha passa a cobrir texto, finalidade e versão. Nota (Inspeção, gate {F4-05}, Drift 2, 2026-09-30): uma ficha nova, nutricao_meta_tolerancia_pct (grupo nutrição, porcentagem, valor inicial 10, faixa 1 a 50), a entregar em {F4-05} na migração 0054, junto da função mfit.meta_atingida, sem marcar entrega. É o parâmetro que decide o dia com meta atingida de RF-DIET-005: o dia conta quando o percentual de calorias de mfit.comparacao_com_meta fica entre cem menos a tolerância e cem mais a tolerância, inclusive. O banco não lê o catálogo em tempo de execução: a tolerância chega à função como argumento, lida pelo ponto único ({ART-CFG-02}). Aritmética do catálogo: 38 fichas mais 1 igual 39 (34 escalares mais as 5 tabulares, listas_fechadas, consentimento_textos, termos_e_aviso_nao_clinico, conquistas e modelos_email; 34 mais 5 igual 39). Em mfit.parametro: 33 linhas mais 1 igual 34, e a trava de cardinalidade da carga passa a 34 no mesmo deploy da migração (o processo antigo recusa subir com 34 linhas, por isso migração e código novo entram no mesmo passo, sem janela). Soma do Estado recalculada: 27 com o consumidor no ponto único + 0 com valor vivo fora do ponto único + 11 sem consumidor + 1 a entregar em {F4-05} = 39; nada foi somado a "com consumidor", porque a ficha só tem consumidor quando {F4-05} fechar. Até lá o Estado vigente continua 27 + 0 + 11 = 38. A tabela acima ganha a linha do parâmetro, com a ressalva "a entregar". O cartão continua [ ]. Fechamento [2026-10-01] de {F4-05}: nutricao_meta_tolerancia_pct (grupo nutrição, porcentagem, 10, faixa 1 a 50) em produção, na migração 0054 (merge f609a9c), com o consumidor no ponto único: acompanhamentoDoPeriodo lê o valor pelo ponto único a cada chamada e o passa a mfit.meta_atingida como argumento, de modo que alterar em /admin/parametros vale na próxima leitura, sem reiniciar (provado em produção: 5 dá 11 dias de 30, 25 dá 28, 0 e 51 recusados com 400, 10 restaurado). Aritmética do catálogo: 39 fichas (34 escalares mais as 5 tabulares); em mfit.parametro, 33 mais 1 igual 34, com a trava de cardinalidade da carga em 34 no mesmo deploy. Estado: 28 com o consumidor no ponto único + 0 com valor vivo fora do ponto único + 11 sem consumidor = 39 (27 do estado anterior mais esta ficha). A migração 0055 só atualiza o texto dos comentários de mfit.parametro e da política de alteração de 33 para 34. Verificador: 51 de 98 pendentes, C 56, universo 154, 7 listas. A linha da tabela acima passa de "a entregar" para entregue. O cartão continua [ ], por causa dos 11 sem consumidor. Nota (Inspeção, gate {F5-01}, Drift 2, 2026-10-01): duas fichas novas, anamnese_texto_curto_max_caracteres (grupo saúde, caracteres, valor inicial 200, faixa 80 a 500) e anamnese_texto_longo_max_caracteres (mesmo grupo, 2000, faixa 500 a 10000), a entregar em {F5-01} na migração 0056, sem marcar entrega, no molde de refeicao_nome_max_caracteres e refeicao_observacoes_max_caracteres: lidas só pelo ponto único ({ART-CFG-02}), na chamada, nunca guardadas, valendo no próximo registro sem reiniciar. As faixas de plausibilidade dos campos numéricos da anamnese não são parâmetro (limite físico, um objeto classificado C no verificador) e a escala de dor de zero a dez é protocolo. Aritmética do catálogo: 39 fichas mais 2 igual 41 (36 escalares mais as 5 tabulares, listas_fechadas, consentimento_textos, termos_e_aviso_nao_clinico, conquistas e modelos_email; 36 mais 5 igual 41). Em mfit.parametro: 34 linhas mais 2 igual 36, e a trava de cardinalidade da carga passa a 36 no mesmo deploy da migração (o processo antigo recusa subir com 36 linhas, por isso migração e código novo entram no mesmo passo, sem janela). Soma do Estado recalculada: 28 com o consumidor no ponto único + 0 com valor vivo fora do ponto único + 11 sem consumidor + 2 a entregar em {F5-01} = 41; nada foi somado a "com consumidor", porque as duas fichas só têm consumidor quando {F5-01} fechar. Até lá o Estado vigente continua 28 + 0 + 11 = 39. Verificador de parâmetros esperado no fechamento, a medir e não a projetar: cardinalidade 36, universo 155, C 57, pendentes 51 de 98, listas 7. A tabela acima ganha as linhas dos dois parâmetros, com a ressalva "a entregar". O título deste cartão, "(39 parâmetros)", descreve o estado vigente e muda no fechamento. O cartão continua [ ]. Fechamento [2026-10-01] de {F5-01}: anamnese_texto_curto_max_caracteres (grupo saúde, caracteres, 200, faixa 80 a 500) e anamnese_texto_longo_max_caracteres (mesmo grupo, 2000, faixa 500 a 10000) em produção, na migração 0056 (merge 9cb16f3), lidas só pelo ponto único ({ART-CFG-02}) dentro das funções, nunca guardadas em escopo de módulo (conferido pelo review), e visíveis em /admin/parametros com texto acentuado (o grupo aparecia como "SAUDE" e foi corrigido em 25b0cc6). O qa provou o efeito dos valores vigentes (200 aceito e 201 recusado, 2000 aceito e 2001 recusado); a alteração dos valores em produção não foi exercitada. Aritmética do catálogo: 41 fichas (36 escalares mais as 5 tabulares); em mfit.parametro, 34 mais 2 igual 36, com a trava de cardinalidade da carga em 36 no mesmo deploy. Estado: 30 com o consumidor no ponto único + 0 com valor vivo fora do ponto único + 11 sem consumidor = 41 (28 do estado anterior mais estas duas fichas). Verificador: 51 de 98 pendentes, C 57, universo 155, 7 listas. As duas linhas da tabela acima passam de "a entregar" para entregue. O cartão continua [ ], por causa dos 11 sem consumidor. Nota (Inspeção, gate {F5-02}, Drifts 2 e 6, 2026-10-01): duas fichas novas, avaliacao_texto_curto_max_caracteres (grupo saúde, caracteres, valor inicial 200, faixa 80 a 500) e avaliacao_texto_longo_max_caracteres (mesmo grupo, 2000, faixa 500 a 10000), a entregar em {F5-02} na migração 0057, sem marcar entrega, no molde dos tetos da anamnese: lidas só pelo ponto único ({ART-CFG-02}), na chamada, nunca guardadas, valendo no próximo registro sem reiniciar. As faixas de plausibilidade dos campos numéricos da avaliação não são parâmetro (limite físico, um objeto classificado C no verificador). A lista ponto_dobra_cutanea (Tríceps, Suprailíaca, Abdominal e Coxa, com o nome "Pontos de dobra cutânea" em /admin/listas) nasce em {F5-02} na mesma tabela mfit.lista_fechada_item: listas_fechadas passa de sete listas com consumidor para oito no fechamento, e a linha acima ganha a ressalva "a entregar". Aritmética do catálogo: 41 fichas mais 2 igual 43 (38 escalares mais as 5 tabulares, listas_fechadas, consentimento_textos, termos_e_aviso_nao_clinico, conquistas e modelos_email; 38 mais 5 igual 43). Em mfit.parametro: 36 linhas mais 2 igual 38, e a trava de cardinalidade da carga passa a 38 no mesmo deploy da migração (o processo antigo recusa subir com 38 linhas, por isso migração e código novo entram no mesmo passo, sem janela). Soma do Estado recalculada: 30 com o consumidor no ponto único + 0 com valor vivo fora do ponto único + 11 sem consumidor + 2 a entregar em {F5-02} = 43; nada foi somado a "com consumidor", porque as duas fichas só têm consumidor quando {F5-02} fechar. Até lá o Estado vigente continua 30 + 0 + 11 = 41. Verificador de parâmetros esperado no fechamento, a medir e não a projetar: cardinalidade 38, listas 8. A tabela acima ganha as linhas dos dois parâmetros, com a ressalva "a entregar". O título deste cartão, "(41 parâmetros)", descreve o estado vigente e muda no fechamento. O cartão continua [ ]. Fechamento [2026-10-06] de {F5-02}: avaliacao_texto_curto_max_caracteres (grupo saúde, caracteres, 200, faixa 80 a 500) e avaliacao_texto_longo_max_caracteres (mesmo grupo, 2000, faixa 500 a 10000) em produção, na migração 0057 (merge 3ab8395), lidas só pelo ponto único ({ART-CFG-02}) dentro das funções, e visíveis em /admin/parametros com o grupo e os itens acentuados. A lista ponto_dobra_cutanea ("Pontos de dobra cutânea", com Tríceps, Suprailíaca, Abdominal e Coxa, todos acentuados) existe em /admin/listas, que passa a mostrar oito listas; listas_fechadas fecha com oito listas com consumidor. O qa provou o efeito dos valores vigentes (200 aceito e 201 recusado, 2000 aceito e 2001 recusado) e não alterou nenhuma lista nem parâmetro de produção; a desativação de item de lista pelo Super foi provada no efêmero (S-8 do db). Aritmética do catálogo: 43 fichas (38 escalares mais as 5 tabulares); em mfit.parametro, 36 mais 2 igual 38, com a trava de cardinalidade da carga em 38 no mesmo deploy. Estado: 32 com o consumidor no ponto único + 0 com valor vivo fora do ponto único + 11 sem consumidor = 43 (30 do estado anterior mais estas duas fichas). Verificador: 51 de 98 pendentes, C 58, universo 156, 8 listas. As duas linhas da tabela acima passam de "a entregar" para entregue. O cartão continua [ ], por causa dos 11 sem consumidor. Nota (Inspeção, gate {F5-04}, Drifts 2, 9 e 11, 2026-10-06): três fichas novas, exame_nome_max_caracteres (grupo saúde, caracteres, valor inicial 160), exame_resumo_max_caracteres (4000) e exame_observacoes_max_caracteres (2000), a entregar em {F5-04} na migração 0059, sem marcar entrega, no molde dos tetos da refeição: lidas só pelo ponto único ({ART-CFG-02}), na chamada, nunca guardadas, valendo no próximo registro sem reiniciar. As linhas da tabela acima trazem a ressalva "a entregar"; as faixas são as já publicadas dos tetos da avaliação, por decisão do Fiscal: 80 a 500 para o nome, igual à de avaliacao_texto_curto_max_caracteres, e 500 a 10000 para o resumo e as observações, igual à de avaliacao_texto_longo_max_caracteres; os valores iniciais 4000 e 2000 cabem nela sem ajuste. O mínimo de 3 caracteres do nome é regra fixa, um objeto classificado C no verificador. A lista tipo_exame (Laboratorial, Imagem, Cardiológico, Funcional e Outro, com o nome "Tipos de exame" em /admin/listas) nasce em {F5-04} na mesma tabela mfit.lista_fechada_item, a entregar em {F5-04}: listas_fechadas passa de oito listas com consumidor para nove no fechamento. Limite de envio: anexo_tamanho_max segue com a faixa de 1 a 50 megabytes, e essa faixa publicada não pode passar do limite de envio do bloco do servidor de fit.modulareasy.com (51 megabytes, só nesse bloco e nunca no arquivo global do servidor web; ficha em {ART-INT-02}); subir a faixa exige subir o limite antes. Aritmética do catálogo: 43 fichas mais 3 igual 46 (41 escalares mais as 5 tabulares, listas_fechadas, consentimento_textos, termos_e_aviso_nao_clinico, conquistas e modelos_email; 41 mais 5 igual 46). Em mfit.parametro: 38 linhas mais 3 igual 41, e a trava de cardinalidade da carga passa a 41 no mesmo deploy da migração (o processo antigo recusa subir com 41 linhas, por isso migração e código novo entram no mesmo passo, sem janela). Soma do Estado recalculada: 32 com o consumidor no ponto único + 0 com valor vivo fora do ponto único + 11 sem consumidor + 3 a entregar em {F5-04} = 46; nada foi somado a "com consumidor", porque as três fichas só têm consumidor quando {F5-04} fechar. Até lá o Estado vigente continua 32 + 0 + 11 = 43. Verificador de parâmetros esperado no fechamento, a medir e não a projetar: cardinalidade 41, listas 9. O título deste cartão, "(43 parâmetros)", descreve o estado vigente e muda no fechamento. O cartão continua [ ]. Fechamento [2026-10-06] de {F5-04}: as três fichas exame_nome_max_caracteres (160, faixa de 80 a 500), exame_resumo_max_caracteres (4000, faixa de 500 a 10000) e exame_observacoes_max_caracteres (2000, faixa de 500 a 10000) estão em mfit.parametro em produção (migração 0059, merge b078e76), com o consumidor no ponto único, valendo no próximo registro sem reiniciar, e a lista tipo_exame está em mfit.lista_fechada_item (cinco itens, editável em /admin/listas). Catálogo de 43 para 46 fichas; mfit.parametro de 38 para 41 linhas (trava de cardinalidade da carga em 41, no mesmo passo da migração); listas fechadas com consumidor de 8 para 9. Estado: 35 de 46 com o consumidor no ponto único, 0 com valor vivo fora do ponto único e 11 sem consumidor: 35 + 0 + 11 = 46 (32 mais as 3 do exame). anexo_tamanho_max segue em 20, faixa de 1 a 50, e a faixa não passa do limite de 51 megabytes do bloco do servidor. Os trechos acima que falam em 43 fichas e em 3 a entregar descrevem o estado anterior a este fechamento. O cartão continua [ ] porque restam 11 parâmetros sem consumidor. Nota (Inspeção, gate {F5-05}, Drifts 4, 5 e 7, 2026-10-06): uma ficha nova, prescricao_texto_longo_max_caracteres (grupo saúde, caracteres, valor inicial 4000, faixa de 500 a 10000, a mesma dos tetos longos da avaliação e do exame), a entregar em {F5-05} na migração 0061, sem marcar entrega, no molde dos tetos do exame: lida só pelo ponto único ({ART-CFG-02}), na chamada, nunca guardada, valendo no próximo registro sem reiniciar; serve os quatro campos longos (diagnóstico, medicamentos, posologia e observações). O teto curto NÃO nasce: a duração deixou de ser texto (Drift 7) e não sobra campo curto. A unidade da duração (dias, semanas ou meses) é constante estrutural, objeto classificado C no verificador, com restrição no banco, e NÃO lista fechada editável (entra no cálculo da vigência; precedente dos dias da semana): listas_fechadas segue em nove listas com consumidor. O texto do aviso do receituário é texto versionado (aviso_receituario, ponto prescricao, em mfit.texto_versionado), não parâmetro. Aritmética do catálogo: 46 fichas mais 1 igual 47 (42 escalares mais as 5 tabulares, listas_fechadas, consentimento_textos, termos_e_aviso_nao_clinico, conquistas e modelos_email; 42 mais 5 igual 47). Em mfit.parametro: 41 linhas mais 1 igual 42, e a trava de cardinalidade da carga passa a 42 no mesmo deploy da migração (migração e código novo no mesmo passo, sem janela); o gate previa 43 (dois tetos), e a decisão da Inspeção sobre a duração derruba o teto curto e fixa 42. Soma do Estado recalculada: 35 com o consumidor no ponto único + 0 com valor vivo fora do ponto único + 11 sem consumidor + 1 a entregar em {F5-05} = 47; nada foi somado a "com consumidor", porque a ficha só tem consumidor quando {F5-05} fechar. Até lá o Estado vigente continua 35 + 0 + 11 = 46. Verificador de parâmetros esperado no fechamento, a medir e não a projetar: cardinalidade 42, listas 9, universo de 160 para 162 (o teto longo e a constante da unidade, C). O título deste cartão, "(46 parâmetros)", descreve o estado vigente e muda no fechamento. O cartão continua [ ]. Fechamento [2026-10-06] de {F5-05}: a ficha prescricao_texto_longo_max_caracteres (4000, faixa de 500 a 10000, em caracteres) está em mfit.parametro em produção (migração 0061, merge de718a6), com o consumidor no ponto único, valendo nos quatro textos longos da prescrição (diagnóstico, medicamentos, posologia e observações) no próximo registro, sem reiniciar. Catálogo de 46 para 47 fichas; mfit.parametro de 41 para 42 linhas (trava de cardinalidade da carga em 42, no mesmo passo da migração); listas fechadas com consumidor inalteradas em 9 (a unidade da duração é constante estrutural, não lista). Estado: 36 de 47 com o consumidor no ponto único, 0 com valor vivo fora do ponto único e 11 sem consumidor: 36 + 0 + 11 = 47 (35 mais a ficha da prescrição). O verificador de parâmetros mede universo 165 e 67 objetos classificados C (a previsão do gate era 162; a decisão do Fiscal trouxe cinco C novas: a faixa da quantidade, as unidades e os três espelhos da migração), 98 editáveis. O texto do aviso do receituário não é parâmetro: é texto versionado. Os trechos acima que falam em 46 fichas e em 1 a entregar em {F5-05} descrevem o estado anterior a este fechamento. O cartão continua [ ] porque restam 11 parâmetros sem consumidor. Nota (Inspeção, gate {F5-06}, Drifts 2, 6 e 7, 2026-10-06): uma ficha nova e uma lista nova, a entregar em {F5-06} na migração 0062, sem marcar entrega. A ficha: reabilitacao_texto_longo_max_caracteres (grupo saúde, caracteres, valor inicial 4000, faixa de 500 a 10000, a mesma dos tetos longos da avaliação, do exame e da prescrição), lida só pelo ponto único ({ART-CFG-02}), na chamada, nunca guardada, valendo no próximo registro sem reiniciar; serve os seis campos longos da sessão (tratamento realizado, exercícios realizados, notas de amplitude, notas de progresso, plano da próxima sessão e observações). O teto curto NÃO nasce: a região é lista, e não sobra campo curto. A lista: regiao_corporal (dezoito itens, com o lado onde há lado, mais "Outra"), editável em /admin/listas na mesma tabela mfit.lista_fechada_item: listas_fechadas passa de nove listas com consumidor para dez no fechamento. É lista editável, e não constante, porque a região é o agrupamento da série de dor de {F7-10} e não regra de cálculo; a escala de dor de 0 a 10 (constante estrutural) e a duração de 1 a 300 minutos (constante técnica) não são parâmetro nem lista, ambas com restrição espelhada no banco. Aritmética do catálogo: 47 fichas mais 1 igual 48 (43 escalares mais as 5 tabulares, listas_fechadas, consentimento_textos, termos_e_aviso_nao_clinico, conquistas e modelos_email; 43 mais 5 igual 48). Em mfit.parametro: 42 linhas mais 1 igual 43, e a trava de cardinalidade da carga passa a 43 no mesmo deploy da migração (migração e código novo no mesmo passo, sem janela). Soma do Estado recalculada: 36 com o consumidor no ponto único + 0 com valor vivo fora do ponto único + 11 sem consumidor + 1 a entregar em {F5-06} = 48; nada foi somado a "com consumidor", porque a ficha só tem consumidor quando {F5-06} fechar. Até lá o Estado vigente continua 36 + 0 + 11 = 47. Verificador de parâmetros esperado no fechamento, a medir e não a projetar: cardinalidade 43, listas 10; o universo e os objetos classificados C se medem no fechamento, sem projeção. O título deste cartão, "(47 parâmetros)", descreve o estado vigente e muda no fechamento. O cartão continua [ ].
Para que serve: garantir que todo valor de operação do catálogo seja lido de um lugar só, e que nenhum literal de negócio novo nasça fora dele.
Relacionado com: RF-PAIN-011, ADR-012, L.2, {ART-CFG-01}; tarefa {AUD-06}.
Onde fica: servidor, módulo único de leitura; e ops/verifica-parametros.mjs.
Especificação: módulo único server/src/parametros.ts com duas leituras: parametro(chave) para os escalares de mfit.parametro e listaFechada(nome) para as listas de mfit.lista_fechada_item, cada uma com cache carregado na subida, invalidado na escrita, e trava de cardinalidade (28 linhas; seis listas, cada uma com ao menos um item ativo). A leitura parametro(chave) é tipada. Duas travas na carga: cardinalidade contra o catálogo publicado (a tabela tem de ter exatamente o número de linhas declarado, senão o processo NÃO sobe) e chave desconhecida (a função lança, nunca devolve nulo). O verificador é por LITERAL, nunca por nome, com lista nominal de exceções técnicas com motivo de uma linha por item, decoy que o reprova, controle negativo que não o reprova, e trava de universo que reprova quando o total de ocorrências sobe sem linha nova no catálogo. Placar honesto obrigatório: o verificador imprime quantos dos valores de negócio medidos já estão no ponto único e quantos faltam, com card dono nominal dos que faltam.
Estado: entregue em {AUD-06} (merge 29380ae, https://fit.modulareasy.com, migrações 0037 e 0038). Função única parametro(chave) com cache invalidado na escrita e as duas travas na carga (cardinalidade 28 e chave desconhecida lança). Verificador ops/verifica-parametros.mjs: RESULTADO OK, 79 de 101 literais de negócio restantes (22 fechados mais 79 restantes igual a 101, universo 148, 121 candidatas, 0 soltas), com decoy que o reprova, controle negativo que não o reprova e dono nominal em cada restante ({AUD-07} 9, {AUD-08} 17, consentimento_textos 1, cards de módulo 52). Ressalva nomeada: o verificador lê a árvore de fonte e não roda dentro da imagem do servidor, roda na árvore do commit. Nota (gate {AUD-07}, Drift 2, 2026-09-29): server/src/arquivos/tipoConteudo.ts é reclassificado de B para C, com o motivo "mapa extensão para tipo MIME (protocolo IANA); serve também os ativos da SPA; a regra de negócio é anexo_extensoes e midia_exercicio_formatos"; o denominador de editáveis passa de 101 para 100 quando {AUD-07} fechar, e a medição acima permanece como o retrato de {AUD-06}.
Nota (gate {AUD-08}, Drifts 4 e 8, 2026-09-29): duas reclassificações de A para C, no molde do tipoConteudo de {AUD-07}. config.emailRemetente: marca única (L.3) e endereço autenticado no provedor de envio (SMTP_URL, SPF e DKIM do domínio): trocar o endereço exige infraestrutura, trocar o nome contraria L.3; {ART-MSG-01} já o fixa como "endereço institucional do produto". config.ajudaRegistroProfissional: reafirma ADR-004 ao usuário; o texto só muda quando a decisão muda, e editar sem deploy deixaria a tela afirmar o que o sistema não faz. Denominador de editáveis: 100 para 98. Trava de cardinalidade 42 linhas (era 28); o verificador também reconhece a forma texto e confere que nenhum parâmetro do catálogo tem cópia literal no web.
Fechamento [2026-09-29] de {AUD-07} (merge 7b47fa6, https://fit.modulareasy.com): a segunda leitura listaFechada(nome) está entregue no mesmo módulo server/src/parametros.ts, com cache carregado na subida, recarregado depois da escrita confirmada e trava de carga (seis listas, cada uma com ao menos um item ativo). O verificador fecha em RESULTADO OK com 70 de 100 literais de negócio restantes (30 fechados, sendo 22 de {AUD-06} mais 8 de {AUD-07}; 47 exceções C; universo 147, 70 + 30 + 47). A nota acima do Drift 2 está cumprida: o denominador de editáveis passou de 101 para 100.
Fechamento [2026-09-29] de {AUD-08} (merge fa725bc, migração 0041, https://fit.modulareasy.com): o verificador fecha em RESULTADO OK com 52 de 98 literais de negócio restantes (46 fechados, sendo 22 de {AUD-06}, 8 de {AUD-07} e 16 de {AUD-08}; 48 exceções C; universo 146, 52 + 46 + 48; 0 soltas), com a trava de cardinalidade em 42 linhas e o denominador de editáveis em 98. Nenhum restante tem dono {AUD-08}. A forma texto é reconhecida e nenhum parâmetro do catálogo tem cópia literal no web.
Para que serve: permitir ao Super Administrador ajustar assunto e corpo de cada e-mail transacional sem publicar versão nova, com as variáveis protegidas e o histórico guardado.
Relacionado com: RF-PAIN-011 (extensão dos modelos de e-mail), ADR-012, L.2; {ART-CFG-01} (a ficha modelos_email), {ART-CFG-02} (o verificador), {ART-MSG-01} a {ART-MSG-03}, {ART-WF-01} a {ART-WF-03} e {ART-WF-05} (quem dispara), {ART-INT-03} (o envio), {ART-SCR-03} (a tela); tarefa {AUD-10}; teste {TA-99}.
Onde fica: banco de dados (tabela do modelo e tabela das versões), servidor (renderizador único e rotas de administração) e aplicação (/admin/emails).
Especificação: entidades: modelo_email (chave única, evento em texto de uma linha, variáveis permitidas, variáveis obrigatórias, versão vigente) e modelo_email_versao (id, modelo, número sequencial por modelo, assunto, corpo, autor, criada em), esta só de acréscimo, com alteração e remoção negadas à aplicação e unicidade de (modelo, número). Semente: um registro por modelo e a versão 1 de cada um, com o assunto vigente em mfit.parametro no dia da migração e o corpo de hoje do código, as interpolações trocadas pelas variáveis. Formulário do editor, um por modelo: assunto (texto, obrigatório, 3 a 120 caracteres, linha única, aceita variáveis da lista do modelo); corpo (texto longo, obrigatório, 20 a 5000 caracteres, parágrafos separados por linha em branco, texto simples, sem HTML); as variáveis permitidas do modelo à vista, cada uma inserível no cursor; ações pré-visualizar, gravar (confirmação nominal do modelo) e cancelar. Histórico: lista das versões com número, autor e data, e a ação restaurar, que cria versão nova com o conteúdo da escolhida. Validação no servidor, na gravação e na prévia: toda ocorrência de chaves duplas tem de ser uma variável da lista do modelo, e a desconhecida é recusada com 422 e a mensagem nomeando a variável e a lista aceita; {{endereco}} é obrigatória no corpo dos onze; chave dupla sem fechamento é recusada; assunto vazio, só de espaços, com quebra de linha ou TAB, ou fora de 3 a 120 caracteres é recusado com a faixa na mensagem; corpo fora de 20 a 5000 é recusado com a faixa; recusa não grava versão. Renderização: um renderizador único, usado pelo envio e pela prévia, lê a versão vigente no momento de renderizar, substitui as variáveis, produz o texto e deriva o HTML (cada parágrafo em <p>, todo valor e todo texto do operador escapados, {{endereco}} como link), e o registro do envio guarda o número da versão usada; nenhum texto de e-mail fica em código, e o verificador de {ART-CFG-02} reprova corpo literal, com o remetente como exceção nomeada. Prévia: dados de demonstração fixos por variável (nome "Maria Exemplo", endereço de exemplo do produto, especialidade "Personal Trainer", validade igual ao valor vigente de recuperacao_validade_min), sem gravar e sem enfileirar. Permissão: o Super Administrador lê, grava e restaura; o Administrador lê a lista, o conteúdo, as variáveis e o histórico, sem controle de edição, e a rota de escrita lhe responde 403; profissional e aluno não alcançam a tela nem as rotas. Auditoria: cada gravação e cada restauração gera entrada com modelo, versão, assunto e corpo antes e depois. Catálogo de variáveis, com os valores entre chaves duplas no texto (exemplo: {{nome}}):
| Modelo | Evento | Variáveis permitidas | Obrigatória no corpo |
|---|---|---|---|
| confirmacao_conta | criação de conta | nome, endereco, validade_minutos | endereco |
| recuperacao_senha | pedido de redefinição de senha | nome, endereco, validade_minutos | endereco |
| acesso_criado | criação de usuário pela administração | nome, endereco, validade_minutos | endereco |
| convite_vinculo | convite de vínculo, ao aluno | nome_aluno, nome_profissional, especialidade, endereco | endereco |
| vinculo_aceito | convite aceito, ao profissional | nome_profissional, nome_aluno, endereco | endereco |
| vinculo_recusado | convite recusado, ao profissional | nome_profissional, nome_aluno, endereco | endereco |
| vinculo_encerrado | vínculo encerrado, às duas partes | nome_destinatario, nome_outra_parte, endereco | endereco |
| convite_cancelado | convite cancelado, ao aluno | nome_aluno, nome_profissional, endereco | endereco |
| solicitacao_ficha_criada | pedido de ficha, ao profissional | nome_profissional, nome_aluno, endereco | endereco |
| solicitacao_ficha_atendida | pedido atendido, ao aluno | nome_aluno, nome_profissional, endereco | endereco |
| solicitacao_ficha_recusada | pedido recusado, ao aluno | nome_aluno, nome_profissional, endereco | endereco |
Estado: entregue em {AUD-10} (ver o Fechamento ao fim desta ficha). Onze modelos no universo, medido em 30/09/2026 por três meios (funções de modelo no código, mapa de modelos do envio e linhas email_assunto_ em mfit.parametro: 11 = 11 = 11). Placar: antes, 0 de 11; vigente, 11 de 11 modelos editáveis. Nota (Inspeção, gate {AUD-10}, drifts 2, 3, 4, 6 e 7, 2026-09-30): cinco correções a esta ficha, que valem onde ela divergir. (1) Assunto: {{endereco}} é recusada no assunto, com a variável nomeada na mensagem, porque nos três primeiros modelos (confirmacao_conta, recuperacao_senha e acesso_criado) ela carrega o endereço de uso único em claro, e no assunto ele iria para o cabeçalho, a notificação do celular, a pré-visualização do cliente de e-mail e o registro do servidor de correio; continua obrigatória no corpo dos onze, e as demais variáveis da lista valem no assunto e no corpo. Onde a Validação acima diz que o assunto aceita variáveis da lista do modelo, leia: as da lista menos endereco. (2) Forma da entidade modelo_email: a versão vigente não é atributo, é derivada, o maior número de versão do modelo, porque restaurar cria versão nova e a vigente é sempre a última (uma coluna própria seria segunda fonte capaz de divergir); a entidade ganha rotulo (o título exibido, a tela nunca mostra a chave técnica) e faixa (as faixas do assunto, 3 a 120 caracteres em linha única, e do corpo, 20 a 5000, como dado na mesma forma da faixa dos demais parâmetros, nunca como número no código). (3) Trilha: a entidade ganha parametro_legado_id, o id da linha email_assunto_<modelo> que a migração remove, e a trilha de /admin/auditoria resolve por ele a frase legível das alterações antigas de assunto ("Assunto do e-mail <rótulo>: antigo para novo"), que não viram versões mas continuam legíveis. (4) Permissão: a pré-visualização é leitura e atende os dois papéis; o Administrador ganha a prévia e o "Ver renderizado" das versões gravadas, continua sem editor, sem gravar e sem restaurar, e a rota de escrita lhe responde 403. (5) Ortografia: os corpos saem do código para a semente da migração e o verificador de ortografia passa a varrer o arquivo dessa migração; o texto que o operador grava depois não passa por verificador de ortografia, perda declarada. Fechamento [2026-09-30] de {AUD-10}: os onze modelos estão em produção (merge 17b62d6, migrações 0048 e 0049, https://fit.modulareasy.com, /api/estado na versão 17b62d6), editáveis pelo Super Administrador em /admin/emails, com a versão 1 de cada um igual ao texto que o código produzia (texto 11 de 11 idêntico; HTML 9 de 11 idêntico e 2 com a troca declarada de "Clique" para "Acesse", em recuperacao_senha e acesso_criado). Placar: 11 de 11. Produção: modelo_email 11 linhas, modelo_email_versao 13 (11 mais a versão 2, de teste, e a versão 3, restauração da 1, ambas de recuperacao_senha), email_saida registra modelo_versao. A migração 0049 tirou o código interno de card da descrição do evento acesso_criado (P2-1 do qa). Ressalva nominal: a tela só recusa o texto inválido depois da confirmação (P2-2). Texto de e-mail em código: 11 antes, 0 depois.
Para que serve: medir se o sistema está sendo usado como se espera.
Relacionado com: N.1, RF-PAIN-007, RF-PAIN-008; tarefas F7-12 e F7-13.
Onde fica: painel do administrador e relatórios.
Especificação: alunos ativos na semana (alunos com ao menos uma atividade em sete dias, contagem distinta); sessões por aluno ativo (sessões concluídas dividido por alunos ativos, no período); refeições por aluno ativo (mesma fórmula com refeições); proporção de fichas criadas pelo aluno (fichas com autor igual ao aluno dividido pelo total de fichas); taxa de aproveitamento da geração (prévias salvas dividido por prévias geradas); tempo até o aceite do vínculo (mediana da diferença entre criação e aceite, em horas); abandono de sessão (sessões abandonadas dividido por sessões iniciadas); vínculos ativos por aluno (média); ocupação de anexos por aluno (soma de bytes dividido por alunos com anexo). Granularidade, diária e mensal. Fonte, tabelas correspondentes. Onde aparece, painel administrativo e relatórios exportáveis.
Painéis e relatórios
Para que serve: dar ao aluno o dia dele em uma tela.
Relacionado com: RF-PAIN-001, RF-ENGA-001 a 006, RF-TREI-010; tarefas F7-01 a F7-06, F7-15 e F3-10.
Onde fica: caminho /painel.
Especificação: responde a pergunta o que eu faço hoje e como estou evoluindo. Quem acessa, aluno. Blocos e definições: treino do dia (ficha ativa mais recente), atalho de retomar a sessão enquanto houver sessão em andamento, indicador de completude do perfil enquanto o percentual for menor que cem, resumo nutricional (consumido, restante e percentual contra a meta vigente), última medida com variação, sequência de dias, calendário de doze semanas, conquistas concedidas e primeiros passos enquanto houver pendente. Sem filtros, o período é o dia corrente. Fonte, tabelas de treino, nutrição, medidas e engajamento. Atualização, a cada carga. Estados, vazio por bloco.
Para que serve: priorizar a carteira de treino do dia.
Relacionado com: RF-PAIN-002, RF-PAIN-006; tarefas F7-07 e F7-11.
Onde fica: caminho /painel para o papel.
Especificação: responde quem precisa de mim hoje. Colunas por aluno: nome, estado do vínculo, dias desde a última atividade, sessões nos últimos sete dias, solicitações abertas e mensagens não lidas. Filtros, estado do vínculo e inatividade. Ações por linha, abrir detalhe, criar ficha, conversar. Fonte, vínculo, sessões, solicitações e mensagens. Escopo, apenas alunos com vínculo ativo com o profissional.
Nota (gate {F3-04}, 2026-09-14): este cartão continua [ ]. O bloco de solicitações abertas que nasce em {F3-04} é a lista mínima que o H1 de RF-TREI-004 cobra por escrito ("vê a solicitação com estado aberto na lista dele"), e não o painel deste cartão, que tem cinco indicadores, carteira, alerta de aluno inativo há sete dias e bloco por especialidade, todos de {F7-07}. Nenhum indicador nasce aqui, nem em forma de número solto.
Para que serve: ver aderência antes de ajustar plano.
Relacionado com: RF-PAIN-003, RF-DIET-005; tarefas F7-08 e F4-05.
Onde fica: caminho /painel para o papel.
Especificação: responde quem está seguindo o plano. Colunas por paciente: nome, plano vigente, média diária de calorias e de cada macronutriente nos últimos sete dias, dias com meta atingida, dias desde o último registro de refeição. Filtros, período de sete ou trinta dias. Ações por linha, abrir detalhe, editar plano, conversar.
Nota (Inspeção, gate {F4-05}, Drift 6, 2026-09-30): este painel precisa da mesma regra de RF-DIET-005 e não a reescreve. A decisão de o dia ter meta atingida mora em mfit.meta_atingida (migração 0054, a entregar em {F4-05}, com a tolerância nutricao_meta_tolerancia_pct) e a agregação do período, em uma função única do servidor (acompanhamentoDoPeriodo, também de {F4-05}); {F7-08} consome as duas. O painel não calcula meta atingida por conta própria: a coluna "dias com meta atingida" e a média diária vêm da mesma conta do acompanhamento, para que a tela de um paciente e a linha do painel nunca divirjam.
Fechamento [2026-10-01] de {F4-05}: a regra do dia com meta atingida (mfit.meta_atingida, migração 0054) e a agregação do período (acompanhamentoDoPeriodo, com a tolerância nutricao_meta_tolerancia_pct) estão entregues e em produção (merge f609a9c), e {F7-08} as consome sem reescrevê-las. O painel em si segue [ ], porque pertence a {F7-08}.
Para que serve: ver o que chegou de clínico.
Relacionado com: RF-PAIN-004; tarefa F7-09.
Onde fica: caminho /painel para o papel.
Especificação: responde o que preciso ler e prescrever. Blocos: exames recentes (paciente, tipo, nome, data, lido ou não), prescrições vigentes com duração, anamneses preenchidas e pacientes sem registro nos últimos trinta dias. Ações por linha, abrir exame, prescrever, conversar. Escopo, apenas pacientes com vínculo ativo.
Para que serve: acompanhar a evolução da dor por tratamento.
Relacionado com: RF-PAIN-005; tarefa F7-10.
Onde fica: caminho /painel para o papel.
Especificação: responde o tratamento está evoluindo. Blocos: sessões recentes, evolução da dor por região corporal (série de dor depois por data), pacientes sem sessão nos últimos trinta dias e fichas de reabilitação ativas. Ações por linha, registrar sessão, abrir detalhe, conversar.
Para que serve: enxergar o sistema inteiro de uma vez.
Relacionado com: RF-PAIN-007; tarefa F7-12.
Onde fica: painel administrativo.
Especificação: responde como está o produto. Indicadores: usuários por papel e especialidade, fichas, sessões e refeições nos últimos trinta dias, alunos ativos em sete dias, vínculos pendentes, mensagens no período e ocupação de armazenamento. Filtros, período. Fonte, contagem direta nas tabelas. Cada indicador é igual à contagem correspondente na base, sem cache que envelheça além de cinco minutos.
Para que serve: levar o número para fora e acompanhar tendência.
Relacionado com: RF-PAIN-008, ART-KPI-01; tarefa F7-13.
Onde fica: caminho /admin/relatorios.
Especificação: relatórios: evolução de cadastros por papel, vínculos por especialidade e estado, atividade por período, uso por módulo e últimas medidas registradas no sistema. Filtros, período e papel. Agrupamento, por dia, semana ou mês. Exportação, arquivo de valores separados com exatamente as linhas exibidas. Rodapé com total igual à soma da coluna.
Integração e infraestrutura
Para que serve: produzir proposta de treino, proposta de dieta, explicação em linguagem simples dos quatro registros clínicos, mídia demonstrativa de exercício e conteúdo do guia da plataforma, os cinco pontos de M.2.
Relacionado com: RF-IAGE-001 a 003, RF-SAUD-010, RF-EXER-005, RF-AJUD-003, ADR-008; tarefas F8-05 a F8-08, F5-10, F8-12 e F9-03.
Onde fica: camada interna no servidor de aplicação.
Especificação: direção, saída. Autenticação, chave de serviço apenas no servidor. Credencial provida por, a operação do produto. Payload de saída, contexto do aluno e instrução; payload de entrada, estrutura própria do sistema com identificadores do catálogo. Mapeamento, identificador de exercício retornado é conferido contra o catálogo antes de compor a prévia. Idempotência, não aplicável, cada acionamento é uma proposta nova; o controle é o limite mensal por plano. Tempo limite, sessenta segundos, com uma nova tentativa. Falha, mensagem de indisponibilidade e composição manual. Limite de uso, o do plano do aluno.
Para que serve: guardar mídia de exercício e anexo sensível com políticas diferentes.
Relacionado com: RF-EXER-002, RF-SAUD-004, RF-SAUD-008, RF-SAUD-009, ADR-009, ADR-013; tarefas F1-01, F2-02, F5-04, F5-08, F5-09.
Onde fica: servidor de aplicação.
Especificação: direção, bidirecional. Autenticação, segredo de assinatura no servidor e diretório no volume próprio (não há serviço externo de armazenamento). Dois repositórios: público, servido pela própria aplicação com cache longo, leitura direta, escrita apenas pelo administrador, para mídia de exercício e assets de marca; privado, sem leitura direta, saída apenas por endereço assinado (HMAC-SHA256) gerado para quem tem direito, com validade configurável de até quinze minutos. Chave do objeto, prefixada por aluno e categoria, com nome derivado de hash do conteúdo no repositório público (reenviar o mesmo arquivo não cria objeto novo, e nome enviado pelo usuário nunca chega ao disco). Falha, envio recusado não cria linha, e linha sem objeto é limpa pela rotina de expurgo.
Estado: leitura dos dois repositórios provisionada e provada em F1-01; a escrita entregue em F2-02, no repositório público, com guarda de tamanho, detecção de formato pelos bytes e remoção do objeto anterior após o commit; a escrita no repositório privado segue em F5-04, F5-08 e F5-09, copiando o mesmo desenho. Estado: 1 de 2 repositórios com escrita.
Nota (Inspeção, gate {F5-04}, Drifts 2, 3 e 4, 2026-10-06): (1) Limite de envio: o limite de corpo de 20 megabytes do servidor web barra um arquivo de exatamente 20 MiB mais o envelope do envio, com um 413 em HTML; ele sobe para 51 megabytes, validado antes da recarga, recarregado e nunca reiniciado. Condição ratificada: vale SÓ no bloco do servidor de fit.modulareasy.com, nunca no arquivo global do servidor web, e a faixa publicada de anexo_tamanho_max (1 a 50 megabytes, {ART-CFG-01}) não pode passar do limite desse bloco: subir a faixa exige subir o limite antes e republicar a faixa. (2) Desativar não apaga o objeto: o exame desativado segue legível ao titular e ao Super Administrador e o anexo segue na cota; o objeto só sai na exclusão definitiva, e o verificador de órfãos disco contra banco no repositório privado é quem garante que não sobra objeto sem linha nem linha sem objeto (a rotina agendada de {ART-JOB-05} continua sendo a da Fase 8). (3) Diretório vazio: remover um objeto apaga o diretório pai quando ele fica vazio, nunca acima da raiz do repositório; o mecanismo é comum aos dois repositórios, então a mídia de exercício ganha a mesma limpeza junto. Estado: a escrita no repositório privado, que a linha de Estado acima dá como seguinte, nasce em {F5-04}; o placar de repositórios com escrita (hoje 1 de 2) a medir no fechamento, não a projetar. O cartão continua [ ].
Fechamento [2026-10-06] de {F5-04}: a escrita no repositório privado está em produção (merge b078e76), pela escrita única arquivos/escrita.ts, que atende os dois repositórios e substituiu escritaPublico.ts; chave privado/exames/<exame_id>/<hash16><ext>, objeto gravado antes da linha e removido se a linha falhar, tipo pelos bytes (formatoPelosBytes, também usado pela mídia). Limite de envio de 51 megabytes no bloco do servidor de https://fit.modulareasy.com, só nele (backup do bloco, validação, recarga e nunca reinício; os outros sites seguem 200); acima de 51 o servidor web recusa em HTML e a tela já barra antes. Remover um objeto apaga o diretório pai vazio, nunca acima da raiz, e o exercício ganhou a mesma limpeza (provado). Verificador de órfãos disco contra banco no repositório privado: 0 órfãos, 0 linhas sem objeto, 0 diretórios vazios. Placar de repositórios com escrita: 2 de 2 (o público desde {F2-02} e o privado agora). O cartão continua [ ] porque {F5-09} (validade curta do endereço e separação mídia x exame) e {F5-08} (foto de progresso) ainda usam este serviço. Débito declarado pelo review: o CHECK da extensão e a allowlist com Content-Disposition do repositório privado ficam em {F5-09} e {F5-08}.
Para que serve: entregar confirmação de conta, recuperação de senha e acesso criado.
Relacionado com: RF-CORE-002, RF-CORE-005, RF-PAIN-009; tarefas F1-04, F1-07, F7-14.
Onde fica: servidor de aplicação.
Especificação: direção, saída. Autenticação, credencial de serviço no servidor. Fila, tabela mfit.email_saida, com chave de evento única garantindo a idempotência por construção. Rotina de envio, no próprio processo mfit-app (ADR-013), sem processo externo. Eventos enviados, os três templates de ART-MSG. Idempotência, um envio por evento, com chave de evento. Falha, nova tentativa em fila com recuo progressivo e alerta quando a fila passa de cinquenta itens. Sem envio de marketing por este canal.
Para que serve: trazer treino, passos e frequência cardíaca do serviço que o aluno já usa, sem exigir aplicativo nativo.
Relacionado com: RF-INTE-003, RF-INTE-004, RF-INTE-005, ADR-011, F.2; tarefas F8-13 a F8-15.
Onde fica: servidor de aplicação, um adaptador por provedor atrás de um contrato interno único.
Especificação: provedores iniciais, Strava, Fitbit, Garmin e Polar, cada um habilitado ou desabilitado pela configuração (provedores_atividade), sem alteração de código para ligar ou desligar um deles. Direção, entrada. Autenticação, autorização delegada concedida pelo aluno no site do provedor, com credencial cifrada guardada apenas no servidor e renovação automática quando o provedor a oferecer. Escopos pedidos, os mínimos para atividades, passos e frequência cardíaca. Payload de entrada, a lista de atividades do período mais os totais diários; mapeamento para atividade_externa, com o identificador da atividade no provedor virando parte da chave de deduplicação. Campo que o provedor não fornece fica vazio no registro, nunca zero. Idempotência, garantida pela chave; a rotina pode rodar quantas vezes for. Limite de chamadas, respeitado por provedor, com a conta excedente adiada para a execução seguinte. Falha, credencial inválida ou revogada marca a conta como precisando reautorizar e notifica o aluno, sem apagar histórico. Acrescentar um quinto provedor é escrever um adaptador e habilitá-lo na configuração, sem tocar em requisito.
Para que serve: parametrizar o servidor sem colocar segredo no código.
Relacionado com: G.1, F.2, ADR-013; tarefas F1-01, F1-07, F8-05, F8-13.
Onde fica: ambiente do servidor de aplicação.
Especificação: URL_BANCO (conexão de runtime, role sem privilégio de dono do schema, segredo, obrigatória no F1-01); URL_BANCO_ADMIN (conexão usada pelo comando de migração e pelas ferramentas de operação que escrevem como dona do schema, role dona do schema, segredo, obrigatória no F1-01); SEGREDO_TOKEN (assinatura do token de sessão, segredo, obrigatória no F1-01, rotação invalida sessões); SEGREDO_ARQUIVOS (segredo que assina o endereço de saída do repositório privado, HMAC, segredo, obrigatória no F1-01; renomeia CHAVE_SERVICO_ARQUIVOS, não há serviço externo de armazenamento, ADR-013); DIR_ARQUIVOS (raiz do volume de arquivos dentro do container, caminho, obrigatória no F1-01); URL_PUBLICA_ARQUIVOS (caminho base do repositório público, servido pela própria aplicação, obrigatória no F1-01); URL_APLICACAO (base usada em e-mail e no retorno de autorização, URL, obrigatória no F1-01); SMTP_URL (envio de e-mail, segredo, usada no F1-07; a ausência degrada o envio, a mensagem fica enfileirada e registrada no log, nunca derruba o arranque; a alternativa de torná-la obrigatória foi reprovada); CHAVE_GERACAO (provedor de geração assistida, segredo, obrigatória no F8-05); MODELO_GERACAO_PADRAO (valor inicial do parâmetro editável, valor, opcional, usada no F8-05); CREDENCIAIS_PROVEDORES_ATIVIDADE (identificador e segredo de cada provedor habilitado, segredo, obrigatória apenas se houver provedor habilitado, um par por provedor, usada no F8-13); CHAVE_CIFRA_CREDENCIAL (chave que cifra a credencial guardada em conta_integracao, segredo, obrigatória se houver provedor habilitado, rotação exige reautorização de todas as contas conectadas, usada no F8-13). Nenhum valor é escrito neste documento; a rotação de cada uma é feita pela administração da operação, e a rotação do segredo do token exige aviso porque desconecta todos.
Estado: as 12 variáveis existem em /opt/modularfit/.env desde F1-01; SMTP_URL preenchida em produção no F1-07 (Postfix do host); as demais 4 opcionais recebem valor no card que as consome.
Para que serve: sustentar a aplicação em produção.
Relacionado com: G.1, G.3, G.4, K.2, K.3, ADR-013; tarefas F1-01 e F8-11.
Onde fica: hospedagem própria da operação, projeto isolado, dois processos (mfit-db, mfit-app).
Especificação: os seis papéis abaixo NÃO são seis serviços provisionados, são papéis dentro de dois processos reais. mfit-app (servidor de aplicação) concentra quatro papéis: servidor de aplicação (papel, servir a interface e as rotas; dependências, banco, identidade, arquivos; verificação de saúde na rota de estado; reinício automático; middleware único de cabeçalhos de segurança em toda resposta, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy e Content-Security-Policy, emitido pela aplicação e não pelo vhost do servidor web da frente, {F2-02}), serviço de identidade (papel, emissão e validação de token, dependência, banco), armazenamento de objetos (dois repositórios, público e privado, servidos pela própria aplicação), canal de tempo real (papel, entrega de mensagem e notificação; degradação aceitável para consulta periódica se indisponível) e agendador (papel, executar as sete rotinas; registro de cada execução). mfit-db concentra o papel de banco de dados (papel, persistência com política por linha; cópia diária e semanal; verificação de conexão). Isolamento, nenhum destes papéis é compartilhado com outro produto. Cópia de segurança conforme K.3, com teste de restauração trimestral.
Para que serve: aplicar a identidade do produto com consistência.
Relacionado com: Apêndice de identidade visual; tarefas F1-02 e M-01.
Onde fica: repositório público de mídia e pasta de identidade do projeto.
Especificação: marca principal em versão clara e em versão escura, formato vetorial mais versão em imagem para uso onde vetor não serve; símbolo isolado para ícone de aplicativo e favorito, em versões de 32, 180 e 512 pixels; imagem de compartilhamento em 1200 por 630; conjunto de ícones de interface, traço uniforme, formato vetorial; imagem de estado vazio, uma por área. Fonte, produzir a partir da identidade do produto. Regra de uso, toda imagem é exibida na proporção natural, com largura automática e ajuste por contenção, e a proporção renderizada é conferida por medição.
Estado: símbolo, assinatura e favicons (32, 180, SVG) entregues em F1-02 a partir de uma fonte única de caminhos; imagem de compartilhamento e ícones de interface pendentes.