Flujo de Schema Branching
Como Git, pero para tu base de datos — branch → test → deploy request → merge
main
producción
→
add-budget-cols
branch dev
→
Deploy Request
review diff
→
Deploy
zero downtime
→
main updated
sin bloqueo
Paso 1–2 · CLI + Creación de Base de Datos
Instalación, autenticación y setup inicial en PlanetScale
# 1. Instalar CLI (macOS) $ brew install planetscale/tap/pscale # 2. Autenticar con tu cuenta PlanetScale $ pscale auth login → Abre navegador · autoriza acceso · vuelves al terminal # 3. Crear la base de datos para Cultiva Commerce $ pscale database create cultiva-commerce --region eu-west → Database "cultiva-commerce" created in region eu-west # 4. Conectar en local al branch main (proxy sin password) $ pscale connect cultiva-commerce main --port 3306 → Listening on 127.0.0.1:3306
Desarrollo local sin credenciales
Con
pscale connect activo, conecta tu app a localhost:3306 sin usuario ni contraseña. El CLI gestiona la autenticación por ti.Paso 3 · Branch de Esquema — add-budget-cols
Añadir budget_approved + approved_at + índice compuesto sin tocar main
Crear el branch y conectarse
# Crear branch de esquema (equivalente a git branch) $ pscale branch create cultiva-commerce add-budget-cols → Branch "add-budget-cols" created # Conectar al branch en otro puerto $ pscale connect cultiva-commerce add-budget-cols --port 3307 # Abrir shell SQL en el branch $ pscale shell cultiva-commerce add-budget-cols
Migraciones SQL en el branch (sin tocar producción)
-- Añadir columnas de aprobación de presupuesto a la tabla orders -- Se ejecuta en el branch add-budget-cols, NO en main ALTER TABLE orders ADD COLUMN budget_approved DECIMAL(12, 2) NULL COMMENT 'Presupuesto aprobado por el cliente', ADD COLUMN approved_at TIMESTAMP NULL COMMENT 'Fecha y hora de aprobación'; -- Índice compuesto para los reportes de la agencia ALTER TABLE orders ADD INDEX idx_client_status_created (client_id, status, created_at); -- Verificar los cambios en el branch DESCRIBE orders;
PlanetScale no soporta Foreign Keys
Vitess no permite FK constraints. Usa
relationMode = "prisma" en el schema de Prisma para que las relaciones se resuelvan en aplicación, no en la BD.Paso 4 · Deploy Request — Zero Downtime
Como un Pull Request para el esquema: revisa el diff y despliega sin bloquear tablas
# Crear deploy request (el "PR" del esquema) $ pscale deploy-request create cultiva-commerce add-budget-cols → Deploy request #7 created # Revisar el diff antes de desplegar $ pscale deploy-request diff cultiva-commerce 7 -- + ALTER TABLE orders ADD COLUMN budget_approved DECIMAL(12,2) NULL -- + ALTER TABLE orders ADD COLUMN approved_at TIMESTAMP NULL -- + ALTER TABLE orders ADD INDEX idx_client_status_created (...) # Desplegar sin downtime (PlanetScale usa gh-ost / online DDL) $ pscale deploy-request deploy cultiva-commerce 7 → Deploy request #7 deploying... done in 12s → 3,847,293 rows migrated with 0 table locks
vs. ALTER TABLE en RDS — de 45 min a 12 seg
PlanetScale aplica los cambios de esquema mediante online DDL (basado en gh-ost). La tabla
orders con 3.8M filas se migra en segundo plano sin bloquear lecturas ni escrituras.Paso 5 · Integración con Prisma ORM
Schema actualizado con las nuevas columnas y relationMode = "prisma"
generator client { provider = "prisma-client-js" } datasource db { provider = "mysql" url = env("DATABASE_URL") relationMode = "prisma" // ← Obligatorio: PS no soporta FK } model Order { id Int @id @default(autoincrement()) clientId Int @map("client_id") campaignId Int @map("campaign_id") amount Decimal @db.Decimal(10, 2) status String @default("pending") // ← Nuevas columnas añadidas en este sprint budgetApproved Decimal? @db.Decimal(12, 2) @map("budget_approved") approvedAt DateTime? @map("approved_at") client Client @relation(fields: [clientId], references: [id]) createdAt DateTime @default(now()) @map("created_at") @@index([clientId]) @@index([clientId, status, createdAt]) // índice compuesto reportes @@map("orders") } model Campaign { id Int @id @default(autoincrement()) name String budget Decimal @db.Decimal(12, 2) clientId Int @map("client_id") @@index([clientId]) @@map("campaigns") }
# Conectar al branch en :3309 y hacer push del schema Prisma $ pscale connect cultiva-commerce add-budget-cols --port 3309 & $ DATABASE_URL="mysql://root@localhost:3309/cultiva-commerce" \ npx prisma db push → Environment variables loaded from .env → ✔ Your database is now in sync with your Prisma schema.
Paso 6 · Driver HTTP para Vercel Edge Functions
@planetscale/database funciona en Edge Runtime sin TCP — ideal para Next.js App Router
import { connect } from "@planetscale/database" // HTTP-based driver: funciona en Edge const db = connect({ host: process.env.DATABASE_HOST, username: process.env.DATABASE_USERNAME, password: process.env.DATABASE_PASSWORD, }) export async function getOrdersByClient( clientId: number ) { const { rows } = await db.execute( `SELECT o.id, o.amount, o.status, o.budget_approved, o.approved_at, c.name AS campaign_name FROM orders o JOIN campaigns c ON c.id = o.campaign_id WHERE o.client_id = ? AND o.status IN ('pending','processing') ORDER BY o.created_at DESC LIMIT 50`, [clientId] ) return rows }
import { NextRequest, NextResponse } from "next/server" import { getOrdersByClient } from "@/lib/db" // Edge Runtime — requiere driver HTTP export const runtime = "edge" export async function GET( req: NextRequest ) { const clientId = Number( req.nextUrl.searchParams.get("clientId") ) const orders = await getOrdersByClient(clientId) return NextResponse.json({ orders }) }
Paso 7 · Variables de Entorno — Vercel + Local
Configuración de credenciales en todos los entornos
# Local: pscale connect en :3306 DATABASE_URL="mysql://root@127.0.0.1:3306/cultiva-commerce" # No necesitas host/user/pass localmente # pscale connect maneja la auth
# Desde PlanetScale console → Settings → Passwords DATABASE_HOST="aws.connect.psdb.cloud" DATABASE_USERNAME="cultiva-app-prod" DATABASE_PASSWORD="pscale_pw_xxx..." # Para Prisma (Node.js, no Edge) DATABASE_URL="mysql://cultiva-app-prod:pscale_pw_xxx@aws.connect.psdb.cloud/cultiva-commerce?sslaccept=strict"
Comparativa: RDS MySQL vs PlanetScale
Por qué Cultiva Commerce migra ahora
| Característica | RDS MySQL (actual) | PlanetScale |
|---|---|---|
| ALTER TABLE 3.8M filas | ~45 min con lock | ~12 seg, zero lock |
| Schema branching | No | Sí (tipo Git) |
| Deploy request (review diff) | No | Sí |
| Driver para Edge Runtime | No (TCP) | Sí (HTTP) |
| Connection pooling serverless | Manual (RDS Proxy) | Integrado |
| Foreign key constraints | Sí | No (usa relationMode) |
| Coste base | ~$180/mes (db.t3.medium) | $0 (hobby) / $39 (scaler) |
| Query insights | CloudWatch + lento | Integrado, en tiempo real |
Buenas Prácticas para Cultiva Commerce
8 reglas de oro para operar PlanetScale en producción
Branch siempre
Nunca modifiques
main directamente. Crea un branch, testa los cambios y usa deploy request.Sin FK → relationMode
Vitess no soporta FK constraints. Usa
relationMode = "prisma" para relaciones en capa de aplicación.HTTP driver en Edge
Usa
@planetscale/database para Vercel Edge / Cloudflare Workers. mysql2 solo para Node.js server.Índices antes de necesitarlos
Añade índices en columnas de filtros y sorts. Query Insights muestra qué queries los necesitan.
Review el diff
Antes de hacer deploy, revisa siempre el diff con
pscale deploy-request diff.Env vars separadas
Credenciales distintas por entorno (dev branch / staging / prod). Rota passwords periódicamente.