Phase 2: Database e API Layer

- Configurado Prisma 7 com multiSchema para staging database
- Models: Site, GA4DailyTraffic, GA4TrafficSources, GSCSearchPerformance
- Created lib utilities (prisma.ts, utils.ts) com formatação PT-PT
- API routes implementadas:
  * GET /api/sites - lista sites activos
  * GET /api/metrics/[siteId]?period=30d - métricas agregadas + charts
  * GET /api/health - health check com conexão DB

Métricas incluem:
- KPIs: visitors, sessions, pageViews, newUsers com % change
- Charts: dailyTraffic, trafficSources, topQueries (GSC)
- Comparação período anterior para trends

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 17:56:56 +00:00
parent 01353cef36
commit b99baa1200
7 changed files with 435 additions and 0 deletions

9
prisma/prisma.config.ts Normal file
View File

@@ -0,0 +1,9 @@
import { defineConfig } from '@prisma/client/generator-helper'
export default defineConfig({
datasources: {
db: {
url: process.env.DATABASE_URL!,
},
},
})

84
prisma/schema.prisma Normal file
View File

@@ -0,0 +1,84 @@
// Prisma schema for BI Descomplicar
// Maps to existing PostgreSQL staging database
datasource db {
provider = "postgresql"
schemas = ["staging"]
}
generator client {
provider = "prisma-client-js"
previewFeatures = ["multiSchema"]
}
// Sites configuration
model Site {
id Int @id @default(autoincrement())
siteName String @map("site_name")
ga4PropertyId String? @map("ga4_property_id")
gscSiteUrl String? @map("gsc_site_url")
deskProjectId Int? @map("desk_project_id")
deskClientId Int? @map("desk_client_id")
active Boolean @default(true)
@@map("sites_config")
@@schema("staging")
}
// GA4 Daily Traffic
model GA4DailyTraffic {
id Int @id @default(autoincrement())
propertyId String @map("property_id")
siteName String? @map("site_name")
date DateTime @db.Date
pagePath String? @map("page_path")
activeUsers Int @default(0) @map("active_users")
sessions Int @default(0)
pageViews Int @default(0) @map("page_views")
engagementRate Decimal @default(0) @map("engagement_rate") @db.Decimal(5, 4)
avgSessionDuration Decimal @default(0) @map("avg_session_duration") @db.Decimal(10, 2)
bounceRate Decimal @default(0) @map("bounce_rate") @db.Decimal(5, 4)
newUsers Int @default(0) @map("new_users")
createdAt DateTime @default(now()) @map("created_at")
@@unique([propertyId, date, pagePath])
@@map("ga4_daily_traffic")
@@schema("staging")
}
// GA4 Traffic Sources
model GA4TrafficSources {
id Int @id @default(autoincrement())
propertyId String @map("property_id")
siteName String? @map("site_name")
date DateTime @db.Date
sessionSource String? @map("session_source")
sessionMedium String? @map("session_medium")
sessionCampaign String? @map("session_campaign")
sessions Int @default(0)
newUsers Int @default(0) @map("new_users")
engagedSessions Int @default(0) @map("engaged_sessions")
createdAt DateTime @default(now()) @map("created_at")
@@unique([propertyId, date, sessionSource, sessionMedium])
@@map("ga4_traffic_sources")
@@schema("staging")
}
// GSC Search Performance
model GSCSearchPerformance {
id Int @id @default(autoincrement())
siteUrl String @map("site_url")
date DateTime @db.Date
query String
page String?
clicks Int @default(0)
impressions Int @default(0)
ctr Decimal @default(0) @db.Decimal(5, 4)
position Decimal @default(0) @db.Decimal(6, 2)
createdAt DateTime @default(now()) @map("created_at")
@@unique([siteUrl, date, query, page])
@@map("gsc_search_performance")
@@schema("staging")
}