feat: Fase 1 - Autenticação completa

- Prisma com SQLite configurado
- Tabelas: users, sessions, subscriptions, children, etc
- Auth.js com credentials provider
- API de registro com criação de usuário + criança
- Middleware para proteger rotas
- Login/Cadastro funcionais
- Dashboard com sessão real
This commit is contained in:
2026-02-07 00:21:04 -03:00
parent f5a2f4870f
commit e12cfbe91c
27 changed files with 3786 additions and 95 deletions

BIN
prisma/dev.db Normal file

Binary file not shown.

View File

@@ -0,0 +1,158 @@
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL PRIMARY KEY,
"email" TEXT NOT NULL,
"password" TEXT NOT NULL,
"name" TEXT NOT NULL,
"phone" TEXT,
"city" TEXT,
"state" TEXT,
"role" TEXT NOT NULL DEFAULT 'parent',
"emailVerified" DATETIME,
"image" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "Account" (
"id" TEXT NOT NULL PRIMARY KEY,
"userId" TEXT NOT NULL,
"type" TEXT NOT NULL,
"provider" TEXT NOT NULL,
"providerAccountId" TEXT NOT NULL,
"refresh_token" TEXT,
"access_token" TEXT,
"expires_at" INTEGER,
"token_type" TEXT,
"scope" TEXT,
"id_token" TEXT,
"session_state" TEXT,
CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "Session" (
"id" TEXT NOT NULL PRIMARY KEY,
"sessionToken" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"expires" DATETIME NOT NULL,
CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "VerificationToken" (
"identifier" TEXT NOT NULL,
"token" TEXT NOT NULL,
"expires" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "Subscription" (
"id" TEXT NOT NULL PRIMARY KEY,
"userId" TEXT NOT NULL,
"plan" TEXT NOT NULL,
"status" TEXT NOT NULL DEFAULT 'pending',
"stripeCustomerId" TEXT,
"stripeSubId" TEXT,
"currentPeriodEnd" DATETIME,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Subscription_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "Child" (
"id" TEXT NOT NULL PRIMARY KEY,
"parentId" TEXT NOT NULL,
"name" TEXT NOT NULL,
"birthDate" DATETIME NOT NULL,
"diagnosis" TEXT NOT NULL,
"diagnosisDate" TEXT,
"currentTherapies" TEXT,
"priorities" TEXT,
"challenges" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Child_parentId_fkey" FOREIGN KEY ("parentId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "TherapistPatient" (
"id" TEXT NOT NULL PRIMARY KEY,
"therapistId" TEXT NOT NULL,
"patientId" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "TherapistPatient_therapistId_fkey" FOREIGN KEY ("therapistId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "TherapistPatient_patientId_fkey" FOREIGN KEY ("patientId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "Appointment" (
"id" TEXT NOT NULL PRIMARY KEY,
"childId" TEXT NOT NULL,
"therapistId" TEXT NOT NULL,
"scheduledAt" DATETIME NOT NULL,
"duration" INTEGER NOT NULL DEFAULT 50,
"status" TEXT NOT NULL DEFAULT 'scheduled',
"roomUrl" TEXT,
"roomName" TEXT,
"notes" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Appointment_childId_fkey" FOREIGN KEY ("childId") REFERENCES "Child" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "Appointment_therapistId_fkey" FOREIGN KEY ("therapistId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "SessionNote" (
"id" TEXT NOT NULL PRIMARY KEY,
"appointmentId" TEXT NOT NULL,
"childId" TEXT NOT NULL,
"therapistId" TEXT NOT NULL,
"content" TEXT NOT NULL,
"objectives" TEXT,
"progress" TEXT,
"nextSteps" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "SessionNote_appointmentId_fkey" FOREIGN KEY ("appointmentId") REFERENCES "Appointment" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "SessionNote_childId_fkey" FOREIGN KEY ("childId") REFERENCES "Child" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "SessionNote_therapistId_fkey" FOREIGN KEY ("therapistId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "Progress" (
"id" TEXT NOT NULL PRIMARY KEY,
"childId" TEXT NOT NULL,
"category" TEXT NOT NULL,
"value" INTEGER NOT NULL,
"notes" TEXT,
"date" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "Progress_childId_fkey" FOREIGN KEY ("childId") REFERENCES "Child" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
-- CreateIndex
CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId");
-- CreateIndex
CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");
-- CreateIndex
CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token");
-- CreateIndex
CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token");
-- CreateIndex
CREATE UNIQUE INDEX "Subscription_userId_key" ON "Subscription"("userId");
-- CreateIndex
CREATE UNIQUE INDEX "TherapistPatient_therapistId_patientId_key" ON "TherapistPatient"("therapistId", "patientId");
-- CreateIndex
CREATE UNIQUE INDEX "SessionNote_appointmentId_key" ON "SessionNote"("appointmentId");

View File

@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "sqlite"

179
prisma/schema.prisma Normal file
View File

@@ -0,0 +1,179 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
// ============ AUTENTICAÇÃO ============
model User {
id String @id @default(cuid())
email String @unique
password String
name String
phone String?
city String?
state String?
role String @default("parent") // parent, therapist, admin
emailVerified DateTime?
image String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relações
accounts Account[]
sessions Session[]
subscription Subscription?
children Child[]
// Para terapeutas
patients TherapistPatient[] @relation("TherapistPatients")
assignedTo TherapistPatient[] @relation("PatientAssignments")
appointments Appointment[] @relation("TherapistAppointments")
sessionsNotes SessionNote[]
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}
// ============ PAGAMENTOS ============
model Subscription {
id String @id @default(cuid())
userId String @unique
plan String // essencial, completo, intensivo
status String @default("pending") // pending, active, cancelled, expired
stripeCustomerId String?
stripeSubId String?
currentPeriodEnd DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
// ============ CRIANÇAS ============
model Child {
id String @id @default(cuid())
parentId String
name String
birthDate DateTime
diagnosis String
diagnosisDate String?
currentTherapies String? // JSON array
priorities String? // JSON array
challenges String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
parent User @relation(fields: [parentId], references: [id], onDelete: Cascade)
progress Progress[]
appointments Appointment[]
sessionNotes SessionNote[]
}
// ============ TERAPEUTAS ============
model TherapistPatient {
id String @id @default(cuid())
therapistId String
patientId String
createdAt DateTime @default(now())
therapist User @relation("TherapistPatients", fields: [therapistId], references: [id])
patient User @relation("PatientAssignments", fields: [patientId], references: [id])
@@unique([therapistId, patientId])
}
// ============ AGENDAMENTOS ============
model Appointment {
id String @id @default(cuid())
childId String
therapistId String
scheduledAt DateTime
duration Int @default(50) // minutos
status String @default("scheduled") // scheduled, completed, cancelled, no-show
roomUrl String? // URL Daily.co
roomName String?
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
child Child @relation(fields: [childId], references: [id])
therapist User @relation("TherapistAppointments", fields: [therapistId], references: [id])
sessionNote SessionNote?
}
// ============ NOTAS DE SESSÃO ============
model SessionNote {
id String @id @default(cuid())
appointmentId String @unique
childId String
therapistId String
content String // Markdown ou texto
objectives String? // JSON array
progress String? // JSON object com métricas
nextSteps String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
appointment Appointment @relation(fields: [appointmentId], references: [id])
child Child @relation(fields: [childId], references: [id])
therapist User @relation(fields: [therapistId], references: [id])
}
// ============ PROGRESSO ============
model Progress {
id String @id @default(cuid())
childId String
category String // comunicacao, habilidades_sociais, autonomia, regulacao_emocional
value Int // 0-100
notes String?
date DateTime @default(now())
createdAt DateTime @default(now())
child Child @relation(fields: [childId], references: [id])
}