Prompt Maestro — Hernani & Co Management App
Prompt Maestro — Hernani & Co Management App
Pega este prompt en Claude Code (o cualquier LLM con capacidad de codigo) dentro de un proyecto nuevo para generar la app completa.
EL PROMPT
Eres un senior full-stack engineer. Construye una aplicacion web de gestion empresarial para "Hernani & Co", una drogueria/cosmetica peruana que importa y comercializa perfumes portatiles premium bajo la marca "Spectra / Spectra Pocket". La app se despliega en Vercel.
---
## STACK TECNICO
- **Framework:** Next.js 15 (App Router, React Server Components)
- **Language:** TypeScript strict
- **Database:** Neon Postgres (via Vercel Marketplace)
- **ORM:** Drizzle ORM
- **Auth:** Clerk (via Vercel Marketplace)
- **UI:** shadcn/ui + Tailwind CSS 4
- **Charts:** Recharts
- **State:** React Server Components + Server Actions (sin Redux, sin Zustand)
- **Deployment:** Vercel
- **Moneda base:** PEN (Soles peruanos), con conversion a USD a tipo de cambio configurable (default PEN 3.50 / USD)
---
## CONTEXTO DEL NEGOCIO
Hernani & Co S.A.C. (RUC 20614632012) es una drogueria autorizada por DIGEMID que importa perfumes portatiles premium desde Dubai y los comercializa en Peru por 3 canales: Retail D2C (Shopify), Mayorista y Distribuidor.
### Datos clave del modelo:
- **64 SKUs activos**, 768 cajas, 18,432 unidades en inventario
- **2 lineas de producto:** Francesa (57 SKUs, costo fabrica PEN 3.50/un) y Arabe (7 SKUs, costo fabrica PEN 5.75/un)
- **24 unidades por caja master** (constante operativa)
- **Landed cost:** Francesa PEN 5.67/un, Arabe PEN 8.54/un
- **Costos fijos mensuales:** PEN 6,094 (quimica PEN 1,200, alquiler PEN 375, almacen PEN 180, Shopify PEN 224, planilla PEN 3,600, otros PEN 500)
- **Break-even:** 297 unidades/mes (PEN 10,223 ingresos/mes)
- **Margen contribucion blended:** 59.61%
- **Mix canal target:** D2C 20% / Mayorista 30% / Distribuidor 50%
### Precios por canal (PEN/un, sin IGV):
| Canal | Francesa | Arabe | Comision canal |
|---|---|---|---|
| Retail D2C | 40.90 | 57.30 | 18% (Shopify + ads) |
| Mayorista | 35.00 | 55.00 | 5% |
| Distribuidor | 27.50 | 45.00 | 3% |
### Costos variables adicionales:
- Empaque promo D2C: PEN 2.50/un
- Marketing: 12% sobre ventas
- Merma estimada: 2%
### Working capital (DSO):
- D2C: 0 dias
- Mayorista: 15 dias
- Distribuidor: 30 dias
- DPO proveedor: 14 dias
---
## MODELO DE DATOS (Drizzle schema)
Implementa las siguientes tablas:
### 1. `skus` — Maestro de productos
```ts
{
id: serial primary key,
code: varchar(10) unique not null, // "053", "102", etc.
spectraName: varchar(100) not null, // "White Mountain"
inspirationBrand: varchar(100), // "Creed"
originalPerfume: varchar(100), // "Silver Mountain Water"
line: enum('francesa', 'arabe') not null,
gender: enum('masculino', 'femenino', 'unisex') not null,
factoryCostPen: decimal(10,4) not null, // 3.50 o 5.75
landedCostPen: decimal(10,4) not null, // calculado
retailPricePen: decimal(10,2), // precio D2C
wholesalePricePen: decimal(10,2), // precio mayorista
distributorPricePen: decimal(10,2), // precio distribuidor
isActive: boolean default true,
imageUrl: varchar(500),
createdAt: timestamp,
updatedAt: timestamp
}
2. inventory_movements — Movimientos de inventario
{
id: serial primary key,
skuId: integer references skus(id),
type: enum('purchase', 'sale', 'return', 'adjustment', 'loss', 'demo') not null,
quantity: integer not null, // positivo = entrada, negativo = salida
unitCostPen: decimal(10,4),
reference: varchar(100), // numero de factura, guia, orden
channel: enum('d2c', 'wholesale', 'distributor') null, // solo para ventas
notes: text,
movementDate: date not null,
createdAt: timestamp
}
3. sales_orders — Ordenes de venta
{
id: serial primary key,
orderNumber: varchar(50) unique not null,
channel: enum('d2c', 'wholesale', 'distributor') not null,
customerName: varchar(200),
customerRuc: varchar(11),
status: enum('pending', 'confirmed', 'shipped', 'delivered', 'cancelled') not null,
subtotalPen: decimal(12,2) not null,
igvPen: decimal(12,2) not null, // 18%
totalPen: decimal(12,2) not null,
paymentStatus: enum('pending', 'partial', 'paid', 'overdue') not null,
paymentDueDate: date,
paidAmount: decimal(12,2) default 0,
orderDate: date not null,
shippedDate: date,
deliveredDate: date,
notes: text,
createdAt: timestamp,
updatedAt: timestamp
}
4. sales_order_items — Detalle de ordenes
{
id: serial primary key,
salesOrderId: integer references sales_orders(id),
skuId: integer references skus(id),
quantity: integer not null,
unitPricePen: decimal(10,2) not null,
subtotalPen: decimal(12,2) not null,
}
5. expenses — Gastos operativos
{
id: serial primary key,
category: enum('quimica', 'alquiler_oficina', 'almacen', 'shopify', 'planilla', 'marketing', 'empaque', 'aduana', 'transporte', 'otros') not null,
description: varchar(300) not null,
amountPen: decimal(12,2) not null,
isFixed: boolean not null, // true = fijo mensual, false = variable
expenseDate: date not null,
invoiceNumber: varchar(50),
notes: text,
createdAt: timestamp
}
6. customers — Clientes
{
id: serial primary key,
name: varchar(200) not null,
ruc: varchar(11),
type: enum('retail', 'wholesale', 'distributor') not null,
contactPhone: varchar(20),
contactEmail: varchar(100),
address: text,
creditDays: integer default 0,
creditLimitPen: decimal(12,2),
isActive: boolean default true,
notes: text,
createdAt: timestamp,
updatedAt: timestamp
}
7. purchases — Ordenes de compra / importaciones
{
id: serial primary key,
supplier: varchar(200) not null,
invoiceNumber: varchar(50),
totalFobUsd: decimal(12,2),
freightUsd: decimal(12,2),
insuranceUsd: decimal(12,2),
cifUsd: decimal(12,2),
exchangeRate: decimal(8,4),
arancelPen: decimal(12,2), // 6% sobre CIF
igvPen: decimal(12,2), // 18% sobre CIF+arancel
customsExpensesPen: decimal(12,2),
localTransportPen: decimal(12,2),
totalLandedPen: decimal(12,2),
totalUnits: integer,
status: enum('ordered', 'in_transit', 'customs', 'warehouse', 'completed') not null,
orderDate: date,
arrivalDate: date,
notes: text,
createdAt: timestamp
}
8. nso_tracker — Seguimiento regulatorio DIGEMID
{
id: serial primary key,
expedienteNumber: varchar(50) not null,
productDescription: varchar(300) not null,
status: enum('draft', 'submitted', 'in_review', 'observed', 'approved', 'rejected') not null,
submissionDate: date,
lastUpdateDate: date,
expectedResolutionDate: date,
observations: text,
resolutionNumber: varchar(50),
notes: text,
createdAt: timestamp,
updatedAt: timestamp
}
9. settings — Configuracion del sistema
{
id: serial primary key,
key: varchar(50) unique not null,
value: text not null,
description: varchar(200),
updatedAt: timestamp
}
Settings iniciales: exchange_rate (3.50), igv_rate (0.18), arancel_rate (0.06), merma_rate (0.02), company_name ("Hernani & Co S.A.C."), ruc ("20614632012").
PAGINAS Y FUNCIONALIDADES
1. /dashboard — Panel ejecutivo (HOME)
Vista ejecutiva con KPIs en tarjetas + graficos:
Tarjetas KPI (fila superior):
- Ventas del mes (PEN + USD)
- Unidades vendidas del mes
- Margen contribucion % del mes
- EBITDA del mes (PEN)
- Cuentas por cobrar (PEN) — orders con paymentStatus != 'paid'
- Inventario total (unidades + valor PEN)
Graficos:
- Ventas mensuales (barras, ultimos 12 meses) con linea de break-even superpuesta
- Ventas por canal (donut: D2C vs Mayorista vs Distribuidor) — comparar mix real vs target
- Top 10 SKUs mas vendidos (barras horizontales)
- Margen por canal (barras agrupadas)
- Flujo de caja simplificado (ingresos cobrados - gastos) ultimos 6 meses
- Cobertura de inventario (dias restantes al ritmo actual de venta)
Alertas automaticas (banner):
- Inventario < 30 dias de cobertura en algun SKU
- Cuentas por cobrar vencidas (paymentDueDate < hoy && paymentStatus != 'paid')
- EBITDA mensual por debajo del break-even (PEN 10,223)
- NSO pendiente de resolucion
2. /inventory — Gestion de inventario
- Tabla de SKUs con stock actual (calculado desde movements), valor en PEN, dias de cobertura
- Filtros: linea (francesa/arabe), genero, estado (activo/inactivo), stock (con stock / agotado)
- Busqueda por nombre Spectra o marca inspiracion
- Vista detalle de SKU: ficha completa + historial de movimientos + grafico de stock en el tiempo
- Boton "Registrar movimiento" (modal): tipo, cantidad, referencia, notas
- Exportar inventario a CSV
- Indicadores de semaforo: verde (>90 dias cobertura), amarillo (30-90 dias), rojo (<30 dias)
3. /sales — Ventas
- Tabla de ordenes con filtros: canal, status, paymentStatus, rango de fechas
- Crear nueva orden: seleccion de cliente, agregar items (SKU + cantidad + precio automatico segun canal), calculo automatico de IGV
- Vista detalle de orden: items, totales, timeline de status, historial de pagos
- Boton "Registrar pago" (parcial o total)
- Al confirmar una orden, generar automaticamente los inventory_movements negativos
- Dashboard de cobranza: ordenes pendientes de pago, agrupadas por cliente, con dias de mora
4. /customers — Clientes
- CRUD de clientes con tipo (retail/wholesale/distributor)
- Vista detalle: datos del cliente + historial de ordenes + saldo pendiente + dias promedio de pago
- Alerta de clientes con saldo vencido
5. /expenses — Gastos
- Tabla de gastos con filtros: categoria, tipo (fijo/variable), rango de fechas
- Crear/editar gasto
- Vista de gastos fijos recurrentes con comparacion vs presupuesto (PEN 6,094/mes)
- Grafico de gastos por categoria (donut) y tendencia mensual (barras)
6. /purchases — Importaciones / Compras
- Tabla de compras/importaciones con status
- Crear nueva importacion: datos FOB, flete, seguro, tipo de cambio → calculo automatico de CIF, arancel, IGV, landed cost
- Al completar, generar inventory_movements de entrada
- Vista detalle con desglose completo de costos de importacion
7. /regulatory — Seguimiento DIGEMID / NSO
- Timeline visual del estado de cada expediente NSO
- Crear/actualizar expedientes
- Alertas de expedientes con observaciones pendientes
- Countdown al tiempo estimado de resolucion
8. /reports — Reportes
- P&L mensual (formato del modelo: ingresos - landed cost - comisiones - marketing - empaque = margen contribucion - fijos = EBITDA)
- Comparativo real vs escenarios (conservador/medio/agresivo del modelo)
- Reporte de cuentas por cobrar aging (0-15, 16-30, 31-60, 60+ dias)
- Reporte de inventario valorizado
- Mix de ventas por canal vs target
- Exportar cualquier reporte a CSV
9. /settings — Configuracion
- Editar parametros del sistema (tipo de cambio, tasas, datos de empresa)
- Gestion de usuarios (via Clerk)
REGLAS DE NEGOCIO (implementar como validaciones)
- IGV siempre es 18% sobre subtotal en todas las ventas
- No vender SKUs inactivos o con stock 0
- Precios automaticos por canal: al crear una orden, autorellenar precio segun canal del cliente
- Dias de credito por tipo de cliente: D2C = 0, Mayorista = 15, Distribuidor = 30
- Alerta automatica cuando un SKU tiene <30 dias de cobertura
- Al confirmar orden → descontar inventario automaticamente
- Al cancelar orden → revertir inventario automaticamente
- Break-even line siempre visible en graficos de ventas (PEN 10,223/mes)
- Tipo de cambio configurable — todos los montos en USD se calculan dinamicamente
- Merma del 2% se aplica en calculo de landed cost
REQUISITOS TECNICOS
- Autenticacion obligatoria en todas las rutas excepto login
- Responsive design — funcional en movil (Renato lo usa desde el telefono frecuentemente)
- Server Actions para todas las mutaciones (no API routes)
- Optimistic updates en tablas para UX fluida
- Loading states con skeletons de shadcn
- Error boundaries por seccion
- Seed script (
npm run db:seed) que cargue los 64 SKUs activos con su inventario inicial de 18,432 unidades - Migraciones con Drizzle Kit (
npm run db:push/npm run db:migrate) - Validacion de formularios con Zod
- Paginacion en todas las tablas (20 items por pagina)
- Dark mode toggle (default dark)
SEED DATA
El seed script debe cargar:
- Los 64 SKUs activos con sus datos completos (codigo, nombre, marca inspiracion, perfume original, linea, genero, precios por canal, costos)
- Los inventory_movements iniciales: 288 unidades por SKU (12 cajas x 24 un/caja)
- Los settings iniciales del sistema
- Las categorias de gasto fijo con sus montos mensuales presupuestados
SKUs a cargar (todos con 12 cajas = 288 unidades):
Linea Arabe (7 SKUs, costo fabrica PEN 5.75, landed PEN 8.54): 102-Oud Cavaliere (Roberto Cavalli/Oud Edition/F), 108-Oud Woods (Tom Ford/Oud Wood/U), 115-Royal Night (D&G/The One Royal Night/U), 118-Pure (Xerjoff/Erba Pura Sospiro/M), 121-Scenta (Xerjoff/Accento Sospiro/M), 119-Boss Oud (Hugo Boss/Boss Bottled Oud/M), 105-Oud Wild (Roberto Cavalli/Tiger Oud/U)
Linea Francesa (57 SKUs, costo fabrica PEN 3.50, landed PEN 5.67): 053-White Mountain, 273-Absolute Avenger, 029-Avenger for Men, 221-Treasure, 205-Ultra Man, 073-Legendary, 163-Y, 017-2 N2 Sexy for Men, 018-VIP for Women, 022-Adorable for Women, 048-Mambu, 021-White Coast for Men, 011-Millionaire for Men, 020-Crystelle for Women, 059-Aqua di Givany, 036-See for Women, 355-Hunted, 276-Her, 032-Aphrodite Gold, 100-Sentiment, 078-Good Lady Red, 079-Good Boy, 080-Good Lady, 082-VIP Rose, 085-VIP Black, 002-One Chance, 026-Demoiselle, 189-Blue Parfum, 025-Blue Canal for Men, 035-Fire N' Heat, 057-Souvenir, 258-Devot, 207-Wild Desire, 016-Magnetic, 245-Strong Feelings Oud, 247-Strong Feelings Amber, 249-Strong, 234-Le Parfum, 238-By Night, 040-La Belle, 023-Infectious for Men, 039-The Excess, 167-One Private, 169-Lucky, 044-Millionaire, 278-Paradise, 013-Into the Blue, 203-Dark Leather, 086-Live in Roma, 225-Hero, 042-Black Opera, 159-Urself, 286-Paris, 362-Libretto Intense, 381-[sin nombre], 232-Libretto, 157-Electric
ESTRUCTURA DE ARCHIVOS ESPERADA
src/
app/
layout.tsx # Root layout con ClerkProvider + ThemeProvider
page.tsx # Redirect a /dashboard
sign-in/[[...sign-in]]/page.tsx
sign-up/[[...sign-up]]/page.tsx
(app)/ # Grupo con sidebar layout
layout.tsx # Sidebar + header + breadcrumbs
dashboard/page.tsx
inventory/
page.tsx
[id]/page.tsx
sales/
page.tsx
new/page.tsx
[id]/page.tsx
customers/
page.tsx
[id]/page.tsx
expenses/page.tsx
purchases/
page.tsx
new/page.tsx
[id]/page.tsx
regulatory/page.tsx
reports/page.tsx
settings/page.tsx
components/
ui/ # shadcn components
layout/
sidebar.tsx
header.tsx
dashboard/
kpi-cards.tsx
sales-chart.tsx
channel-donut.tsx
top-skus.tsx
alerts-banner.tsx
inventory/
sku-table.tsx
movement-modal.tsx
stock-indicator.tsx
sales/
order-form.tsx
order-table.tsx
payment-modal.tsx
shared/
data-table.tsx # Tabla reutilizable con sorting, filtering, pagination
currency-display.tsx # Muestra PEN y USD
date-picker.tsx
export-csv.tsx
lib/
db/
schema.ts # Drizzle schema (todas las tablas)
index.ts # DB connection
seed.ts # Seed script
actions/ # Server Actions
inventory.ts
sales.ts
customers.ts
expenses.ts
purchases.ts
regulatory.ts
settings.ts
utils/
currency.ts # Conversion PEN/USD, formateo
calculations.ts # Landed cost, margenes, break-even
validators.ts # Zod schemas
types/
index.ts # TypeScript types
drizzle.config.ts
INSTRUCCIONES DE EJECUCION
- Empieza creando el proyecto con
npx create-next-app@latest hernani-app --typescript --tailwind --eslint --app --src-dir - Instala dependencias:
npm install drizzle-orm @neondatabase/serverless,npm install -D drizzle-kit,npx shadcn@latest init,npm install @clerk/nextjs,npm install recharts,npm install zod - Configura Drizzle con Neon Postgres
- Implementa el schema completo primero
- Luego las Server Actions
- Luego los componentes y paginas, empezando por el dashboard
- Al final, el seed script
Construye toda la app modulo por modulo. Empieza por la infraestructura (schema, db, auth), luego dashboard, luego inventory, luego sales, y asi sucesivamente. Cada modulo debe estar completo y funcional antes de pasar al siguiente.
NO uses mocks, placeholders, ni "TODO" en el codigo. Todo debe ser funcional end-to-end.
---
## NOTAS DE USO
- **Donde usarlo:** Pega el prompt en un proyecto Next.js nuevo con Claude Code, Cursor, o Windsurf
- **Prerequisitos:** Tener una cuenta Vercel, un proyecto Neon Postgres creado (o usar `vercel marketplace`), y una app Clerk configurada
- **Variables de entorno necesarias:**
- `DATABASE_URL` (Neon Postgres)
- `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY`
- `CLERK_SECRET_KEY`
- `NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in`
- `NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up`
# Prompt Maestro — Hernani & Co Management App
> Pega este prompt en Claude Code (o cualquier LLM con capacidad de codigo) dentro de un proyecto nuevo para generar la app completa.
---
## EL PROMPT
```
Eres un senior full-stack engineer. Construye una aplicacion web de gestion empresarial para "Hernani & Co", una drogueria/cosmetica peruana que importa y comercializa perfumes portatiles premium bajo la marca "Spectra / Spectra Pocket". La app se despliega en Vercel.
---
## STACK TECNICO
- **Framework:** Next.js 15 (App Router, React Server Components)
- **Language:** TypeScript strict
- **Database:** Neon Postgres (via Vercel Marketplace)
- **ORM:** Drizzle ORM
- **Auth:** Clerk (via Vercel Marketplace)
- **UI:** shadcn/ui + Tailwind CSS 4
- **Charts:** Recharts
- **State:** React Server Components + Server Actions (sin Redux, sin Zustand)
- **Deployment:** Vercel
- **Moneda base:** PEN (Soles peruanos), con conversion a USD a tipo de cambio configurable (default PEN 3.50 / USD)
---
## CONTEXTO DEL NEGOCIO
Hernani & Co S.A.C. (RUC 20614632012) es una drogueria autorizada por DIGEMID que importa perfumes portatiles premium desde Dubai y los comercializa en Peru por 3 canales: Retail D2C (Shopify), Mayorista y Distribuidor.
### Datos clave del modelo:
- **64 SKUs activos**, 768 cajas, 18,432 unidades en inventario
- **2 lineas de producto:** Francesa (57 SKUs, costo fabrica PEN 3.50/un) y Arabe (7 SKUs, costo fabrica PEN 5.75/un)
- **24 unidades por caja master** (constante operativa)
- **Landed cost:** Francesa PEN 5.67/un, Arabe PEN 8.54/un
- **Costos fijos mensuales:** PEN 6,094 (quimica PEN 1,200, alquiler PEN 375, almacen PEN 180, Shopify PEN 224, planilla PEN 3,600, otros PEN 500)
- **Break-even:** 297 unidades/mes (PEN 10,223 ingresos/mes)
- **Margen contribucion blended:** 59.61%
- **Mix canal target:** D2C 20% / Mayorista 30% / Distribuidor 50%
### Precios por canal (PEN/un, sin IGV):
| Canal | Francesa | Arabe | Comision canal |
|---|---|---|---|
| Retail D2C | 40.90 | 57.30 | 18% (Shopify + ads) |
| Mayorista | 35.00 | 55.00 | 5% |
| Distribuidor | 27.50 | 45.00 | 3% |
### Costos variables adicionales:
- Empaque promo D2C: PEN 2.50/un
- Marketing: 12% sobre ventas
- Merma estimada: 2%
### Working capital (DSO):
- D2C: 0 dias
- Mayorista: 15 dias
- Distribuidor: 30 dias
- DPO proveedor: 14 dias
---
## MODELO DE DATOS (Drizzle schema)
Implementa las siguientes tablas:
### 1. `skus` — Maestro de productos
```ts
{
id: serial primary key,
code: varchar(10) unique not null, // "053", "102", etc.
spectraName: varchar(100) not null, // "White Mountain"
inspirationBrand: varchar(100), // "Creed"
originalPerfume: varchar(100), // "Silver Mountain Water"
line: enum('francesa', 'arabe') not null,
gender: enum('masculino', 'femenino', 'unisex') not null,
factoryCostPen: decimal(10,4) not null, // 3.50 o 5.75
landedCostPen: decimal(10,4) not null, // calculado
retailPricePen: decimal(10,2), // precio D2C
wholesalePricePen: decimal(10,2), // precio mayorista
distributorPricePen: decimal(10,2), // precio distribuidor
isActive: boolean default true,
imageUrl: varchar(500),
createdAt: timestamp,
updatedAt: timestamp
}
```
### 2. `inventory_movements` — Movimientos de inventario
```ts
{
id: serial primary key,
skuId: integer references skus(id),
type: enum('purchase', 'sale', 'return', 'adjustment', 'loss', 'demo') not null,
quantity: integer not null, // positivo = entrada, negativo = salida
unitCostPen: decimal(10,4),
reference: varchar(100), // numero de factura, guia, orden
channel: enum('d2c', 'wholesale', 'distributor') null, // solo para ventas
notes: text,
movementDate: date not null,
createdAt: timestamp
}
```
### 3. `sales_orders` — Ordenes de venta
```ts
{
id: serial primary key,
orderNumber: varchar(50) unique not null,
channel: enum('d2c', 'wholesale', 'distributor') not null,
customerName: varchar(200),
customerRuc: varchar(11),
status: enum('pending', 'confirmed', 'shipped', 'delivered', 'cancelled') not null,
subtotalPen: decimal(12,2) not null,
igvPen: decimal(12,2) not null, // 18%
totalPen: decimal(12,2) not null,
paymentStatus: enum('pending', 'partial', 'paid', 'overdue') not null,
paymentDueDate: date,
paidAmount: decimal(12,2) default 0,
orderDate: date not null,
shippedDate: date,
deliveredDate: date,
notes: text,
createdAt: timestamp,
updatedAt: timestamp
}
```
### 4. `sales_order_items` — Detalle de ordenes
```ts
{
id: serial primary key,
salesOrderId: integer references sales_orders(id),
skuId: integer references skus(id),
quantity: integer not null,
unitPricePen: decimal(10,2) not null,
subtotalPen: decimal(12,2) not null,
}
```
### 5. `expenses` — Gastos operativos
```ts
{
id: serial primary key,
category: enum('quimica', 'alquiler_oficina', 'almacen', 'shopify', 'planilla', 'marketing', 'empaque', 'aduana', 'transporte', 'otros') not null,
description: varchar(300) not null,
amountPen: decimal(12,2) not null,
isFixed: boolean not null, // true = fijo mensual, false = variable
expenseDate: date not null,
invoiceNumber: varchar(50),
notes: text,
createdAt: timestamp
}
```
### 6. `customers` — Clientes
```ts
{
id: serial primary key,
name: varchar(200) not null,
ruc: varchar(11),
type: enum('retail', 'wholesale', 'distributor') not null,
contactPhone: varchar(20),
contactEmail: varchar(100),
address: text,
creditDays: integer default 0,
creditLimitPen: decimal(12,2),
isActive: boolean default true,
notes: text,
createdAt: timestamp,
updatedAt: timestamp
}
```
### 7. `purchases` — Ordenes de compra / importaciones
```ts
{
id: serial primary key,
supplier: varchar(200) not null,
invoiceNumber: varchar(50),
totalFobUsd: decimal(12,2),
freightUsd: decimal(12,2),
insuranceUsd: decimal(12,2),
cifUsd: decimal(12,2),
exchangeRate: decimal(8,4),
arancelPen: decimal(12,2), // 6% sobre CIF
igvPen: decimal(12,2), // 18% sobre CIF+arancel
customsExpensesPen: decimal(12,2),
localTransportPen: decimal(12,2),
totalLandedPen: decimal(12,2),
totalUnits: integer,
status: enum('ordered', 'in_transit', 'customs', 'warehouse', 'completed') not null,
orderDate: date,
arrivalDate: date,
notes: text,
createdAt: timestamp
}
```
### 8. `nso_tracker` — Seguimiento regulatorio DIGEMID
```ts
{
id: serial primary key,
expedienteNumber: varchar(50) not null,
productDescription: varchar(300) not null,
status: enum('draft', 'submitted', 'in_review', 'observed', 'approved', 'rejected') not null,
submissionDate: date,
lastUpdateDate: date,
expectedResolutionDate: date,
observations: text,
resolutionNumber: varchar(50),
notes: text,
createdAt: timestamp,
updatedAt: timestamp
}
```
### 9. `settings` — Configuracion del sistema
```ts
{
id: serial primary key,
key: varchar(50) unique not null,
value: text not null,
description: varchar(200),
updatedAt: timestamp
}
```
Settings iniciales: exchange_rate (3.50), igv_rate (0.18), arancel_rate (0.06), merma_rate (0.02), company_name ("Hernani & Co S.A.C."), ruc ("20614632012").
---
## PAGINAS Y FUNCIONALIDADES
### 1. `/dashboard` — Panel ejecutivo (HOME)
Vista ejecutiva con KPIs en tarjetas + graficos:
**Tarjetas KPI (fila superior):**
- Ventas del mes (PEN + USD)
- Unidades vendidas del mes
- Margen contribucion % del mes
- EBITDA del mes (PEN)
- Cuentas por cobrar (PEN) — orders con paymentStatus != 'paid'
- Inventario total (unidades + valor PEN)
**Graficos:**
- Ventas mensuales (barras, ultimos 12 meses) con linea de break-even superpuesta
- Ventas por canal (donut: D2C vs Mayorista vs Distribuidor) — comparar mix real vs target
- Top 10 SKUs mas vendidos (barras horizontales)
- Margen por canal (barras agrupadas)
- Flujo de caja simplificado (ingresos cobrados - gastos) ultimos 6 meses
- Cobertura de inventario (dias restantes al ritmo actual de venta)
**Alertas automaticas (banner):**
- Inventario < 30 dias de cobertura en algun SKU
- Cuentas por cobrar vencidas (paymentDueDate < hoy && paymentStatus != 'paid')
- EBITDA mensual por debajo del break-even (PEN 10,223)
- NSO pendiente de resolucion
### 2. `/inventory` — Gestion de inventario
- Tabla de SKUs con stock actual (calculado desde movements), valor en PEN, dias de cobertura
- Filtros: linea (francesa/arabe), genero, estado (activo/inactivo), stock (con stock / agotado)
- Busqueda por nombre Spectra o marca inspiracion
- Vista detalle de SKU: ficha completa + historial de movimientos + grafico de stock en el tiempo
- Boton "Registrar movimiento" (modal): tipo, cantidad, referencia, notas
- Exportar inventario a CSV
- Indicadores de semaforo: verde (>90 dias cobertura), amarillo (30-90 dias), rojo (<30 dias)
### 3. `/sales` — Ventas
- Tabla de ordenes con filtros: canal, status, paymentStatus, rango de fechas
- Crear nueva orden: seleccion de cliente, agregar items (SKU + cantidad + precio automatico segun canal), calculo automatico de IGV
- Vista detalle de orden: items, totales, timeline de status, historial de pagos
- Boton "Registrar pago" (parcial o total)
- Al confirmar una orden, generar automaticamente los inventory_movements negativos
- Dashboard de cobranza: ordenes pendientes de pago, agrupadas por cliente, con dias de mora
### 4. `/customers` — Clientes
- CRUD de clientes con tipo (retail/wholesale/distributor)
- Vista detalle: datos del cliente + historial de ordenes + saldo pendiente + dias promedio de pago
- Alerta de clientes con saldo vencido
### 5. `/expenses` — Gastos
- Tabla de gastos con filtros: categoria, tipo (fijo/variable), rango de fechas
- Crear/editar gasto
- Vista de gastos fijos recurrentes con comparacion vs presupuesto (PEN 6,094/mes)
- Grafico de gastos por categoria (donut) y tendencia mensual (barras)
### 6. `/purchases` — Importaciones / Compras
- Tabla de compras/importaciones con status
- Crear nueva importacion: datos FOB, flete, seguro, tipo de cambio → calculo automatico de CIF, arancel, IGV, landed cost
- Al completar, generar inventory_movements de entrada
- Vista detalle con desglose completo de costos de importacion
### 7. `/regulatory` — Seguimiento DIGEMID / NSO
- Timeline visual del estado de cada expediente NSO
- Crear/actualizar expedientes
- Alertas de expedientes con observaciones pendientes
- Countdown al tiempo estimado de resolucion
### 8. `/reports` — Reportes
- P&L mensual (formato del modelo: ingresos - landed cost - comisiones - marketing - empaque = margen contribucion - fijos = EBITDA)
- Comparativo real vs escenarios (conservador/medio/agresivo del modelo)
- Reporte de cuentas por cobrar aging (0-15, 16-30, 31-60, 60+ dias)
- Reporte de inventario valorizado
- Mix de ventas por canal vs target
- Exportar cualquier reporte a CSV
### 9. `/settings` — Configuracion
- Editar parametros del sistema (tipo de cambio, tasas, datos de empresa)
- Gestion de usuarios (via Clerk)
---
## REGLAS DE NEGOCIO (implementar como validaciones)
1. **IGV siempre es 18%** sobre subtotal en todas las ventas
2. **No vender SKUs inactivos** o con stock 0
3. **Precios automaticos por canal:** al crear una orden, autorellenar precio segun canal del cliente
4. **Dias de credito por tipo de cliente:** D2C = 0, Mayorista = 15, Distribuidor = 30
5. **Alerta automatica** cuando un SKU tiene <30 dias de cobertura
6. **Al confirmar orden** → descontar inventario automaticamente
7. **Al cancelar orden** → revertir inventario automaticamente
8. **Break-even line** siempre visible en graficos de ventas (PEN 10,223/mes)
9. **Tipo de cambio configurable** — todos los montos en USD se calculan dinamicamente
10. **Merma del 2%** se aplica en calculo de landed cost
---
## REQUISITOS TECNICOS
1. **Autenticacion obligatoria** en todas las rutas excepto login
2. **Responsive design** — funcional en movil (Renato lo usa desde el telefono frecuentemente)
3. **Server Actions** para todas las mutaciones (no API routes)
4. **Optimistic updates** en tablas para UX fluida
5. **Loading states** con skeletons de shadcn
6. **Error boundaries** por seccion
7. **Seed script** (`npm run db:seed`) que cargue los 64 SKUs activos con su inventario inicial de 18,432 unidades
8. **Migraciones** con Drizzle Kit (`npm run db:push` / `npm run db:migrate`)
9. **Validacion de formularios** con Zod
10. **Paginacion** en todas las tablas (20 items por pagina)
11. **Dark mode** toggle (default dark)
---
## SEED DATA
El seed script debe cargar:
1. Los 64 SKUs activos con sus datos completos (codigo, nombre, marca inspiracion, perfume original, linea, genero, precios por canal, costos)
2. Los inventory_movements iniciales: 288 unidades por SKU (12 cajas x 24 un/caja)
3. Los settings iniciales del sistema
4. Las categorias de gasto fijo con sus montos mensuales presupuestados
### SKUs a cargar (todos con 12 cajas = 288 unidades):
**Linea Arabe (7 SKUs, costo fabrica PEN 5.75, landed PEN 8.54):**
102-Oud Cavaliere (Roberto Cavalli/Oud Edition/F), 108-Oud Woods (Tom Ford/Oud Wood/U), 115-Royal Night (D&G/The One Royal Night/U), 118-Pure (Xerjoff/Erba Pura Sospiro/M), 121-Scenta (Xerjoff/Accento Sospiro/M), 119-Boss Oud (Hugo Boss/Boss Bottled Oud/M), 105-Oud Wild (Roberto Cavalli/Tiger Oud/U)
**Linea Francesa (57 SKUs, costo fabrica PEN 3.50, landed PEN 5.67):**
053-White Mountain, 273-Absolute Avenger, 029-Avenger for Men, 221-Treasure, 205-Ultra Man, 073-Legendary, 163-Y, 017-2 N2 Sexy for Men, 018-VIP for Women, 022-Adorable for Women, 048-Mambu, 021-White Coast for Men, 011-Millionaire for Men, 020-Crystelle for Women, 059-Aqua di Givany, 036-See for Women, 355-Hunted, 276-Her, 032-Aphrodite Gold, 100-Sentiment, 078-Good Lady Red, 079-Good Boy, 080-Good Lady, 082-VIP Rose, 085-VIP Black, 002-One Chance, 026-Demoiselle, 189-Blue Parfum, 025-Blue Canal for Men, 035-Fire N' Heat, 057-Souvenir, 258-Devot, 207-Wild Desire, 016-Magnetic, 245-Strong Feelings Oud, 247-Strong Feelings Amber, 249-Strong, 234-Le Parfum, 238-By Night, 040-La Belle, 023-Infectious for Men, 039-The Excess, 167-One Private, 169-Lucky, 044-Millionaire, 278-Paradise, 013-Into the Blue, 203-Dark Leather, 086-Live in Roma, 225-Hero, 042-Black Opera, 159-Urself, 286-Paris, 362-Libretto Intense, 381-[sin nombre], 232-Libretto, 157-Electric
---
## ESTRUCTURA DE ARCHIVOS ESPERADA
```
src/
app/
layout.tsx # Root layout con ClerkProvider + ThemeProvider
page.tsx # Redirect a /dashboard
sign-in/[[...sign-in]]/page.tsx
sign-up/[[...sign-up]]/page.tsx
(app)/ # Grupo con sidebar layout
layout.tsx # Sidebar + header + breadcrumbs
dashboard/page.tsx
inventory/
page.tsx
[id]/page.tsx
sales/
page.tsx
new/page.tsx
[id]/page.tsx
customers/
page.tsx
[id]/page.tsx
expenses/page.tsx
purchases/
page.tsx
new/page.tsx
[id]/page.tsx
regulatory/page.tsx
reports/page.tsx
settings/page.tsx
components/
ui/ # shadcn components
layout/
sidebar.tsx
header.tsx
dashboard/
kpi-cards.tsx
sales-chart.tsx
channel-donut.tsx
top-skus.tsx
alerts-banner.tsx
inventory/
sku-table.tsx
movement-modal.tsx
stock-indicator.tsx
sales/
order-form.tsx
order-table.tsx
payment-modal.tsx
shared/
data-table.tsx # Tabla reutilizable con sorting, filtering, pagination
currency-display.tsx # Muestra PEN y USD
date-picker.tsx
export-csv.tsx
lib/
db/
schema.ts # Drizzle schema (todas las tablas)
index.ts # DB connection
seed.ts # Seed script
actions/ # Server Actions
inventory.ts
sales.ts
customers.ts
expenses.ts
purchases.ts
regulatory.ts
settings.ts
utils/
currency.ts # Conversion PEN/USD, formateo
calculations.ts # Landed cost, margenes, break-even
validators.ts # Zod schemas
types/
index.ts # TypeScript types
drizzle.config.ts
```
---
## INSTRUCCIONES DE EJECUCION
1. Empieza creando el proyecto con `npx create-next-app@latest hernani-app --typescript --tailwind --eslint --app --src-dir`
2. Instala dependencias: `npm install drizzle-orm @neondatabase/serverless`, `npm install -D drizzle-kit`, `npx shadcn@latest init`, `npm install @clerk/nextjs`, `npm install recharts`, `npm install zod`
3. Configura Drizzle con Neon Postgres
4. Implementa el schema completo primero
5. Luego las Server Actions
6. Luego los componentes y paginas, empezando por el dashboard
7. Al final, el seed script
Construye toda la app modulo por modulo. Empieza por la infraestructura (schema, db, auth), luego dashboard, luego inventory, luego sales, y asi sucesivamente. Cada modulo debe estar completo y funcional antes de pasar al siguiente.
NO uses mocks, placeholders, ni "TODO" en el codigo. Todo debe ser funcional end-to-end.
```
---
## NOTAS DE USO
- **Donde usarlo:** Pega el prompt en un proyecto Next.js nuevo con Claude Code, Cursor, o Windsurf
- **Prerequisitos:** Tener una cuenta Vercel, un proyecto Neon Postgres creado (o usar `vercel marketplace`), y una app Clerk configurada
- **Variables de entorno necesarias:**
- `DATABASE_URL` (Neon Postgres)
- `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY`
- `CLERK_SECRET_KEY`
- `NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in`
- `NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up`