frontend/ directory. It uses the App Router with route groups to separate unauthenticated and authenticated layouts, and communicates with the Express API through a typed services layer.
Tech stack
| Technology | Version | Role |
|---|---|---|
| Next.js | 15 | React framework / App Router |
| React | 19 | UI rendering |
| Tailwind CSS | 3 | Utility-first styling |
| shadcn/ui | — | Owned component library |
| Zustand | 5 | Client-side state management |
| Axios | — | HTTP client |
| Zod | — | Schema validation |
| React Hook Form | — | Form state and submission |
Source directory structure
App Router layout
Next.js route groups (folders wrapped in parentheses) split the application into two layout trees without affecting the URL structure.(auth) group
Contains /login and /register. The (auth)/layout.js renders a minimal centered layout with no navigation chrome. Unauthenticated users land here.
(dashboard) group
Contains all protected pages: /dashboard, /projects, /tasks, /users, and /admin. The (dashboard)/layout.js renders the persistent sidebar and top bar. Pages in this group read authentication state from the Zustand store and redirect to /login if isLogged is false.
Route groups are a Next.js convention. The parentheses in
(auth) and (dashboard) are not part of the URL — /login and /dashboard are the actual paths.Services layer
Every API resource has a dedicated service file insrc/services/. Each file exports async functions that call the shared Axios instance. No page or component calls Axios directly.
| Service file | Backend module | Responsible for |
|---|---|---|
auth.services.js | auth/ | Login and registration |
proyectos.service.js | proyectos/ | Project CRUD + task creation |
tareas.service.js | tareas/ | Task operations for assigned users |
usuarios.service.js | usuarios/ | User search and management |
admin.service.js | tareas/ (admin endpoints) | Admin-scoped task operations |
Custom hooks
Data-fetching logic lives insrc/hooks/ rather than directly in page components. Each hook wraps one or more service calls, manages loading and error state, and returns a refetch function to trigger revalidation.
Zustand auth store
Client-side authentication state is managed insrc/store/authStore.js using Zustand with the persist middleware.
localStorage under the key auth-storage, so the session survives a page refresh. The Axios instance reads token from the store (or directly from localStorage) to attach the Authorization header on every request.
Zod validation
Each form uses a Zod schema to validate input before submission. The schemas mirror the validation rules enforced by the backend validators, so error feedback is consistent whether the error is caught client-side or returned by the API. Zod schemas are used with React Hook Form’szodResolver, which integrates schema validation into the form’s submit and change handlers and surfaces field-level errors in real time.
shadcn/ui components
UI primitives (Button, Input, Dialog, Select, etc.) live insrc/components/ui/. These files are part of the project — they are not an external dependency that is imported from node_modules. This means:
- Components can be modified freely without a library upgrade.
- There is no version mismatch between the component source and the installed package.
- New primitives can be added using the shadcn CLI (
npx shadcn add <component>), which copies the source intosrc/components/ui/.
Proyectos/, TareaCard/, ColumnasTareas/, sidebar/) compose the shadcn primitives.
Related pages
Architecture overview
How the frontend and backend fit together, CORS setup, and the authentication flow.
Backend architecture
Domain-driven module structure, middleware pipeline, Knex.js migrations, and logging.