Skip to content

feat(database): expand schema with complete recruitment system (db_hso)#14

Open
Helysalgado wants to merge 5 commits intoLIDR-academy:mainfrom
Helysalgado:db-hso
Open

feat(database): expand schema with complete recruitment system (db_hso)#14
Helysalgado wants to merge 5 commits intoLIDR-academy:mainfrom
Helysalgado:db-hso

Conversation

@Helysalgado
Copy link

@Helysalgado Helysalgado commented Nov 18, 2025

🎯 Objetivo

Expandir la base de datos del sistema LTI de un gestor básico de candidatos (4 modelos) a un sistema completo de reclutamiento end-to-end.

📊 Resumen de Cambios

Antes

  • ✅ 4 modelos: Candidate, Education, WorkExperience, Resume
  • ✅ Funcionalidad: Solo gestión de perfiles de candidatos

Después

  • 12 modelos (4 existentes + 8 nuevos)
  • Sistema completo: Empresas → Posiciones → Aplicaciones → Entrevistas
  • 5 ENUMs para estados y tipos
  • 26 índices estratégicos para performance
  • 16 Foreign Keys con integridad referencial

🆕 Nuevos Modelos

  1. Company - Empresas que utilizan el sistema
  2. Employee - Empleados/reclutadores de las empresas
  3. Position - Posiciones/vacantes publicadas
  4. InterviewFlow - Flujos de entrevista configurables
  5. InterviewStep - Pasos dentro de un flujo de entrevista
  6. InterviewType - Catálogo de tipos de entrevista (técnica, cultural, HR)
  7. Application - Aplicaciones de candidatos a posiciones
  8. Interview - Entrevistas individuales con resultados y scoring

🎨 ENUMs Creados

  • PositionStatus: DRAFT | OPEN | CLOSED | ON_HOLD
  • EmploymentType: FULL_TIME | PART_TIME | CONTRACT | TEMPORARY | INTERNSHIP
  • ApplicationStatus: PENDING | REVIEWING | INTERVIEWED | ACCEPTED | REJECTED | WITHDRAWN
  • InterviewResult: PENDING | PASSED | FAILED | NO_SHOW
  • EmployeeRole: RECRUITER | HIRING_MANAGER | INTERVIEWER | ADMIN

🏗️ Buenas Prácticas Aplicadas

Normalización

  • 3FN completa - Sin redundancia de datos
  • ✅ Separación correcta de concerns
  • ✅ Relaciones claras y bien definidas

Performance

  • 26 índices estratégicos:
    • 13 índices en Foreign Keys
    • 12 índices en campos de búsqueda
    • 4 UNIQUE constraints
  • ✅ Tipos de datos apropiados (Decimal para salarios, ENUM para estados)

Integridad Referencial

  • CASCADE (9 relaciones): Para composición (hijo no existe sin padre)
  • RESTRICT (7 relaciones): Para mantener histórico de datos valiosos

Decisiones de Diseño Destacadas

  • ✅ Timestamps solo en entidades principales (evita redundancia)
  • Application con UNIQUE (positionId, candidateId) - Un candidato aplica una sola vez por posición
  • InterviewStep con UNIQUE (interviewFlowId, orderIndex) - Orden correcto garantizado
  • ✅ Separación de InterviewFlow y InterviewStep para máxima flexibilidad

📁 Archivos Modificados/Creados

Core (Requeridos)

  • backend/prisma/schema.prisma - 243 líneas, 12 modelos
  • backend/prisma/migrations/20251117233207_db_hso/migration.sql - 298 líneas SQL
  • prompts/prompts-hso.md - Documentación completa del proceso

Documentación Extra (Valor Agregado)

  • backend/docs/database-dictionary.md - 702 líneas, diccionario profesional
  • backend/docs/er-diagram.md - 554 líneas, diagramas Mermaid completos
  • backend/prisma/seed-test-data.sql - 17 registros de prueba realistas
  • backend/prisma/validation-queries.sql - 10 queries de validación con EXPLAIN ANALYZE

Total: ~2,800 líneas de código y documentación


🧪 Testing/Validación

Migración

  • ✅ Migración ejecutada exitosamente: 20251117233207_db_hso
  • ✅ Base de datos sincronizada sin errores
  • ✅ 12 tablas creadas
  • ✅ 5 ENUMs creados
  • ✅ Todos los índices y constraints aplicados

Datos de Prueba

  • ✅ 17 registros insertados correctamente
  • ✅ Flujo completo probado: Company → Employee → Position → Candidate → Application → Interview

Queries Validadas

  • ✅ Búsquedas usando índices (UNIQUE, FK, campos de búsqueda)
  • ✅ JOINs múltiples funcionando correctamente
  • ✅ Integridad referencial validada (0 registros huérfanos)
  • ✅ Constraints UNIQUE funcionando (0 duplicados)

Query de prueba ejecutada:

SELECT 
    c."firstName" || ' ' || c."lastName" as candidate,
    p.title as position,
    a.status,
    i.result,
    i.score,
    e.name as interviewer
FROM "Application" a
JOIN "Candidate" c ON a."candidateId" = c.id
JOIN "Position" p ON a."positionId" = p.id
LEFT JOIN "Interview" i ON a.id = i."applicationId"
LEFT JOIN "Employee" e ON i."employeeId" = e.id;

Resultado: ✅ Juan Pérez → Desarrollador Full Stack Senior → REVIEWING → PASSED (85 pts) → María García


📚 Documentación

Diccionario de Datos (database-dictionary.md)

  • Descripción detallada de las 12 tablas
  • Todos los campos con tipos, constraints y justificaciones
  • Matriz de relaciones completa
  • Estrategia de índices explicada
  • Decisiones de diseño documentadas

Diagrama ER (er-diagram.md)

  • Diagrama completo en formato Mermaid
  • Diagramas por módulos (Candidatos, Empresas, Entrevistas, Proceso)
  • Documentación de cardinalidad y políticas onDelete
  • Queries de ejemplo y métricas

Proceso Completo (prompts-hso.md)

  • Todos los 11 pasos del ejercicio documentados
  • Prompts utilizados con contexto
  • Buenas prácticas aplicadas explicadas
  • Decisiones de diseño justificadas
  • Aprendizajes del proceso

🎯 Checklist de QA

  • Schema Prisma válido sin errores de sintaxis
  • Migración ejecutada exitosamente
  • Base de datos sincronizada
  • Datos de prueba insertados correctamente
  • Queries de validación ejecutadas exitosamente
  • Normalización 3FN verificada
  • Índices en todas las Foreign Keys
  • Índices en campos de búsqueda frecuente
  • Constraints UNIQUE donde corresponde
  • onDelete apropiado (CASCADE vs RESTRICT)
  • Tipos de datos correctos
  • ENUMs bien definidos
  • Documentación completa
  • Diagramas ER creados
  • Cliente Prisma generado sin errores

🔄 Cambios Breaking

⚠️ Atención: Esta migración requiere reset de la base de datos si hay datos previos.

Razón: Modificaciones en modelos existentes (agregado de índices, onDelete, timestamps en Candidate)

Acción requerida:

npx prisma migrate reset --force
npx prisma migrate dev

🚀 Próximos Pasos (Post-Merge)

Inmediato

  1. Generar cliente Prisma: npx prisma generate
  2. Actualizar servicios TypeScript para usar nuevos modelos
  3. Crear endpoints REST para nuevas entidades

Corto Plazo

  1. Implementar autenticación (modelo User)
  2. CRUD completo para Position y Application
  3. Dashboard de reclutador con métricas

Mediano Plazo

  1. Sistema de notificaciones
  2. Roles y permisos granulares
  3. Analytics y reportes avanzados

🤝 Revisores

Por favor validar:

  • ✅ Normalización de la base de datos
  • ✅ Estrategia de índices
  • ✅ Políticas onDelete (CASCADE vs RESTRICT)
  • ✅ Naming conventions
  • ✅ Documentación completa

📖 Referencias

  • Plan seguido: backend/docs/prompts-cursor-db-plan-hso_bp.md
  • Diccionario de datos: backend/docs/database-dictionary.md
  • Diagramas ER: backend/docs/er-diagram.md
  • Proceso completo: prompts/prompts-hso.md
  • Migración SQL: backend/prisma/migrations/20251117233207_db_hso/migration.sql

🏷️ Labels Sugeridos

  • feature - Nueva funcionalidad
  • database - Cambios en base de datos
  • breaking-change - Requiere reset de BD
  • documentation - Incluye docs extensas

Desarrollado en rama: db-hso
Modelo de IA: Claude Sonnet 4.5
IDE: Cursor
Ejercicio: AI4Devs - Módulo de Bases de Datos

Summary by CodeRabbit

  • New Features

    • Enabled recruitment system supporting companies, positions, job applications, and interview management workflow.
    • Enhanced candidate records with creation and update timestamps.
  • Documentation

    • Added comprehensive database schema documentation including data dictionary, entity relationship diagrams, and design rationale.
  • Chores

    • Database migration implementing expanded schema structure.
    • Added test data and validation queries for system integrity.

@coderabbitai
Copy link

coderabbitai bot commented Nov 18, 2025

Walkthrough

This PR introduces a comprehensive recruitment system database schema with 12 new tables (Company, Employee, Position, Application, Interview, InterviewType, InterviewFlow, InterviewStep), five ENUMs, extensive relationships with cascade delete rules, supporting Prisma models, SQL migration, seed test data, validation queries, and detailed schema documentation.

Changes

Cohort / File(s) Summary
Database Documentation
backend/docs/database-dictionary.md, backend/docs/er-diagram.md, prompts/prompts-hso.md
Comprehensive Markdown guides documenting the PostgreSQL Prisma schema, including entity definitions, relationships, cardinalities, constraints, design decisions (normalization, cascading rules, ENUM usage), ER diagrams in Mermaid format, indexing strategy, optimized queries, and exercise workflow/learnings.
Schema & Migration
backend/prisma/schema.prisma, backend/prisma/migrations/20251117233207_db_hso/migration.sql, backend/prisma/migrations/migration_lock.toml
Prisma schema expansion adding 5 ENUMs (PositionStatus, EmploymentType, ApplicationStatus, InterviewResult, EmployeeRole) and 8 new models (Company, Employee, Position, Application, Interview, InterviewFlow, InterviewStep, InterviewType) with relationships, indexes, unique constraints, and cascade/restrict delete rules. SQL migration creates all 12 tables with constraints and indices. Minor comment update to migration_lock.toml.
Test Data & Validation
backend/prisma/seed-test-data.sql, backend/prisma/validation-queries.sql
Test data seeding script populating all 12 tables with realistic recruitment data and sequence resets. Validation script with 10 EXPLAIN ANALYZE queries covering index usage, joins, referential integrity, unique constraints, aggregations, and interview flows.
Planning & Workflow
backend/docs/prompts-cursor-db-plan-hso_bp.md
Detailed workflow guide for schema analysis, ERD-to-SQL conversion, Prisma model generation, migration quality validation, test data generation, and PR artifact generation with role-based prompts and templates.

Sequence Diagram(s)

sequenceDiagram
    actor Candidate
    participant App as Application
    participant Position
    participant Interview
    participant Employee
    participant Result

    Candidate->>App: Submits Application
    App->>Position: References Position
    activate Position
    Position-->>App: Returns InterviewFlow
    deactivate Position

    App->>Interview: Creates Interview Records<br/>(per InterviewStep)
    activate Interview
    Interview->>Employee: Assigns to Employee
    Employee-->>Interview: Confirms Assignment
    Interview->>Result: Records Result & Score
    Result-->>Interview: Stores in DB
    deactivate Interview

    Interview-->>App: Updates Application Status
    activate App
    App-->>Candidate: Notifies Outcome
    deactivate App
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

  • Migration integrity: Review foreign key constraints, cascade/restrict delete policies on Education/WorkExperience/Resume/Application/Interview to ensure referential integrity and no unintended data loss.
  • Unique constraints: Verify unique constraints on (positionId, candidateId) in Application and email fields prevent duplicates and enforce business rules.
  • Index strategy: Validate index coverage across common queries—particularly on Position.status, Employee.companyId, Application.candidateId—to ensure performance.
  • Cascade delete implications: Confirm that cascading deletes on Candidate→Education/WorkExperience/Resume/Application are intentional and won't cause data loss in production.
  • Schema completeness: Ensure all new ENUMs and models match documented design decisions and requirements in the database dictionary.

Poem

🐰 A schema blooms with twelve new tables strong,
Candidates, positions, interviews long—
Cascades and constraints in harmony dance,
Recruitment flows find their second chance!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: expanding the database schema from a basic candidate manager to a complete recruitment system with 12 models, 5 ENUMs, and comprehensive relationships.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (6)
backend/prisma/validation-queries.sql (4)

19-33: Query 1 (email index): Correct but consider FILTER alternative.

The EXPLAIN ANALYZE and LEFT JOIN pattern for counting applications is sound. However, using a FILTER clause on COUNT would be more idiomatic PostgreSQL:

-COUNT(a.id) as total_applications
+COUNT(a.id) FILTER (WHERE a.id IS NOT NULL) as total_applications

This is a minor style improvement; current form is correct.


74-114: Query 3: Verify PostgreSQL version for json_agg(DISTINCT ...) compatibility.

The query uses json_agg(DISTINCT ...) to build JSON objects from multi-joined rows. This syntax requires PostgreSQL 9.4+ but has subtle behavior: DISTINCT on complex objects (like JSONB) may not work as expected in all versions or may be inefficient.

Consider as a safer alternative using window functions or subqueries to deduplicate before aggregation, especially if portability across PostgreSQL versions is a concern:

-- Example: Subquery approach for Education
WITH candidate_education AS (
  SELECT DISTINCT ON (e.id) 
    c.id as candidate_id,
    jsonb_build_object(...) as edu_obj
  FROM ...
)
SELECT 
  ...,
  json_agg(edu_obj) as education
FROM ...

If your target is PostgreSQL 14+, the current form is acceptable.


227-278: Query 6: Foreign key integrity checks are comprehensive but incomplete.

The orphan detection for Education, WorkExperience, Application, and Interview is thorough. However, two potential gaps:

  1. Resume table: The PR summary mentions Resume but no orphan check exists for it. Verify this is intentional (e.g., if Resume is a document reference with different lifecycle).
  2. InterviewFlow and InterviewType: Not validated for orphaned records (though Position.interviewFlowId is a FK, InterviewFlow records themselves could be unused).

Consider adding:

-- InterviewFlow without Position reference
SELECT 'InterviewFlow sin Position', COUNT(*)
FROM "InterviewFlow" intf
WHERE NOT EXISTS (SELECT 1 FROM "Position" p WHERE p."interviewFlowId" = intf.id)

UNION ALL

-- InterviewType without InterviewStep reference
SELECT 'InterviewType sin uso', COUNT(*)
FROM "InterviewType" it
WHERE NOT EXISTS (SELECT 1 FROM "InterviewStep" ist WHERE ist."interviewTypeId" = it.id)

437-450: Validation summary is well-documented.

The checklist clearly articulates what each query validates. Consider augmenting with:

  • PostgreSQL version requirement (e.g., "PostgreSQL 12.x+")
  • Expected execution time ranges (ms) for each EXPLAIN ANALYZE query
  • Example seed data row counts (e.g., "Assumes ~100 candidates, ~50 positions, ~20 applications" from seed-test-data.sql)

These additions would help developers understand when performance regressions occur.

backend/docs/prompts-cursor-db-plan-hso_bp.md (1)

17-119: Add language specifications to all fenced code blocks.

Markdown linting (MD040) requires language identifiers for code blocks. This improves readability and enables syntax highlighting. Apply the following language tags:

  • Lines with SQL statements → sql
  • Lines with Prisma schema → prisma
  • Lines with bash commands → bash
  • Lines with TypeScript code → typescript

For example:

- ```
+ ```bash
  git checkout -b db-hso


This will ensure compliance with markdown standards and improve code visibility for readers using markdown renderers.



Also applies to: 134-146, 162-173, 186-199, 214-223, 230-232, 247-254, 266-276, 285-292, 304-310, 323-330

</blockquote></details>
<details>
<summary>prompts/prompts-hso.md (1)</summary><blockquote>

`47-49`: **Add language specifications to all fenced code blocks.**

All code blocks throughout this file lack language identifiers (bash, sql, prisma, typescript), which triggers MD040 linting errors and reduces syntax highlighting. Apply consistent language tags to:
- Bash commands → `bash`
- SQL queries → `sql`
- Prisma schema → `prisma`
- TypeScript code → `typescript`





Also applies to: 61-68, 94-104, 128-136, 167-176, 192-195, 212-226, 248-250, 256-261, 265-271, 276-291, 294-300, 305-310, 316-320, 323-328, 332-337, 343-352

</blockquote></details>

</blockquote></details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant