1800 lines
120 KiB
HTML
1800 lines
120 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="pt-BR">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>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 (0–100)</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 (1–120 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 <= 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: 1–120 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 1–3</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 10–20 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 4–8</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: 3–5 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 9–18</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>1–2</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>3–4</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>1–2</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>3–4</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>1–2</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>3–4</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 10–20 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 10–20 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>
|