COREEB — SKILL
DIRECTIVA SUPREMA
- Frontend: Next.js (App Router).
- Arquitectura: Estructura modular organizada en 4 niveles (Routing, Modules, Global UI, Infrastructure).
- ORM: Prisma + PostgreSQL (cuando aplique).
- Entorno local: Next.js local (
next dev) and Docker para servicios. - UI: Librería
coreebexclusivamente. - Paquetes: pnpm.
- Verificación de Dependencias Previa: Antes de comenzar a escribir cualquier archivo de código, el agente DEBE revisar el archivo
package.jsonde la raíz. Si no están presentes las dependencias obligatorias (coreeb,sonner,tw-animate-css,axios), el agente debe proceder a instalarlas automáticamente mediantepnpmantes de realizar otra tarea. - Estilo de Páginas Obligatorio: Cada página, vista, formulario y sub-componente frontend generado DEBE seguir y heredar rigurosamente el sistema de diseño, la maquetación, los iconos y la estética unificada de la librería
coreebde forma obligatoria.
[!IMPORTANT] GUÍA DE ESTILOS GLOBALES (
coreebUI Base): Para proyectos desde cero, el agente debe generar una base de CSS limpia y bien documentada englobals.css(por ejemplo, implementando clases de scrollbar personalizadas como.custom-scrollbarpara las tablas, resets de diseño compatibles o utilidades específicas) para que sirva de guía y ejemplo a los desarrolladores. Sin embargo, toda esta base y cualquier estilo creado debe estar en estricta sincronía con la libreríacoreeb, heredando y respetando siempre sus tokens, variables, inputs y estructura para que actúe como una extensión natural del sistema de diseño oficial, y nunca como estilos conflictivos.
📦 INSTALACIÓN & DEPENDENCIAS (Solo para Proyectos desde Cero)
pnpm add coreeb sonner tw-animate-css axios
pnpm add @prisma/client
pnpm add -D prisma tsx @types/node
pnpm dlx prisma init --datasource-provider postgresql
ESTRUCTURA DE DIRECTORIOS
El proyecto sigue una estructura organizada en 4 niveles de abstracción (no hay directorios
API/niViews/).
Estructura de carpetas (OBLIGATORIA)
nombre-proyecto/
│
├── pnpm-workspace.yaml # pnpm v11 config (approved build scripts)
├── next.config.ts
├── tsconfig.json # Alias @/* → ./src/*
├── tailwind / postcss config
│
└── src/
│
├── app/ # ── LEVEL 1: Routing (Next.js App Router) ──
│ ├── layout.tsx # Root HTML shell · Montserrat + Open Sans fonts
│ ├── page.tsx # Redirect → /dashboard
│ ├── globals.css # Color tokens + global typography
│ │
│ └── (pages)/ # Route group (does not affect URLs)
│ ├── layout.tsx # App shell: Sidebar + Header + <main>
│ │
│ ├── dashboard/
│ │ └── page.tsx
│ │
│ └── [modulo]/ # Ejemplo de ruta modular
│ ├── page.tsx
│ ├── create/page.tsx
│ └── [id]/
│ ├── page.tsx
│ └── edit/page.tsx
│
├── modules/ # ── LEVEL 2: Business logic per module ──
│ │
│ │ Pattern uniforme dentro de cada módulo:
│ │ └── [module]/
│ │ └── [action]/ list · create · detail · edit
│ │ ├── screens/ Full view (imported by page.tsx)
│ │ ├── components/ Reusable pieces of that screen
│ │ ├── hooks/ Data fetching and local state
│ │ └── helpers/ Pure functions and formatters
│ │
│ ├── dashboard/
│ │ └── list/
│ │ ├── screens/ DashboardScreen.tsx
│ │ ├── components/
│ │ ├── hooks/
│ │ └── helpers/
│ │
│ └── [modulo]/ # Módulo de ejemplo
│ ├── list/
│ │ ├── screens/ ModuloListScreen.tsx
│ │ ├── components/
│ │ ├── hooks/
│ │ └── helpers/
│ ├── create/
│ │ ├── screens/ ModuloCreateScreen.tsx
│ │ ├── components/
│ │ ├── hooks/
│ │ └── helpers/
│ ├── detail/
│ │ ├── screens/ ModuloDetailScreen.tsx
│ │ ├── components/
│ │ ├── hooks/
│ │ └── helpers/
│ └── edit/
│ ├── screens/ ModuloEditScreen.tsx
│ ├── components/
│ ├── hooks/
│ └── helpers/
│
├── components/ # ── LEVEL 3: Global shared UI ──
│ ├── Sidebar.tsx # Side navigation
│ ├── Header.tsx # Top bar: search · notifications · user
│ └── ...
│
├── hooks/ # Global hooks (auth, permissions, etc.)
├── helpers/ # Global utilities (dates, formatters, etc.)
│
└── lib/ # ── LEVEL 4: Infrastructure ──
├── types/
│ └── index.ts # Domain TypeScript types (User, Session, etc.)
├── constants/
│ └── routes.ts # All routes as typed constants
└── api/ # HTTP client and service connectors (next stage)
Reglas que nunca se rompen
- LEVEL 1: Routing (
src/app/): El enrutador solo define las páginas (page.tsx) y los layouts (layout.tsx). Cada archivopage.tsxdebe ser un contenedor delgado que importe y renderice el componente de pantalla (Screen) correspondiente de LEVEL 2. No debe haber lógica de negocio ni maquetación compleja de la interfaz en esta capa. - LEVEL 2: Modules (
src/modules/): Contiene toda la lógica de negocio, hooks locales, helpers locales y subcomponentes organizados por módulo y acción. Cada acción de un módulo (list,create,detail,edit) tiene subcarpetasscreens/,components/,hooks/yhelpers/. - LEVEL 3: Global UI (
src/components/): Contiene componentes de UI compartidos a nivel global en la aplicación (comoSidebar.tsx,Header.tsx, botones y modales genéricos). - LEVEL 4: Infrastructure (
src/lib/): Contiene los tipos compartidos de dominio (src/lib/types/), constantes de rutas (src/lib/constants/routes.ts), y la configuración de clientes HTTP y conectores a servicios (src/lib/api/). - Estructura modular: Toda la lógica está encapsulada en la estructura de 4 niveles descrita anteriormente (no se usan directorios
API/niViews/).
¿Dónde pongo esto?
| Lo que necesitas crear | Va en |
|---|---|
| Una nueva ruta/página | src/app/(pages)/[modulo]/page.tsx |
| Vista principal (Screen) de una acción | src/modules/[modulo]/[action]/screens/[ScreenName].tsx |
| Componente específico de una pantalla | src/modules/[modulo]/[action]/components/ |
| Hook específico de una acción | src/modules/[modulo]/[action]/hooks/ |
| Helper específico de una acción | src/modules/[modulo]/[action]/helpers/ |
| Componente global reutilizable | src/components/ |
| Hook global reutilizable | src/hooks/ |
| Helper global reutilizable | src/helpers/ |
| Tipos de dominio compartidos | src/lib/types/index.ts |
| Constantes de enrutamiento | src/lib/constants/routes.ts |
| Cliente HTTP o conectores a APIs | src/lib/api/ |
1. CONFIGURACIÓN DOCKER & ENTORNO
A. docker-compose.yml
services:
db:
image: postgres:16-alpine
container_name: ${COMPOSE_PROJECT_NAME:-app}_db
restart: unless-stopped
environment:
POSTGRES_USER: ${DB_USER:-postgres}
POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres}
POSTGRES_DB: ${DB_NAME:-appdb}
ports:
- "${DB_PORT:-5432}:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-appdb}"]
interval: 5s
timeout: 5s
retries: 10
volumes:
postgres_data:
B. .env
# === VARIABLES EXCLUSIVAS DE DOCKER COMPOSE ===
COMPOSE_PROJECT_NAME=coreeb_proyectos
DB_USER=postgres
DB_PASSWORD=postgres
DB_NAME=appdb
DB_PORT=5432
# === VARIABLES EXCLUSIVAS DEL PROYECTO (NEXT.JS / PRISMA) ===
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/appdb?schema=public"
NEXT_PUBLIC_COREEB_LOGIN_API= # Producción: URL del Coreeb Backend
PORT=3000
C. Scripts en package.json
"scripts": {
"dev": "docker compose up -d db && next dev",
"build": "next build",
"start": "next start",
"db:migrate": "prisma migrate dev",
"db:studio": "prisma studio"
}
2. CONFIGURACIÓN DE LIBRERÍA coreeb (UI)
A. next.config.mjs
const nextConfig = { transpilePackages: ['coreeb'] };
export default nextConfig;
B. postcss.config.mjs
const config = { plugins: { '@tailwindcss/postcss': {} } };
export default config;
C. src/app/globals.css
Esta es la importación base y obligatoria para todos los desarrollos de COREEB.
@import "tailwindcss";
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
@import "coreeb/styles.css";
/* Cualquier estilo específico del proyecto va aquí debajo */
D. src/app/layout.tsx
import './globals.css';
import { Toaster } from 'coreeb';
export const metadata = { title: 'App' };
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="es">
<head>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
</head>
<body>
{children}
<Toaster position="top-right" richColors />
</body>
</html>
);
}
E. CATÁLOGO DE COMPONENTES coreeb (Obligatorio)
Para que el proyecto tenga una apariencia uniforme y agradable desde el inicio, todo el diseño y maquetación de vistas y formularios debe utilizar los componentes nativos de coreeb:
- General / Layout:
Icons,Button,Badge,Separator,Skeleton,Spinner,Visually Hidden,Card,Collapsible,Scroll Area,Tabs. - Formularios:
Floating Input,Floating Select,Floating Date Picker,Chip Selector,Checkbox,Form,Radio Group,Switch,Textarea,File Dropzone,Date Range Pill. - Data Display & Feedback:
Avatar,Table,Sonner (Toast)(Toaster),Tooltip. - Overlay:
Command,Dialog,Dropdown Menu,Popover,Sheet.
Nota: La interfaz debe crearse inicialmente al 100% usando estos componentes. La navegación general y la distribución de paneles de cada vista debe estar perfectamente coordinada con el estilo de pestañas de la aplicación, utilizando los componentes Tabs y Sheet de la librería de forma estricta. Cambios o personalizaciones se aplican después a petición del desarrollador.
3. AUTENTICACIÓN — INTEGRACIÓN CON COREEB AUTH SERVICE
[!IMPORTANT] REGLA CRÍTICA: Todo proyecto generado con esta skill DEBE conectar su sistema de login al Coreeb Auth Service centralizado (backend Express independiente). El frontend NUNCA maneja autenticación propia, encriptación de contraseñas ni base de datos de usuarios directamente. Solo consume el Auth Service mediante API.
A. Variable de Entorno Obligatoria (.env)
Agregar al .env del proyecto:
NEXT_PUBLIC_COREEB_LOGIN_API= # Producción: URL del Coreeb Backend
La URL real del Auth Service se configura aquí. Nunca hardcodear URLs en el código.
B. src/lib/api/apiClient.ts — Cliente HTTP centralizado
import axios from 'axios';
const BASE_URL = process.env.NEXT_PUBLIC_COREEB_LOGIN_API!;
const api = axios.create({ baseURL: BASE_URL });
api.interceptors.request.use((config) => {
const token = typeof window !== 'undefined' ? localStorage.getItem('accessToken') : null;
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
});
const AUTH_SKIP_REFRESH = ['/auth/login', '/auth/refresh', '/auth/reset-password'];
api.interceptors.response.use(
(res) => res,
async (error) => {
const url: string = error.config?.url ?? '';
const isAuthRoute = AUTH_SKIP_REFRESH.some((p) => url.includes(p));
if (error.response?.status === 401 && !isAuthRoute) {
const refreshToken = localStorage.getItem('refreshToken');
if (!refreshToken) {
localStorage.clear();
window.location.href = '/';
return Promise.reject(error);
}
try {
const { data } = await axios.post(`${BASE_URL}/auth/refresh`, { refreshToken });
localStorage.setItem('accessToken', data.data.accessToken);
localStorage.setItem('refreshToken', data.data.refreshToken);
error.config.headers.Authorization = `Bearer ${data.data.accessToken}`;
return api.request(error.config);
} catch {
localStorage.clear();
window.location.href = '/';
}
}
return Promise.reject(error);
}
);
export default api;
C. src/lib/api/authService.ts
import api from '@/lib/api/apiClient';
export interface User {
id: string;
email: string;
firstName: string;
lastName: string;
isActive: boolean;
createdAt: string;
updatedAt: string;
}
interface LoginResponse {
accessToken: string;
refreshToken: string;
user: User;
}
export const authService = {
login: async (email: string, password: string): Promise<LoginResponse> => {
const { data } = await api.post('/auth/login', { email, password });
return data.data;
},
me: async (): Promise<User> => {
const { data } = await api.get('/auth/me');
return data.data;
},
requestReset: async (email: string): Promise<{ resetToken: string }> => {
const { data } = await api.post('/auth/reset-password/request', { email });
return data.data;
},
confirmReset: async (token: string, newPassword: string): Promise<void> => {
await api.post('/auth/reset-password/confirm', { token, newPassword });
},
};
D. Reglas de integración (NO negociables)
- La URL del Auth Service siempre viene de
NEXT_PUBLIC_COREEB_LOGIN_API— nunca hardcodeada en el código. - Los tokens (
accessToken,refreshToken,user) se almacenan enlocalStoragetras un login exitoso. - El interceptor de Axios auto-refresca el
accessTokenen cualquier 401, excepto en rutas de auth. - Las rutas
/auth/login,/auth/refreshy/auth/reset-passwordestán enAUTH_SKIP_REFRESH— no disparan el refresco automático para evitar bucles infinitos. - Toda pantalla protegida debe verificar
localStorage.getItem('accessToken')enuseEffecty redirigir a/si no existe. - El diseño del formulario de login y cualquier pantalla de autenticación queda USANDO LA LIBRERIA DE COREEB. Solo es obligatorio que la conexión al Auth Service use
apiClient.tsyauthService.ts. - Toda creación, actualización, desactivación o activación de usuarios debe pasar siempre por el Coreeb Auth Service — nunca manejar usuarios directamente en el frontend ni en otros backends.
5. Checklist de Cumplimiento
- Estructura modular de 4 niveles (Routing, Modules, Global UI, Infrastructure) implementada.
- Las rutas de la aplicación en
src/app/son delgadas e importan/renderizan los componentes de pantalla desdesrc/modules/[module]/[action]/screens/. - La interfaz está construida exclusivamente con componentes e iconos de la librería coreeb.
-
NEXT_PUBLIC_COREEB_LOGIN_APIdefinida en.envapuntando al Coreeb Auth Service. -
apiClient.tsensrc/lib/api/apiClient.tsconfigurado con interceptores de token y auto-refresco, usandoAUTH_SKIP_REFRESH. -
authService.tsensrc/lib/api/authService.tsimplementado conlogin,me,requestReset,confirmReset. - Formulario de login llama a
authService.loginy guarda los tokens enlocalStorage. - Rutas protegidas verifican
accessTokenenlocalStoragey redirigen a/si no existe.