# ============================================================================= # ENVIRONMENT-INVENTORY.yml - CLINICA-DENTAL # ============================================================================= # Inventario Completo de Entorno de Desarrollo y Produccion # Generado por: @PERFIL_DEVENV # Basado en: orchestration/templates/TEMPLATE-ENVIRONMENT-INVENTORY.yml # ============================================================================= version: "1.1.0" fecha_creacion: "2026-01-04" fecha_actualizacion: "2026-01-04" responsable: "@PERFIL_DEVENV" # ----------------------------------------------------------------------------- # IDENTIFICACION DEL PROYECTO # ----------------------------------------------------------------------------- proyecto: nombre: "Clinica Dental" alias: "clinica-dental" codigo: "CD" nivel: "NIVEL_2B.3" tipo: "vertical-especializada" estado: "desarrollo" descripcion: "Sistema de gestion para clinicas dentales y odontologicas" parent: "erp-clinicas" herencia: - erp-core - erp-clinicas normativas: - "NOM-024-SSA3-2012 (Expediente clinico electronico)" - "NOM-013-SSA2-2015 (Prevencion y control enfermedades bucales)" # ----------------------------------------------------------------------------- # HERRAMIENTAS Y RUNTIME # ----------------------------------------------------------------------------- herramientas: runtime: node: version: "20.x" version_minima: "18.x" requerido: true notas: "LTS recomendado para NestJS y React" python: version: "" requerido: false notas: "No requerido para este proyecto" package_managers: npm: version: "10.x" requerido: true pnpm: version: "8.x" requerido: false notas: "Alternativa opcional" build_tools: - nombre: "Vite" version: "5.x" uso: "Frontend build y dev server" - nombre: "TypeScript" version: "5.x" uso: "Compilacion de codigo" - nombre: "NestJS CLI" version: "10.x" uso: "Backend scaffolding y build" linters: - nombre: "ESLint" version: "8.x" config: ".eslintrc.js" - nombre: "Prettier" version: "3.x" config: ".prettierrc" testing: - nombre: "Jest" version: "29.x" tipo: "unit backend" config: "jest.config.js" - nombre: "Vitest" version: "1.x" tipo: "unit frontend" config: "vitest.config.ts" - nombre: "Supertest" version: "6.x" tipo: "e2e" config: "jest-e2e.config.js" # ----------------------------------------------------------------------------- # SERVICIOS Y PUERTOS # ----------------------------------------------------------------------------- servicios: frontend: nombre: "clinica-dental-frontend" framework: "React" version: "18.x" puerto: 3130 comando_dev: "npm run dev" comando_build: "npm run build" comando_preview: "npm run preview" ubicacion: "apps/frontend/" url_local: "http://localhost:3130" build_output: "dist/" backend: nombre: "clinica-dental-backend" framework: "NestJS" version: "10.x" puerto: 3131 comando_dev: "npm run start:dev" comando_build: "npm run build" comando_prod: "npm run start:prod" ubicacion: "apps/backend/" url_local: "http://localhost:3131" api_prefix: "/api/v1" swagger_url: "http://localhost:3131/api/docs" # ----------------------------------------------------------------------------- # BASE DE DATOS - CONFIGURACION COMPLETA # ----------------------------------------------------------------------------- base_de_datos: principal: engine: "PostgreSQL" version: "15" host_variable: "DB_HOST" puerto_variable: "DB_PORT" ambientes: development: host: "localhost" puerto: 5441 nombre: "clinica_dental_dev" usuario: "dental_dev" password_ref: "DB_PASSWORD en .env" ssl: false pool_size: 10 conexion: "postgresql://dental_dev:{password}@localhost:5441/clinica_dental_dev" test: host: "localhost" puerto: 5441 nombre: "clinica_dental_test" usuario: "dental_dev" password_ref: "DB_PASSWORD en .env" ssl: false pool_size: 5 conexion: "postgresql://dental_dev:{password}@localhost:5441/clinica_dental_test" staging: host: "${DB_HOST}" puerto: 5432 nombre: "clinica_dental_staging" usuario: "dental_staging" password_ref: "DB_PASSWORD en variables de CI/CD" ssl: true pool_size: 20 conexion: "postgresql://dental_staging:{password}@${DB_HOST}:5432/clinica_dental_staging?sslmode=require" production: host: "${DB_HOST}" puerto: 5432 nombre: "clinica_dental_prod" usuario: "dental_prod" password_ref: "DB_PASSWORD en secrets manager" ssl: true pool_size: 50 conexion: "postgresql://dental_prod:{password}@${DB_HOST}:5432/clinica_dental_prod?sslmode=require" schemas: - nombre: "public" descripcion: "Schema principal PostgreSQL" - nombre: "dental" descripcion: "Entidades odontologicas (odontograma, piezas, tratamientos, ortodoncia)" - nombre: "clinical" descripcion: "Heredado de erp-clinicas (consultorios, citas, historiales)" - nombre: "financial" descripcion: "Heredado de erp-core (pagos, facturacion, presupuestos)" - nombre: "hr" descripcion: "Heredado de erp-core (empleados, especialidades)" - nombre: "inventory" descripcion: "Heredado de erp-core (materiales, insumos dentales)" scripts_inicializacion: orden: - "database/init/00-extensions.sql" - "database/init/01-schemas.sql" - "database/schemas/01-dental-schema-ddl.sql" - "database/seeds/fase8/01-dental-catalogos.sql" - "database/seeds/fase8/02-piezas-dentales-fdi.sql" datos_iniciales: piezas_dentales: total: 52 nomenclatura: "FDI (Federation Dentaire Internationale)" cuadrantes: - id: 1 nombre: "Superior derecho" piezas: "18-11" tipo: "permanente" - id: 2 nombre: "Superior izquierdo" piezas: "21-28" tipo: "permanente" - id: 3 nombre: "Inferior izquierdo" piezas: "31-38" tipo: "permanente" - id: 4 nombre: "Inferior derecho" piezas: "41-48" tipo: "permanente" - id: 5 nombre: "Superior derecho temporal" piezas: "55-51" tipo: "temporal" - id: 6 nombre: "Superior izquierdo temporal" piezas: "61-65" tipo: "temporal" - id: 7 nombre: "Inferior izquierdo temporal" piezas: "71-75" tipo: "temporal" - id: 8 nombre: "Inferior derecho temporal" piezas: "81-85" tipo: "temporal" redis: host_variable: "REDIS_HOST" puerto_variable: "REDIS_PORT" ambientes: development: host: "localhost" puerto: 6388 database: 0 password: "" conexion: "redis://localhost:6388/0" production: host: "${REDIS_HOST}" puerto: 6379 database: 0 password_ref: "REDIS_PASSWORD en secrets" conexion: "redis://:${REDIS_PASSWORD}@${REDIS_HOST}:6379/0" uso: - "Cache de sesiones" - "Cache de odontogramas" - "Rate limiting" - "Queue de tareas (Bull)" # ----------------------------------------------------------------------------- # VARIABLES DE ENTORNO - DESARROLLO # ----------------------------------------------------------------------------- variables_entorno: archivos: ejemplo: ".env.example" desarrollo: ".env" test: ".env.test" produccion: ".env.production" development: - nombre: "NODE_ENV" valor: "development" descripcion: "Ambiente de ejecucion" requerido: true sensible: false - nombre: "APP_NAME" valor: "clinica-dental" descripcion: "Nombre de la aplicacion" requerido: true sensible: false - nombre: "APP_VERSION" valor: "1.0.0" descripcion: "Version de la aplicacion" requerido: false sensible: false # Puertos - nombre: "FRONTEND_PORT" valor: "3130" descripcion: "Puerto del frontend React" requerido: true sensible: false - nombre: "BACKEND_PORT" valor: "3131" descripcion: "Puerto del backend NestJS" requerido: true sensible: false # Base de datos - nombre: "DB_HOST" valor: "localhost" descripcion: "Host de PostgreSQL" requerido: true sensible: false - nombre: "DB_PORT" valor: "5441" descripcion: "Puerto de PostgreSQL" requerido: true sensible: false - nombre: "DB_NAME" valor: "clinica_dental_dev" descripcion: "Nombre de la base de datos" requerido: true sensible: false - nombre: "DB_USER" valor: "dental_dev" descripcion: "Usuario de PostgreSQL" requerido: true sensible: false - nombre: "DB_PASSWORD" valor: "" descripcion: "Password de PostgreSQL" requerido: true sensible: true generacion: "openssl rand -base64 32" - nombre: "DATABASE_URL" valor: "postgresql://dental_dev:${DB_PASSWORD}@localhost:5441/clinica_dental_dev" descripcion: "Connection string completo" requerido: true sensible: true # Redis - nombre: "REDIS_HOST" valor: "localhost" descripcion: "Host de Redis" requerido: true sensible: false - nombre: "REDIS_PORT" valor: "6388" descripcion: "Puerto de Redis" requerido: true sensible: false - nombre: "REDIS_URL" valor: "redis://localhost:6388/0" descripcion: "Connection string de Redis" requerido: true sensible: false # Autenticacion - nombre: "JWT_SECRET" valor: "" descripcion: "Secreto para firmar JWT (min 32 caracteres)" requerido: true sensible: true generacion: "openssl rand -base64 64" - nombre: "JWT_EXPIRES_IN" valor: "24h" descripcion: "Tiempo de expiracion del access token" requerido: true sensible: false - nombre: "JWT_REFRESH_EXPIRES_IN" valor: "7d" descripcion: "Tiempo de expiracion del refresh token" requerido: true sensible: false # CORS - nombre: "FRONTEND_URL" valor: "http://localhost:3130" descripcion: "URL del frontend para CORS" requerido: true sensible: false - nombre: "ALLOWED_ORIGINS" valor: "http://localhost:3130,http://localhost:3131" descripcion: "Origenes permitidos (comma separated)" requerido: true sensible: false # Logging - nombre: "LOG_LEVEL" valor: "debug" descripcion: "Nivel de logging (debug, info, warn, error)" requerido: false sensible: false - nombre: "LOG_FORMAT" valor: "pretty" descripcion: "Formato de logs (pretty, json)" requerido: false sensible: false # File Storage (radiografias, documentos) - nombre: "STORAGE_TYPE" valor: "local" descripcion: "Tipo de storage (local, s3, minio)" requerido: false sensible: false - nombre: "STORAGE_PATH" valor: "./uploads" descripcion: "Path para almacenamiento local" requerido: false sensible: false - nombre: "MAX_FILE_SIZE" valor: "20971520" descripcion: "Tamano maximo de archivo en bytes (20MB para radiografias)" requerido: false sensible: false - nombre: "ALLOWED_FILE_TYPES" valor: "image/jpeg,image/png,image/dicom,application/pdf" descripcion: "Tipos de archivo permitidos" requerido: false sensible: false # Email (opcional) - nombre: "SMTP_HOST" valor: "localhost" descripcion: "Host SMTP para emails" requerido: false sensible: false - nombre: "SMTP_PORT" valor: "1025" descripcion: "Puerto SMTP (1025 para MailHog)" requerido: false sensible: false # Configuracion Dental Especifica - nombre: "DENTAL_FDI_NOTATION" valor: "true" descripcion: "Usar notacion FDI para piezas dentales" requerido: false sensible: false - nombre: "ODONTOGRAM_VERSION" valor: "2.0" descripcion: "Version del formato de odontograma" requerido: false sensible: false production: notas: | En produccion, las siguientes variables deben configurarse via secrets manager o variables de CI/CD: - DB_PASSWORD (secreto) - JWT_SECRET (secreto) - REDIS_PASSWORD (secreto) - AWS_ACCESS_KEY_ID (si usa S3) - AWS_SECRET_ACCESS_KEY (si usa S3) IMPORTANTE - Cumplimiento Normativo: - NOM-024-SSA3-2012: Logs de auditoria obligatorios - Encriptacion de datos sensibles (historiales) - Backups diarios con retencion minima 5 anos diferencias: - nombre: "NODE_ENV" valor: "production" - nombre: "LOG_LEVEL" valor: "info" - nombre: "LOG_FORMAT" valor: "json" - nombre: "DB_PORT" valor: "5432" - nombre: "REDIS_PORT" valor: "6379" - nombre: "STORAGE_TYPE" valor: "s3" - nombre: "AUDIT_ENABLED" valor: "true" - nombre: "DATA_ENCRYPTION" valor: "true" # ----------------------------------------------------------------------------- # CONTENEDORES DOCKER # ----------------------------------------------------------------------------- docker: compose_file: "docker-compose.yml" compose_dev: "docker-compose.dev.yml" compose_prod: "docker-compose.prod.yml" services: - nombre: "db" imagen: "postgres:15-alpine" puerto_host: 5441 puerto_container: 5432 variables: POSTGRES_DB: "clinica_dental_dev" POSTGRES_USER: "dental_dev" POSTGRES_PASSWORD: "${DB_PASSWORD}" volumes: - "postgres_data:/var/lib/postgresql/data" healthcheck: "pg_isready -U dental_dev" - nombre: "redis" imagen: "redis:7-alpine" puerto_host: 6388 puerto_container: 6379 volumes: - "redis_data:/data" healthcheck: "redis-cli ping" - nombre: "mailhog" imagen: "mailhog/mailhog" puerto_smtp: 1025 puerto_web: 8025 uso: "Testing de emails en desarrollo" volumes: - nombre: "postgres_data" descripcion: "Datos persistentes de PostgreSQL" - nombre: "redis_data" descripcion: "Datos persistentes de Redis" - nombre: "uploads_data" descripcion: "Radiografias y documentos" networks: - nombre: "clinica_dental_network" driver: "bridge" # ----------------------------------------------------------------------------- # MIGRACIONES Y SEEDS # ----------------------------------------------------------------------------- migraciones: herramienta: "TypeORM" directorio: "apps/backend/src/database/migrations" comandos: generar: "npm run migration:generate -- -n NombreMigracion" ejecutar: "npm run migration:run" revertir: "npm run migration:revert" mostrar: "npm run migration:show" seeds: directorio: "database/seeds" orden: - "fase8/01-dental-catalogos.sql" - "fase8/02-piezas-dentales-fdi.sql" comandos: ejecutar: "npm run seed" desarrollo: "npm run seed:dev" # ----------------------------------------------------------------------------- # SCRIPTS DE DESARROLLO # ----------------------------------------------------------------------------- scripts: setup: descripcion: "Configurar entorno desde cero" pasos: - comando: "npm install" descripcion: "Instalar dependencias" - comando: "cp .env.example .env" descripcion: "Crear archivo de configuracion" - comando: "docker-compose up -d db redis" descripcion: "Levantar servicios de infraestructura" - comando: "npm run db:create" descripcion: "Crear base de datos" - comando: "npm run migration:run" descripcion: "Ejecutar migraciones" - comando: "npm run seed" descripcion: "Cargar datos iniciales (incluye 52 piezas FDI)" desarrollo: frontend: "cd apps/frontend && npm run dev" backend: "cd apps/backend && npm run start:dev" ambos: "npm run dev:all" docker: "docker-compose up -d" testing: unit: "npm run test" unit_watch: "npm run test:watch" e2e: "npm run test:e2e" coverage: "npm run test:cov" build: frontend: "cd apps/frontend && npm run build" backend: "cd apps/backend && npm run build" docker: "docker-compose -f docker-compose.prod.yml build" database: create: "npm run db:create" drop: "npm run db:drop" reset: "npm run db:reset" migrations_run: "npm run migration:run" migrations_revert: "npm run migration:revert" seed: "npm run seed" linting: lint: "npm run lint" lint_fix: "npm run lint:fix" format: "npm run format" # ----------------------------------------------------------------------------- # INSTRUCCIONES DE SETUP # ----------------------------------------------------------------------------- setup_instrucciones: | ## Setup del Entorno de Desarrollo - Clinica Dental ### Prerequisitos - Node.js 20.x (LTS) - PostgreSQL 15 (o Docker) - Redis 7 (o Docker) - npm 10.x - Git ### Opcion 1: Setup con Docker (Recomendado) ```bash # 1. Clonar repositorio git clone cd clinica-dental # 2. Instalar dependencias npm install # 3. Configurar variables de entorno cp .env.example .env # Editar .env - generar passwords seguros: # openssl rand -base64 32 # para DB_PASSWORD # openssl rand -base64 64 # para JWT_SECRET # 4. Levantar infraestructura docker-compose up -d db redis # 5. Crear base de datos y ejecutar migraciones npm run db:create npm run migration:run npm run seed # Carga 52 piezas dentales FDI # 6. Iniciar desarrollo npm run dev:all ``` ### Opcion 2: Setup con PostgreSQL Local ```bash # 1-3. Igual que arriba # 4. Crear usuario y base de datos en PostgreSQL sudo -u postgres psql CREATE USER dental_dev WITH PASSWORD 'tu_password'; CREATE DATABASE clinica_dental_dev OWNER dental_dev; GRANT ALL PRIVILEGES ON DATABASE clinica_dental_dev TO dental_dev; \q # 5. Configurar Redis local o Docker docker run -d --name redis-dental -p 6388:6379 redis:7-alpine # 6-7. Continuar con migraciones y seeds ``` ### Verificar Instalacion - Frontend: http://localhost:3130 - Backend API: http://localhost:3131/api/v1 - Swagger Docs: http://localhost:3131/api/docs - Health Check: http://localhost:3131/health ### Usuarios de Prueba (despues de seed) - Admin: admin@clinica-dental.local / Admin123! - Odontologo: doctor@clinica-dental.local / Doctor123! - Recepcion: recepcion@clinica-dental.local / Recep123! ### Nomenclatura Dental FDI El sistema usa la nomenclatura FDI (Federation Dentaire Internationale): - Cuadrante 1: Superior derecho (18-11) - Cuadrante 2: Superior izquierdo (21-28) - Cuadrante 3: Inferior izquierdo (31-38) - Cuadrante 4: Inferior derecho (41-48) - Cuadrantes 5-8: Denticion temporal # ----------------------------------------------------------------------------- # TROUBLESHOOTING # ----------------------------------------------------------------------------- troubleshooting: - problema: "Puerto 3130 o 3131 en uso" solucion: | Verificar con: lsof -i :3130 Terminar proceso: kill -9 O cambiar puertos en .env - problema: "Error de conexion a PostgreSQL" solucion: | 1. Verificar que PostgreSQL esta corriendo: docker-compose ps # o: systemctl status postgresql 2. Verificar credenciales en .env 3. Verificar que la BD existe: psql -h localhost -p 5441 -U dental_dev -l - problema: "Error de conexion a Redis" solucion: | 1. Verificar que Redis esta corriendo: docker-compose ps # o: redis-cli -p 6388 ping 2. Verificar puerto en .env - problema: "Migraciones fallan" solucion: | 1. Verificar que la BD existe 2. Verificar permisos del usuario 3. Revisar logs: npm run migration:run --verbose 4. Si es necesario, resetear: npm run db:reset - problema: "Piezas dentales no cargadas" solucion: | Ejecutar seeds manualmente: npm run seed Verificar: SELECT COUNT(*) FROM dental.piezas_dentales; Debe retornar 52 (32 permanentes + 20 temporales) - problema: "Radiografias no se suben" solucion: | 1. Verificar STORAGE_PATH existe y tiene permisos 2. Verificar MAX_FILE_SIZE en .env (default 20MB) 3. Verificar ALLOWED_FILE_TYPES incluye el tipo de archivo - problema: "JWT errors" solucion: | Verificar que JWT_SECRET esta configurado (min 32 caracteres) Generar nuevo: openssl rand -base64 64 - problema: "CORS errors en frontend" solucion: | Verificar FRONTEND_URL y ALLOWED_ORIGINS en .env Deben coincidir con la URL del frontend # ----------------------------------------------------------------------------- # CONFIGURACION DE PRODUCCION # ----------------------------------------------------------------------------- produccion: checklist: - item: "Variables de entorno configuradas via secrets manager" - item: "SSL/TLS habilitado para BD y Redis" - item: "Backups automaticos configurados (retencion 5 anos)" - item: "Monitoreo y alertas activas" - item: "Rate limiting configurado" - item: "CORS restringido a dominios autorizados" - item: "Logs en formato JSON para agregacion" - item: "Audit logging habilitado (NOM-024-SSA3-2012)" - item: "Encriptacion de datos sensibles" infraestructura_recomendada: base_de_datos: "AWS RDS PostgreSQL 15 o equivalente" cache: "AWS ElastiCache Redis o equivalente" storage: "AWS S3 o equivalente (para radiografias)" cdn: "CloudFront o equivalente" ci_cd: "GitHub Actions / GitLab CI" escalado: backend_replicas: 2 pool_db_size: 50 redis_maxmemory: "512mb" storage_bucket_region: "us-east-1" cumplimiento: nom_024_ssa3: descripcion: "Expediente clinico electronico" requisitos: - "Logs de auditoria inmutables" - "Firma electronica de expedientes" - "Control de versiones de historiales" retencion_datos: expedientes: "5 anos minimo" radiografias: "5 anos minimo" logs_auditoria: "5 anos" # ----------------------------------------------------------------------------- # REFERENCIAS # ----------------------------------------------------------------------------- referencias: perfil_devenv: "orchestration/agents/perfiles/PERFIL-DEVENV.md" inventario_master: "orchestration/inventarios/DEVENV-MASTER-INVENTORY.yml" inventario_puertos: "orchestration/inventarios/DEVENV-PORTS-INVENTORY.yml" contexto_proyecto: "orchestration/00-guidelines/CONTEXTO-PROYECTO.md" parent_clinicas: "../erp-clinicas/orchestration/environment/ENVIRONMENT-INVENTORY.yml" schema_dental: "database/schemas/01-dental-schema-ddl.sql" nomenclatura_fdi: "https://www.fdiworlddental.org/tooth-numbering-system" # ============================================================================= # FIN DE INVENTARIO # =============================================================================