2026-06-26 00:29:09 +00:00
2026-06-11 04:56:01 +02:00
2026-06-11 04:56:01 +02:00
2025-11-12 15:30:12 +01:00
2025-11-12 15:30:12 +01:00
2026-06-11 04:56:01 +02:00
2026-06-11 04:56:01 +02:00
2025-11-12 15:30:12 +01:00
2026-06-11 04:56:01 +02:00
2025-11-12 15:30:12 +01:00

Stock Manager Home

Sistema de gestión de inventario, activos serializados, asignaciones y movimientos construido con Next.js, Prisma, PostgreSQL, NextAuth y Bun.

Quick start

bun install
cp .env.example .env
bun run db:generate
bun run db:migrate
bun run db:seed
bun run dev

Abrí la aplicación en http://localhost:3000.

db:seed crea un administrador inicial cuando no existe ningún admin activo. Configurá las variables ADMIN_* en .env antes de usarlo en entornos compartidos o productivos.

Qué hace la aplicación

Stock Manager permite gestionar:

  • Ítems genéricos: productos gestionados por cantidad de stock.
  • Activos serializados: equipos individuales con número de serie único.
  • Categorías: clasificación de ítems y activos.
  • Personas: personas o departamentos que reciben asignaciones. Cada persona puede tener un usuario del sistema vinculado o existir sin credenciales.
  • Asignaciones: entrega y devolución de ítems o activos.
  • Movimientos: historial auditable de entradas, salidas, asignaciones, devoluciones y ajustes.
  • Usuarios del sistema: gestión unificada con personas, roles, estado activo y reseteo de contraseña.
  • Importación CSV: flujo legacy de importación masiva, mantenido estructuralmente pero pendiente de rediseño.

Stack técnico

Área Tecnología
Framework Next.js 16 App Router
Runtime/package manager Bun
UI React 19, Tailwind CSS, Radix UI/Shadcn-style components
Formularios React Hook Form
Validación Zod
Autenticación NextAuth v5
ORM Prisma 7
Base de datos PostgreSQL
Formato/lint Biome
Deploy Docker / Docker Compose

Internacionalización (i18n)

La aplicación soporta inglés (en) y español (es) en todas las superficies de usuario. La selección de idioma se persiste mediante una cookie stock-manager-locale validada en servidor y se aplica con un cambio de idioma por página sin rutas prefijadas.

Superficies localizadas:

  • Login y navbar compartida con selector de idioma compacto.
  • Shell común: sidebar, navegación, search, paginación, botón submit, página de acceso denegado.
  • Inventario: categorías, ítems, activos, personas, asignaciones, movimientos.
  • Personas: gestión unificada de personas y usuarios del sistema.

La arquitectura i18n sigue un patrón consistente:

  • Diccionarios tipados en src/i18n/dictionaries/en.ts y es.ts con paridad de claves obligatoria.
  • Resolución server-side: las páginas obtienen getI18n() y pasan props acotadas a componentes cliente.
  • Schemas localizados: builders (buildCreateXSchema(copy)) que aceptan copia de diccionario e inyectan mensajes de validación localizados.
  • Actions localizadas: resuelven locale en servidor, construyen schemas con copia localizada y mapean errores de use-case mediante message mappers.
  • Datos de usuario vs UI: nombres, emails, seriales y valores de enumeraciones canónicas nunca se traducen; solo se localizan las etiquetas de presentación.

La importación CSV queda fuera del alcance actual de i18n por su rediseño previsto.

Configuración de entorno

Copiá el ejemplo y completá los valores reales:

cp .env.example .env

Variables principales:

Grupo Variables
Base de datos DATABASE_URL, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, POSTGRES_HOST, POSTGRES_PORT
Auth AUTH_SECRET, AUTH_TRUST_HOST, DOMAIN, NODE_ENV, DEMO_MODE
Bootstrap admin ADMIN_BOOTSTRAP_ENABLED, ADMIN_EMAIL, ADMIN_NAME, ADMIN_PASSWORD

Bootstrap admin

El seed ejecuta prisma/seed.ts, que llama a prisma/bootstrap-admin.ts.

Comportamiento:

  • Si ya existe un usuario ADMIN activo, no hace nada.
  • Si ADMIN_BOOTSTRAP_ENABLED=false, no crea administrador.
  • En producción, ADMIN_PASSWORD es obligatorio.
  • En desarrollo, si no se define contraseña, usa un valor por defecto sólo para facilitar el arranque local.

Ejecutar manualmente:

bun run db:seed

Desarrollo local

Prerrequisitos

  • Bun 1.3+
  • PostgreSQL accesible mediante DATABASE_URL
  • Docker disponible para tests con Testcontainers
  • Git

Pasos

# 1. Instalar dependencias
bun install

# 2. Configurar entorno
cp .env.example .env

# 3. Generar cliente Prisma
bun run db:generate

# 4. Aplicar migraciones en desarrollo
bun run db:migrate

# 5. Crear admin inicial, si corresponde
bun run db:seed

# 6. Levantar Next
bun run dev

Desarrollo con DevContainer

El proyecto incluye configuración para desarrollo en contenedor.

  1. Abrí el repo en VS Code.
  2. Elegí Reopen in Container.
  3. El entorno instala dependencias y puede levantar el servidor de desarrollo.
  4. Accedé a http://localhost:3000.

Docker / despliegue

Con Docker Compose:

docker compose -f compose.yaml up -d

El Dockerfile ejecuta al iniciar:

bun run db:deploy && bun run db:seed && bun run start

Esto aplica migraciones pendientes, ejecuta el bootstrap admin si corresponde y luego inicia Next.

Scripts disponibles

Script Descripción
bun run dev Inicia Next en desarrollo con Turbopack
bun run build Construye la aplicación para producción
bun run start Inicia la build de producción
bun run lint Ejecuta Biome lint con escritura de fixes
bun run format Formatea con Biome
bun run check Ejecuta Biome check con escritura de fixes
bun run test Ejecuta toda la suite Vitest: unit + integración
bun run test:unit Ejecuta unit tests rápidos
bun run test:integration Genera Prisma y ejecuta integration tests con PostgreSQL Testcontainers
bun run test:e2e Genera Prisma y ejecuta Playwright E2E smoke con DB aislada
bun run test:coverage Ejecuta Vitest con coverage V8
bun run db:push Sincroniza el schema sin crear migraciones
bun run db:migrate Crea/aplica migraciones en desarrollo
bun run db:migrate:reset Resetea la base y reaplica migraciones
bun run db:deploy Aplica migraciones en entornos de deploy
bun run db:generate Genera el cliente Prisma en src/generated/prisma
bun run db:seed Ejecuta el seed/bootstrap admin
bun run db:studio Abre Prisma Studio

Prisma

El proyecto usa Prisma 7 con configuración en:

prisma.config.ts
prisma/schema.prisma
prisma/migrations/

El cliente Prisma se genera en:

src/generated/prisma

Ese directorio está ignorado por Git. Después de clonar, cambiar schema o instalar dependencias, ejecutá:

bun run db:generate

Validar schema:

bunx prisma validate

Arquitectura del código

La aplicación separa responsabilidades por capa:

Capa Ruta Responsabilidad
UI / routes src/app Páginas, layouts y componentes por ruta
Server Actions src/actions Boundary de servidor: auth, Zod, llamada a use-case, revalidación
Use-cases src/use-cases Reglas de negocio, coordinación multi-entidad y transacciones
Services src/services Acceso a datos/repositories Prisma; muchos aceptan tx opcional
Schemas src/schemas Validación Zod y tipos de formularios/actions
Types src/types Tipos compartidos y aliases de Prisma
Lib src/lib Infraestructura común: auth, prisma, paginate, security, constants, utils

Regla práctica

  • Las Actions deben ser finas.
  • Las reglas de negocio viven en use-cases.
  • Los services no orquestan flujos: leen/escriben datos y aceptan transacciones cuando participan en una operación mayor.

Estructura principal

src/
├── actions/              # Server Actions finas
├── app/                  # Next.js App Router
│   ├── (auth)/           # Login
│   ├── (dashboard)/      # Dashboard, inventario, asignaciones, importación, people
│   ├── api/              # API routes
│   └── forbidden/        # Página de acceso denegado
├── components/           # Componentes compartidos y UI
├── generated/            # Cliente Prisma generado, ignorado por Git
├── hooks/                # Hooks React
├── lib/                  # Infraestructura y utilidades
├── schemas/              # Schemas Zod
├── services/             # Repositories Prisma / read models
├── styles/               # Estilos globales
├── types/                # Tipos compartidos
└── use-cases/            # Casos de uso transaccionales

prisma/
├── bootstrap-admin.ts    # Crea/activa admin inicial si corresponde
├── migrations/           # Migraciones Prisma
├── schema.prisma         # Modelo de datos
└── seed.ts               # Entry point de seed

Autenticación y autorización

  • Login con NextAuth credentials.
  • Passwords hasheadas con bcryptjs.
  • Roles soportados: ADMIN, MANAGER, STAFF, VIEWER.
  • /people/* requiere rol ADMIN para operaciones de gestión.
  • Usuarios inactivos no pueden iniciar sesión.

Helpers relevantes:

src/services/auth.service.ts
src/lib/auth.ts
src/proxy.ts

Modelo de datos

Entidades principales:

Entidad Descripción
User Usuarios del sistema, roles y estados de ciclo de vida
Person Personas del organigrama; pueden vincularse a un User
Category Categorías de inventario
Item Ítems genéricos con stock
Asset Activos serializados
Assignment Asignaciones y devoluciones
Movement Historial auditable de movimientos

Ver el schema completo en:

prisma/schema.prisma

Flujos importantes

Asignaciones

  • Crear asignación decrementa stock de forma transaccional.
  • Devolver asignación incrementa stock si aplica y libera activo.
  • Movimientos ASSIGNMENT y RETURN se crean dentro del use-case.

Activos

  • Crear activo disponible incrementa stock.
  • Crear activo asignado crea asignación y movimiento asociado.
  • Cambios de estado generan movimientos adecuados (IN, OUT, ASSIGNMENT, RETURN, ADJUSTMENT).

Ítems

  • Item.name es único.
  • Crear item con stock inicial genera movimiento IN.
  • El borrado es soft delete y se bloquea si hay stock o assets asociados.

Usuarios

  • Sólo ADMIN puede gestionar personas y usuarios.
  • No se puede quitar el propio acceso admin.
  • No se puede dejar el sistema sin admin activo.
  • La protección de último admin usa transacción serializable con retry de conflictos Prisma P2034.

Transición de arquitectura

La aplicación está migrando de un modelo separado de usuarios y destinatarios hacia una gestión unificada de personas:

Antes Después
Recipient Person
Gestión en /admin/users Gestión en /people
Usuarios y personas desvinculados Persona puede vincularse a un User opcional

Estado actual:

  • El schema Prisma y la migración inicial reflejan el nuevo modelo.
  • Las rutas y componentes de UI ya fueron migrados a /people.

Testing

El proyecto tiene una base inicial de tests en tres niveles:

Nivel Comando Cobertura
Unit bun run test:unit Schemas Zod, helpers de seguridad y helpers de roles auth
Integración bun run test:integration Use-cases principales contra PostgreSQL real con Testcontainers
E2E smoke bun run test:e2e Login, dashboard, admin users, inventory items y assignments con Playwright

Integration tests

Los tests de integración viven en:

tests/integration/

Usan PostgreSQL real mediante Testcontainers. El helper de DB:

  1. levanta un contenedor PostgreSQL aislado;
  2. setea DATABASE_URL antes de importar Prisma/use-cases;
  3. aplica migraciones con prisma migrate deploy;
  4. limpia tablas entre tests.

Importante: src/lib/prisma.ts lee DATABASE_URL al importarse. En tests, configurá el entorno antes de importar @/lib/prisma, services o use-cases.

E2E smoke tests

Los tests E2E viven en:

tests/e2e/

Playwright levanta una app real contra una DB Testcontainers aislada y crea un admin determinístico para el smoke test.

El server E2E usa next dev --webpack. Next 16 puede usar Turbopack por defecto y durante la configuración inicial emitió un panic compilando /assignments; para E2E automatizado se fuerza Webpack por estabilidad.

Secuencia completa recomendada

Antes de subir cambios grandes, ejecutá:

bun run test && bun run test:e2e && bunx tsc --noEmit && bunx prisma validate

Validación antes de subir cambios

Ejecutá al menos:

bunx tsc --noEmit
bunx prisma validate

Para cambios de Prisma:

bun run db:generate
bunx prisma validate

Para cambios de formato/lint:

bun run check

Estado conocido

  • La importación CSV actual es legacy y se mantiene por compatibilidad; está previsto rediseñarla.
  • El cliente Prisma generado no se versiona; debe generarse antes de build/deploy.
S
Description
No description provided
Readme 14 MiB
Languages
TypeScript 65.6%
JavaScript 32.3%
CSS 1.8%
Dockerfile 0.3%