Files
agenciapsilmno/docs/estrategia/plataforma_saude_mental_v2.html

1800 lines
120 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Plataforma de Saúde Mental — Documento Estratégico v2.0</title>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,600;0,800;1,400&family=DM+Sans:ital,wght@0,300;0,400;0,500;0,600;1,300&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
:root {
--azul-escuro: #0F1F33;
--azul-medio: #1B4F7A;
--azul-claro: #2E7FBF;
--azul-ice: #EAF4FC;
--verde: #1E6B52;
--verde-suave: #EAF5F0;
--laranja: #C96A3A;
--laranja-suave: #FDF0E8;
--roxo: #5C3D8F;
--roxo-suave: #F0EAF8;
--cinza-claro: #F7F9FC;
--cinza-medio: #8A9AB5;
--cinza-texto: #4A5568;
--linha: #DDE6F0;
--branco: #FFFFFF;
--sombra: 0 4px 24px rgba(15,31,51,0.08);
--sombra-hover: 0 8px 40px rgba(15,31,51,0.14);
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
font-family: 'DM Sans', sans-serif;
background: var(--cinza-claro);
color: var(--azul-escuro);
line-height: 1.7;
font-size: 16px;
}
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: var(--cinza-claro); }
::-webkit-scrollbar-thumb { background: var(--azul-claro); border-radius: 3px; }
/* ── CAPA ── */
.cover {
min-height: 100vh;
background: var(--azul-escuro);
display: flex; flex-direction: column;
align-items: center; justify-content: center;
position: relative; overflow: hidden; padding: 4rem 2rem;
}
.cover-bg {
position: absolute; inset: 0;
background:
radial-gradient(ellipse 80% 60% at 20% 40%, rgba(46,127,191,0.18) 0%, transparent 60%),
radial-gradient(ellipse 60% 80% at 80% 70%, rgba(30,107,82,0.12) 0%, transparent 60%),
radial-gradient(ellipse 40% 40% at 60% 10%, rgba(92,61,143,0.1) 0%, transparent 50%);
}
.cover-grid {
position: absolute; inset: 0;
background-image:
linear-gradient(rgba(46,127,191,0.06) 1px, transparent 1px),
linear-gradient(90deg, rgba(46,127,191,0.06) 1px, transparent 1px);
background-size: 60px 60px;
}
.cover-content { position: relative; z-index: 2; text-align: center; max-width: 820px; }
.cover-eyebrow {
font-family: 'DM Mono', monospace; font-size: 0.72rem;
letter-spacing: 0.22em; text-transform: uppercase;
color: rgba(46,127,191,0.8); margin-bottom: 1.5rem;
animation: fadeUp 0.8s ease both;
}
.cover-title {
font-family: 'Playfair Display', serif;
font-size: clamp(3rem, 8vw, 5.5rem); font-weight: 800;
color: var(--branco); line-height: 1.05; margin-bottom: 1rem;
animation: fadeUp 0.8s ease 0.1s both;
}
.cover-title span { color: transparent; -webkit-text-stroke: 1.5px rgba(46,127,191,0.6); }
.cover-subtitle {
font-size: 1.1rem; color: rgba(255,255,255,0.55);
font-weight: 300; margin-bottom: 3rem;
animation: fadeUp 0.8s ease 0.2s both;
}
.cover-badges {
display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap;
animation: fadeUp 0.8s ease 0.3s both;
}
.badge {
background: rgba(255,255,255,0.07); border: 1px solid rgba(255,255,255,0.12);
border-radius: 100px; padding: 0.4rem 1.1rem; font-size: 0.78rem;
color: rgba(255,255,255,0.65); font-family: 'DM Mono', monospace;
letter-spacing: 0.05em; backdrop-filter: blur(8px);
}
.badge.novo { background: rgba(30,107,82,0.3); border-color: rgba(30,107,82,0.5); color: #6ee7b7; }
.cover-scroll {
position: absolute; bottom: 2.5rem; left: 50%; transform: translateX(-50%);
display: flex; flex-direction: column; align-items: center; gap: 0.5rem;
color: rgba(255,255,255,0.3); font-size: 0.7rem; letter-spacing: 0.1em;
animation: fadeUp 1s ease 0.6s both;
}
.scroll-line {
width: 1px; height: 40px;
background: linear-gradient(to bottom, rgba(46,127,191,0.6), transparent);
animation: scrollPulse 2s ease infinite;
}
/* ── SIDENAV ── */
.sidenav {
position: fixed; left: 0; top: 0; bottom: 0; width: 270px;
background: var(--azul-escuro); padding: 2rem 0; overflow-y: auto;
z-index: 100; transform: translateX(-100%); transition: transform 0.3s ease;
box-shadow: 4px 0 24px rgba(0,0,0,0.2);
}
.sidenav.open { transform: translateX(0); }
.sidenav-logo { padding: 0 1.5rem 1.5rem; border-bottom: 1px solid rgba(255,255,255,0.08); margin-bottom: 1rem; }
.sidenav-logo span { font-family: 'Playfair Display', serif; font-size: 1rem; color: var(--branco); font-weight: 600; }
.sidenav-logo small { display: block; font-size: 0.65rem; color: var(--cinza-medio); letter-spacing: 0.1em; text-transform: uppercase; margin-top: 0.2rem; }
.sidenav a {
display: flex; align-items: center; gap: 0.75rem;
padding: 0.6rem 1.5rem; color: rgba(255,255,255,0.5);
text-decoration: none; font-size: 0.82rem; transition: all 0.2s;
border-left: 2px solid transparent;
}
.sidenav a:hover, .sidenav a.active {
color: var(--branco); background: rgba(46,127,191,0.12); border-left-color: var(--azul-claro);
}
.sidenav a .num { font-family: 'DM Mono', monospace; font-size: 0.65rem; color: var(--azul-claro); min-width: 1.5rem; }
.sidenav-section {
font-family: 'DM Mono', monospace; font-size: 0.58rem; letter-spacing: 0.15em;
text-transform: uppercase; color: rgba(255,255,255,0.2);
padding: 1rem 1.5rem 0.3rem; margin-top: 0.5rem;
}
/* ── NAV TOGGLE ── */
.nav-toggle {
position: fixed; top: 1.2rem; left: 1.2rem; z-index: 200;
width: 44px; height: 44px; background: var(--azul-escuro);
border: 1px solid rgba(46,127,191,0.3); border-radius: 10px; cursor: pointer;
display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
transition: all 0.2s; box-shadow: var(--sombra);
}
.nav-toggle:hover { background: var(--azul-medio); }
.nav-toggle span { width: 20px; height: 1.5px; background: var(--branco); border-radius: 2px; transition: all 0.2s; }
/* ── OVERLAY ── */
.overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 99; opacity: 0; pointer-events: none; transition: opacity 0.3s; }
.overlay.show { opacity: 1; pointer-events: all; }
/* ── PROGRESS BAR ── */
.progress-bar { position: fixed; top: 0; left: 0; height: 3px; background: linear-gradient(to right, var(--azul-claro), var(--verde)); z-index: 1000; transition: width 0.1s; }
/* ── MAIN ── */
.main { max-width: 880px; margin: 0 auto; padding: 0 2rem 6rem; }
/* ── CHAPTER ── */
.chapter { margin-top: 5rem; opacity: 0; transform: translateY(20px); transition: opacity 0.6s ease, transform 0.6s ease; }
.chapter.visible { opacity: 1; transform: translateY(0); }
.chapter-header { display: flex; align-items: flex-start; gap: 1.5rem; margin-bottom: 2rem; padding-bottom: 1.5rem; border-bottom: 1px solid var(--linha); }
.chapter-num { font-family: 'DM Mono', monospace; font-size: 0.7rem; color: var(--azul-claro); letter-spacing: 0.1em; background: var(--azul-ice); border: 1px solid rgba(46,127,191,0.2); border-radius: 8px; padding: 0.4rem 0.8rem; white-space: nowrap; margin-top: 0.3rem; }
.chapter-title { font-family: 'Playfair Display', serif; font-size: clamp(1.6rem, 4vw, 2.2rem); font-weight: 700; color: var(--azul-escuro); line-height: 1.2; }
/* ── SECTION ── */
.section { margin-top: 2rem; }
.section-title { font-family: 'DM Sans', sans-serif; font-size: 1.05rem; font-weight: 600; color: var(--azul-medio); margin-bottom: 0.75rem; padding-left: 0.75rem; border-left: 3px solid var(--azul-claro); }
.subsection-title { font-size: 0.9rem; font-weight: 600; color: var(--verde); margin: 1.2rem 0 0.4rem; }
p { color: var(--cinza-texto); font-size: 0.97rem; line-height: 1.75; margin-bottom: 0.9rem; font-weight: 300; }
strong { color: var(--azul-escuro); font-weight: 600; }
/* ── CALLOUT ── */
.callout { background: var(--azul-ice); border-left: 4px solid var(--azul-claro); border-radius: 0 12px 12px 0; padding: 1.25rem 1.5rem; margin: 1.5rem 0; font-style: italic; font-size: 0.97rem; color: var(--azul-medio); font-weight: 400; line-height: 1.7; }
.callout.verde { background: var(--verde-suave); border-left-color: var(--verde); color: var(--verde); }
.callout.laranja { background: var(--laranja-suave); border-left-color: var(--laranja); color: var(--laranja); }
/* ── BULLETS ── */
.bullet-list { list-style: none; padding: 0; margin: 0.5rem 0 1rem; }
.bullet-list li { display: flex; gap: 0.75rem; align-items: flex-start; padding: 0.4rem 0; font-size: 0.94rem; color: var(--cinza-texto); border-bottom: 1px solid var(--linha); font-weight: 300; }
.bullet-list li:last-child { border-bottom: none; }
.bullet-list li::before { content: ''; width: 6px; height: 6px; background: var(--azul-claro); border-radius: 50%; margin-top: 0.55rem; flex-shrink: 0; }
/* ── CARDS ── */
.cards-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin: 1.5rem 0; }
.card { background: var(--branco); border: 1px solid var(--linha); border-radius: 14px; padding: 1.25rem; transition: all 0.25s; box-shadow: var(--sombra); }
.card:hover { box-shadow: var(--sombra-hover); transform: translateY(-2px); }
.card-icon { font-size: 1.5rem; margin-bottom: 0.75rem; }
.card-title { font-weight: 600; font-size: 0.88rem; color: var(--azul-escuro); margin-bottom: 0.4rem; }
.card-desc { font-size: 0.8rem; color: var(--cinza-medio); line-height: 1.55; margin: 0; font-weight: 300; }
/* ── TABELA ── */
.table-wrap { overflow-x: auto; margin: 1.5rem 0; border-radius: 12px; box-shadow: var(--sombra); }
table { width: 100%; border-collapse: collapse; font-size: 0.88rem; background: var(--branco); border-radius: 12px; overflow: hidden; }
thead { background: var(--azul-escuro); }
thead th { padding: 0.9rem 1rem; color: var(--branco); font-weight: 500; text-align: left; letter-spacing: 0.03em; font-size: 0.82rem; }
tbody tr:nth-child(even) { background: var(--cinza-claro); }
tbody tr:hover { background: var(--azul-ice); }
tbody td { padding: 0.85rem 1rem; border-bottom: 1px solid var(--linha); color: var(--cinza-texto); vertical-align: top; line-height: 1.6; font-weight: 300; }
code { font-family: 'DM Mono', monospace; font-size: 0.78rem; background: var(--azul-ice); color: var(--azul-medio); padding: 0.15rem 0.4rem; border-radius: 4px; }
/* ── FASES ── */
.fase { border-radius: 16px; overflow: hidden; margin-bottom: 1.5rem; box-shadow: var(--sombra); transition: box-shadow 0.25s; }
.fase:hover { box-shadow: var(--sombra-hover); }
.fase-header { display: flex; align-items: center; justify-content: space-between; padding: 1.1rem 1.5rem; color: var(--branco); }
.fase-header-left { display: flex; align-items: center; gap: 1rem; }
.fase-num { font-family: 'DM Mono', monospace; font-size: 0.7rem; background: rgba(255,255,255,0.18); border-radius: 6px; padding: 0.25rem 0.6rem; letter-spacing: 0.08em; }
.fase-title { font-family: 'Playfair Display', serif; font-size: 1.05rem; font-weight: 600; }
.fase-period { font-size: 0.78rem; opacity: 0.8; font-family: 'DM Mono', monospace; white-space: nowrap; }
.fase-body { background: var(--branco); padding: 1.25rem 1.5rem; border: 1px solid var(--linha); border-top: none; border-radius: 0 0 16px 16px; }
/* ── PRODUTOS ── */
.produtos-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; margin: 1.5rem 0; }
@media (max-width: 640px) { .produtos-grid { grid-template-columns: 1fr; } }
.produto-card { border-radius: 16px; overflow: hidden; box-shadow: var(--sombra); transition: box-shadow 0.25s; }
.produto-card:hover { box-shadow: var(--sombra-hover); }
.produto-header { padding: 1.25rem 1.5rem; color: var(--branco); }
.produto-header .label { font-family: 'DM Mono', monospace; font-size: 0.65rem; letter-spacing: 0.12em; opacity: 0.7; text-transform: uppercase; margin-bottom: 0.3rem; }
.produto-header .name { font-family: 'Playfair Display', serif; font-size: 1.1rem; font-weight: 700; }
.produto-body { background: var(--branco); padding: 1.25rem 1.5rem; border: 1px solid var(--linha); border-top: none; border-radius: 0 0 16px 16px; font-size: 0.88rem; color: var(--cinza-texto); font-weight: 300; line-height: 1.65; }
/* ── PAPEIS ── */
.papeis-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; margin: 1.5rem 0; }
.papel-card { background: var(--branco); border: 1px solid var(--linha); border-radius: 14px; padding: 1.25rem; box-shadow: var(--sombra); transition: all 0.25s; }
.papel-card:hover { transform: translateY(-3px); box-shadow: var(--sombra-hover); }
.papel-num { font-family: 'DM Mono', monospace; font-size: 0.65rem; color: var(--azul-claro); letter-spacing: 0.1em; margin-bottom: 0.5rem; }
.papel-nome { font-weight: 700; font-size: 0.95rem; color: var(--azul-escuro); margin-bottom: 0.5rem; }
.papel-desc { font-size: 0.8rem; color: var(--cinza-medio); line-height: 1.55; font-weight: 300; margin: 0; }
.papel-badge { display: inline-block; margin-top: 0.5rem; font-family: 'DM Mono', monospace; font-size: 0.6rem; background: var(--azul-ice); color: var(--azul-claro); border-radius: 4px; padding: 0.15rem 0.5rem; letter-spacing: 0.06em; }
/* ── PLANOS ── */
.planos-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; margin: 1.5rem 0; }
.plano-card { background: var(--branco); border: 1px solid var(--linha); border-radius: 14px; padding: 1.25rem; box-shadow: var(--sombra); transition: all 0.25s; position: relative; padding-top: 1.5rem; overflow: hidden; }
.plano-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; }
.plano-card.free::before { background: var(--cinza-medio); }
.plano-card.pro::before { background: var(--azul-claro); }
.plano-card.clinica::before { background: var(--verde); }
.plano-card.supervisor::before { background: var(--roxo); }
.plano-card.conteudo::before { background: var(--laranja); }
.plano-card:hover { transform: translateY(-3px); box-shadow: var(--sombra-hover); }
.plano-nome { font-weight: 700; font-size: 1rem; color: var(--azul-escuro); margin-bottom: 0.25rem; }
.plano-perfil { font-size: 0.75rem; color: var(--cinza-medio); margin-bottom: 1rem; font-weight: 400; }
.plano-key { font-family: 'DM Mono', monospace; font-size: 0.6rem; background: var(--cinza-claro); color: var(--cinza-medio); border-radius: 4px; padding: 0.1rem 0.4rem; margin-bottom: 0.75rem; display: inline-block; }
.plano-features { list-style: none; padding: 0; }
.plano-features li { font-size: 0.8rem; color: var(--cinza-texto); padding: 0.3rem 0; border-bottom: 1px solid var(--linha); display: flex; gap: 0.5rem; align-items: flex-start; font-weight: 300; }
.plano-features li:last-child { border-bottom: none; }
.plano-features li::before { content: '→'; color: var(--azul-claro); font-size: 0.7rem; margin-top: 0.15rem; flex-shrink: 0; }
/* ── RISCOS ── */
.risco { background: var(--branco); border: 1px solid var(--linha); border-radius: 14px; padding: 1.25rem 1.5rem; margin-bottom: 1rem; box-shadow: var(--sombra); display: grid; grid-template-columns: 1fr auto; gap: 1rem; align-items: start; }
.risco-title { font-weight: 600; font-size: 0.92rem; color: var(--azul-escuro); margin-bottom: 0.4rem; }
.risco-mit { font-size: 0.84rem; color: var(--cinza-texto); line-height: 1.65; font-weight: 300; }
.risco-tags { display: flex; flex-direction: column; gap: 0.4rem; align-items: flex-end; }
.tag { font-family: 'DM Mono', monospace; font-size: 0.65rem; letter-spacing: 0.06em; padding: 0.2rem 0.6rem; border-radius: 100px; white-space: nowrap; }
.tag-alto { background: #FDE8E8; color: #B91C1C; }
.tag-medio { background: #FEF3C7; color: #92400E; }
.tag-baixo { background: #D1FAE5; color: #065F46; }
/* ── FUNIL ── */
.funil { margin: 1.5rem 0; }
.funil-step { display: flex; gap: 1.25rem; align-items: flex-start; padding: 1.1rem 1.25rem; background: var(--branco); border: 1px solid var(--linha); border-radius: 12px; margin-bottom: 0.75rem; box-shadow: var(--sombra); transition: all 0.25s; }
.funil-step:hover { box-shadow: var(--sombra-hover); transform: translateX(4px); }
.funil-icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 1.1rem; flex-shrink: 0; }
.funil-step-title { font-weight: 600; font-size: 0.9rem; color: var(--azul-escuro); margin-bottom: 0.25rem; }
.funil-step-desc { font-size: 0.84rem; color: var(--cinza-texto); line-height: 1.6; font-weight: 300; }
/* ── CRONOGRAMA ── */
.crono { margin: 1.5rem 0; }
.crono-mes { margin-bottom: 2rem; }
.crono-mes-title { font-family: 'Playfair Display', serif; font-size: 1rem; font-weight: 700; color: var(--azul-escuro); padding: 0.6rem 1rem; background: var(--azul-ice); border-radius: 8px; margin-bottom: 0.75rem; display: flex; align-items: center; gap: 0.75rem; }
.crono-mes-title span { font-family: 'DM Mono', monospace; font-size: 0.68rem; background: var(--azul-claro); color: var(--branco); border-radius: 4px; padding: 0.15rem 0.5rem; letter-spacing: 0.06em; }
.crono-semanas { display: grid; gap: 0.6rem; }
.crono-semana { display: grid; grid-template-columns: 80px 1fr 1fr 1fr; gap: 0.5rem; background: var(--branco); border: 1px solid var(--linha); border-radius: 10px; overflow: hidden; font-size: 0.8rem; }
.crono-periodo { background: var(--azul-escuro); color: var(--branco); font-family: 'DM Mono', monospace; font-size: 0.65rem; letter-spacing: 0.06em; padding: 0.75rem; display: flex; align-items: center; justify-content: center; text-align: center; line-height: 1.4; }
.crono-cell { padding: 0.75rem; color: var(--cinza-texto); line-height: 1.55; border-left: 1px solid var(--linha); font-weight: 300; }
.crono-cell.front { background: rgba(46,127,191,0.04); }
.crono-cell.back { background: rgba(30,107,82,0.04); }
.crono-cell.entrega { background: rgba(201,106,58,0.04); font-weight: 500; color: var(--azul-escuro); }
.crono-header { display: grid; grid-template-columns: 80px 1fr 1fr 1fr; gap: 0.5rem; margin-bottom: 0.4rem; }
.crono-header-cell { font-size: 0.7rem; font-weight: 600; color: var(--cinza-medio); letter-spacing: 0.06em; text-transform: uppercase; padding: 0 0.5rem; }
/* ── MÓDULOS ── */
.modulo { background: var(--branco); border: 1px solid var(--linha); border-radius: 16px; margin-bottom: 1.25rem; box-shadow: var(--sombra); overflow: hidden; transition: box-shadow 0.25s; }
.modulo:hover { box-shadow: var(--sombra-hover); }
.modulo-header { display: flex; align-items: center; gap: 1rem; padding: 1.1rem 1.5rem; background: var(--cinza-claro); border-bottom: 1px solid var(--linha); }
.modulo-num { width: 32px; height: 32px; background: var(--azul-escuro); color: var(--branco); border-radius: 8px; display: flex; align-items: center; justify-content: center; font-family: 'DM Mono', monospace; font-size: 0.72rem; font-weight: 500; flex-shrink: 0; }
.modulo-title { font-weight: 600; font-size: 0.95rem; color: var(--azul-escuro); }
.modulo-body { padding: 1.25rem 1.5rem; }
.modulo-desc { font-size: 0.88rem; color: var(--cinza-texto); margin-bottom: 0.75rem; font-weight: 300; line-height: 1.7; }
/* ── TRILHAS ── */
.trilha { background: var(--branco); border: 1px solid var(--linha); border-radius: 14px; margin-bottom: 1rem; box-shadow: var(--sombra); overflow: hidden; }
.trilha-header { padding: 1rem 1.25rem; background: linear-gradient(135deg, var(--azul-escuro), var(--azul-medio)); color: var(--branco); font-family: 'Playfair Display', serif; font-size: 0.95rem; font-weight: 600; }
.trilha-body { padding: 1rem 1.25rem; }
/* ── SCHEMA BLOCKS ── */
.schema-block { background: #0d1b2a; border-radius: 12px; padding: 1.25rem 1.5rem; margin: 1rem 0; overflow-x: auto; border: 1px solid rgba(46,127,191,0.2); }
.schema-block pre { font-family: 'DM Mono', monospace; font-size: 0.78rem; line-height: 1.7; color: #a8c5e8; margin: 0; }
.schema-block pre .keyword { color: #7ec8e3; }
.schema-block pre .type { color: #6ee7b7; }
.schema-block pre .string { color: #fcd34d; }
.schema-block pre .comment { color: #4a5f70; font-style: italic; }
.schema-block pre .constraint { color: #c4b5fd; }
.schema-table-card {
background: var(--branco); border: 1px solid var(--linha); border-radius: 12px;
margin-bottom: 1rem; box-shadow: var(--sombra); overflow: hidden;
}
.schema-table-header {
background: var(--azul-escuro); padding: 0.75rem 1.25rem;
display: flex; align-items: center; justify-content: space-between;
}
.schema-table-name { font-family: 'DM Mono', monospace; font-size: 0.82rem; color: #7ec8e3; font-weight: 500; }
.schema-table-desc { font-size: 0.72rem; color: rgba(255,255,255,0.4); }
.schema-cols { padding: 0.75rem 1.25rem; }
.schema-col { display: grid; grid-template-columns: 180px 120px 1fr; gap: 0.5rem; padding: 0.35rem 0; border-bottom: 1px solid var(--linha); font-size: 0.8rem; align-items: start; }
.schema-col:last-child { border-bottom: none; }
.schema-col-name { font-family: 'DM Mono', monospace; color: var(--azul-medio); font-size: 0.75rem; }
.schema-col-type { font-family: 'DM Mono', monospace; color: var(--verde); font-size: 0.72rem; }
.schema-col-desc { color: var(--cinza-medio); font-size: 0.76rem; font-weight: 300; line-height: 1.4; }
.schema-col-pk { background: rgba(201,106,58,0.15); color: var(--laranja); font-family: 'DM Mono', monospace; font-size: 0.58rem; padding: 0.1rem 0.35rem; border-radius: 3px; margin-left: 0.3rem; }
.schema-col-fk { background: rgba(92,61,143,0.15); color: var(--roxo); font-family: 'DM Mono', monospace; font-size: 0.58rem; padding: 0.1rem 0.35rem; border-radius: 3px; margin-left: 0.3rem; }
.schema-col-nn { background: rgba(46,127,191,0.12); color: var(--azul-claro); font-family: 'DM Mono', monospace; font-size: 0.58rem; padding: 0.1rem 0.35rem; border-radius: 3px; margin-left: 0.3rem; }
/* ── ENUM BLOCKS ── */
.enum-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; margin: 1.5rem 0; }
.enum-card { background: var(--branco); border: 1px solid var(--linha); border-radius: 12px; overflow: hidden; box-shadow: var(--sombra); }
.enum-header { background: #0d1b2a; padding: 0.6rem 1rem; display: flex; align-items: center; justify-content: space-between; }
.enum-name { font-family: 'DM Mono', monospace; font-size: 0.75rem; color: #7ec8e3; }
.enum-schema { font-family: 'DM Mono', monospace; font-size: 0.6rem; color: rgba(255,255,255,0.3); }
.enum-values { padding: 0.75rem 1rem; display: flex; flex-wrap: wrap; gap: 0.4rem; }
.enum-val { font-family: 'DM Mono', monospace; font-size: 0.7rem; background: var(--azul-ice); color: var(--azul-medio); padding: 0.2rem 0.5rem; border-radius: 4px; }
.enum-val.status-ok { background: #d1fae5; color: #065f46; }
.enum-val.status-warn { background: #fef3c7; color: #92400e; }
.enum-val.status-err { background: #fee2e2; color: #991b1b; }
/* ── VISÃO ── */
.visao-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin: 1.5rem 0; }
.visao-card { background: var(--azul-escuro); border-radius: 16px; padding: 1.5rem; transition: all 0.25s; }
.visao-card:hover { transform: translateY(-3px); background: var(--azul-medio); }
.visao-card .icon { font-size: 1.75rem; margin-bottom: 0.75rem; }
.visao-card .title { font-family: 'Playfair Display', serif; font-size: 0.92rem; font-weight: 600; color: var(--branco); margin-bottom: 0.5rem; }
.visao-card .desc { font-size: 0.78rem; color: rgba(255,255,255,0.5); line-height: 1.6; font-weight: 300; margin: 0; }
/* ── DIVIDER ── */
.divider { height: 1px; background: linear-gradient(to right, transparent, var(--linha), transparent); margin: 3rem 0; }
/* ── FOOTER ── */
.footer { background: var(--azul-escuro); color: rgba(255,255,255,0.4); text-align: center; padding: 3rem 2rem; font-size: 0.8rem; font-family: 'DM Mono', monospace; letter-spacing: 0.06em; }
.footer strong { color: rgba(255,255,255,0.7); }
/* ── ANIMAÇÕES ── */
@keyframes fadeUp { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
@keyframes scrollPulse { 0%, 100% { opacity: 0.4; } 50% { opacity: 1; } }
/* ── RESPONSIVE ── */
@media (max-width: 768px) {
.chapter-header { flex-direction: column; gap: 0.75rem; }
.risco { grid-template-columns: 1fr; }
.risco-tags { flex-direction: row; }
.crono-semana { grid-template-columns: 60px 1fr; }
.crono-cell.back, .crono-header-cell:nth-child(3) { display: none; }
.crono-header { grid-template-columns: 60px 1fr 1fr; }
.schema-col { grid-template-columns: 130px 90px 1fr; }
}
/* ── NOTAS DE VERSÃO ── */
.version-note {
background: linear-gradient(135deg, rgba(30,107,82,0.08), rgba(46,127,191,0.06));
border: 1px solid rgba(30,107,82,0.2); border-radius: 12px;
padding: 1rem 1.5rem; margin: 1.5rem 0;
font-size: 0.84rem; color: var(--cinza-texto); line-height: 1.7;
}
.version-note strong { color: var(--verde); }
/* ── TENANT KINDS ── */
.tenant-kind-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0.75rem; margin: 1.5rem 0; }
.tenant-kind { background: var(--branco); border: 1px solid var(--linha); border-radius: 12px; padding: 1rem; box-shadow: var(--sombra); }
.tenant-kind-key { font-family: 'DM Mono', monospace; font-size: 0.72rem; color: var(--azul-claro); margin-bottom: 0.4rem; }
.tenant-kind-name { font-weight: 600; font-size: 0.88rem; color: var(--azul-escuro); margin-bottom: 0.3rem; }
.tenant-kind-desc { font-size: 0.78rem; color: var(--cinza-medio); font-weight: 300; line-height: 1.5; margin: 0; }
</style>
</head>
<body>
<div class="progress-bar" id="progressBar"></div>
<button class="nav-toggle" id="navToggle" aria-label="Menu">
<span></span><span></span><span></span>
</button>
<div class="overlay" id="overlay"></div>
<!-- SIDENAV -->
<nav class="sidenav" id="sidenav">
<div class="sidenav-logo">
<span>Saúde Mental</span>
<small>Documento Estratégico v2.0</small>
</div>
<div class="sidenav-section">Estratégia</div>
<a href="#cap1"><span class="num">01</span> Visão Geral</a>
<a href="#cap2"><span class="num">02</span> Origem e Motivação</a>
<a href="#cap3"><span class="num">03</span> O Problema</a>
<a href="#cap4"><span class="num">04</span> Mercado</a>
<a href="#cap5"><span class="num">05</span> Lacunas</a>
<div class="sidenav-section">Produto</div>
<a href="#cap6"><span class="num">06</span> Arquitetura</a>
<a href="#cap7"><span class="num">07</span> Multi-Papel</a>
<a href="#cap8"><span class="num">08</span> Módulos</a>
<a href="#cap9"><span class="num">09</span> Microlearning</a>
<a href="#cap10"><span class="num">10</span> Monetização</a>
<div class="sidenav-section">Banco de Dados</div>
<a href="#cap11"><span class="num">11</span> Modelo de Dados</a>
<a href="#cap12"><span class="num">12</span> Enums e Status</a>
<a href="#cap13"><span class="num">13</span> Funções RPC</a>
<div class="sidenav-section">Execução</div>
<a href="#cap14"><span class="num">14</span> Fases de Dev.</a>
<a href="#cap15"><span class="num">15</span> Cronograma MVP</a>
<a href="#cap16"><span class="num">16</span> Riscos</a>
<a href="#cap17"><span class="num">17</span> Adoção</a>
<a href="#cap18"><span class="num">18</span> Visão de Futuro</a>
</nav>
<!-- CAPA -->
<section class="cover">
<div class="cover-bg"></div>
<div class="cover-grid"></div>
<div class="cover-content">
<p class="cover-eyebrow">Documento Estratégico Fundacional</p>
<h1 class="cover-title">Plataforma de<br><span>Saúde Mental</span></h1>
<p class="cover-subtitle">Ecossistema completo para gestão clínica, educação continuada e conexão terapêutica — com modelo de dados real documentado</p>
<div class="cover-badges">
<span class="badge novo">Versão 2.0</span>
<span class="badge">Confidencial</span>
<span class="badge">Schema Supabase v17.6</span>
<span class="badge">PostgreSQL 17</span>
<span class="badge">2025</span>
</div>
</div>
<div class="cover-scroll"><span>scroll</span><div class="scroll-line"></div></div>
</section>
<!-- MAIN -->
<main class="main">
<!-- CAP 1 -->
<section class="chapter" id="cap1">
<div class="chapter-header">
<span class="chapter-num">01</span>
<h2 class="chapter-title">Visão Geral do Projeto</h2>
</div>
<p>Este documento descreve de forma completa e minuciosa o projeto de uma <strong>Plataforma de Saúde Mental</strong> — um ecossistema digital integrado que reúne gestão clínica, educação continuada e conexão entre profissionais e pacientes em um único ambiente.</p>
<p>A versão 2.0 deste documento incorpora a realidade do banco de dados já construído: tabelas reais, enums implementados, funções RPC em produção e decisões arquiteturais que foram tomadas durante o desenvolvimento. Este não é mais um documento de intenções — é o espelho fiel do que existe e do que está sendo construído.</p>
<div class="callout">"Não estamos construindo um software de gestão. Estamos construindo o ecossistema que o profissional de saúde mental brasileiro nunca teve."</div>
<div class="version-note">
<strong>O que mudou na v2.0:</strong> Adicionados os capítulos 11, 12 e 13 com a documentação completa do schema real do banco de dados (Supabase/PostgreSQL 17.6), incluindo as 60+ tabelas do schema público, todos os enums implementados e as principais funções RPC de negócio. O capítulo 07 foi expandido com os tipos de tenant reais. O capítulo 10 foi atualizado com as chaves de plano reais (<code>plans.target</code>: patient, therapist, clinic, supervisor).
</div>
<div class="section">
<h3 class="section-title">Pilares Fundadores</h3>
<div class="cards-grid">
<div class="card">
<div class="card-icon">🏛</div>
<div class="card-title">Confiança Clínica</div>
<p class="card-desc">Seriedade, conformidade com LGPD e segurança de dados sensíveis desde a fundação.</p>
</div>
<div class="card">
<div class="card-icon"></div>
<div class="card-title">Redução de Fricção</div>
<p class="card-desc">Cada funcionalidade deve economizar tempo real do profissional, nunca criar mais trabalho.</p>
</div>
<div class="card">
<div class="card-icon">🕸</div>
<div class="card-title">Efeito de Rede</div>
<p class="card-desc">Quanto mais profissionais entram, mais o produto vale para cada um deles.</p>
</div>
<div class="card">
<div class="card-icon">📚</div>
<div class="card-title">Educação como Aquisição</div>
<p class="card-desc">Conteúdo de microlearning que atrai, engaja e converte o profissional ideal.</p>
</div>
<div class="card">
<div class="card-icon">🔐</div>
<div class="card-title">RLS por Design</div>
<p class="card-desc">Row Level Security do Supabase garante que cada tenant só acessa seus próprios dados — sem possibilidade de vazamento cruzado.</p>
</div>
<div class="card">
<div class="card-icon">🧩</div>
<div class="card-title">Multi-Tenant Real</div>
<p class="card-desc">A coluna <code>tenant_id</code> está em todas as tabelas críticas, garantindo isolamento total por clínica ou terapeuta.</p>
</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- CAP 2 -->
<section class="chapter" id="cap2">
<div class="chapter-header">
<span class="chapter-num">02</span>
<h2 class="chapter-title">Origem e Motivação</h2>
</div>
<p>O projeto surgiu da observação direta de um problema recorrente: profissionais de saúde mental altamente capacitados clinicamente, mas completamente despreparados para gerir o aspecto administrativo e financeiro de suas práticas.</p>
<p>A pandemia de COVID-19 acelerou a digitalização do setor — o atendimento online normalizou-se, a demanda por terapia explodiu e o número de profissionais cresceu. Porém, as ferramentas disponíveis no mercado não acompanharam essa evolução em profundidade. Resolvem o agendamento, mas ignoram a clínica. Resolvem o financeiro, mas ignoram o paciente.</p>
<p>A motivação central é construir o produto que o mercado deveria ter criado há anos: uma plataforma que entende que o terapeuta <strong>também é paciente</strong>, que a clínica é feita de relações humanas, e que educação e prática clínica são inseparáveis.</p>
<div class="section">
<h3 class="section-title">O Papel do Parceiro Acadêmico</h3>
<p>Um dos diferenciais estratégicos do projeto é a parceria com um profissional em formação em psicologia e já atuante como psicanalista. Essa combinação une a visão clínica prática com o rigor acadêmico, permitindo a produção de conteúdo de microlearning com autoridade real.</p>
<p>Com o tempo, esse parceiro poderá atuar como supervisor clínico dentro da plataforma. O schema já prevê isso: <code>plans.target = 'supervisor'</code> e <code>tenants.kind = 'supervisor'</code> são tipos nativos do sistema, não adições futuras.</p>
</div>
</section>
<div class="divider"></div>
<!-- CAP 3 -->
<section class="chapter" id="cap3">
<div class="chapter-header">
<span class="chapter-num">03</span>
<h2 class="chapter-title">O Problema que Resolvemos</h2>
</div>
<div class="section">
<h3 class="subsection-title">1. Fragmentação de Ferramentas</h3>
<p>O profissional usa Google Agenda para agendamento, WhatsApp para comunicação, planilha para financeiro, Word para prontuário e e-mail para cobrança. São 5 ferramentas para uma única prática clínica.</p>
<h3 class="subsection-title">2. Ausência de Visão Clínica nos Sistemas Atuais</h3>
<p>Os softwares existentes tratam o atendimento como uma transação comercial. Não há suporte para acompanhamento de evolução do paciente, aplicação de escalas validadas ou registro estruturado por abordagem terapêutica.</p>
<h3 class="subsection-title">3. Isolamento Profissional</h3>
<p>Terapeutas trabalham em silos. Não há plataforma que facilite encaminhamentos entre colegas, supervisão clínica estruturada ou rede de colaboração profissional.</p>
<h3 class="subsection-title">4. Falta de Educação em Gestão</h3>
<p>A formação em psicologia, psicanálise e psiquiatria é excelente clinicamente, mas praticamente nula em gestão. O profissional não sabe precificar, não sabe lidar com inadimplência, não conhece suas obrigações fiscais e de LGPD.</p>
<h3 class="subsection-title">5. Experiência do Paciente Negligenciada</h3>
<p>O paciente é tratado como destinatário passivo do serviço. Não existe ferramenta que engaje o paciente entre sessões, acompanhe seu humor, envie tarefas terapêuticas ou registre seu progresso de forma visual.</p>
</div>
</section>
<div class="divider"></div>
<!-- CAP 4 -->
<section class="chapter" id="cap4">
<div class="chapter-header">
<span class="chapter-num">04</span>
<h2 class="chapter-title">O Mercado e seus Concorrentes</h2>
</div>
<p>O mercado brasileiro de software para saúde mental está em crescimento acelerado, mas ainda dominado por soluções parciais. Os principais players cobrem bem o básico administrativo, porém falham na profundidade clínica e na experiência do usuário.</p>
<div class="table-wrap">
<table>
<thead><tr><th>Player</th><th>Pontos Fortes</th><th>Lacunas Críticas</th></tr></thead>
<tbody>
<tr><td><strong>PsicoManager</strong></td><td>Prontuário, agendamento sólido</td><td>UX datada, sem app do paciente, sem microlearning</td></tr>
<tr><td><strong>Clínica Ágil</strong></td><td>Interface moderna, financeiro</td><td>Sem escalas clínicas, sem rede entre profissionais</td></tr>
<tr><td><strong>Amplimed</strong></td><td>Multi-especialidade, robusto</td><td>Complexo demais para terapeuta solo, custo elevado</td></tr>
<tr><td><strong>Nuvem Psicologia</strong></td><td>Foco em psicólogos, simples</td><td>Funcionalidades limitadas, sem crescimento de produto</td></tr>
<tr><td><strong>Google Agenda + Planilha</strong></td><td>Gratuito, familiar</td><td>Não é um produto — é um remendo</td></tr>
</tbody>
</table>
</div>
<div class="callout">Nossa plataforma compete em uma categoria nova: <strong>ecossistema terapêutico integrado</strong>. Enquanto os concorrentes vendem software de gestão, vendemos crescimento profissional, conexão clínica e educação continuada — com a gestão como consequência natural.</div>
</section>
<div class="divider"></div>
<!-- CAP 5 -->
<section class="chapter" id="cap5">
<div class="chapter-header">
<span class="chapter-num">05</span>
<h2 class="chapter-title">Lacunas de Mercado Identificadas</h2>
</div>
<p>A análise competitiva revelou oportunidades concretas que nenhum player atual preenche de forma satisfatória. São estas lacunas que definem nossa vantagem estratégica.</p>
<div class="section">
<h3 class="subsection-title">Lacuna 1 — Acompanhamento de Progresso Clínico Visual</h3>
<p>Nenhum sistema entrega um painel visual que mostre a evolução do paciente sessão a sessão com métricas e gráficos. Nossa tabela <code>agenda_eventos</code> já registra cada sessão com status, modalidade e preço — base para dashboards longitudinais.</p>
<h3 class="subsection-title">Lacuna 2 — Ferramentas para o Paciente entre Sessões</h3>
<p>Um módulo do paciente com diário de humor, tarefas terapêuticas e check-ins automáticos é praticamente inexistente no Brasil. A tabela <code>patients</code> já prevê <code>user_id</code>, permitindo que pacientes tenham login nativo na plataforma.</p>
<h3 class="subsection-title">Lacuna 3 — Escalas Psicológicas Integradas</h3>
<p>PHQ-9, GAD-7, BDI e outras escalas não estão integradas com envio ao paciente, correção automática e gráfico de evolução temporal. O sistema de <code>determined_commitments</code> com campos dinâmicos (<code>determined_commitment_fields</code>) forma a base técnica para isso.</p>
<h3 class="subsection-title">Lacuna 4 — Rede de Encaminhamentos</h3>
<p>Terapeutas frequentemente precisam encaminhar pacientes para colegas. O campo <code>patients.encaminhado_por</code> e o status <code>'Encaminhado'</code> já existem na tabela de pacientes. A estrutura de rede é o passo seguinte.</p>
<h3 class="subsection-title">Lacuna 5 — Módulo de Supervisão Clínica</h3>
<p>Nenhum sistema tem módulo específico para supervisores. No nosso schema: <code>plans.target = 'supervisor'</code>, <code>tenants.kind = 'supervisor'</code> e <code>plans.max_supervisees</code> (limite de supervisionados) já estão modelados nativamente.</p>
<h3 class="subsection-title">Lacuna 6 — Educação em Gestão para a Área</h3>
<p>A plataforma de microlearning — produto 2 — é um diferencial único. Conteúdos específicos sobre gestão de clínica, precificação, LGPD aplicada à psicologia e finanças do autônomo.</p>
<h3 class="subsection-title">Lacuna 7 — IA de Suporte Clínico</h3>
<p>Sugestão de bibliografias por apresentação clínica e rascunho de evoluções por voz são funcionalidades com altíssimo valor e quase inexistentes. O campo <code>agenda_eventos.extra_fields</code> (jsonb) e os campos de notas estruturadas já preparam o terreno para ingestão de IA.</p>
</div>
</section>
<div class="divider"></div>
<!-- CAP 6 -->
<section class="chapter" id="cap6">
<div class="chapter-header">
<span class="chapter-num">06</span>
<h2 class="chapter-title">Arquitetura do Produto</h2>
</div>
<p>A plataforma é composta por dois produtos complementares que compartilham a mesma base de usuários, infraestrutura Supabase e identidade de marca:</p>
<div class="produtos-grid">
<div class="produto-card">
<div class="produto-header" style="background: linear-gradient(135deg, #1B4F7A, #2E7FBF);">
<div class="label">Produto 1</div>
<div class="name">Sistema de Gestão Clínica</div>
</div>
<div class="produto-body">Agendamento com recorrência, prontuário, financeiro com Pix/Asaas, multi-papel, escalas clínicas, módulo do paciente, rede de profissionais e supervisão clínica.</div>
</div>
<div class="produto-card">
<div class="produto-header" style="background: linear-gradient(135deg, #1E6B52, #2DA882);">
<div class="label">Produto 2</div>
<div class="name">Plataforma de Microlearning</div>
</div>
<div class="produto-body">Trilhas de microlearning por especialidade, carrossel de slides, quiz, vídeo, banners no sistema e assinatura independente ou inclusa no plano.</div>
</div>
</div>
<div class="section">
<h3 class="section-title">Stack Tecnológica Real</h3>
<div class="cards-grid">
<div class="card"><div class="card-icon">🗄</div><div class="card-title">Supabase (Backend)</div><p class="card-desc">PostgreSQL 17.6, Auth, Storage, RLS, Realtime. Hospeda 60+ tabelas do schema público.</p></div>
<div class="card"><div class="card-icon">🔐</div><div class="card-title">Auth Supabase</div><p class="card-desc">JWT com refresh token. <code>auth.uid()</code> em todas as RLS policies. Login por e-mail e Google (Apple futuro).</p></div>
<div class="card"><div class="card-icon">💳</div><div class="card-title">Asaas (Pagamentos)</div><p class="card-desc">Integração via webhooks para Pix, boleto. Tabela <code>payment_settings</code> guarda configurações por owner.</p></div>
<div class="card"><div class="card-icon">📬</div><div class="card-title">Notificações</div><p class="card-desc">Sistema completo com <code>notification_queue</code>, canais (email, WhatsApp, SMS), opt-in por paciente e cleanup automático.</p></div>
</div>
</div>
<div class="section">
<h3 class="section-title">Como os Dois Produtos se Integram</h3>
<ul class="bullet-list">
<li>O mesmo login (<code>auth.users</code><code>profiles</code>) acessa os dois produtos.</li>
<li>Banners rotativos dentro do sistema de gestão exibem conteúdos do microlearning — tabela <code>login_carousel_slides</code> já existe no schema.</li>
<li>O modelo de planos (<code>plans</code>) pode incluir acesso ao microlearning como benefício por meio de <code>plan_features</code>.</li>
<li>O sistema de módulos (<code>modules</code>, <code>module_features</code>, <code>tenant_modules</code>) controla quais funcionalidades cada tenant tem acesso.</li>
</ul>
</div>
</section>
<div class="divider"></div>
<!-- CAP 7 -->
<section class="chapter" id="cap7">
<div class="chapter-header">
<span class="chapter-num">07</span>
<h2 class="chapter-title">O Sistema Multi-Papel e Multi-Tenant</h2>
</div>
<p>Um dos diferenciais arquiteturais mais importantes da plataforma é o sistema de <strong>multi-papel por usuário combinado com multi-tenant</strong>. Na maioria dos concorrentes, um usuário é ou terapeuta ou paciente. Em nossa plataforma, um único usuário pode exercer múltiplos papéis simultaneamente, refletindo a realidade clínica.</p>
<div class="callout">Insight central: O terapeuta também faz análise pessoal. Logo, ele é simultaneamente profissional de saúde mental e paciente de outro profissional. O sistema precisa respeitar e suportar essa dualidade de forma natural e sem fricção.</div>
<div class="section">
<h3 class="section-title">Os Papéis do Sistema</h3>
<div class="papeis-grid">
<div class="papel-card">
<div class="papel-num">PAPEL 01</div>
<div class="papel-nome">Paciente</div>
<p class="papel-desc">Agenda sessões, acessa histórico, responde escalas, usa o diário entre sessões e visualiza tarefas.</p>
<span class="papel-badge">profiles.account_type = 'patient'</span>
</div>
<div class="papel-card">
<div class="papel-num">PAPEL 02</div>
<div class="papel-nome">Terapeuta</div>
<p class="papel-desc">Gerencia agenda e pacientes, registra prontuário, aplica escalas, emite cobranças e acessa relatórios.</p>
<span class="papel-badge">profiles.account_type = 'therapist'</span>
</div>
<div class="papel-card">
<div class="papel-num">PAPEL 03</div>
<div class="papel-nome">Clínica</div>
<p class="papel-desc">Gerencia múltiplos terapeutas, controla agenda compartilhada, realiza repasse financeiro e métricas.</p>
<span class="papel-badge">profiles.account_type = 'clinic'</span>
</div>
<div class="papel-card">
<div class="papel-num">PAPEL 04</div>
<div class="papel-nome">Supervisor</div>
<p class="papel-desc">Acompanha casos de supervisionados com acesso controlado. Plano com limite de supervisionados via <code>plans.max_supervisees</code>.</p>
<span class="papel-badge">plans.target = 'supervisor'</span>
</div>
</div>
</div>
<div class="section">
<h3 class="section-title">Tipos de Tenant — <code>tenants.kind</code></h3>
<p>Cada workspace (tenant) tem um tipo imutável definido na criação. Isso determina o comportamento, permissões e funcionalidades disponíveis:</p>
<div class="tenant-kind-grid">
<div class="tenant-kind">
<div class="tenant-kind-key">therapist</div>
<div class="tenant-kind-name">Terapeuta Solo</div>
<p class="tenant-kind-desc">Terapeuta autônomo que gerencia sua própria prática. Um tenant por profissional.</p>
</div>
<div class="tenant-kind">
<div class="tenant-kind-key">clinic_coworking</div>
<div class="tenant-kind-name">Clínica Coworking</div>
<p class="tenant-kind-desc">Múltiplos terapeutas com espaço compartilhado, agenda independente por profissional.</p>
</div>
<div class="tenant-kind">
<div class="tenant-kind-key">clinic_reception</div>
<div class="tenant-kind-name">Clínica com Recepção</div>
<p class="tenant-kind-desc">Clínica com recepcionista centralizada gerenciando agendamento de múltiplos profissionais.</p>
</div>
<div class="tenant-kind">
<div class="tenant-kind-key">clinic_full</div>
<div class="tenant-kind-name">Clínica Completa</div>
<p class="tenant-kind-desc">Gestão completa: recepção, financeiro centralizado, repasse, relatórios gerenciais.</p>
</div>
<div class="tenant-kind">
<div class="tenant-kind-key">supervisor</div>
<div class="tenant-kind-name">Workspace de Supervisão</div>
<p class="tenant-kind-desc">Ambiente dedicado à supervisão clínica. Supervisores acompanham casos de supervisionados.</p>
</div>
</div>
</div>
<div class="section">
<h3 class="section-title">Regras de Transição entre Papéis</h3>
<ul class="bullet-list">
<li>Todo usuário começa com <code>profiles.account_type = 'free'</code> — sem perfil definido ainda.</li>
<li>O usuário escolhe se é paciente (<code>'patient'</code>) ou terapeuta (<code>'therapist'</code>) — o campo é <strong>imutável</strong> após a escolha.</li>
<li>Um Terapeuta pode criar ou se vincular a uma Clínica via <code>tenant_members</code> com <code>role = 'tenant_admin'</code> ou <code>'therapist'</code>.</li>
<li>A tabela <code>tenant_members</code> controla quem pertence a qual tenant e com qual papel (admin, terapeuta, recepcionista).</li>
<li>Um usuário Terapeuta pode simultaneamente ser Paciente de outro terapeuta — os dados são segregados por <code>tenant_id</code> e <code>owner_id</code>.</li>
<li>A troca de contexto entre papéis na interface não contamina dados — RLS garante isolamento total no banco.</li>
<li>Papéis globais de plataforma (ex: editor de microlearning) ficam em <code>profiles.platform_roles[]</code>, independentes de tenant.</li>
</ul>
</div>
</section>
<div class="divider"></div>
<!-- CAP 8 -->
<section class="chapter" id="cap8">
<div class="chapter-header">
<span class="chapter-num">08</span>
<h2 class="chapter-title">Módulos do Sistema de Gestão</h2>
</div>
<div class="modulo">
<div class="modulo-header"><div class="modulo-num">M1</div><div class="modulo-title">Autenticação e Multi-Papel</div></div>
<div class="modulo-body">
<p class="modulo-desc">Fundação de toda a plataforma. Usa <code>auth.users</code> (Supabase Auth) + <code>profiles</code> para dados do usuário. O <code>profiles.role</code> controla acesso administrativo ao sistema SaaS; <code>profiles.account_type</code> controla o tipo de conta do usuário.</p>
<ul class="bullet-list">
<li>Login com e-mail, Google e futuramente Apple</li>
<li>JWT com <code>auth.uid()</code> usado em todas as RLS policies</li>
<li>Middleware de permissão por papel em todas as rotas</li>
<li>Auditoria via <code>support_sessions</code> — admins SaaS podem acessar tenants com token temporário</li>
<li><code>profiles.platform_roles[]</code> para permissões globais independentes de tenant</li>
</ul>
</div>
</div>
<div class="modulo">
<div class="modulo-header"><div class="modulo-num">M2</div><div class="modulo-title">Agendamento com Recorrência</div></div>
<div class="modulo-body">
<p class="modulo-desc">Sistema de agenda completo com suporte a sessões recorrentes, exceções, bloqueios e agendamento online pelo paciente. Núcleo operacional do produto.</p>
<ul class="bullet-list">
<li><code>agenda_regras_semanais</code> — disponibilidade semanal do terapeuta (dia, horário, modalidade)</li>
<li><code>agenda_eventos</code> — cada sessão individual (status: agendado, realizado, faltou, cancelado, remarcar)</li>
<li><code>recurrence_rules</code> — regras de recorrência (weekly, biweekly, monthly, yearly, custom_weekdays)</li>
<li><code>recurrence_exceptions</code> — exceções pontuais: cancelamento, remarcação, feriado</li>
<li><code>agenda_excecoes</code> — bloqueios e horários extras do terapeuta</li>
<li><code>agendador_solicitacoes</code> — agendamento online pelos pacientes com aprovação do terapeuta</li>
<li>Conflito de horário validado pela função <code>cancelar_eventos_serie()</code></li>
</ul>
</div>
</div>
<div class="modulo">
<div class="modulo-header"><div class="modulo-num">M3</div><div class="modulo-title">Cadastro de Pacientes</div></div>
<div class="modulo-body">
<p class="modulo-desc">Cadastro completo do paciente com dados pessoais, endereço, responsável, notas clínicas e vínculo com terapeuta. Suporta escopo clínica (<code>patient_scope = 'clinic'</code>) e terapeuta (<code>patient_scope = 'therapist'</code>).</p>
<ul class="bullet-list">
<li>Tabela <code>patients</code> com 40+ campos: dados pessoais, endereço completo, responsável, CPF/RG</li>
<li>Status do paciente: Ativo, Inativo, Alta, Encaminhado, Arquivado</li>
<li><code>patient_invites</code> — link de auto-cadastro com token, expiração e limite de usos</li>
<li><code>patient_intake_requests</code> — ficha de anamnese via link público (função <code>create_patient_intake_request_v2</code>)</li>
<li><code>patient_tags</code> e <code>patient_groups</code> — organização e segmentação de pacientes</li>
<li><code>patient_discounts</code> — descontos por paciente com data de vigência</li>
<li>Suporte a responsável: campos de nome, telefone, CPF e cobrança no responsável</li>
</ul>
</div>
</div>
<div class="modulo">
<div class="modulo-header"><div class="modulo-num">M4</div><div class="modulo-title">Financeiro</div></div>
<div class="modulo-body">
<p class="modulo-desc">Controle financeiro completo com receitas, despesas, parcelamentos, repasse para clínica e integração com gateway de pagamento.</p>
<ul class="bullet-list">
<li><code>financial_records</code> — registro financeiro (receita/despesa) com status: pending, paid, partial, overdue, cancelled, refunded</li>
<li>Criação automática de cobrança quando sessão é marcada como realizada (trigger <code>auto_create_financial_record_from_session</code>)</li>
<li><code>financial_categories</code> — categorias personalizáveis de receita e despesa</li>
<li><code>billing_contracts</code> — contratos de cobrança por paciente (preço, frequência, método)</li>
<li><code>therapist_payouts</code> e <code>therapist_payout_records</code> — repasse financeiro para terapeutas em clínicas</li>
<li><code>payment_settings</code> — configuração de formas de pagamento aceitas (Pix, depósito, dinheiro, cartão, convênio)</li>
<li><code>insurance_plans</code> e <code>insurance_plan_services</code> — gestão de convênios e planos de saúde</li>
<li>Campo <code>clinic_fee_pct</code> e <code>clinic_fee_amount</code> para split entre clínica e terapeuta</li>
</ul>
</div>
</div>
<div class="modulo">
<div class="modulo-header"><div class="modulo-num">M5</div><div class="modulo-title">Notificações</div></div>
<div class="modulo-body">
<p class="modulo-desc">Sistema de notificações multi-canal com fila, agendamento, opt-in por canal e limpeza automática de mensagens antigas.</p>
<ul class="bullet-list">
<li><code>notification_queue</code> — fila de notificações (pendente → processando → enviado)</li>
<li>Canais: email, WhatsApp, SMS — opt-in individual por paciente em <code>notification_preferences</code></li>
<li><code>notification_templates</code> e <code>email_templates_tenant</code> — templates personalizáveis por tenant</li>
<li>Cancelamento automático de notificações quando sessão é cancelada ou paciente faz opt-out</li>
<li>Cleanup automático de mensagens enviadas/canceladas após 90 dias</li>
</ul>
</div>
</div>
<div class="modulo">
<div class="modulo-header"><div class="modulo-num">M6</div><div class="modulo-title">Serviços e Precificação</div></div>
<div class="modulo-body">
<p class="modulo-desc">Catálogo de serviços por terapeuta/clínica com vínculo à recorrência e precificação por sessão.</p>
<ul class="bullet-list">
<li><code>services</code> — catálogo de serviços (consulta, avaliação, retorno etc.) por owner/tenant</li>
<li><code>recurrence_rule_services</code> — serviços vinculados a uma recorrência com quantidade, preço unitário e desconto</li>
<li>Prioridade de preço na sessão: <code>recurrence_rule_services</code> > <code>recurrence_rules.price</code> > <code>agenda_eventos.price</code></li>
<li><code>professional_pricing</code> — tabela legada, substituída por <code>services</code></li>
</ul>
</div>
</div>
</section>
<div class="divider"></div>
<!-- CAP 9 -->
<section class="chapter" id="cap9">
<div class="chapter-header">
<span class="chapter-num">09</span>
<h2 class="chapter-title">Plataforma de Microlearning</h2>
</div>
<p>O produto de microlearning é o motor de aquisição orgânica da plataforma. Profissionais chegam pelo conteúdo e descobrem o sistema de gestão. É a estratégia que transforma educação em produto.</p>
<div class="callout verde">Insight-chave: o melhor canal de aquisição de um terapeuta é outro terapeuta. O microlearning cria o contexto social onde isso acontece naturalmente.</div>
<div class="section">
<h3 class="section-title">Trilhas de Conteúdo por Abordagem</h3>
<div class="trilha">
<div class="trilha-header">Gestão de Clínica para Psicólogos (TCC, Gestalt, Humanista)</div>
<div class="trilha-body">
<ul class="bullet-list">
<li>Como precificar sua sessão sem culpa e com consciência de mercado</li>
<li>LGPD na prática clínica: o que você precisa fazer hoje</li>
<li>Gestão de inadimplência sem comprometer o vínculo terapêutico</li>
<li>Quando e como reajustar o valor da sessão</li>
<li>Organização financeira para o profissional autônomo</li>
</ul>
</div>
</div>
<div class="trilha">
<div class="trilha-header" style="background: linear-gradient(135deg, #5C3D8F, #8B6FC4);">Gestão de Clínica para Psicanalistas</div>
<div class="trilha-body">
<ul class="bullet-list">
<li>Frequência de sessões e modelo de cobrança na psicanálise</li>
<li>Documentação mínima necessária na clínica psicanalítica</li>
<li>Como estruturar uma clínica particular sendo psicanalista</li>
<li>Supervisão e análise pessoal: como e onde buscar</li>
</ul>
</div>
</div>
<div class="trilha">
<div class="trilha-header" style="background: linear-gradient(135deg, #C96A3A, #E8935A);">Gestão de Clínica para Psiquiatras</div>
<div class="trilha-body">
<ul class="bullet-list">
<li>Receituário, laudos e documentação clínica</li>
<li>Credenciamento e faturamento com planos de saúde</li>
<li>Integração com outros profissionais de saúde mental</li>
<li>Como montar um consultório particular de psiquiatria</li>
</ul>
</div>
</div>
<div class="trilha">
<div class="trilha-header" style="background: linear-gradient(135deg, #374151, #6B7280);">Para Clínicas Multiprofissionais</div>
<div class="trilha-body">
<ul class="bullet-list">
<li>Como estruturar o repasse financeiro entre profissionais</li>
<li>Gestão de agenda compartilhada sem conflitos</li>
<li>Contrato de parceria entre clínica e profissional</li>
</ul>
</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- CAP 10 -->
<section class="chapter" id="cap10">
<div class="chapter-header">
<span class="chapter-num">10</span>
<h2 class="chapter-title">Modelo de Negócio e Monetização</h2>
</div>
<p>O modelo de negócio é SaaS com camada freemium. Os planos são gerenciados pela tabela <code>plans</code> com preços em <code>plan_prices</code> e vitrine pública em <code>plan_public</code>. Cada plano tem um <code>target</code> que define para qual tipo de conta ele é válido.</p>
<div class="section">
<h3 class="section-title">Estrutura de Planos</h3>
<div class="planos-grid">
<div class="plano-card free">
<div class="plano-nome">Gratuito</div>
<div class="plano-perfil">Paciente / Terapeuta iniciante</div>
<div class="plano-key">target: patient / therapist</div>
<ul class="plano-features">
<li>Até 10 pacientes</li>
<li>Agendamento básico</li>
<li>Conteúdo introdutório grátis</li>
</ul>
</div>
<div class="plano-card pro">
<div class="plano-nome">Profissional</div>
<div class="plano-perfil">Terapeuta autônomo</div>
<div class="plano-key">target: therapist</div>
<ul class="plano-features">
<li>Pacientes ilimitados</li>
<li>Prontuário completo</li>
<li>Financeiro + escalas</li>
<li>Todas as trilhas de conteúdo</li>
</ul>
</div>
<div class="plano-card clinica">
<div class="plano-nome">Clínica</div>
<div class="plano-perfil">Múltiplos terapeutas</div>
<div class="plano-key">target: clinic</div>
<ul class="plano-features">
<li>Multi-terapeuta via <code>tenant_members</code></li>
<li>Repasse financeiro (<code>therapist_payouts</code>)</li>
<li>Agenda compartilhada</li>
<li>Acesso para toda a equipe</li>
</ul>
</div>
<div class="plano-card supervisor">
<div class="plano-nome">Supervisor</div>
<div class="plano-perfil">Psicanalistas / supervisores</div>
<div class="plano-key">target: supervisor</div>
<ul class="plano-features">
<li>Limite de supervisionados (<code>max_supervisees</code>)</li>
<li>Acesso controlado a casos</li>
<li>Workspace próprio de supervisão</li>
</ul>
</div>
<div class="plano-card conteudo">
<div class="plano-nome">Conteúdo</div>
<div class="plano-perfil">Estudante / Paciente curioso</div>
<div class="plano-key">target: patient</div>
<ul class="plano-features">
<li>Acesso completo às trilhas</li>
<li>Sem sistema de gestão</li>
<li>Assinatura mensal independente</li>
</ul>
</div>
</div>
</div>
<div class="section">
<h3 class="section-title">Infraestrutura de Assinaturas</h3>
<ul class="bullet-list">
<li>Tabela <code>subscriptions</code> — assinatura ativa do usuário ou tenant (XOR: ou <code>user_id</code> ou <code>tenant_id</code>, nunca ambos)</li>
<li>Status de assinatura: pending, active, past_due, suspended, cancelled, expired</li>
<li>Tabela <code>subscription_intents_personal</code> e <code>subscription_intents_tenant</code> — intenção de pagamento antes da ativação</li>
<li>Função <code>activate_subscription_from_intent()</code> — ativa assinatura após confirmação de pagamento</li>
<li>Função <code>change_subscription_plan()</code> — muda plano com log em <code>subscription_events</code></li>
<li><code>entitlements_invalidation</code> — cache de entitlements é invalidado quando o plano muda</li>
<li><code>plan_prices</code> — histórico de preços por plano com intervalos (month/year)</li>
</ul>
</div>
</section>
<div class="divider"></div>
<!-- CAP 11 — NOVO: MODELO DE DADOS -->
<section class="chapter" id="cap11">
<div class="chapter-header">
<span class="chapter-num">11</span>
<h2 class="chapter-title">Modelo de Dados — Schema Real</h2>
</div>
<p>Documentação minuciosa das tabelas principais do schema <code>public</code> do banco de dados PostgreSQL 17.6 via Supabase. Este capítulo é a referência autoritativa para qualquer decisão de desenvolvimento.</p>
<div class="version-note">
<strong>Convenção:</strong> Todas as tabelas usam <code>uuid</code> como PK via <code>gen_random_uuid()</code>. Campos <code>tenant_id</code> e <code>owner_id</code> estão presentes em todas as tabelas de negócio para garantir isolamento multi-tenant. O campo <code>deleted_at</code> implementa soft-delete onde aplicável.
</div>
<div class="section">
<h3 class="section-title">Tabela: <code>profiles</code></h3>
<p>Extensão do <code>auth.users</code> do Supabase. Criado automaticamente no signup. Contém dados públicos do usuário e configurações de perfil.</p>
<div class="schema-table-card">
<div class="schema-table-header">
<span class="schema-table-name">public.profiles</span>
<span class="schema-table-desc">1 registro por auth.users</span>
</div>
<div class="schema-cols">
<div class="schema-col"><span class="schema-col-name">id<span class="schema-col-pk">PK</span><span class="schema-col-fk">FK→auth.users</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Mesmo ID do auth.users</span></div>
<div class="schema-col"><span class="schema-col-name">role</span><span class="schema-col-type">text</span><span class="schema-col-desc">Papel no sistema SaaS: saas_admin | tenant_member | portal_user | patient</span></div>
<div class="schema-col"><span class="schema-col-name">account_type</span><span class="schema-col-type">text</span><span class="schema-col-desc">Tipo de conta: free | patient | therapist | clinic. Imutável após definição.</span></div>
<div class="schema-col"><span class="schema-col-name">platform_roles</span><span class="schema-col-type">text[]</span><span class="schema-col-desc">Papéis globais de plataforma (ex: editor de microlearning). Atribuído pelo saas_admin.</span></div>
<div class="schema-col"><span class="schema-col-name">full_name</span><span class="schema-col-type">text</span><span class="schema-col-desc">Nome completo do usuário</span></div>
<div class="schema-col"><span class="schema-col-name">avatar_url</span><span class="schema-col-type">text</span><span class="schema-col-desc">URL pública no Supabase Storage</span></div>
<div class="schema-col"><span class="schema-col-name">phone</span><span class="schema-col-type">text</span><span class="schema-col-desc">WhatsApp no formato (99) 99999-9999</span></div>
<div class="schema-col"><span class="schema-col-name">bio</span><span class="schema-col-type">text</span><span class="schema-col-desc">Breve apresentação pública (máx 300 chars no front)</span></div>
<div class="schema-col"><span class="schema-col-name">language</span><span class="schema-col-type">text</span><span class="schema-col-desc">Default: 'pt-BR'</span></div>
<div class="schema-col"><span class="schema-col-name">timezone</span><span class="schema-col-type">text</span><span class="schema-col-desc">Default: 'America/Sao_Paulo'</span></div>
<div class="schema-col"><span class="schema-col-name">social_custom</span><span class="schema-col-type">jsonb</span><span class="schema-col-desc">Redes sociais adicionais: [{name, url}]</span></div>
</div>
</div>
</div>
<div class="section">
<h3 class="section-title">Tabela: <code>tenants</code></h3>
<p>Representa um workspace isolado — pode ser um terapeuta solo, uma clínica ou um workspace de supervisão. O <code>kind</code> é imutável após criação.</p>
<div class="schema-table-card">
<div class="schema-table-header">
<span class="schema-table-name">public.tenants</span>
<span class="schema-table-desc">Workspaces isolados multi-tenant</span>
</div>
<div class="schema-cols">
<div class="schema-col"><span class="schema-col-name">id<span class="schema-col-pk">PK</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">ID único do tenant</span></div>
<div class="schema-col"><span class="schema-col-name">name</span><span class="schema-col-type">text</span><span class="schema-col-desc">Nome do workspace (clínica ou nome do terapeuta)</span></div>
<div class="schema-col"><span class="schema-col-name">kind<span class="schema-col-nn">NN</span></span><span class="schema-col-type">text</span><span class="schema-col-desc">therapist | clinic_coworking | clinic_reception | clinic_full | supervisor | clinic (legado) | saas (legado)</span></div>
<div class="schema-col"><span class="schema-col-name">created_at</span><span class="schema-col-type">timestamptz</span><span class="schema-col-desc">Data de criação</span></div>
</div>
</div>
</div>
<div class="section">
<h3 class="section-title">Tabela: <code>tenant_members</code></h3>
<p>Vincula usuários a tenants com um papel específico. Um usuário pode pertencer a múltiplos tenants (ex: terapeuta em duas clínicas).</p>
<div class="schema-table-card">
<div class="schema-table-header">
<span class="schema-table-name">public.tenant_members</span>
<span class="schema-table-desc">Membros por workspace</span>
</div>
<div class="schema-cols">
<div class="schema-col"><span class="schema-col-name">tenant_id<span class="schema-col-fk">FK→tenants</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Workspace ao qual pertence</span></div>
<div class="schema-col"><span class="schema-col-name">user_id<span class="schema-col-fk">FK→profiles</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Usuário membro</span></div>
<div class="schema-col"><span class="schema-col-name">role</span><span class="schema-col-type">text</span><span class="schema-col-desc">Papel no tenant: tenant_admin | therapist | receptionist | viewer</span></div>
<div class="schema-col"><span class="schema-col-name">status</span><span class="schema-col-type">text</span><span class="schema-col-desc">active | invited | suspended</span></div>
</div>
</div>
</div>
<div class="section">
<h3 class="section-title">Tabela: <code>patients</code></h3>
<p>Registro completo do paciente. O campo <code>patient_scope</code> define se o paciente pertence à clínica ou a um terapeuta específico. Quando <code>patient_scope = 'therapist'</code>, o campo <code>therapist_member_id</code> é obrigatório.</p>
<div class="schema-table-card">
<div class="schema-table-header">
<span class="schema-table-name">public.patients</span>
<span class="schema-table-desc">~40 campos por paciente</span>
</div>
<div class="schema-cols">
<div class="schema-col"><span class="schema-col-name">id<span class="schema-col-pk">PK</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">ID único do paciente</span></div>
<div class="schema-col"><span class="schema-col-name">tenant_id<span class="schema-col-fk">FK→tenants</span><span class="schema-col-nn">NN</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Workspace ao qual pertence</span></div>
<div class="schema-col"><span class="schema-col-name">owner_id<span class="schema-col-fk">FK→profiles</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Quem criou/é responsável pelo paciente</span></div>
<div class="schema-col"><span class="schema-col-name">responsible_member_id<span class="schema-col-nn">NN</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Membro responsável pelo paciente no tenant</span></div>
<div class="schema-col"><span class="schema-col-name">therapist_member_id</span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Terapeuta vinculado (obrigatório quando patient_scope = 'therapist')</span></div>
<div class="schema-col"><span class="schema-col-name">user_id<span class="schema-col-fk">FK→profiles</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Conta de login do paciente (quando é usuário nativo)</span></div>
<div class="schema-col"><span class="schema-col-name">patient_scope</span><span class="schema-col-type">text</span><span class="schema-col-desc">'clinic' | 'therapist' — define a quem o paciente pertence</span></div>
<div class="schema-col"><span class="schema-col-name">status</span><span class="schema-col-type">text</span><span class="schema-col-desc">Ativo | Inativo | Alta | Encaminhado | Arquivado</span></div>
<div class="schema-col"><span class="schema-col-name">nome_completo<span class="schema-col-nn">NN</span></span><span class="schema-col-type">text</span><span class="schema-col-desc">Nome completo do paciente</span></div>
<div class="schema-col"><span class="schema-col-name">cpf</span><span class="schema-col-type">text</span><span class="schema-col-desc">CPF sem formatação (validado por regex ^\d{11}$)</span></div>
<div class="schema-col"><span class="schema-col-name">data_nascimento</span><span class="schema-col-type">date</span><span class="schema-col-desc">Data de nascimento</span></div>
<div class="schema-col"><span class="schema-col-name">cobranca_no_responsavel</span><span class="schema-col-type">boolean</span><span class="schema-col-desc">Cobrar no responsável em vez do paciente</span></div>
<div class="schema-col"><span class="schema-col-name">notas_internas</span><span class="schema-col-type">text</span><span class="schema-col-desc">Notas privadas do terapeuta (não visíveis ao paciente)</span></div>
</div>
</div>
</div>
<div class="section">
<h3 class="section-title">Tabela: <code>agenda_eventos</code></h3>
<p>Cada sessão individual na agenda. Gerada manualmente ou automaticamente por regras de recorrência. O campo <code>billed</code> controla se já foi gerada cobrança.</p>
<div class="schema-table-card">
<div class="schema-table-header">
<span class="schema-table-name">public.agenda_eventos</span>
<span class="schema-table-desc">Sessões e bloqueios de agenda</span>
</div>
<div class="schema-cols">
<div class="schema-col"><span class="schema-col-name">id<span class="schema-col-pk">PK</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">ID único do evento</span></div>
<div class="schema-col"><span class="schema-col-name">tenant_id<span class="schema-col-nn">NN</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Workspace</span></div>
<div class="schema-col"><span class="schema-col-name">owner_id<span class="schema-col-nn">NN</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Terapeuta dono do evento</span></div>
<div class="schema-col"><span class="schema-col-name">patient_id<span class="schema-col-fk">FK→patients</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Paciente da sessão (null em bloqueios)</span></div>
<div class="schema-col"><span class="schema-col-name">tipo</span><span class="schema-col-type">tipo_evento_agenda</span><span class="schema-col-desc">'sessao' | 'bloqueio'</span></div>
<div class="schema-col"><span class="schema-col-name">status</span><span class="schema-col-type">status_evento_agenda</span><span class="schema-col-desc">agendado | realizado | faltou | cancelado | remarcar</span></div>
<div class="schema-col"><span class="schema-col-name">inicio_em<span class="schema-col-nn">NN</span></span><span class="schema-col-type">timestamptz</span><span class="schema-col-desc">Início da sessão (com timezone)</span></div>
<div class="schema-col"><span class="schema-col-name">fim_em<span class="schema-col-nn">NN</span></span><span class="schema-col-type">timestamptz</span><span class="schema-col-desc">Fim da sessão — constraint: fim_em > inicio_em</span></div>
<div class="schema-col"><span class="schema-col-name">modalidade</span><span class="schema-col-type">text</span><span class="schema-col-desc">'presencial' | 'online' — default: 'presencial'</span></div>
<div class="schema-col"><span class="schema-col-name">recurrence_id<span class="schema-col-fk">FK→recurrence_rules</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Regra de recorrência que gerou este evento</span></div>
<div class="schema-col"><span class="schema-col-name">price</span><span class="schema-col-type">numeric(10,2)</span><span class="schema-col-desc">Valor da sessão em BRL</span></div>
<div class="schema-col"><span class="schema-col-name">billed</span><span class="schema-col-type">boolean</span><span class="schema-col-desc">true = cobrança já foi gerada para esta sessão</span></div>
<div class="schema-col"><span class="schema-col-name">extra_fields</span><span class="schema-col-type">jsonb</span><span class="schema-col-desc">Campos customizáveis por abordagem/tenant</span></div>
<div class="schema-col"><span class="schema-col-name">insurance_plan_id</span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Plano de saúde da sessão (quando convênio)</span></div>
</div>
</div>
</div>
<div class="section">
<h3 class="section-title">Tabela: <code>financial_records</code></h3>
<p>Registro financeiro central. Gerado automaticamente por trigger quando sessão é marcada como realizada. Suporta parcelamento, split de comissão e múltiplos status.</p>
<div class="schema-table-card">
<div class="schema-table-header">
<span class="schema-table-name">public.financial_records</span>
<span class="schema-table-desc">Receitas e despesas</span>
</div>
<div class="schema-cols">
<div class="schema-col"><span class="schema-col-name">id<span class="schema-col-pk">PK</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">ID único</span></div>
<div class="schema-col"><span class="schema-col-name">owner_id<span class="schema-col-nn">NN</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Terapeuta dono do registro</span></div>
<div class="schema-col"><span class="schema-col-name">tenant_id</span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Clínica (quando em contexto de clínica)</span></div>
<div class="schema-col"><span class="schema-col-name">type</span><span class="schema-col-type">financial_record_type</span><span class="schema-col-desc">'receita' | 'despesa'</span></div>
<div class="schema-col"><span class="schema-col-name">amount<span class="schema-col-nn">NN</span></span><span class="schema-col-type">numeric(10,2)</span><span class="schema-col-desc">Valor bruto</span></div>
<div class="schema-col"><span class="schema-col-name">discount_amount</span><span class="schema-col-type">numeric(10,2)</span><span class="schema-col-desc">Desconto aplicado</span></div>
<div class="schema-col"><span class="schema-col-name">final_amount</span><span class="schema-col-type">numeric(10,2)</span><span class="schema-col-desc">Valor final após desconto</span></div>
<div class="schema-col"><span class="schema-col-name">clinic_fee_pct</span><span class="schema-col-type">numeric(5,2)</span><span class="schema-col-desc">Percentual da clínica (0100)</span></div>
<div class="schema-col"><span class="schema-col-name">clinic_fee_amount</span><span class="schema-col-type">numeric(10,2)</span><span class="schema-col-desc">Valor absoluto da taxa da clínica</span></div>
<div class="schema-col"><span class="schema-col-name">net_amount</span><span class="schema-col-type">numeric(10,2)</span><span class="schema-col-desc">GENERATED: amount - clinic_fee_amount (valor líquido do terapeuta)</span></div>
<div class="schema-col"><span class="schema-col-name">status<span class="schema-col-nn">NN</span></span><span class="schema-col-type">text</span><span class="schema-col-desc">pending | paid | partial | overdue | cancelled | refunded</span></div>
<div class="schema-col"><span class="schema-col-name">agenda_evento_id<span class="schema-col-fk">FK→agenda_eventos</span></span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Sessão que originou a cobrança</span></div>
<div class="schema-col"><span class="schema-col-name">installments</span><span class="schema-col-type">smallint</span><span class="schema-col-desc">Número de parcelas (default: 1)</span></div>
<div class="schema-col"><span class="schema-col-name">installment_group</span><span class="schema-col-type">uuid</span><span class="schema-col-desc">UUID que agrupa parcelas de um mesmo parcelamento</span></div>
<div class="schema-col"><span class="schema-col-name">deleted_at</span><span class="schema-col-type">timestamptz</span><span class="schema-col-desc">Soft-delete — null = registro ativo</span></div>
</div>
</div>
</div>
<div class="section">
<h3 class="section-title">Tabela: <code>recurrence_rules</code></h3>
<p>Regras de recorrência de sessões. Define o padrão de repetição (semanal, quinzenal etc.) com data de início e fim opcional. Gera os <code>agenda_eventos</code> automaticamente.</p>
<div class="schema-table-card">
<div class="schema-table-header">
<span class="schema-table-name">public.recurrence_rules</span>
<span class="schema-table-desc">Padrões de sessões recorrentes</span>
</div>
<div class="schema-cols">
<div class="schema-col"><span class="schema-col-name">type</span><span class="schema-col-type">recurrence_type</span><span class="schema-col-desc">weekly | biweekly | monthly | yearly | custom_weekdays</span></div>
<div class="schema-col"><span class="schema-col-name">interval</span><span class="schema-col-type">smallint</span><span class="schema-col-desc">Intervalo entre ocorrências (ex: 2 para quinzenal)</span></div>
<div class="schema-col"><span class="schema-col-name">weekdays</span><span class="schema-col-type">smallint[]</span><span class="schema-col-desc">Dias da semana (0=Dom, 1=Seg...6=Sab) para custom_weekdays</span></div>
<div class="schema-col"><span class="schema-col-name">start_time / end_time</span><span class="schema-col-type">time</span><span class="schema-col-desc">Horário de início e fim da sessão</span></div>
<div class="schema-col"><span class="schema-col-name">duration_min</span><span class="schema-col-type">smallint</span><span class="schema-col-desc">Duração em minutos (default: 50)</span></div>
<div class="schema-col"><span class="schema-col-name">open_ended</span><span class="schema-col-type">boolean</span><span class="schema-col-desc">true = sem data de fim definida</span></div>
<div class="schema-col"><span class="schema-col-name">status</span><span class="schema-col-type">text</span><span class="schema-col-desc">ativo | pausado | cancelado</span></div>
<div class="schema-col"><span class="schema-col-name">price</span><span class="schema-col-type">numeric(10,2)</span><span class="schema-col-desc">Preço padrão da sessão desta recorrência</span></div>
<div class="schema-col"><span class="schema-col-name">modalidade</span><span class="schema-col-type">text</span><span class="schema-col-desc">'presencial' | 'online'</span></div>
<div class="schema-col"><span class="schema-col-name">insurance_plan_id</span><span class="schema-col-type">uuid</span><span class="schema-col-desc">Convênio vinculado a esta recorrência</span></div>
</div>
</div>
</div>
<div class="section">
<h3 class="section-title">Tabelas de Suporte — Referência Rápida</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Tabela</th><th>Finalidade</th><th>Observação</th></tr></thead>
<tbody>
<tr><td><code>subscriptions</code></td><td>Assinatura ativa do usuário ou tenant</td><td>XOR: user_id OU tenant_id</td></tr>
<tr><td><code>plans</code></td><td>Planos disponíveis com preço e target</td><td>target: patient/therapist/clinic/supervisor</td></tr>
<tr><td><code>plan_features</code></td><td>Features incluídas em cada plano</td><td>Vincula plans ↔ features</td></tr>
<tr><td><code>features</code></td><td>Catálogo de funcionalidades</td><td>Chave técnica imutável</td></tr>
<tr><td><code>modules</code> + <code>tenant_modules</code></td><td>Módulos disponíveis por tenant</td><td>Controle granular de acesso</td></tr>
<tr><td><code>notification_queue</code></td><td>Fila de notificações multi-canal</td><td>Email, WhatsApp, SMS</td></tr>
<tr><td><code>patient_invites</code></td><td>Links de auto-cadastro para pacientes</td><td>Token + expiração + limite de usos</td></tr>
<tr><td><code>patient_intake_requests</code></td><td>Fichas de anamnese via link público</td><td>Aprovadas pelo terapeuta</td></tr>
<tr><td><code>billing_contracts</code></td><td>Contratos de cobrança por paciente</td><td>Preço, frequência, método</td></tr>
<tr><td><code>services</code></td><td>Catálogo de serviços do terapeuta</td><td>Substitui professional_pricing</td></tr>
<tr><td><code>insurance_plans</code></td><td>Convênios e planos de saúde</td><td>Vinculado a sessões e recorrências</td></tr>
<tr><td><code>therapist_payouts</code></td><td>Repasse financeiro do terapeuta</td><td>Período, sessões, valor líquido</td></tr>
<tr><td><code>support_sessions</code></td><td>Sessões de suporte do saas_admin</td><td>Token temporário com TTL (1120 min)</td></tr>
<tr><td><code>user_settings</code></td><td>Preferências de UI por usuário</td><td>Theme, layout, modo de menu</td></tr>
<tr><td><code>feriados</code></td><td>Feriados nacionais/locais</td><td>Integração com bloqueios de agenda</td></tr>
<tr><td><code>global_notices</code></td><td>Avisos da plataforma para usuários</td><td>Com dismissal individual</td></tr>
<tr><td><code>saas_docs</code> + <code>saas_faq</code></td><td>Documentação e FAQ da plataforma</td><td>Com votos de utilidade</td></tr>
</tbody>
</table>
</div>
</div>
</section>
<div class="divider"></div>
<!-- CAP 12 — NOVO: ENUMS -->
<section class="chapter" id="cap12">
<div class="chapter-header">
<span class="chapter-num">12</span>
<h2 class="chapter-title">Enums e Tipos — Referência Completa</h2>
</div>
<p>O schema define enums PostgreSQL para todos os campos com valores discretos. Isso garante integridade de dados no nível do banco — sem strings inválidas passando pelo sistema.</p>
<div class="section">
<h3 class="section-title">Enums do Schema <code>public</code></h3>
<div class="enum-grid">
<div class="enum-card">
<div class="enum-header"><span class="enum-name">status_evento_agenda</span><span class="enum-schema">public</span></div>
<div class="enum-values">
<span class="enum-val status-ok">agendado</span>
<span class="enum-val status-ok">realizado</span>
<span class="enum-val status-err">faltou</span>
<span class="enum-val status-err">cancelado</span>
<span class="enum-val status-warn">remarcar</span>
</div>
</div>
<div class="enum-card">
<div class="enum-header"><span class="enum-name">recurrence_type</span><span class="enum-schema">public</span></div>
<div class="enum-values">
<span class="enum-val">weekly</span>
<span class="enum-val">biweekly</span>
<span class="enum-val">monthly</span>
<span class="enum-val">yearly</span>
<span class="enum-val">custom_weekdays</span>
</div>
</div>
<div class="enum-card">
<div class="enum-header"><span class="enum-name">tipo_evento_agenda</span><span class="enum-schema">public</span></div>
<div class="enum-values">
<span class="enum-val">sessao</span>
<span class="enum-val">bloqueio</span>
</div>
</div>
<div class="enum-card">
<div class="enum-header"><span class="enum-name">recurrence_exception_type</span><span class="enum-schema">public</span></div>
<div class="enum-values">
<span class="enum-val">cancel_session</span>
<span class="enum-val">reschedule_session</span>
<span class="enum-val">patient_missed</span>
<span class="enum-val">therapist_canceled</span>
<span class="enum-val">holiday_block</span>
</div>
</div>
<div class="enum-card">
<div class="enum-header"><span class="enum-name">financial_record_type</span><span class="enum-schema">public</span></div>
<div class="enum-values">
<span class="enum-val status-ok">receita</span>
<span class="enum-val status-err">despesa</span>
</div>
</div>
<div class="enum-card">
<div class="enum-header"><span class="enum-name">status_agenda_serie</span><span class="enum-schema">public</span></div>
<div class="enum-values">
<span class="enum-val status-ok">ativo</span>
<span class="enum-val status-warn">pausado</span>
<span class="enum-val status-err">cancelado</span>
</div>
</div>
<div class="enum-card">
<div class="enum-header"><span class="enum-name">tipo_excecao_agenda</span><span class="enum-schema">public</span></div>
<div class="enum-values">
<span class="enum-val status-err">bloqueio</span>
<span class="enum-val status-ok">horario_extra</span>
</div>
</div>
<div class="enum-card">
<div class="enum-header"><span class="enum-name">status_excecao_agenda</span><span class="enum-schema">public</span></div>
<div class="enum-values">
<span class="enum-val status-warn">pendente</span>
<span class="enum-val status-ok">ativo</span>
<span class="enum-val">arquivado</span>
</div>
</div>
<div class="enum-card">
<div class="enum-header"><span class="enum-name">determined_field_type</span><span class="enum-schema">public</span></div>
<div class="enum-values">
<span class="enum-val">text</span>
<span class="enum-val">textarea</span>
<span class="enum-val">number</span>
<span class="enum-val">date</span>
<span class="enum-val">select</span>
<span class="enum-val">boolean</span>
</div>
</div>
<div class="enum-card">
<div class="enum-header"><span class="enum-name">commitment_log_source</span><span class="enum-schema">public</span></div>
<div class="enum-values">
<span class="enum-val">manual</span>
<span class="enum-val">auto</span>
</div>
</div>
</div>
</div>
<div class="section">
<h3 class="section-title">Constraints de Texto — Equivalentes a Enums</h3>
<p>Alguns campos usam <code>CHECK</code> constraints em vez de enums PostgreSQL. São igualmente seguros no banco:</p>
<div class="table-wrap">
<table>
<thead><tr><th>Tabela.Coluna</th><th>Valores Permitidos</th></tr></thead>
<tbody>
<tr><td><code>profiles.role</code></td><td>saas_admin | tenant_member | portal_user | patient</td></tr>
<tr><td><code>profiles.account_type</code></td><td>free | patient | therapist | clinic</td></tr>
<tr><td><code>tenants.kind</code></td><td>therapist | clinic_coworking | clinic_reception | clinic_full | clinic | saas | supervisor</td></tr>
<tr><td><code>patients.status</code></td><td>Ativo | Inativo | Alta | Encaminhado | Arquivado</td></tr>
<tr><td><code>patients.patient_scope</code></td><td>clinic | therapist</td></tr>
<tr><td><code>financial_records.status</code></td><td>pending | paid | partial | overdue | cancelled | refunded</td></tr>
<tr><td><code>subscriptions.status</code></td><td>pending | active | past_due | suspended | cancelled | expired</td></tr>
<tr><td><code>subscriptions.interval</code></td><td>month | year</td></tr>
<tr><td><code>plans.target</code></td><td>patient | therapist | clinic | supervisor</td></tr>
<tr><td><code>therapist_payouts.status</code></td><td>pending | paid | cancelled</td></tr>
<tr><td><code>agenda_eventos.modalidade</code></td><td>presencial | online</td></tr>
<tr><td><code>user_settings.theme_mode</code></td><td>light | dark</td></tr>
<tr><td><code>user_settings.layout_variant</code></td><td>classic | rail</td></tr>
</tbody>
</table>
</div>
</div>
</section>
<div class="divider"></div>
<!-- CAP 13 — NOVO: FUNÇÕES RPC -->
<section class="chapter" id="cap13">
<div class="chapter-header">
<span class="chapter-num">13</span>
<h2 class="chapter-title">Funções RPC — Lógica de Negócio no Banco</h2>
</div>
<p>O sistema usa extensivamente <strong>funções PostgreSQL SECURITY DEFINER</strong> para encapsular lógica de negócio complexa e garantir atomicidade. Todas são chamadas via <code>supabase.rpc()</code> no frontend.</p>
<div class="callout laranja">Atenção arquitetural: Funções SECURITY DEFINER executam com as permissões do dono da função (supabase_admin), não do usuário chamador. Isso permite operações que burlariam o RLS de forma controlada. Use com responsabilidade.</div>
<div class="section">
<h3 class="section-title">Funções Críticas de Negócio</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Função</th><th>O que faz</th><th>Observação crítica</th></tr></thead>
<tbody>
<tr>
<td><code>create_clinic_tenant(p_name)</code></td>
<td>Cria um tenant do tipo 'clinic' e já vincula o usuário atual como tenant_admin</td>
<td>Atômico: cria tenant + tenant_members em uma transação</td>
</tr>
<tr>
<td><code>activate_subscription_from_intent(p_intent_id)</code></td>
<td>Ativa assinatura após pagamento confirmado (intent.status = 'paid')</td>
<td>Valida target (clinic/therapist/supervisor). Suporta todos os 3 tipos.</td>
</tr>
<tr>
<td><code>change_subscription_plan(p_subscription_id, p_new_plan_id)</code></td>
<td>Muda o plano de uma assinatura ativa com log em subscription_events</td>
<td>Valida compatibilidade de target (clinic ≠ therapist)</td>
</tr>
<tr>
<td><code>cancel_subscription(p_subscription_id)</code></td>
<td>Cancela assinatura e invalida cache de entitlements</td>
<td>Logs em subscription_events, invalida entitlements_invalidation</td>
</tr>
<tr>
<td><code>create_financial_record_for_session(...)</code></td>
<td>Cria cobrança para uma sessão, com idempotência (não duplica)</td>
<td>Marca billed=true na agenda_eventos após criar</td>
</tr>
<tr>
<td><code>auto_create_financial_record_from_session()</code></td>
<td>Trigger: cria financial_record automaticamente quando sessão é marcada como realizada</td>
<td>Prioridade de preço: recurrence_rule_services > recurrence_rules.price > agenda_eventos.price</td>
</tr>
<tr>
<td><code>create_patient_intake_request_v2(p_token, p_payload)</code></td>
<td>Cria ficha de anamnese via link público com validação do token</td>
<td>Valida token, expiração, limite de usos e processa 30+ campos do paciente</td>
</tr>
<tr>
<td><code>cancelar_eventos_serie(p_serie_id, p_a_partir_de)</code></td>
<td>Cancela todos os eventos futuros de uma série recorrente</td>
<td>Não cancela eventos já realizados</td>
</tr>
<tr>
<td><code>cancel_recurrence_from(p_recurrence_id, p_from_date)</code></td>
<td>Encerra uma recorrência a partir de uma data, ajustando end_date</td>
<td>Se from_date &lt;= start_date, cancela a recorrência inteira</td>
</tr>
<tr>
<td><code>create_therapist_payout(p_tenant_id, p_therapist_id, p_period_start, p_period_end)</code></td>
<td>Calcula e registra repasse financeiro para terapeuta em uma clínica</td>
<td>Agrega sessões realizadas no período com cálculo de comissão</td>
</tr>
<tr>
<td><code>create_support_session(p_tenant_id, p_ttl_minutes)</code></td>
<td>Cria sessão temporária de acesso ao suporte (saas_admin only)</td>
<td>TTL: 1120 minutos. Valida role = 'saas_admin'</td>
</tr>
<tr>
<td><code>cancel_patient_pending_notifications(patient_id, channel, evento_id)</code></td>
<td>Cancela notificações pendentes de um paciente por canal ou evento</td>
<td>Chamada por trigger quando sessão é cancelada ou paciente faz opt-out</td>
</tr>
<tr>
<td><code>can_delete_patient(p_patient_id)</code></td>
<td>Verifica se é seguro deletar um paciente (sem eventos, recorrências ou contratos)</td>
<td>Retorna boolean — chame antes de qualquer DELETE em patients</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="section">
<h3 class="section-title">Triggers Automáticos</h3>
<ul class="bullet-list">
<li><strong>Sessão realizada → cobrança criada:</strong> Trigger <code>auto_create_financial_record_from_session</code> dispara quando <code>agenda_eventos.status</code> muda para <code>'realizado'</code>. Cria <code>financial_record</code> com status <code>'pending'</code> e vencimento 7 dias após a sessão.</li>
<li><strong>Sessão cancelada → notificações canceladas:</strong> Trigger <code>cancel_notifications_on_session_cancel</code> cancela todas as notificações pendentes relacionadas à sessão.</li>
<li><strong>Opt-out do paciente → notificações canceladas:</strong> Trigger <code>cancel_notifications_on_opt_out</code> cancela notificações do canal específico quando paciente faz opt-out.</li>
</ul>
</div>
</section>
<div class="divider"></div>
<!-- CAP 14 -->
<section class="chapter" id="cap14">
<div class="chapter-header">
<span class="chapter-num">14</span>
<h2 class="chapter-title">Estratégia de Fases de Desenvolvimento</h2>
</div>
<p>O desenvolvimento é organizado em quatro fases estratégicas. A infraestrutura de banco de dados (tenants, profiles, agenda, financeiro, notificações) já está substancialmente implementada — o foco atual é na experiência de produto sobre ela.</p>
<div class="fase">
<div class="fase-header" style="background: linear-gradient(135deg, #1B4F7A, #2E7FBF);">
<div class="fase-header-left"><span class="fase-num">FASE 1</span><span class="fase-title">MVP e Validação</span></div>
<span class="fase-period">Meses 13</span>
</div>
<div class="fase-body">
<ul class="bullet-list">
<li>Sistema multi-papel funcional e sólido — <code>profiles</code>, <code>tenants</code>, <code>tenant_members</code> implementados</li>
<li>Agendamento completo com recorrência e lembretes via e-mail e WhatsApp</li>
<li>Cadastro de pacientes com vínculo terapeuta-paciente e ficha de anamnese online</li>
<li>Prontuário com anotações de sessão em <code>agenda_eventos.extra_fields</code></li>
<li>Financeiro básico: cobrança automática por trigger, integração Asaas (Pix)</li>
<li>LGPD implementada: criptografia, consentimento, auditoria via <code>support_sessions</code></li>
<li>Beta fechado com 1020 terapeutas reais</li>
<li>Landing page de microlearning com 1 trilha inicial</li>
</ul>
</div>
</div>
<div class="fase">
<div class="fase-header" style="background: linear-gradient(135deg, #1E6B52, #2DA882);">
<div class="fase-header-left"><span class="fase-num">FASE 2</span><span class="fase-title">Diferenciação Clínica</span></div>
<span class="fase-period">Meses 48</span>
</div>
<div class="fase-body">
<ul class="bullet-list">
<li>Escalas psicológicas integradas (PHQ-9, GAD-7, BDI) usando <code>determined_commitments</code> com campos dinâmicos</li>
<li>Dashboard de evolução do paciente com gráficos longitudinais</li>
<li>Módulo do paciente: diário de humor, tarefas, visualização de agenda (PWA)</li>
<li>Relatórios e laudos com template e exportação em PDF</li>
<li>Módulo de Clínica: tenant kind <code>clinic_*</code>, repasse financeiro (<code>therapist_payouts</code>)</li>
<li>Prontuário completo com campos estruturados por abordagem via <code>extra_fields</code></li>
<li>Expansão do microlearning: 35 trilhas completas</li>
<li><strong>Meta:</strong> 100 terapeutas pagantes, churn abaixo de 5%/mês</li>
</ul>
</div>
</div>
<div class="fase">
<div class="fase-header" style="background: linear-gradient(135deg, #C96A3A, #E8935A);">
<div class="fase-header-left"><span class="fase-num">FASE 3</span><span class="fase-title">Rede e Crescimento</span></div>
<span class="fase-period">Meses 918</span>
</div>
<div class="fase-body">
<ul class="bullet-list">
<li>Diretório de terapeutas: pacientes encontram profissionais usando <code>profiles</code> públicos</li>
<li>Rede de encaminhamentos estruturada — status <code>'Encaminhado'</code> em <code>patients</code> com rastreio</li>
<li>Módulo de supervisão clínica — tenant kind <code>'supervisor'</code> + plano <code>target='supervisor'</code> + <code>max_supervisees</code></li>
<li>Programa de indicação com benefícios para terapeutas indicadores</li>
<li>Expansão para clínicas multiprofissionais — kind <code>clinic_full</code></li>
<li><strong>Meta:</strong> 1.000 terapeutas ativos, 20+ clínicas, efeito de rede ativado</li>
</ul>
</div>
</div>
<div class="fase">
<div class="fase-header" style="background: linear-gradient(135deg, #5C3D8F, #8B6FC4);">
<div class="fase-header-left"><span class="fase-num">FASE 4</span><span class="fase-title">Inteligência e Escala</span></div>
<span class="fase-period">18+ meses</span>
</div>
<div class="fase-body">
<ul class="bullet-list">
<li>IA de suporte clínico: sugestão bibliográfica por CID, rascunho de evolução por voz — ingerindo <code>agenda_eventos.extra_fields</code></li>
<li>Alertas de risco baseados em padrões comportamentais do paciente</li>
<li>Integração com planos de saúde: tabelas <code>insurance_plans</code>, <code>insurance_plan_services</code> já existem no schema</li>
<li>API aberta para parceiros — <code>profiles.platform_roles</code> já suporta roles de API</li>
<li>Expansão internacional para mercados lusófonos</li>
</ul>
</div>
</div>
</section>
<div class="divider"></div>
<!-- CAP 15 -->
<section class="chapter" id="cap15">
<div class="chapter-header">
<span class="chapter-num">15</span>
<h2 class="chapter-title">Cronograma do MVP (3 Meses)</h2>
</div>
<p>Cronograma desenhado para um time com frontend e backend separados, priorizando entregas que gerem valor real para o primeiro usuário no prazo de 2 a 3 meses. A infraestrutura de banco já existe — o trabalho é de produto, UX e integração.</p>
<div class="crono">
<div class="crono-mes">
<div class="crono-mes-title"><span>MÊS 1</span> Fundação Sólida</div>
<div class="crono-header">
<div class="crono-header-cell"></div>
<div class="crono-header-cell">Frontend</div>
<div class="crono-header-cell">Backend</div>
<div class="crono-header-cell">Entrega</div>
</div>
<div class="crono-semanas">
<div class="crono-semana">
<div class="crono-periodo">Sem<br>12</div>
<div class="crono-cell front">Telas de login, cadastro, seleção de account_type, navegação base por papel</div>
<div class="crono-cell back">Auth Supabase, profiles criado no signup, middleware de permissão por role e account_type</div>
<div class="crono-cell entrega">Usuário cria conta, define se é terapeuta ou paciente e navega no ambiente correto</div>
</div>
<div class="crono-semana">
<div class="crono-periodo">Sem<br>34</div>
<div class="crono-cell front">Dashboard por papel, perfil do usuário, criação de tenant (clínica/solo)</div>
<div class="crono-cell back">RPC create_clinic_tenant, tenant_members, RLS policies por tenant_id</div>
<div class="crono-cell entrega">Terapeuta cria workspace, convida colegas — multi-tenant funcionando</div>
</div>
</div>
</div>
<div class="crono-mes">
<div class="crono-mes-title"><span>MÊS 2</span> Core do Produto</div>
<div class="crono-header">
<div class="crono-header-cell"></div>
<div class="crono-header-cell">Frontend</div>
<div class="crono-header-cell">Backend</div>
<div class="crono-header-cell">Entrega</div>
</div>
<div class="crono-semanas">
<div class="crono-semana">
<div class="crono-periodo">Sem<br>12</div>
<div class="crono-cell front">Tela de agenda do terapeuta, configuração de disponibilidade (agenda_regras_semanais)</div>
<div class="crono-cell back">CRUD de agenda_regras_semanais, recurrence_rules, geração de agenda_eventos</div>
<div class="crono-cell entrega">Terapeuta configura agenda semanal com recorrência</div>
</div>
<div class="crono-semana">
<div class="crono-periodo">Sem<br>34</div>
<div class="crono-cell front">Cadastro de pacientes, ficha de anamnese, link de auto-cadastro</div>
<div class="crono-cell back">CRUD patients, patient_invites, create_patient_intake_request_v2, notificações de agendamento</div>
<div class="crono-cell entrega">Paciente agenda sessão via link, terapeuta recebe notificação</div>
</div>
</div>
</div>
<div class="crono-mes">
<div class="crono-mes-title"><span>MÊS 3</span> Fechar o Ciclo e Lançar</div>
<div class="crono-header">
<div class="crono-header-cell"></div>
<div class="crono-header-cell">Frontend</div>
<div class="crono-header-cell">Backend</div>
<div class="crono-header-cell">Entrega</div>
</div>
<div class="crono-semanas">
<div class="crono-semana">
<div class="crono-periodo">Sem<br>12</div>
<div class="crono-cell front">Tela financeira, histórico de sessões, status de pagamento (financial_records)</div>
<div class="crono-cell back">Integração Asaas (Pix), trigger auto_create_financial_record_from_session, webhooks</div>
<div class="crono-cell entrega">Ciclo financeiro completo: sessão realizada → cobrança automática → confirmação Pix</div>
</div>
<div class="crono-semana">
<div class="crono-periodo">Sem<br>34</div>
<div class="crono-cell front">Anotações de sessão em extra_fields, UX refinado, landing page de microlearning</div>
<div class="crono-cell back">Revisão de segurança, RLS audit via support_sessions, ambiente de produção, monitoramento</div>
<div class="crono-cell entrega">Beta com 1020 terapeutas reais</div>
</div>
</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- CAP 16 -->
<section class="chapter" id="cap16">
<div class="chapter-header">
<span class="chapter-num">16</span>
<h2 class="chapter-title">Riscos e Mitigações</h2>
</div>
<div class="risco">
<div>
<div class="risco-title">RLS mal configurada vazando dados entre tenants</div>
<p class="risco-mit">O risco mais crítico do sistema. Toda query deve filtrar por <code>tenant_id = auth.uid()</code> ou similar. Testar com usuário de tenant B tentando acessar dados do tenant A. Usar <code>support_sessions</code> para auditoria. Code review obrigatório em toda RLS policy nova.</p>
</div>
<div class="risco-tags"><span class="tag tag-alto">Impacto Alto</span><span class="tag tag-medio">Prob. Médio</span></div>
</div>
<div class="risco">
<div>
<div class="risco-title">Trigger financeiro falhando silenciosamente</div>
<p class="risco-mit">O trigger <code>auto_create_financial_record_from_session</code> usa EXCEPTION WHEN OTHERS com RAISE WARNING — nunca bloqueia a agenda. Monitorar logs do Supabase para warnings. Implementar painel de sessões <code>billed=false</code> com status <code>'realizado'</code> como alerta de cobrança perdida.</p>
</div>
<div class="risco-tags"><span class="tag tag-medio">Impacto Médio</span><span class="tag tag-medio">Prob. Médio</span></div>
</div>
<div class="risco">
<div>
<div class="risco-title">Integração de pagamento subestimada</div>
<p class="risco-mit">Reservar pelo menos 2 semanas dedicadas para a integração com Asaas. Testar todos os fluxos de webhook, falha de pagamento e conciliação. A tabela <code>payment_settings</code> já existe — focar na lógica de webhook e mapeamento de status.</p>
</div>
<div class="risco-tags"><span class="tag tag-medio">Impacto Médio</span><span class="tag tag-alto">Prob. Alto</span></div>
</div>
<div class="risco">
<div>
<div class="risco-title">Dados sensíveis sem criptografia</div>
<p class="risco-mit">Implementar criptografia em repouso para prontuários e anotações desde o início. O campo <code>notas_internas</code> dos pacientes e <code>extra_fields</code> das sessões são os mais críticos. Usar Supabase Vault para secrets. Tratar como requisito não-negociável.</p>
</div>
<div class="risco-tags"><span class="tag tag-alto">Impacto Alto</span><span class="tag tag-baixo">Prob. Baixo</span></div>
</div>
<div class="risco">
<div>
<div class="risco-title">Complexidade do sistema multi-tenant na UI</div>
<p class="risco-mit">O schema suporta todos os tipos de tenant, mas a UI precisa ser simples. Terapeuta solo não deve ver opções de clínica. Usar <code>tenants.kind</code> para esconder/mostrar funcionalidades. Criar versão simplificada do onboarding para <code>kind='therapist'</code>.</p>
</div>
<div class="risco-tags"><span class="tag tag-medio">Impacto Médio</span><span class="tag tag-alto">Prob. Alto</span></div>
</div>
<div class="risco">
<div>
<div class="risco-title">Adoção lenta pelos terapeutas</div>
<p class="risco-mit">Beta fechado com 1020 terapeutas antes do lançamento público. Onboarding em 5 minutos. Plano gratuito generoso. Microlearning como canal de aquisição orgânica. Usar <code>global_notices</code> para comunicação de novidades in-app.</p>
</div>
<div class="risco-tags"><span class="tag tag-alto">Impacto Alto</span><span class="tag tag-medio">Prob. Médio</span></div>
</div>
<div class="risco">
<div>
<div class="risco-title">Escopo crescente comprometendo o prazo</div>
<p class="risco-mit">O schema já tem muitas funcionalidades implementadas (convênios, repasse, supervisão). Resistir à tentação de ativar tudo no MVP. Usar o sistema de <code>modules</code> e <code>tenant_modules</code> para liberar features gradualmente por tenant, sem reescrever código.</p>
</div>
<div class="risco-tags"><span class="tag tag-alto">Impacto Alto</span><span class="tag tag-alto">Prob. Alto</span></div>
</div>
</section>
<div class="divider"></div>
<!-- CAP 17 -->
<section class="chapter" id="cap17">
<div class="chapter-header">
<span class="chapter-num">17</span>
<h2 class="chapter-title">Estratégia de Adoção e Crescimento</h2>
</div>
<div class="section">
<h3 class="section-title">O Funil de Aquisição</h3>
<div class="funil">
<div class="funil-step">
<div class="funil-icon" style="background: var(--azul-ice);">📢</div>
<div>
<div class="funil-step-title">Topo do Funil — Conteúdo</div>
<p class="funil-step-desc">Microlearning gratuito atrai terapeutas buscando aprender gestão. SEO em conteúdo de blog e trilhas. Presença no Instagram e LinkedIn com dicas de gestão clínica.</p>
</div>
</div>
<div class="funil-step">
<div class="funil-icon" style="background: var(--verde-suave);">🔬</div>
<div>
<div class="funil-step-title">Meio do Funil — Experimentação</div>
<p class="funil-step-desc">Plano gratuito com limite generoso (<code>account_type = 'free'</code>). Onboarding em 5 minutos. O terapeuta experimenta sem compromisso e vê valor antes de pagar.</p>
</div>
</div>
<div class="funil-step">
<div class="funil-icon" style="background: var(--laranja-suave);">💳</div>
<div>
<div class="funil-step-title">Fundo do Funil — Conversão</div>
<p class="funil-step-desc">Quando ultrapassa o limite do plano gratuito, a conversão é natural. O sistema de <code>subscription_intents</code> facilita o checkout sem atrito.</p>
</div>
</div>
<div class="funil-step">
<div class="funil-icon" style="background: var(--roxo-suave);">🔒</div>
<div>
<div class="funil-step-title">Retenção — Profundidade</div>
<p class="funil-step-desc">Escalas clínicas, prontuário acumulado em <code>agenda_eventos</code> e histórico financeiro criam lock-in legítimo. O custo de sair é alto porque os dados clínicos estão na plataforma.</p>
</div>
</div>
<div class="funil-step">
<div class="funil-icon" style="background: var(--azul-ice);">🌐</div>
<div>
<div class="funil-step-title">Expansão — Indicação</div>
<p class="funil-step-desc">Programa de indicação: terapeuta indica colega, ambos ganham benefício. O sistema de <code>patient_invites</code> é o modelo para o sistema de indicação de terapeutas.</p>
</div>
</div>
</div>
</div>
<div class="section">
<h3 class="section-title">Estratégia de Beta — Os Primeiros 20 Terapeutas</h3>
<ul class="bullet-list">
<li>Recrutar manualmente via LinkedIn, grupos de psicólogos no WhatsApp e Facebook, indicações pessoais.</li>
<li>Oferecer 6 meses gratuitos no plano Profissional em troca de uso semanal e feedback honesto — configurado via <code>subscriptions</code> com <code>source = 'manual'</code>.</li>
<li>Realizar call de 30 minutos com cada beta-tester após 2 semanas de uso.</li>
<li>Observar onde travam no onboarding, o que tentam fazer e não encontram, o que elogiam espontaneamente.</li>
<li>Usar esses aprendizados para uma rodada de ajustes de 2 semanas antes do lançamento público.</li>
<li>Transformar os melhores beta-testers em embaixadores com benefícios permanentes.</li>
</ul>
</div>
</section>
<div class="divider"></div>
<!-- CAP 18 -->
<section class="chapter" id="cap18">
<div class="chapter-header">
<span class="chapter-num">18</span>
<h2 class="chapter-title">Visão de Longo Prazo</h2>
</div>
<p>Em 5 anos, a plataforma deve ser reconhecida como a infraestrutura da saúde mental brasileira — o ambiente onde profissionais aprendem, trabalham, colaboram e crescem.</p>
<div class="callout">Visão de longo prazo: Ser para o terapeuta brasileiro o que a Bloomberg é para o mercado financeiro — a plataforma que nenhum profissional sério consegue imaginar trabalhar sem ela.</div>
<div class="visao-grid">
<div class="visao-card">
<div class="icon">🗺</div>
<div class="title">Plataforma de Referência Nacional</div>
<p class="desc">O maior diretório de terapeutas do Brasil, com pacientes encontrando profissionais por abordagem, especialidade e localização. Base técnica: <code>profiles</code> públicos com bio e redes sociais.</p>
</div>
<div class="visao-card">
<div class="icon">🎓</div>
<div class="title">Educação Continuada Reconhecida</div>
<p class="desc">Certificações reconhecidas pelo mercado. Parcerias com conselhos profissionais e universidades. Base: plataforma de microlearning e <code>platform_roles</code>.</p>
</div>
<div class="visao-card">
<div class="icon">🤖</div>
<div class="title">IA Clínica de Suporte</div>
<p class="desc">Assistente que apoia na documentação, sugestão de intervenções e identificação de padrões de risco — ingerindo <code>agenda_eventos.extra_fields</code> e histórico longitudinal.</p>
</div>
<div class="visao-card">
<div class="icon">🌍</div>
<div class="title">Expansão Lusófona</div>
<p class="desc">Portugal, Angola e Moçambique como mercados naturais. O schema já prevê <code>profiles.language</code> e <code>profiles.timezone</code> para internacionalização.</p>
</div>
<div class="visao-card">
<div class="icon">💚</div>
<div class="title">Impacto Social Mensurável</div>
<p class="desc">Contribuir para o aumento da qualidade e acessibilidade do cuidado em saúde mental no Brasil, com métricas públicas de impacto.</p>
</div>
</div>
<div style="margin-top: 3rem; text-align: center; padding: 2rem; border: 1px solid var(--linha); border-radius: 16px; background: var(--branco);">
<p style="font-style: italic; color: var(--cinza-medio); font-size: 0.9rem; margin: 0;">Este documento é vivo. Deve ser revisado e atualizado a cada fase concluída, incorporando os aprendizados do mercado, as decisões do time e as evoluções do schema de banco de dados.</p>
</div>
</section>
</main>
<!-- FOOTER -->
<footer class="footer">
<strong>Plataforma de Saúde Mental</strong> — Documento Estratégico Fundacional<br>
Versão 2.0 · 2025 · Uso interno restrito · PostgreSQL 17.6 · Supabase
</footer>
<script>
// Progress bar
window.addEventListener('scroll', () => {
const total = document.documentElement.scrollHeight - window.innerHeight;
const progress = (window.scrollY / total) * 100;
document.getElementById('progressBar').style.width = progress + '%';
});
// Nav toggle
const toggle = document.getElementById('navToggle');
const sidenav = document.getElementById('sidenav');
const overlay = document.getElementById('overlay');
toggle.addEventListener('click', () => {
sidenav.classList.toggle('open');
overlay.classList.toggle('show');
});
overlay.addEventListener('click', () => {
sidenav.classList.remove('open');
overlay.classList.remove('show');
});
sidenav.querySelectorAll('a').forEach(a => {
a.addEventListener('click', () => {
sidenav.classList.remove('open');
overlay.classList.remove('show');
});
});
// Intersection observer for chapters
const chapters = document.querySelectorAll('.chapter');
const obs = new IntersectionObserver((entries) => {
entries.forEach(e => {
if (e.isIntersecting) e.target.classList.add('visible');
});
}, { threshold: 0.05 });
chapters.forEach(c => obs.observe(c));
// Active nav link
const navLinks = document.querySelectorAll('.sidenav a');
const secObs = new IntersectionObserver((entries) => {
entries.forEach(e => {
if (e.isIntersecting) {
navLinks.forEach(a => a.classList.remove('active'));
const id = e.target.getAttribute('id');
const link = document.querySelector(`.sidenav a[href="#${id}"]`);
if (link) link.classList.add('active');
}
});
}, { threshold: 0.25 });
chapters.forEach(c => secObs.observe(c));
</script>
</body>
</html>