Sesión 1 · chuleta
En el orden de las slides. Copia con el botón de cada bloque; si la slide dice «teclea», esas líneas van a mano.
📋 S1·01 · clonar el repo y crear tu rama (terminal)
Sección titulada «📋 S1·01 · clonar el repo y crear tu rama (terminal)»git clone -b s1-start \ https://github.com/EmilioCarrion/academia-api-alumnos.git academia-apicd academia-apigit switch -c mi-trabajo📋 S1·02 · proyecto Node + dependencias (terminal)
Sección titulada «📋 S1·02 · proyecto Node + dependencias (terminal)»npm init -ynpm pkg set type=modulenpm i -D prisma@7 typescript tsx @types/nodenpm i @prisma/client@7 @prisma/adapter-pg pg dotenv📋 S1·03 · docker-compose.yml completo
Sección titulada «📋 S1·03 · docker-compose.yml completo»# docker-compose.yml (en la raíz del proyecto)services: db: image: postgres:16 restart: unless-stopped environment: POSTGRES_USER: academia POSTGRES_PASSWORD: academia POSTGRES_DB: academia ports: - "5432:5432" volumes: - academia_pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U academia"] interval: 5s timeout: 3s retries: 10
volumes: academia_pgdata:📋 S1·04 · levantar PostgreSQL con Docker (terminal)
Sección titulada «📋 S1·04 · levantar PostgreSQL con Docker (terminal)»docker compose up -ddocker compose ps# esperad a ver (healthy) en STATUS📋 S1·05 · plan B, Postgres de Prisma sin Docker (terminal)
Sección titulada «📋 S1·05 · plan B, Postgres de Prisma sin Docker (terminal)»npx prisma dev --name academia --detach📋 S1·06 · inicializar Prisma (terminal)
Sección titulada «📋 S1·06 · inicializar Prisma (terminal)»npx prisma init --datasource-provider postgresql📋 S1·07 · borrar las skills que deja prisma init (terminal)
Sección titulada «📋 S1·07 · borrar las skills que deja prisma init (terminal)»rm -rf .claude .agents .windsurf skills-lock.json📋 S1·08 · .env y .env.example
Sección titulada «📋 S1·08 · .env y .env.example»# .env (y el mismo contenido en .env.example)DATABASE_URL="postgresql://academia:academia@localhost:5432/academia"📋 S1·09 · líneas mínimas del .gitignore
Sección titulada «📋 S1·09 · líneas mínimas del .gitignore»# .gitignore (al menos estas líneas)node_modules.env/generated/prisma📋 S1·10 · comprobar y hacer el primer commit (terminal)
Sección titulada «📋 S1·10 · comprobar y hacer el primer commit (terminal)»cat .gitignoregit add .git status # ni .env ni .claude/ deben aparecergit commit -m "Setup inicial: Postgres + Prisma 7"📋 S1·11 · tsconfig.json completo
Sección titulada «📋 S1·11 · tsconfig.json completo»// tsconfig.json (en la raíz del proyecto){ "compilerOptions": { "target": "ES2023", "module": "NodeNext", "moduleResolution": "NodeNext", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "verbatimModuleSyntax": true, "noEmit": true, "types": ["node"] }, "include": ["src", "prisma7.config.ts"]}📋 S1·12 · script typecheck en package.json (terminal)
Sección titulada «📋 S1·12 · script typecheck en package.json (terminal)»npm pkg set scripts.typecheck="tsc --noEmit"📋 S1·13 · enums Role y Level (prisma/schema.prisma)
Sección titulada «📋 S1·13 · enums Role y Level (prisma/schema.prisma)»// prisma/schema.prisma (añade al final, debajo de los modelos)enum Role { STUDENT INSTRUCTOR ADMIN}
enum Level { BEGINNER INTERMEDIATE ADVANCED}📋 S1·14 · primera migración y cliente (terminal)
Sección titulada «📋 S1·14 · primera migración y cliente (terminal)»npx prisma migrate dev --name initnpx prisma generate📋 S1·15 · commit de los modelos (terminal)
Sección titulada «📋 S1·15 · commit de los modelos (terminal)»git add . && git commit -m "Modelos User y Course"📋 S1·16 · código de la IA para revisar (src/crud.ia.ts)
Sección titulada «📋 S1·16 · código de la IA para revisar (src/crud.ia.ts)»// ─────────────────────────────────────────────────────────────────────────// Generado por un asistente de IA · Sesión 1// Prompt: "Escríbeme un script con Prisma que haga create, read, update y// delete de un usuario en mi proyecto AcademIA"// Tu tarea: revísalo con la checklist ANTES de ejecutarlo. ¿Lo aceptarías?// ─────────────────────────────────────────────────────────────────────────import { PrismaClient } from '@prisma/client';
async function createUser(email: string, name: string) { const prisma = new PrismaClient(); return prisma.user.create({ data: { email, name, password: 'ana1234', role: 'INSTRUCTOR' }, });}
async function getUser(email: string) { const prisma = new PrismaClient(); return prisma.user.findFirst({ where: { email } });}
async function renameUser(id: number, name: string) { const prisma = new PrismaClient(); try { return await prisma.user.update({ where: { id }, data: { name } }); } catch (e) { console.log('Error'); }}
async function deleteUser(id: number) { const prisma = new PrismaClient(); await prisma.user.delete({ where: { id } });}
const user = await createUser('ana@academia.dev', 'Ana');console.log(await getUser(user.email));await renameUser(user.id, 'Ana García');await deleteUser(user.id);📋 S1·17 · ejecutar el código de la IA (terminal)
Sección titulada «📋 S1·17 · ejecutar el código de la IA (terminal)»npx tsx src/crud.ia.ts📋 S1·18 · src/db.ts completo
Sección titulada «📋 S1·18 · src/db.ts completo»import 'dotenv/config';import { PrismaPg } from '@prisma/adapter-pg';import { PrismaClient } from '../generated/prisma/client.js';
// Una sola instancia para toda la aplicación (no una por request).const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL,});
export const prisma = new PrismaClient({ adapter });📋 S1·19 · esqueleto de src/crud.ts (las llamadas ✍️ las escribes tú)
Sección titulada «📋 S1·19 · esqueleto de src/crud.ts (las llamadas ✍️ las escribes tú)»// src/crud.ts · Ejecutar: npx tsx src/crud.ts// Esqueleto: escribe tú cada línea marcada ✍️ (el código completo está en las slides y justo debajo).import { prisma } from './db.js';
async function main() { // Create ✍️ const user = await prisma.user.create({ data: { … } }); // email `ana+${Date.now()}@academia.dev` (único en cada ejecución), name 'Ana', // password 'hashed-password-placeholder' (sesión 4: Argon2id), role 'INSTRUCTOR'
console.log('create →', user);
// Read ✍️ const found = … findUnique por email (user.email) // ✍️ const instructors = … findMany con where role 'INSTRUCTOR'
console.log('findUnique →', found?.name, '| instructores:', instructors.length);
// Si no existe → null (no excepción) ✍️ const maybeUser = … findUnique con id 999_999
console.log('id inexistente →', maybeUser);
// Update ✍️ const updated = … update por user.id, name 'Ana García'
console.log('update →', updated.name);
// Count console.log('total usuarios →', await prisma.user.count());
// Delete ✍️ … delete por user.id
console.log('delete → ok');}
main().finally(() => prisma.$disconnect());📋 S1·20 · ejecutar el CRUD, limpiar y commit (terminal)
Sección titulada «📋 S1·20 · ejecutar el CRUD, limpiar y commit (terminal)»npx tsx src/crud.tsrm src/crud.ia.ts # no se commitea: rompería el typecheckgit add . && git commit -m "Cliente Prisma y CRUD"📋 S1·21 · receta «Cambiar de rama» al checkpoint (terminal, rescate)
Sección titulada «📋 S1·21 · receta «Cambiar de rama» al checkpoint (terminal, rescate)»git add -A && git commit -m "wip: mi trabajo" # guarda lo tuyo (si hay algo)git fetch origingit switch -c mi-s1-cp origin/s1-checkpointnpm installnpx prisma generatenpx prisma migrate dev # desde tu rama pedirá reset (esperado): npx prisma migrate reset y npm run seed📋 S1·22 · migración de la práctica y cliente (terminal)
Sección titulada «📋 S1·22 · migración de la práctica y cliente (terminal)»npx prisma migrate dev --name add_category_and_publishednpx prisma generate📋 S1·23 · script seed y ejecutarlo dos veces (terminal)
Sección titulada «📋 S1·23 · script seed y ejecutarlo dos veces (terminal)»npm pkg set scripts.seed="tsx src/seed-manual.ts" # una veznpm run seed && npm run seed📋 S1·25 · receta «Cambiar de rama» para la sesión 2 (terminal, rescate)
Sección titulada «📋 S1·25 · receta «Cambiar de rama» para la sesión 2 (terminal, rescate)»git add -A && git commit -m "wip: mi trabajo" # guarda lo tuyo (si hay algo)git fetch origingit switch -c mi-s2 origin/s2-start # o: git switch -c mi-s2-cp origin/s2-checkpointnpm installnpx prisma generatenpx prisma migrate dev # desde tu rama pedirá reset (esperado): npx prisma migrate reset y npm run seed