JVG Agentic Coding — UI Architecture v0.1
Prompt
Actúa como agente de desarrollo senior trabajando sobre una aplicación real existente. No estás diseñando un proyecto desde cero. Tu responsabilidad es comprender la arquitectura disponible, identificar la causa de los problemas descritos y realizar la intervención mínima que deje el sistema más coherente y mantenible. ## Contexto del proyecto Aplicación web construida con: - Next.js con App Router - React - TypeScript - Tailwind CSS - sin librerías adicionales de UI - sin librería de iconos externa La aplicación tiene varias pantallas autenticadas y un pequeño sistema de componentes compartidos. Estructura relevante: ```text app/ ├── globals.css ├── (auth)/ │ └── login/ │ └── page.tsx └── (app)/ ├── layout.tsx ├── dashboard/ │ └── page.tsx ├── patients/ │ └── [id]/ │ └── page.tsx └── sessions/ └── [id]/ └── page.tsx components/ ├── layout/ │ ├── AppShell.tsx │ └── Sidebar.tsx └── ui/ └── Button.tsx ``` ### `app/(app)/layout.tsx` ```tsx export default function AppLayout({ children, }: { children: React.ReactNode; }) { return <main className="min-h-screen bg-slate-50">{children}</main>; } ``` ### `components/layout/AppShell.tsx` ```tsx "use client"; import { useState } from "react"; import Sidebar from "./Sidebar"; export default function AppShell({ children, }: { children: React.ReactNode; }) { const [open, setOpen] = useState(false); return ( <div className="flex min-h-screen"> {open && <Sidebar />} <div className="flex-1"> <button onClick={() => setOpen(!open)} className="m-4 rounded-lg bg-violet-600 px-4 py-2 text-white" > Menu </button> {children} </div> </div> ); } ``` ### `components/layout/Sidebar.tsx` ```tsx import Link from "next/link"; export default function Sidebar() { return ( <aside className="w-64 bg-slate-950 p-4 text-white"> <nav className="space-y-2"> <Link href="/dashboard">Dashboard</Link> <Link href="/patients/1">Patients</Link> </nav> </aside> ); } ``` ### `components/ui/Button.tsx` ```tsx import type { ButtonHTMLAttributes } from "react"; type Props = ButtonHTMLAttributes<HTMLButtonElement> & { variant?: "primary" | "secondary"; }; export function Button({ variant = "primary", className = "", ...props }: Props) { const styles = variant === "primary" ? "bg-violet-600 text-white hover:bg-violet-700" : "border border-slate-300 bg-white text-slate-900 hover:bg-slate-50"; return ( <button className={`rounded-lg px-4 py-2 font-medium ${styles} ${className}`} {...props} /> ); } ``` ### `app/(app)/dashboard/page.tsx` ```tsx import AppShell from "@/components/layout/AppShell"; import { Button } from "@/components/ui/Button"; export default function DashboardPage() { return ( <AppShell> <section className="p-6"> <h1 className="text-2xl font-semibold">Dashboard</h1> <Button className="mt-4">Nueva sesión</Button> </section> </AppShell> ); } ``` ### `app/(app)/patients/[id]/page.tsx` ```tsx export default function PatientPage() { return ( <section className="p-6"> <h1 className="text-2xl font-semibold">Paciente</h1> <button className="mt-4 rounded-md bg-purple-600 px-5 py-2 text-white"> Iniciar sesión </button> </section> ); } ``` ### `app/(app)/sessions/[id]/page.tsx` ```tsx import Sidebar from "@/components/layout/Sidebar"; export default function SessionPage() { return ( <div className="flex min-h-screen"> <Sidebar /> <section className="flex-1 p-6"> <h1 className="text-2xl font-semibold">Sesión activa</h1> <button className="mt-4 rounded-xl bg-violet-500 px-4 py-2 text-white"> Finalizar sesión </button> </section> </div> ); } ``` ### `app/globals.css` ```css @import "tailwindcss"; :root { --color-primary: #7c3aed; --color-primary-hover: #6d28d9; --radius-control: 0.5rem; } ``` --- # Objetivo Queremos mejorar la coherencia estructural y visual de la aplicación. Actualmente: 1. algunas pantallas tienen sidebar y otras no; 2. algunas crean su propio sidebar; 3. `DashboardPage` introduce `AppShell` localmente en vez de existir una arquitectura común; 4. existen botones visualmente equivalentes implementados de tres maneras distintas; 5. los colores y radios están hardcodeados a pesar de existir tokens globales; 6. el comportamiento en móvil de la navegación no está bien resuelto; 7. modificar visualmente un botón obliga actualmente a buscar implementaciones duplicadas. Queremos que **todas las pantallas autenticadas compartan el mismo shell de aplicación**, mientras que `/login` debe permanecer fuera de él. La sidebar debe: - estar disponible en todas las pantallas autenticadas; - poder colapsarse en escritorio; - funcionar como drawer superpuesto en móvil; - cerrarse automáticamente en móvil después de navegar; - poder cerrarse con `Escape`; - mantener navegación accesible mediante teclado; - no provocar que cada página implemente su propia navegación. Además, todos los botones estándar de la aplicación deben usar `Button`. Si cambiamos posteriormente el color principal o el radio de los controles, el cambio debe propagarse desde una única fuente de verdad. --- # Restricciones Debes respetarlas todas. 1. No añadas dependencias. 2. No cambies las rutas existentes. 3. No modifiques backend, base de datos, autenticación ni contratos de API. 4. No introduzcas un framework de diseño nuevo. 5. No reescribas componentes o archivos que no sea necesario modificar. 6. Reutiliza componentes existentes antes de crear otros. 7. No dupliques `Sidebar`. 8. No mantengas `AppShell` dentro de páginas individuales si existe un lugar arquitectónicamente superior donde pueda aplicarse correctamente. 9. No uses colores principales hardcodeados en los componentes finales. 10. No uses pseudocódigo ni omitas partes necesarias de la implementación. 11. No inventes funciones, paquetes, archivos o APIs que no aparezcan aquí salvo que sean estrictamente necesarios y puedas implementarlos tú mismo. 12. Si detectas algo que no puede saberse con la información disponible, declara la suposición en vez de presentarla como un hecho. 13. Evita sobreingeniería. Este cambio no justifica crear un sistema complejo de estado global. 14. Preserva el comportamiento funcional existente salvo donde los requisitos pidan explícitamente cambiarlo. 15. La solución debe ser razonablemente mantenible y accesible. --- # Qué debes hacer Analiza primero el problema y decide dónde pertenece cada responsabilidad antes de escribir código. Después proporciona una implementación completa. Presta especial atención a: - qué responsabilidad debe pertenecer al `layout`; - qué responsabilidad pertenece a `AppShell`; - qué estado es exclusivamente de presentación; - reutilización de `Button`; - desktop frente a móvil; - accesibilidad; - eliminación de duplicidades; - fuente única de verdad para los estilos compartidos. No optimices por mostrar mucho código. Optimiza por resolver correctamente el problema con el cambio estructural mínimo suficiente. --- # Formato obligatorio de respuesta Devuelve exactamente estas cinco secciones y en este orden: ## 1. Diagnóstico Explica las causas estructurales de los problemas. Máximo 8 puntos. ## 2. Plan de cambio Indica qué archivos modificarías y por qué. No incluyas archivos que no necesiten cambios. ## 3. Implementación Proporciona el contenido final completo de cada archivo modificado. Cada archivo debe comenzar con: `### ruta/del/archivo` No uses pseudocódigo. ## 4. Verificación Explica cómo verificarías: - sidebar en escritorio; - sidebar en móvil; - navegación; - cierre mediante Escape; - botones; - cambio global de color/radio; - regresiones básicas. Distingue claramente entre comprobaciones que puedes razonar a partir del código y pruebas que requerirían ejecutar realmente la aplicación. ## 5. Riesgos o supuestos Incluye únicamente riesgos o supuestos materiales. Si no existen, escribe: `Ninguno material.`