Files
agenciapsilmno/docs/architecture/Pacientes/pacientes_status_implementacao.html

965 lines
46 KiB
HTML

<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pacientes — Status de Implementacao</title>
<style>
:root {
--bg: #ffffff;
--bg-card: #f8f9fb;
--bg-card-hover: #f1f3f6;
--bg-sidebar: #f4f5f7;
--border: #e2e5ea;
--border-light: #eceef2;
--text: #1a1d23;
--text-secondary: #5f6775;
--text-muted: #8a91a0;
--accent: #2563eb;
--accent-dim: #2563eb14;
--green: #16a34a;
--green-dim: #16a34a14;
--green-bg: #dcfce7;
--orange: #d97706;
--orange-dim: #d9770614;
--orange-bg: #fef3c7;
--red: #dc2626;
--red-dim: #dc262614;
--red-bg: #fee2e2;
--purple: #7c3aed;
--purple-dim: #7c3aed14;
--cyan: #0891b2;
--cyan-dim: #0891b214;
--pink: #db2777;
--pink-dim: #db277714;
--font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
--font-mono: 'SF Mono', 'Fira Code', 'Cascadia Code', Consolas, monospace;
--radius: 8px;
--radius-lg: 12px;
--shadow: 0 1px 3px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04);
--shadow-lg: 0 4px 12px rgba(0,0,0,.08);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: var(--font);
background: var(--bg);
color: var(--text);
line-height: 1.6;
padding: 40px 24px 80px;
max-width: 1120px;
margin: 0 auto;
}
/* ── Header ─────────────────────────── */
.page-header {
text-align: center;
margin-bottom: 36px;
padding-bottom: 28px;
border-bottom: 1px solid var(--border);
}
.page-header h1 {
font-size: 28px;
font-weight: 700;
letter-spacing: -0.03em;
color: var(--text);
margin-bottom: 6px;
}
.page-header .subtitle {
font-size: 14px;
color: var(--text-secondary);
margin-bottom: 14px;
}
.meta {
display: flex;
gap: 8px;
justify-content: center;
flex-wrap: wrap;
}
.meta-tag {
font-size: 11px;
font-family: var(--font-mono);
padding: 4px 12px;
border-radius: 20px;
border: 1px solid var(--border);
color: var(--text-secondary);
background: var(--bg-card);
}
/* ── Summary grid ──────────────────── */
.summary-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
gap: 10px;
margin-bottom: 36px;
}
.summary-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 16px 14px;
text-align: center;
box-shadow: var(--shadow);
}
.summary-card .number { font-size: 26px; font-weight: 700; line-height: 1.2; }
.summary-card .label { font-size: 10px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.07em; margin-top: 3px; }
.c-green .number { color: var(--green); }
.c-orange .number { color: var(--orange); }
.c-red .number { color: var(--red); }
.c-accent .number { color: var(--accent); }
.c-purple .number { color: var(--purple); }
.c-cyan .number { color: var(--cyan); }
.c-pink .number { color: var(--pink); }
/* ── Legend ─────────────────────────── */
.legend {
display: flex;
gap: 20px;
justify-content: center;
margin-bottom: 32px;
flex-wrap: wrap;
}
.legend-item {
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(--text-secondary);
}
.legend-item .dot { width: 9px; height: 9px; border-radius: 50%; }
.dot-green { background: var(--green); }
.dot-orange { background: var(--orange); }
.dot-red { background: var(--red); }
/* ── Section ────────────────────────── */
.section { margin-bottom: 36px; }
.section-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
padding-bottom: 10px;
border-bottom: 2px solid var(--border-light);
}
.section-icon {
width: 32px;
height: 32px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: 700;
flex-shrink: 0;
}
.section-icon.blue { background: var(--accent-dim); color: var(--accent); }
.section-icon.green { background: var(--green-dim); color: var(--green); }
.section-icon.orange { background: var(--orange-dim); color: var(--orange); }
.section-icon.purple { background: var(--purple-dim); color: var(--purple); }
.section-icon.cyan { background: var(--cyan-dim); color: var(--cyan); }
.section-icon.pink { background: var(--pink-dim); color: var(--pink); }
.section-icon.red { background: var(--red-dim); color: var(--red); }
.section-title { font-size: 17px; font-weight: 600; }
/* ── Content: cards + sidebar ───────── */
.content-row {
display: grid;
grid-template-columns: 1fr 270px;
gap: 16px;
align-items: start;
}
@media (max-width: 850px) {
.content-row { grid-template-columns: 1fr; }
}
/* ── Cards ──────────────────────────── */
.cards { display: flex; flex-direction: column; gap: 10px; }
.card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 16px 20px;
box-shadow: var(--shadow);
transition: box-shadow .15s, border-color .15s;
}
.card:hover { box-shadow: var(--shadow-lg); border-color: #d0d4db; }
.card-top {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 10px;
margin-bottom: 6px;
}
.card-title {
font-size: 13.5px;
font-weight: 600;
display: flex;
align-items: center;
gap: 8px;
}
.card-desc {
font-size: 12.5px;
color: var(--text-secondary);
line-height: 1.6;
}
.card-fields {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-top: 10px;
}
.field {
font-size: 10px;
font-family: var(--font-mono);
padding: 3px 8px;
border-radius: 12px;
border: 1px solid var(--border);
color: var(--text-muted);
background: var(--bg);
}
.card-file {
font-size: 11px;
font-family: var(--font-mono);
color: var(--accent);
margin-top: 8px;
opacity: .75;
}
/* ── Badges ─────────────────────────── */
.badge {
font-size: 10px;
font-weight: 600;
padding: 3px 10px;
border-radius: 20px;
white-space: nowrap;
flex-shrink: 0;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.badge-done { background: var(--green-bg); color: var(--green); }
.badge-partial { background: var(--orange-bg); color: var(--orange); }
.badge-pending { background: var(--red-bg); color: var(--red); }
/* ── Sidebar ────────────────────────── */
.sidebar {
background: var(--bg-sidebar);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 18px;
position: sticky;
top: 20px;
box-shadow: var(--shadow);
}
.sidebar-title {
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-muted);
margin-bottom: 10px;
padding-bottom: 8px;
border-bottom: 1px solid var(--border-light);
}
.sidebar-item {
display: flex;
align-items: center;
gap: 8px;
padding: 5px 0;
font-size: 12px;
color: var(--text-secondary);
}
.sidebar-item .dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.sidebar-item .label { flex: 1; }
.sidebar-item .status {
font-size: 10px;
font-family: var(--font-mono);
color: var(--text-muted);
}
.sidebar-divider { height: 1px; background: var(--border-light); margin: 12px 0; }
/* ── Note ───────────────────────────── */
.note {
background: var(--bg-card);
border: 1px solid var(--border);
border-left: 3px solid var(--accent);
border-radius: var(--radius);
padding: 14px 18px;
font-size: 12.5px;
color: var(--text-secondary);
margin-top: 14px;
line-height: 1.6;
box-shadow: var(--shadow);
}
.note strong { color: var(--text); }
.note.warn { border-left-color: var(--orange); }
.note.info { border-left-color: var(--cyan); }
</style>
</head>
<body>
<!-- ══════════════════════════════ HEADER ══════════════════════════════ -->
<div class="page-header">
<h1>Modulo Pacientes</h1>
<div class="subtitle">Status de implementacao confrontado com banco de dados, services e frontend</div>
<div class="meta">
<span class="meta-tag">AgenciaPsi v5</span>
<span class="meta-tag">Vue 3 + Supabase</span>
<span class="meta-tag">Atualizado: 2026-03-30</span>
</div>
</div>
<!-- ══════════════════════════════ STATS ═══════════════════════════════ -->
<div class="summary-grid">
<div class="summary-card c-green">
<div class="number">5</div>
<div class="label">Tabelas core</div>
</div>
<div class="summary-card c-accent">
<div class="number">4</div>
<div class="label">Tabelas aux</div>
</div>
<div class="summary-card c-green">
<div class="number">2</div>
<div class="label">Views</div>
</div>
<div class="summary-card c-green">
<div class="number">3</div>
<div class="label">Services</div>
</div>
<div class="summary-card c-green">
<div class="number">10</div>
<div class="label">Componentes</div>
</div>
<div class="summary-card c-green">
<div class="number">8+8</div>
<div class="label">Rotas (T+C)</div>
</div>
<div class="summary-card c-purple">
<div class="number">50+</div>
<div class="label">Colunas patients</div>
</div>
<div class="summary-card c-cyan">
<div class="number">5</div>
<div class="label">Triggers</div>
</div>
</div>
<!-- ══════════════════════════════ LEGENDA ═════════════════════════════ -->
<div class="legend">
<div class="legend-item"><span class="dot dot-green"></span> Implementado (DB + frontend)</div>
<div class="legend-item"><span class="dot dot-orange"></span> Parcial / migration pendente</div>
<div class="legend-item"><span class="dot dot-red"></span> Planejado / nao implementado</div>
</div>
<!-- ══════════════════════════════ 1. CADASTRO ═════════════════════════ -->
<div class="section">
<div class="section-header">
<div class="section-icon blue">1</div>
<div class="section-title">Cadastro & Dados Pessoais</div>
</div>
<div class="content-row">
<div class="cards">
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Identidade & dados pessoais</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">Formulario completo com 6 secoes em accordion. Nome completo, nome social, pronomes, data nascimento, genero, estado civil, CPF (validacao checksum), RG, naturalidade, etnia, profissao, escolaridade. Avatar com upload ao Storage.</div>
<div class="card-fields">
<span class="field">nome_completo</span><span class="field">nome_social</span><span class="field">pronomes</span>
<span class="field">data_nascimento</span><span class="field">genero</span><span class="field">estado_civil</span>
<span class="field">cpf</span><span class="field">rg</span><span class="field">etnia</span>
<span class="field">profissao</span><span class="field">escolaridade</span><span class="field">avatar_url</span>
</div>
<div class="card-file">PatientsCadastroPage.vue &rarr; secao "Identidade"</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Contato & preferencias</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">Telefone principal e alternativo, email principal e alternativo. Canal preferido de contato (WhatsApp, Telefone, E-mail, SMS). Horario preferido para contato com janela inicio/fim. Idioma.</div>
<div class="card-fields">
<span class="field">telefone</span><span class="field">telefone_alternativo</span><span class="field">email_principal</span>
<span class="field">email_alternativo</span><span class="field">canal_preferido</span>
<span class="field">horario_contato_inicio</span><span class="field">horario_contato_fim</span><span class="field">idioma</span>
</div>
<div class="card-file">DB: CHECK canal_preferido IN (whatsapp, email, sms, telefone)</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Endereco com auto-preenchimento</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">CEP com consulta ViaCEP automatica (onBlur). Preenche logradouro, bairro, cidade, estado. Complemento e numero manuais. Pais default Brasil.</div>
<div class="card-fields">
<span class="field">cep</span><span class="field">endereco</span><span class="field">numero</span>
<span class="field">bairro</span><span class="field">complemento</span><span class="field">cidade</span>
<span class="field">estado</span><span class="field">pais</span>
</div>
<div class="card-file">PatientsCadastroPage.vue &rarr; secao "Endereco" + ViaCEP API</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Responsavel legal</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">Para menores ou cobranca em terceiro. Nome, CPF (validacao), telefone, observacao. Flag de cobranca no responsavel.</div>
<div class="card-fields">
<span class="field">nome_responsavel</span><span class="field">cpf_responsavel</span>
<span class="field">telefone_responsavel</span><span class="field">observacao_responsavel</span>
<span class="field">cobranca_no_responsavel</span>
</div>
<div class="card-file">PatientsCadastroPage.vue &rarr; secao "Responsavel"</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Cadastro rapido & link externo</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">3 modos de criacao: Cadastro rapido (nome, email, telefone), Cadastro completo (formulario full), Link externo (paciente preenche). Convite via token com validade.</div>
<div class="card-file">ComponentCadastroRapido.vue + PatientCreatePopover.vue + PatientsExternalLinkPage.vue</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Dados socioeconomicos</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">Religiao, faixa de renda (ate_1sm, 1_3sm, 3_6sm, 6_10sm, acima_10sm, nao_informado), origem (indicacao, agendador, redes_sociais, encaminhamento).</div>
<div class="card-fields">
<span class="field">religiao</span><span class="field">faixa_renda</span><span class="field">origem</span>
<span class="field">onde_nos_conheceu</span><span class="field">encaminhado_por</span>
</div>
<div class="card-file">DB: CHECK constraints com valores permitidos</div>
</div>
</div>
<!-- Sidebar -->
<div class="sidebar">
<div class="sidebar-title">Banco de Dados</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">patients</span><span class="status">50+ cols</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">RLS por owner + tenant</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">12+ indexes</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">5 triggers</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">CPF checksum</span></div>
<div class="sidebar-divider"></div>
<div class="sidebar-title">Frontend</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">PatientsCadastroPage</span><span class="status">1985 ln</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">CadastroRapido</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">PatientCreatePopover</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">ExternalLinkPage</span></div>
<div class="sidebar-divider"></div>
<div class="sidebar-title">Validacao</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">useFormValidation</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">validators.js</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">CPF, Phone, Email, CEP</span></div>
</div>
</div>
</div>
<!-- ══════════════════════════════ 2. LISTAGEM & BUSCA ════════════════ -->
<div class="section">
<div class="section-header">
<div class="section-icon green">2</div>
<div class="section-title">Listagem, Busca & Organizacao</div>
</div>
<div class="content-row">
<div class="cards">
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Lista de pacientes com filtros</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">DataTable com busca por nome/email/telefone (debounce 250ms). Filtros: status, grupo, tag, data de criacao. Colunas dinamicas com visibilidade configuravel. Vista tabela (desktop) e cards (mobile). Vista agrupada por grupo.</div>
<div class="card-fields">
<span class="field">search</span><span class="field">status</span><span class="field">groupId</span>
<span class="field">tagId</span><span class="field">createdFrom</span><span class="field">createdTo</span>
</div>
<div class="card-file">PatientsListPage.vue (1457 linhas)</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Grupos de pacientes</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">CRUD completo de grupos com cor. Associacao paciente &harr; grupo via junction table. Contagem de pacientes por grupo. Pagina de gestao dedicada.</div>
<div class="card-fields">
<span class="field">patient_groups</span><span class="field">patient_group_patient</span>
</div>
<div class="card-file">GruposPacientesPage.vue + GruposPacientes.service.js</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Tags de pacientes</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">CRUD de tags com cor e nome. Multi-select no cadastro. Autocomplete. Contagem de pacientes por tag. Tags padrao do sistema.</div>
<div class="card-fields">
<span class="field">patient_tags</span><span class="field">patient_patient_tag</span>
</div>
<div class="card-file">TagsPage.vue + patientTags.service.js</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Medicos & referencias</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">Cadastro de medicos que encaminham pacientes. CRM, especialidade (13 opcoes), contatos. Contagem de pacientes por medico. Soft delete. Busca de pacientes referidos.</div>
<div class="card-fields">
<span class="field">medicos</span><span class="field">nome</span><span class="field">crm</span>
<span class="field">especialidade</span><span class="field">encaminhado_por</span>
</div>
<div class="card-file">MedicosPage.vue + Medicos.service.js</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-orange"></span> Lista de espera</div>
<span class="badge badge-partial">placeholder</span>
</div>
<div class="card-desc">Tab "Lista de espera" existe na PatientsListPage mas e um placeholder. Comentario no codigo: "Quando voce quiser, podemos ligar isso a uma tabela (ex: patient_waitlist)". Nao tem tabela no banco.</div>
<div class="card-file">PatientsListPage.vue &rarr; tab placeholder</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Cadastros recebidos (intake)</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">Formularios de cadastro externo submetidos por pacientes prospectivos. Status: new, converted, rejected. Pagina de gestao dedicada com badge no menu.</div>
<div class="card-fields">
<span class="field">patient_intake_requests</span><span class="field">status</span><span class="field">converted_patient_id</span>
</div>
<div class="card-file">CadastrosRecebidosPage.vue</div>
</div>
</div>
<!-- Sidebar -->
<div class="sidebar">
<div class="sidebar-title">Tabelas Auxiliares</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">patient_groups</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">patient_group_patient</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">patient_tags</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">patient_patient_tag</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">medicos</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">patient_intake_requests</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">patient_invites</span></div>
<div class="sidebar-item"><span class="dot dot-red"></span><span class="label">patient_waitlist</span><span class="status">nao existe</span></div>
<div class="sidebar-divider"></div>
<div class="sidebar-title">Rotas</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">/therapist/patients</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">/therapist/.../grupos</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">/therapist/.../tags</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">/therapist/.../medicos</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">/admin/pacientes/*</span><span class="status">8 rotas</span></div>
</div>
</div>
</div>
<!-- ══════════════════════════════ 3. PRONTUARIO ══════════════════════ -->
<div class="section">
<div class="section-header">
<div class="section-icon purple">3</div>
<div class="section-title">Prontuario do Paciente</div>
</div>
<div class="content-row">
<div class="cards">
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Perfil completo (tab 1)</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">Sidebar com avatar, badges (status, convenio, scope), tags e metricas (sessoes, comparecimento %, LTV, dias sem sessao). Corpo com 6 sub-secoes em accordion: dados pessoais, contato, endereco, dados adicionais, responsavel, anotacoes.</div>
<div class="card-file">PatientProntuario.vue &rarr; tab "Perfil" (1167 linhas total)</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-orange"></span> Prontuario clinico (tab 2)</div>
<span class="badge badge-partial">estrutura</span>
</div>
<div class="card-desc">Tab existe no componente mas conteudo clinico (notas de sessao, evolucao, plano terapeutico) ainda precisa ser detalhado. Placeholder no modal.</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-orange"></span> Agenda do paciente (tab 3)</div>
<span class="badge badge-partial">estrutura</span>
</div>
<div class="card-desc">Tab de sessoes/agenda existe. Lista de agenda_eventos carregada. Falta validar se a UI mostra corretamente os agendamentos futuros e historico completo.</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-orange"></span> Financeiro do paciente (tab 4)</div>
<span class="badge badge-partial">estrutura</span>
</div>
<div class="card-desc">Tab existe. patient_discounts funciona (desconto percentual ou valor fixo, periodo de validade). Detalhes de cobrancas e pagamentos por paciente a validar.</div>
<div class="card-fields">
<span class="field">patient_discounts</span><span class="field">discount_pct</span><span class="field">discount_flat</span>
</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Documentos do paciente (tab 5)</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">DocumentsListPage embarcada no prontuario com prop embedded. Upload, preview, download, geracao de PDF, compartilhamento. Integrado com modulo de documentos completo.</div>
<div class="card-file">DocumentsListPage.vue (embedded)</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Flag de risco clinico</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">Banner vermelho no prontuario quando risco_elevado = true. Obriga risco_nota e risco_sinalizado_por (CHECK constraint). Trigger registra na patient_timeline. View v_patients_risco para dashboard.</div>
<div class="card-fields">
<span class="field">risco_elevado</span><span class="field">risco_nota</span>
<span class="field">risco_sinalizado_em</span><span class="field">risco_sinalizado_por</span>
</div>
<div class="card-file">DB: trg_patient_risco_timeline + v_patients_risco</div>
</div>
</div>
<!-- Sidebar -->
<div class="sidebar">
<div class="sidebar-title">Tabs do Prontuario</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">1. Perfil</span><span class="status">completo</span></div>
<div class="sidebar-item"><span class="dot dot-orange"></span><span class="label">2. Prontuario</span><span class="status">estrutura</span></div>
<div class="sidebar-item"><span class="dot dot-orange"></span><span class="label">3. Agenda</span><span class="status">estrutura</span></div>
<div class="sidebar-item"><span class="dot dot-orange"></span><span class="label">4. Financeiro</span><span class="status">estrutura</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">5. Documentos</span><span class="status">completo</span></div>
<div class="sidebar-divider"></div>
<div class="sidebar-title">Metricas Sidebar</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">Total sessoes</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">Comparecimento %</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">LTV total</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">Dias sem sessao</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">Risk flag</span></div>
</div>
</div>
</div>
<!-- ══════════════════════════════ 4. REDE DE SUPORTE ═════════════════ -->
<div class="section">
<div class="section-header">
<div class="section-icon cyan">4</div>
<div class="section-title">Rede de Suporte & Contatos</div>
</div>
<div class="content-row">
<div class="cards">
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Contatos de suporte (legado)</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">patient_support_contacts: nome, relacao, tipo (emergencia, familiar, profissional_saude, amigo, outro), telefone, email, flag is_primario. CRUD no cadastro do paciente.</div>
<div class="card-fields">
<span class="field">nome</span><span class="field">relacao</span><span class="field">tipo</span>
<span class="field">telefone</span><span class="field">email</span><span class="field">is_primario</span>
</div>
<div class="card-file">PatientsCadastroPage.vue &rarr; secao "Rede de Suporte"</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-orange"></span> Contatos estruturados (novo)</div>
<span class="badge badge-partial">db pronto</span>
</div>
<div class="card-desc">patient_contacts: tabela mais completa que substitui campos legado (nome_parente, telefone_parente). Inclui CPF, especialidade, registro profissional (CRM/CRP). Unique constraint para contato primario. Migrada com dados legados. Frontend ainda usa patient_support_contacts.</div>
<div class="card-fields">
<span class="field">nome</span><span class="field">tipo</span><span class="field">cpf</span>
<span class="field">especialidade</span><span class="field">registro_profissional</span>
<span class="field">is_primario</span><span class="field">ativo</span>
</div>
<div class="card-file">DB: patient_contacts (migration_patients.sql) &mdash; frontend pendente</div>
</div>
</div>
<!-- Sidebar -->
<div class="sidebar">
<div class="sidebar-title">Tabelas de Contatos</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">patient_support_contacts</span><span class="status">em uso</span></div>
<div class="sidebar-item"><span class="dot dot-orange"></span><span class="label">patient_contacts</span><span class="status">db ok</span></div>
<div class="sidebar-divider"></div>
<div class="sidebar-title">Campos legado (patients)</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">nome_parente</span><span class="status">legado</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">telefone_parente</span><span class="status">legado</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">nome_responsavel</span><span class="status">legado</span></div>
</div>
</div>
</div>
<!-- ══════════════════════════════ 5. STATUS & TIMELINE ═══════════════ -->
<div class="section">
<div class="section-header">
<div class="section-icon pink">5</div>
<div class="section-title">Status, Timeline & Engajamento</div>
</div>
<div class="content-row">
<div class="cards">
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Gestao de status</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">6 status: Ativo, Em espera, Inativo, Alta, Encaminhado, Arquivado. Campos de saida: motivo_saida, data_saida, encaminhado_para. Historico automatico via trigger.</div>
<div class="card-fields">
<span class="field">status</span><span class="field">motivo_saida</span><span class="field">data_saida</span>
<span class="field">encaminhado_para</span>
</div>
<div class="card-file">DB: patient_status_history (trigger automatico)</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Historico de status</div>
<span class="badge badge-done">db pronto</span>
</div>
<div class="card-desc">Tabela imutavel patient_status_history. Registra automaticamente: status anterior, novo, motivo, encaminhamento, data saida, quem alterou. Trigger trg_patient_status_history.</div>
<div class="card-fields">
<span class="field">status_anterior</span><span class="field">status_novo</span><span class="field">motivo</span>
<span class="field">alterado_por</span><span class="field">alterado_em</span>
</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Timeline do paciente</div>
<span class="badge badge-done">db pronto</span>
</div>
<div class="card-desc">patient_timeline: feed cronologico com 18 tipos de evento. Auto-populada por triggers (status, risco, documentos, assinaturas). Cores por tipo. Referencia polimorfica para links.</div>
<div class="card-fields">
<span class="field">evento_tipo</span><span class="field">titulo</span><span class="field">descricao</span>
<span class="field">icone_cor</span><span class="field">link_ref_tipo</span><span class="field">link_ref_id</span>
</div>
<div class="card-file">DB: 18 event types + 3 triggers auto-insert</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> View de engajamento</div>
<span class="badge badge-done">db pronto</span>
</div>
<div class="card-desc">v_patient_engajamento: score 0-100 calculado em real-time. Metricas: total sessoes, sessoes ultimo mes, taxa comparecimento, LTV, ticket medio, cobrancas vencidas/pagas, taxa pagamentos em dia, duracao tratamento. Formula: 50% frequencia + 30% financeiro + 20% recencia.</div>
<div class="card-file">DB: VIEW v_patient_engajamento (security_invoker = on)</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> View de pacientes em risco</div>
<span class="badge badge-done">db pronto</span>
</div>
<div class="card-desc">v_patients_risco: lista pacientes que precisam de atencao. Criterios: risco_elevado, sem sessao ha 30+ dias, comparecimento &lt;60%, cobranca vencida. Alertas categorizados.</div>
<div class="card-file">DB: VIEW v_patients_risco</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-orange"></span> UI de timeline no prontuario</div>
<span class="badge badge-partial">pendente</span>
</div>
<div class="card-desc">A tabela patient_timeline e as views estao prontas no banco. Falta o componente frontend para exibir a timeline visualmente no prontuario do paciente (feed cronologico com icones e cores).</div>
</div>
</div>
<!-- Sidebar -->
<div class="sidebar">
<div class="sidebar-title">Tabelas</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">patient_status_history</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">patient_timeline</span></div>
<div class="sidebar-divider"></div>
<div class="sidebar-title">Views</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">v_patient_engajamento</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">v_patients_risco</span></div>
<div class="sidebar-divider"></div>
<div class="sidebar-title">Triggers automaticos</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">status &rarr; history</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">status &rarr; timeline</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">risco &rarr; timeline</span></div>
<div class="sidebar-divider"></div>
<div class="sidebar-title">18 Eventos Timeline</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">primeira_sessao</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">sessao_realizada</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">status_alterado</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">risco_sinalizado</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">documento_adicionado</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">pagamento_recebido</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">+ 12 outros</span></div>
</div>
</div>
</div>
<!-- ══════════════════════════════ 6. FINANCEIRO ══════════════════════ -->
<div class="section">
<div class="section-header">
<div class="section-icon orange">6</div>
<div class="section-title">Financeiro & Convenios</div>
</div>
<div class="content-row">
<div class="cards">
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Convenio / plano de saude</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">Associacao paciente &rarr; insurance_plans. Campo convenio (texto livre) + convenio_id (FK). Cadastro rapido de convenio via dialog. Exibido no prontuario como badge.</div>
<div class="card-fields">
<span class="field">convenio</span><span class="field">convenio_id</span><span class="field">insurance_plans</span>
</div>
<div class="card-file">CadastroRapidoConvenio.vue + PatientsCadastroPage.vue</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Metodo de pagamento preferido</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">PIX, cartao, dinheiro, deposito, convenio. CHECK constraint no banco. Selecionavel no cadastro.</div>
<div class="card-fields">
<span class="field">metodo_pagamento_preferido</span>
</div>
<div class="card-file">DB: CHECK (pix, cartao, dinheiro, deposito, convenio)</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-green"></span> Descontos por paciente</div>
<span class="badge badge-done">pronto</span>
</div>
<div class="card-desc">patient_discounts: desconto percentual ou valor fixo, motivo, periodo de validade (active_from, active_to). Gerenciavel pela listagem de pacientes.</div>
<div class="card-fields">
<span class="field">discount_pct</span><span class="field">discount_flat</span><span class="field">reason</span>
<span class="field">active_from</span><span class="field">active_to</span>
</div>
</div>
</div>
<div class="sidebar">
<div class="sidebar-title">Tabelas</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">insurance_plans</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">patient_discounts</span></div>
<div class="sidebar-divider"></div>
<div class="sidebar-title">Validacao</div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">metodo_pagamento CHECK</span></div>
<div class="sidebar-item"><span class="dot dot-green"></span><span class="label">convenio_id FK</span></div>
</div>
</div>
</div>
<!-- ══════════════════════════════ PENDENCIAS ══════════════════════════ -->
<div class="section">
<div class="section-header">
<div class="section-icon red">!</div>
<div class="section-title">Pendencias & Itens a Implementar</div>
</div>
<div class="cards">
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-orange"></span> Prontuario clinico (tab 2) — notas de sessao e evolucao</div>
<span class="badge badge-partial">estrutura</span>
</div>
<div class="card-desc">Tab existe no modal mas sem conteudo clinico detalhado. Precisa: notas de sessao vinculadas a agenda_eventos, evolucao terapeutica, plano de tratamento, hipoteses diagnosticas.</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-orange"></span> UI da timeline no prontuario</div>
<span class="badge badge-partial">db pronto</span>
</div>
<div class="card-desc">Tabela patient_timeline com 18 event types e triggers automaticos existe. Falta componente frontend para exibir feed cronologico no prontuario (icones, cores, links para entidades referenciadas).</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-orange"></span> Dashboard de engajamento e risco</div>
<span class="badge badge-partial">db pronto</span>
</div>
<div class="card-desc">Views v_patient_engajamento e v_patients_risco existem no banco. Score de engajamento (0-100) calculado em real-time. Falta UI para exibir dashboard de risco e engajamento geral dos pacientes.</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-orange"></span> Migrar frontend para patient_contacts</div>
<span class="badge badge-partial">db pronto</span>
</div>
<div class="card-desc">Tabela patient_contacts (mais completa: CPF, especialidade, registro profissional) existe e foi populada com dados legados. Frontend ainda usa patient_support_contacts (mais simples). Migrar UI para usar a nova tabela.</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-red"></span> Lista de espera (patient_waitlist)</div>
<span class="badge badge-pending">nao existe</span>
</div>
<div class="card-desc">Tab placeholder na PatientsListPage. Nao existe tabela no banco. Precisa: criacao da tabela, service, UI com gestao de fila (posicao, prioridade, data de entrada, notificacao quando vaga abrir).</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-orange"></span> Botao "+ Sessao" no prontuario</div>
<span class="badge badge-partial">placeholder</span>
</div>
<div class="card-desc">Botao existe no header do prontuario mas sem click handler. Precisa abrir dialog de agendamento rapido pre-preenchido com o paciente atual.</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-orange"></span> Tabs Agenda e Financeiro no prontuario</div>
<span class="badge badge-partial">estrutura</span>
</div>
<div class="card-desc">Tabs existem no modal. Dados de agenda_eventos e patient_discounts carregam. Falta validar se a UI mostra corretamente: agendamentos futuros, historico completo, cobrancas, pagamentos, recibos.</div>
</div>
<div class="card">
<div class="card-top">
<div class="card-title"><span class="dot dot-orange"></span> Migrations nao aplicadas</div>
<span class="badge badge-partial">verificar</span>
</div>
<div class="card-desc">Verificar se as migrations estao aplicadas no banco local: 20260328000002 (new columns), 20260328000003 (drop constraints), 20260328000004 (support_contacts), migration_patients.sql (timeline, contacts, views, risk). Algumas dependem de tabelas que podem nao existir ainda (insurance_plans, etc).</div>
</div>
</div>
<div class="note info" style="margin-top: 16px;">
<strong>Multi-tenant:</strong> Todas as queries filtram por owner_id (terapeuta individual) ou tenant_id (clinica). RLS no banco garante isolamento. Feature flags (patients.view, patients.create, patients.edit, patients.delete) controlam acesso por plano. Rotas admin usam meta tenantFeature: 'patients'.
</div>
<div class="note" style="margin-top: 10px;">
<strong>Escopo dual:</strong> patient_scope = 'clinic' (paciente da clinica, sem therapist_member_id) ou 'therapist' (paciente particular, com therapist_member_id obrigatorio). CHECK constraint garante consistencia.
</div>
</div>
</body>
</html>