siesa-agents 2.1.71 → 2.1.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "siesa-agents",
3
- "version": "2.1.71",
3
+ "version": "2.1.72",
4
4
  "description": "Paquete para instalar y configurar agentes SIESA en tu proyecto",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -30,7 +30,42 @@ Output to the user:
30
30
 
31
31
  ---
32
32
 
33
- ## 2. MANDATORY RULE PHASE COMMIT AT WORKFLOW END
33
+ ## 2. INITIALIZATIONCHECK FOR EXISTING UX DESIGN DOCUMENT
34
+
35
+ Before executing any workflow step, search for an existing UX design document:
36
+
37
+ 1. Look for a file matching `*ux-design-specification*.md` inside the `{planning_artifacts}/` folder.
38
+ - Glob pattern to check: `{planning_artifacts}/*ux-design-specification*.md`
39
+
40
+ ---
41
+
42
+ ## 3. DECISION BRANCH
43
+
44
+ ### If `ux-design-specification.md` EXISTS
45
+
46
+ Use the **AskUserQuestion** tool to present the following options (respect `communication_language` from config):
47
+
48
+ > Se encontró un documento de especificación UX/UI existente en `{planning_artifacts}/ux-design-specification.md`.
49
+ >
50
+ > ¿Qué deseas hacer?
51
+ >
52
+ > **[1] Editar** — Abrir el documento para revisarlo y modificarlo de forma colaborativa.
53
+ > **[2] Resumen** — Generar un resumen ejecutivo del documento actual.
54
+
55
+ Wait for the user's selection and act accordingly:
56
+
57
+ - **Option 1 — Edit:** Read the full contents of `{planning_artifacts}/ux-design-specification.md`, present it to the user section by section, and facilitate collaborative editing. Apply changes directly to the file using the Edit tool.
58
+ - **Option 2 — Summary:** Read the full contents of `{planning_artifacts}/ux-design-specification.md` and produce a concise executive summary covering: design vision, target users, design system decisions, visual foundations, component strategy, and any open design questions.
59
+
60
+ ---
61
+
62
+ ### If `ux-design-specification.md` does NOT EXIST
63
+
64
+ LOAD the FULL `@_bmad/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md`, READ its entire contents and follow its directions exactly!
65
+
66
+ ---
67
+
68
+ ## 4. MANDATORY RULE — PHASE COMMIT AT WORKFLOW END
34
69
 
35
70
  **TRIGGER:** Immediately after all workflow steps complete and the UX Design document has been generated/saved.
36
71
 
@@ -39,6 +39,8 @@ Before doing anything else, search for an existing architecture document:
39
39
 
40
40
  ### If `architecture.md` EXISTS
41
41
 
42
+ Use the **AskUserQuestion** tool to present the following options:
43
+
42
44
  Present the user with the following options (respect `communication_language` from config):
43
45
 
44
46
  > Se encontró un documento de arquitectura existente en `{planning_artifacts}/architecture.md`.
@@ -1,3 +1,45 @@
1
+ # REGLA OBLIGATORIA: MENÚ DE INICIO
2
+
3
+ **TRIGGER:** Al inicio del modo `interactive`, **antes del Step 1**.
4
+
5
+ Invocar `AskUserQuestion` con la siguiente configuración:
6
+
7
+ ```json
8
+ {
9
+ "questions": [
10
+ {
11
+ "question": "¿Qué deseas ejecutar?",
12
+ "header": "Modo",
13
+ "multiSelect": false,
14
+ "options": [
15
+ {
16
+ "label": "Sprint Status + Retrospective",
17
+ "description": "Ejecuta el resumen del sprint y encadena automáticamente con el workflow de Retrospective al finalizar."
18
+ },
19
+ {
20
+ "label": "Solo Sprint Status",
21
+ "description": "Ejecuta únicamente el resumen del sprint sin encadenar con Retrospective."
22
+ }
23
+ ]
24
+ }
25
+ ]
26
+ }
27
+ ```
28
+
29
+ - Si elige `Sprint Status + Retrospective`: guardar `run_retrospective = true`
30
+ - Si elige `Solo Sprint Status`: guardar `run_retrospective = false`
31
+
32
+ **Al finalizar el Step 5** (después de que el usuario elija su acción), si `run_retrospective == true`:
33
+
34
+ ```
35
+ ---
36
+ ➡️ Encadenando con Retrospective tal como seleccionaste al inicio...
37
+ ```
38
+
39
+ Luego invocar `/bmad:bmm:workflows:retrospective`.
40
+
41
+ ---
42
+
1
43
  # REGLA OBLIGATORIA: SPRINT-STATUS CON SINCRONIZACIÓN DE FEATURE-STATUS
2
44
 
3
45
  **TRIGGER:** Cada vez que se ejecute `/sprint-status`.
@@ -43,6 +43,13 @@ Copy the file `@_siesa-agents/resources/architecture/architecture-both.md ` to `
43
43
  - Do not modify the file contents — copy as-is.
44
44
  - After copying, confirm the file exists at the destination.
45
45
 
46
+ Create base UX/UI specifications
47
+ Copy the file `@_siesa-agents/resources/ux-ui/ux-design-specification.md` to `{planning_artifacts}/ux-design-specification.md.md`.
48
+
49
+ - If the destination directory does not exist, create it first.
50
+ - Do not modify the file contents — copy as-is.
51
+ - After copying, confirm the file exists at the destination.
52
+
46
53
  Check and clone Frontend:
47
54
  ```bash
48
55
  # Only run if apps/Frontend does NOT exist
@@ -0,0 +1,837 @@
1
+ ---
2
+ type: base-ux-design-specification.md
3
+ status: base
4
+ note: >
5
+ This document was automatically generated during siesa-agents installation.
6
+ It represents the Siesa corporate base UX/UI specification applicable to all frontend projects.
7
+ It can be extended with the /create-ux-design workflow for project-specific decisions.
8
+ ---
9
+
10
+ # UX/UI Specification Document — Siesa Corporate Base
11
+
12
+ _This document establishes the mandatory UX/UI decisions for all Siesa frontend projects. It serves as the source of truth for consistent, accessible, and brand-aligned user interfaces._
13
+
14
+ ---
15
+
16
+ ## 1. Design System Foundation
17
+
18
+ ### 1.1 Color Palette
19
+
20
+ #### Brand Colors
21
+
22
+ | Token | Value | Usage |
23
+ |-------|-------|-------|
24
+ | `--color-primary-600` | `#0e79fd` | Main brand color — CTAs, links, focus |
25
+ | `--color-secondary-950` | `#000000` | Brand secondary — NOT for backgrounds or grays |
26
+ | `--color-tertiary-800` | `#154ca9` | Brand tertiary — Secondary actions, accents |
27
+
28
+ #### Full Primary Scale
29
+
30
+ ```css
31
+ :root {
32
+ --color-primary-50: #f7fcff;
33
+ --color-primary-100: #dbeefe;
34
+ --color-primary-200: #bfe2fe;
35
+ --color-primary-300: #93d1fd;
36
+ --color-primary-400: #60b6fa;
37
+ --color-primary-500: #3c9bf6;
38
+ --color-primary-600: #0e79fd; /* Main Primary */
39
+ --color-primary-700: #0f6ae3;
40
+ --color-primary-800: #1355b7;
41
+ --color-primary-900: #154990;
42
+ --color-primary-950: #112d57;
43
+ }
44
+ ```
45
+
46
+ #### Full Secondary Scale (Brand, NOT Neutrals)
47
+
48
+ ```css
49
+ :root {
50
+ --color-secondary-50: #f6f6f6;
51
+ --color-secondary-100: #e7e7e7;
52
+ --color-secondary-200: #d1d1d1;
53
+ --color-secondary-300: #b0b0b0;
54
+ --color-secondary-400: #888888;
55
+ --color-secondary-500: #6d6d6d;
56
+ --color-secondary-600: #5d5d5d;
57
+ --color-secondary-700: #4f4f4f;
58
+ --color-secondary-800: #454545;
59
+ --color-secondary-900: #3d3d3d;
60
+ --color-secondary-950: #000000; /* Main Secondary */
61
+ }
62
+ ```
63
+
64
+ #### Full Tertiary Scale
65
+
66
+ ```css
67
+ :root {
68
+ --color-tertiary-50: #eef8ff;
69
+ --color-tertiary-100: #d9efff;
70
+ --color-tertiary-200: #bce4ff;
71
+ --color-tertiary-300: #8ed4ff;
72
+ --color-tertiary-400: #58bbff;
73
+ --color-tertiary-500: #329cff;
74
+ --color-tertiary-600: #1b7df5;
75
+ --color-tertiary-700: #1465e1;
76
+ --color-tertiary-800: #154ca9; /* Main Tertiary */
77
+ --color-tertiary-900: #19478f;
78
+ --color-tertiary-950: #051938;
79
+ }
80
+ ```
81
+
82
+ #### Semantic Colors
83
+
84
+ | Color | Tailwind | Usage |
85
+ |-------|----------|-------|
86
+ | Success | `green.500` | Confirmations, active states |
87
+ | Warning | `amber.500` | Alerts, cautions |
88
+ | Error | `red.500` | Errors, destructive actions |
89
+ | Info | `cyan.500` | Informational messages |
90
+ | Neutral | `slate.*` | Backgrounds, borders, text — NEVER use secondary brand for this |
91
+
92
+ #### Surfaces & Backgrounds
93
+
94
+ ```css
95
+ :root {
96
+ /* Light Theme */
97
+ --color-background: theme('colors.white');
98
+ --color-surface: theme('colors.slate.50');
99
+ --color-surface-secondary: theme('colors.slate.100');
100
+ --color-border: theme('colors.slate.200');
101
+ --color-border-secondary: theme('colors.slate.300');
102
+
103
+ /* Dark Theme */
104
+ --color-background-dark: theme('colors.slate.950');
105
+ --color-surface-dark: theme('colors.slate.900');
106
+ --color-surface-secondary-dark: theme('colors.slate.800');
107
+ --color-border-dark: theme('colors.slate.700');
108
+ --color-border-secondary-dark: theme('colors.slate.600');
109
+ }
110
+ ```
111
+
112
+ #### Tailwind Config Extension
113
+
114
+ ```javascript
115
+ // tailwind.config.js
116
+ module.exports = {
117
+ darkMode: 'class',
118
+ theme: {
119
+ extend: {
120
+ colors: {
121
+ primary: {
122
+ 50: '#f7fcff', 100: '#dbeefe', 200: '#bfe2fe', 300: '#93d1fd',
123
+ 400: '#60b6fa', 500: '#3c9bf6', 600: '#0e79fd', 700: '#0f6ae3',
124
+ 800: '#1355b7', 900: '#154990', 950: '#112d57',
125
+ },
126
+ secondary: {
127
+ 50: '#f6f6f6', 100: '#e7e7e7', 200: '#d1d1d1', 300: '#b0b0b0',
128
+ 400: '#888888', 500: '#6d6d6d', 600: '#5d5d5d', 700: '#4f4f4f',
129
+ 800: '#454545', 900: '#3d3d3d', 950: '#000000',
130
+ },
131
+ tertiary: {
132
+ 50: '#eef8ff', 100: '#d9efff', 200: '#bce4ff', 300: '#8ed4ff',
133
+ 400: '#58bbff', 500: '#329cff', 600: '#1b7df5', 700: '#1465e1',
134
+ 800: '#154ca9', 900: '#19478f', 950: '#051938',
135
+ },
136
+ },
137
+ },
138
+ },
139
+ };
140
+ ```
141
+
142
+ ---
143
+
144
+ ### 1.2 Typography
145
+
146
+ #### Font Family
147
+
148
+ ```css
149
+ :root {
150
+ --font-primary: 'Inter_18pt-Regular', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
151
+ --font-light: 'Inter_18pt-Light', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
152
+ --font-bold: 'Inter_18pt-Bold', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
153
+ --font-mono: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
154
+ }
155
+ ```
156
+
157
+ **Font files (3 weights only):**
158
+
159
+ | Weight | File | CSS Variable |
160
+ |--------|------|--------------|
161
+ | Light (300) | `Inter_18pt-Light.ttf` | `--font-light` |
162
+ | Regular (400) | `Inter_18pt-Regular.ttf` | `--font-primary` |
163
+ | Bold (700) | `Inter_18pt-Bold.ttf` | `--font-bold` |
164
+
165
+ > **Rule:** There are only 3 physical font weights. All Tailwind weight values `medium`, `semibold`, `extrabold`, `black` resolve to the Bold file (700).
166
+
167
+ #### Typographic Scale
168
+
169
+ | Element | Tailwind Classes |
170
+ |---------|-----------------|
171
+ | H1 | `text-4xl font-bold leading-tight tracking-tight` |
172
+ | H2 | `text-3xl font-bold leading-tight tracking-tight` |
173
+ | H3 | `text-2xl font-semibold leading-snug tracking-tight` |
174
+ | H4 | `text-xl font-semibold leading-snug` |
175
+ | H5 | `text-lg font-medium leading-normal` |
176
+ | H6 | `text-base font-medium leading-normal` |
177
+ | Body | `text-base font-normal leading-relaxed` |
178
+ | Body Large | `text-lg font-normal leading-relaxed` |
179
+ | Body Small | `text-sm font-normal leading-normal` |
180
+ | Caption | `text-xs font-light leading-normal` |
181
+ | Label | `text-sm font-medium leading-normal` |
182
+ | Button Primary | `text-base font-semibold leading-none` |
183
+ | Button Secondary | `text-sm font-medium leading-none` |
184
+ | Link | `text-base font-normal leading-normal` |
185
+ | Code | `text-sm font-normal leading-normal font-mono` |
186
+ | Badge | `text-xs font-semibold leading-none` |
187
+ | Tooltip | `text-sm font-normal leading-snug` |
188
+
189
+ **Constraints:**
190
+ - Minimum font size: `16px` (browser default, never go below)
191
+ - Maximum line length: `75ch`
192
+ - One single `<h1>` per page, headings in descending order
193
+
194
+ ---
195
+
196
+ ### 1.3 Dark Mode
197
+
198
+ | Aspect | Value |
199
+ |--------|-------|
200
+ | Method | Tailwind `class` strategy |
201
+ | Selector | `html` element (root) |
202
+ | Framework | `next-themes` (SSR-safe) |
203
+ | Default | System preference (`system`) |
204
+
205
+ #### Standard Dark Mode Class Pairs
206
+
207
+ ```yaml
208
+ text_colors:
209
+ primary: "text-zinc-900 dark:text-zinc-50"
210
+ secondary: "text-gray-700 dark:text-gray-300"
211
+ muted: "text-gray-500 dark:text-gray-400"
212
+ disabled: "text-gray-400 dark:text-gray-600"
213
+
214
+ brand_colors:
215
+ primary: "text-primary-600 dark:text-primary-400"
216
+ secondary: "text-secondary-950 dark:text-slate-50"
217
+ tertiary: "text-tertiary-800 dark:text-tertiary-400"
218
+
219
+ surfaces:
220
+ page: "bg-white dark:bg-slate-950"
221
+ card: "bg-slate-50 dark:bg-slate-900"
222
+ elevated: "bg-white dark:bg-slate-800"
223
+ input: "bg-white dark:bg-slate-900"
224
+
225
+ borders:
226
+ subtle: "border-slate-200 dark:border-slate-700"
227
+ prominent: "border-slate-300 dark:border-slate-600"
228
+ tertiary: "border-zinc-400 dark:border-zinc-400"
229
+ focus: "ring-primary-600 dark:ring-primary-400"
230
+
231
+ buttons:
232
+ primary: "bg-primary-600 text-white hover:bg-primary-700 dark:bg-primary-600 dark:hover:bg-primary-500"
233
+ secondary: "bg-slate-200 text-slate-900 hover:bg-slate-300 dark:bg-slate-700 dark:text-slate-100 dark:hover:bg-slate-600"
234
+ ghost: "text-slate-700 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-800"
235
+
236
+ navigation:
237
+ navbar: "bg-white border-slate-200 dark:bg-slate-900 dark:border-slate-700"
238
+ sidebar: "bg-slate-50 border-slate-200 dark:bg-slate-900 dark:border-slate-700"
239
+ active: "bg-primary-50 text-primary-700 border-primary-200 dark:bg-primary-950 dark:text-primary-300 dark:border-primary-800"
240
+
241
+ feedback:
242
+ success: "bg-green-50 text-green-800 border-green-200 dark:bg-green-950 dark:text-green-300 dark:border-green-800"
243
+ warning: "bg-amber-50 text-amber-800 border-amber-200 dark:bg-amber-950 dark:text-amber-300 dark:border-amber-800"
244
+ error: "bg-red-50 text-red-800 border-red-200 dark:bg-red-950 dark:text-red-300 dark:border-red-800"
245
+ ```
246
+
247
+ ---
248
+
249
+ ## 2. Component Library
250
+
251
+ ### 2.1 Component Selection Priority
252
+
253
+ **MANDATORY ORDER — must be followed exactly:**
254
+
255
+ | Priority | Source | Action |
256
+ |----------|--------|--------|
257
+ | 1 | `siesa-ui-kit` (local) | Always check first — any type, any complexity |
258
+ | 2 | Component does not exist | Ask: [1] Use shadcn directly, [2] Create for siesa-ui-kit (requires MR) |
259
+ | 3 | shadcn/ui via MCP registry | Only if user explicitly chose option [1] |
260
+
261
+ > **Rule:** 90% fewer bugs using existing components vs manual creation. Never bypass this order.
262
+
263
+ ### 2.2 MasterCrud — Orchestrator Component
264
+
265
+ `MasterCrud` is the highest-level component for master data management. **All master modules MUST use it.**
266
+
267
+ ```tsx
268
+ import { MasterCrud } from '@/components/MasterCrud';
269
+ import type { MasterCrudField, CrudService } from '@/components/MasterCrud/MasterCrud.types';
270
+
271
+ <MasterCrud<Product>
272
+ title="Catálogo de Productos"
273
+ entityName="Producto"
274
+ fields={productFields}
275
+ service={productService}
276
+ />
277
+ ```
278
+
279
+ #### MasterCrud Props
280
+
281
+ | Property | Type | Default | Description |
282
+ |----------|------|---------|-------------|
283
+ | `title` | string | — | Module title (Spanish) |
284
+ | `entityName` | string | — | Entity name singular (Spanish) |
285
+ | `fields` | `MasterCrudField<T>[]` | — | Columns and form field config |
286
+ | `service` | `CrudService<T>` | — | Network operations contract |
287
+ | `idField` | `keyof T` | `'id'` | Unique identifier field |
288
+ | `pageSize` | number | `10` | Records per page |
289
+ | `navigationType` | `'modal' \| 'sidebar' \| 'page'` | — | Navigation type for form |
290
+ | `activeByCompany` | boolean | `false` | Enable multi-company selector |
291
+ | `companyRequired` | boolean | `false` | Hide "Global" option |
292
+ | `companies` | `MasterCrudCompany[]` | `[]` | Available companies |
293
+ | `showCreateButton` | boolean | `true` | Show/hide "Nuevo" button |
294
+ | `allowDelete` | boolean | `true` | Enable delete/deactivate |
295
+ | `formColumns` | `1 \| 2` | `2` | Form layout columns |
296
+ | `enableMultiSelect` | boolean | `false` | Enable row checkboxes |
297
+ | `showViewToggle` | boolean | `false` | Toggle between table and card view |
298
+ | `renderForm` | Function | — | Custom form body rendering |
299
+ | `actions` | `MasterCrudAction<T>[]` | `[]` | Extra actions per record |
300
+
301
+ #### Navigation Type Selection Guide
302
+
303
+ | Use Case | `navigationType` |
304
+ |----------|-----------------|
305
+ | Simple forms (≤ 8 fields) | `'modal'` |
306
+ | Medium forms (9–15 fields) | `'sidebar'` |
307
+ | Complex forms (16+ fields, tabs, sections) | `'page'` |
308
+
309
+ #### FieldType Reference
310
+
311
+ | Type | Visual Control | Use For |
312
+ |------|---------------|---------|
313
+ | `'text'` | Standard input | Names, codes, descriptions |
314
+ | `'number'` | Numeric input with controls | Quantities, rates, amounts |
315
+ | `'email'` | Email-validated input | Email addresses |
316
+ | `'date'` | Calendar picker (ISO format) | Dates |
317
+ | `'boolean'` | Toggle switch | Active/inactive flags |
318
+ | `'select'` | Dropdown (requires `options`) | Fixed lists |
319
+ | `'lookup'` | Async search (requires `lookupConfig`) | Master record selection |
320
+
321
+ > **Rule R-LF-001:** For master record selection, ALWAYS use `type: 'lookup'` with LookupField. Never use `type: 'select'` for data from the backend.
322
+
323
+ ### 2.3 Form Standards
324
+
325
+ | Technology | Version | Purpose |
326
+ |-----------|---------|---------|
327
+ | React Hook Form | 7.x | Form state management |
328
+ | Zod | 3.x | Schema validation |
329
+
330
+ ```typescript
331
+ // Standard form pattern
332
+ import { useForm } from 'react-hook-form';
333
+ import { zodResolver } from '@hookform/resolvers/zod';
334
+ import { z } from 'zod';
335
+
336
+ const schema = z.object({
337
+ nombre: z.string().min(1, 'El nombre es requerido'),
338
+ codigo: z.string().min(1, 'El código es requerido'),
339
+ });
340
+
341
+ const form = useForm({ resolver: zodResolver(schema) });
342
+ ```
343
+
344
+ ---
345
+
346
+ ## 3. Icons & Assets
347
+
348
+ ### 3.1 Icon Libraries
349
+
350
+ | Priority | Library | Version | Usage |
351
+ |----------|---------|---------|-------|
352
+ | Primary | Heroicons | Latest | Default for all UI icons |
353
+ | Secondary | Font Awesome | 6.5+ | When Heroicons lacks the icon |
354
+
355
+ #### Icon Sizes
356
+
357
+ | Name | Tailwind Classes | Use |
358
+ |------|-----------------|-----|
359
+ | Small | `w-4 h-4` | Inline text, badges |
360
+ | Default | `w-5 h-5` | Buttons, menu items |
361
+ | Medium | `w-6 h-6` | Section headers |
362
+ | Large | `w-8 h-8` | Feature illustrations |
363
+
364
+ #### Icon Colors
365
+
366
+ | Context | Class |
367
+ |---------|-------|
368
+ | Inherit from text | `text-current` |
369
+ | Primary brand | `text-primary-600` |
370
+ | Secondary brand | `text-secondary-600` |
371
+ | Neutral | `text-gray-500` |
372
+
373
+ ### 3.2 Logo Assets
374
+
375
+ | Variant | File | Usage |
376
+ |---------|------|-------|
377
+ | Full (blue) | `Siesa_Logosimbolo_Azul.svg` | Default header, footer |
378
+ | Full (white) | `Siesa_Logosimbolo_Blanco.svg` | Dark theme header |
379
+ | Symbol (blue) | `Siesa_Simbolo_Azul.svg` | Favicon, collapsed sidebar |
380
+ | Symbol (white) | `Siesa_Simbolo_Blanco.svg` | Dark theme favicon |
381
+
382
+ **Asset locations:**
383
+ - Build-time: `assets/images/logos/`
384
+ - Runtime public: `/images/logos/`
385
+ - Min size (full logo): `120px`
386
+ - Min size (symbol): `24px`
387
+ - Format: SVG always
388
+
389
+ ---
390
+
391
+ ## 4. Layout & Navigation Patterns
392
+
393
+ ### 4.1 App Shell Structure
394
+
395
+ ```
396
+ ┌──────────────────────────────────────────────────────┐
397
+ │ TopNav (bg-white / dark:bg-slate-900) │
398
+ │ border-b border-slate-200 / dark:border-slate-700 │
399
+ ├──────────────┬───────────────────────────────────────┤
400
+ │ │ │
401
+ │ Sidebar │ Main Content │
402
+ │ (w-64) │ (flex-1 overflow-auto p-6) │
403
+ │ │ │
404
+ │ bg-slate-50 │ bg-white / dark:bg-slate-950 │
405
+ │ dark: │ │
406
+ │ bg-slate-900│ │
407
+ │ │ │
408
+ └──────────────┴───────────────────────────────────────┘
409
+ ```
410
+
411
+ ```tsx
412
+ // Protected app layout — routes/_app.tsx
413
+ function AppLayout() {
414
+ return (
415
+ <div className="flex h-screen bg-white dark:bg-slate-950">
416
+ <Sidebar />
417
+ <div className="flex-1 flex flex-col overflow-hidden">
418
+ <TopNav />
419
+ <main className="flex-1 overflow-auto p-6">
420
+ <Outlet />
421
+ </main>
422
+ </div>
423
+ </div>
424
+ );
425
+ }
426
+ ```
427
+
428
+ ### 4.2 Route Layout Conventions (TanStack Router)
429
+
430
+ | Prefix | Effect | Example |
431
+ |--------|--------|---------|
432
+ | `_` | Pathless layout (no URL segment) | `_app.tsx` → protected layout |
433
+ | `.` | Flat routing | `orders.$id.tsx` → `/orders/:id` |
434
+ | `-` | Ignored by router (colocated files) | `-components/` |
435
+ | `$` | Dynamic parameter | `$orderId.tsx` → `:orderId` |
436
+ | `__` | Root | `__root.tsx` only |
437
+
438
+ ### 4.3 Page Structure
439
+
440
+ ```tsx
441
+ // Standard page layout
442
+ <div className="space-y-6">
443
+ {/* Page header */}
444
+ <div className="flex items-center justify-between">
445
+ <div>
446
+ <h1 className="text-2xl font-semibold text-zinc-900 dark:text-zinc-50">
447
+ {pageTitle}
448
+ </h1>
449
+ <p className="text-sm text-gray-500 dark:text-gray-400">
450
+ {pageDescription}
451
+ </p>
452
+ </div>
453
+ <div className="flex gap-2">
454
+ {/* Actions */}
455
+ </div>
456
+ </div>
457
+
458
+ {/* Page content */}
459
+ <div className="bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-slate-700">
460
+ {/* Content */}
461
+ </div>
462
+ </div>
463
+ ```
464
+
465
+ ---
466
+
467
+ ## 5. Interaction & Feedback Patterns
468
+
469
+ ### 5.1 Loading States — Skeleton Screens
470
+
471
+ | Library | Version |
472
+ |---------|---------|
473
+ | `react-loading-skeleton` | `^3.4.0` |
474
+
475
+ ```yaml
476
+ skeleton_config:
477
+ light:
478
+ base: "theme('colors.slate.200')"
479
+ highlight: "theme('colors.slate.100')"
480
+ dark:
481
+ base: "theme('colors.slate.700')"
482
+ highlight: "theme('colors.slate.600')"
483
+ border_radius: "rounded-md"
484
+ animation_duration: "1.5s"
485
+ ```
486
+
487
+ **Rule:** Always use skeleton screens (not spinners) for content placeholders. Spinners are only acceptable for action confirmation (button submit states).
488
+
489
+ ### 5.2 Toast Notifications
490
+
491
+ | Library | Placement | Stack |
492
+ |---------|-----------|-------|
493
+ | `sonner` | `bottom-right` | Max 3 visible |
494
+
495
+ ```tsx
496
+ // Standard notification messages (Spanish required)
497
+ toast.success('Datos guardados correctamente');
498
+ toast.error('No se pudo completar la operación. Intenta de nuevo.');
499
+ toast.warning('Este cambio afectará registros relacionados.');
500
+ toast.info('El proceso puede tardar unos minutos.');
501
+ ```
502
+
503
+ ### 5.3 Error States
504
+
505
+ ```tsx
506
+ // Inline field error
507
+ <p className="text-sm text-red-600 dark:text-red-400 mt-1">
508
+ {error.message}
509
+ </p>
510
+
511
+ // Error boundary fallback
512
+ <div className="flex flex-col items-center justify-center p-8 text-center">
513
+ <h2 className="text-lg font-semibold text-red-600 dark:text-red-400">
514
+ Algo salió mal
515
+ </h2>
516
+ <p className="text-sm text-gray-500 dark:text-gray-400 mt-2">
517
+ Por favor, intenta recargar la página
518
+ </p>
519
+ <Button variant="outline" className="mt-4" onClick={() => window.location.reload()}>
520
+ Recargar
521
+ </Button>
522
+ </div>
523
+ ```
524
+
525
+ ### 5.4 Empty States
526
+
527
+ ```tsx
528
+ // Empty list state
529
+ <div className="flex flex-col items-center justify-center py-12 text-center">
530
+ <IconComponent className="w-12 h-12 text-gray-300 dark:text-gray-600 mb-4" />
531
+ <h3 className="text-base font-medium text-gray-900 dark:text-gray-100">
532
+ No hay {entityNamePlural} registrados
533
+ </h3>
534
+ <p className="text-sm text-gray-500 dark:text-gray-400 mt-1">
535
+ Comienza creando el primer registro.
536
+ </p>
537
+ </div>
538
+ ```
539
+
540
+ ### 5.5 Confirmation Dialogs
541
+
542
+ - Use modal dialogs for destructive or irreversible actions
543
+ - Title must state the action explicitly: "¿Eliminar {entidad}?"
544
+ - Description must state the consequence: "Esta acción no se puede deshacer."
545
+ - Destructive button: `text-red-600` or `variant="destructive"`
546
+ - Cancel always on the left, confirm on the right
547
+
548
+ ---
549
+
550
+ ## 6. Accessibility Standards (WCAG 2.1 AA)
551
+
552
+ ### 6.1 Color Contrast
553
+
554
+ | Context | Minimum Ratio |
555
+ |---------|--------------|
556
+ | Normal text (< 18px) | 4.5:1 |
557
+ | Large text (≥ 18px or bold ≥ 14px) | 3.1:1 |
558
+ | UI components, icons | 3:1 |
559
+
560
+ ### 6.2 Focus Indicators
561
+
562
+ ```css
563
+ /* Standard focus ring */
564
+ focus-visible:ring-2 focus-visible:ring-primary-600 focus-visible:ring-offset-2
565
+ dark:focus-visible:ring-primary-400
566
+ ```
567
+
568
+ **Rules:**
569
+ - Never use `outline: none` without a custom focus indicator
570
+ - Focus indicators must be visible in both light and dark modes
571
+ - Minimum focus ring width: `2px`
572
+
573
+ ### 6.3 Touch & Interactive Targets
574
+
575
+ | Requirement | Value |
576
+ |-------------|-------|
577
+ | Minimum touch target | 44px × 44px |
578
+ | Minimum font size | 16px |
579
+ | Maximum line length | 75ch |
580
+
581
+ ### 6.4 Semantic HTML
582
+
583
+ ```tsx
584
+ // ✅ Correct — semantic HTML first
585
+ <nav aria-label="Navegación principal">
586
+ <main>
587
+ <article>
588
+ <section>
589
+ <aside>
590
+ <header>
591
+ <footer>
592
+
593
+ // ✅ Correct — ARIA only when necessary
594
+ <div role="tabpanel" aria-labelledby="tab-products" aria-expanded={isOpen}>
595
+
596
+ // ❌ Incorrect — redundant ARIA
597
+ <button role="button" aria-label="button">Guardar</button>
598
+ ```
599
+
600
+ ### 6.5 Accessibility Requirements Checklist
601
+
602
+ | Requirement | Standard |
603
+ |-------------|---------|
604
+ | Landmarks | `<nav>`, `<main>`, `<header>`, `<footer>` on every page |
605
+ | Heading hierarchy | Single `<h1>`, descending order, no skips |
606
+ | Form labels | `<label>` associated with every input via `htmlFor` |
607
+ | Alt text | All images with `alt` attribute (empty `alt=""` for decorative) |
608
+ | Skip links | "Saltar al contenido" link before main navigation |
609
+ | Keyboard nav | All interactions reachable and operable via keyboard |
610
+ | Screen reader | Test with VoiceOver / NVDA on critical flows |
611
+
612
+ ---
613
+
614
+ ## 7. Language Standards
615
+
616
+ ### 7.1 Critical Rule — Spanish for All User-Visible Text
617
+
618
+ **All text visible to the end user MUST be in Spanish.**
619
+
620
+ | Content Type | Language |
621
+ |-------------|----------|
622
+ | UI labels, buttons, forms | ✅ Spanish |
623
+ | Error messages, toasts | ✅ Spanish |
624
+ | API response messages shown to user | ✅ Spanish |
625
+ | Validation feedback | ✅ Spanish |
626
+ | Code (variables, functions, classes) | ✅ English |
627
+ | Technical logs, comments, git commits | ✅ English |
628
+ | Developer documentation | ✅ English |
629
+
630
+ ```tsx
631
+ // ✅ Correct
632
+ <Button>Guardar</Button>
633
+ toast.success('Datos guardados correctamente');
634
+
635
+ // ❌ Incorrect
636
+ <Button>Save</Button>
637
+ toast.error('Failed to save');
638
+ ```
639
+
640
+ ### 7.2 Standard Message Tokens
641
+
642
+ ```typescript
643
+ // shared/constants/messages.ts
644
+ export const MESSAGES = {
645
+ SUCCESS: {
646
+ SAVED: 'Datos guardados correctamente',
647
+ DELETED: 'Elemento eliminado correctamente',
648
+ UPDATED: 'Información actualizada',
649
+ },
650
+ ERROR: {
651
+ GENERIC: 'Ha ocurrido un error. Por favor, intenta de nuevo',
652
+ NOT_FOUND: 'El recurso solicitado no fue encontrado',
653
+ UNAUTHORIZED: 'No tienes permisos para realizar esta acción',
654
+ VALIDATION: 'Por favor, verifica los datos ingresados',
655
+ CONFLICT: 'No se puede completar la operación debido a un conflicto',
656
+ },
657
+ LOADING: {
658
+ DEFAULT: 'Cargando...',
659
+ SAVING: 'Guardando...',
660
+ PROCESSING: 'Procesando...',
661
+ DELETING: 'Eliminando...',
662
+ },
663
+ CONFIRM: {
664
+ DELETE: '¿Estás seguro de que deseas eliminar este registro?',
665
+ UNSAVED: 'Tienes cambios sin guardar. ¿Deseas descartarlos?',
666
+ },
667
+ } as const;
668
+ ```
669
+
670
+ ---
671
+
672
+ ## 8. Performance Targets
673
+
674
+ ### 8.1 Bundle Budgets
675
+
676
+ | Scope | Maximum |
677
+ |-------|---------|
678
+ | Initial bundle | < 500 KB gzipped |
679
+ | Per-route chunk | < 200 KB gzipped |
680
+ | Individual component | < 100 KB gzipped |
681
+
682
+ ### 8.2 Core Web Vitals Targets
683
+
684
+ | Metric | Target |
685
+ |--------|--------|
686
+ | FCP (First Contentful Paint) | < 1.5s |
687
+ | LCP (Largest Contentful Paint) | < 2.5s |
688
+ | CLS (Cumulative Layout Shift) | < 0.1 |
689
+ | TTI (Time to Interactive) | < 3s |
690
+
691
+ ### 8.3 Optimization Techniques
692
+
693
+ | Technique | Implementation |
694
+ |-----------|---------------|
695
+ | Code splitting | Automatic per route (TanStack Router) |
696
+ | Lazy loading | `React.lazy()` for non-critical components |
697
+ | Tree shaking | Specific imports; no barrel exports in `shared/` |
698
+ | Memoization | `React.memo` for expensive components, `useMemo`/`useCallback` |
699
+ | Virtual scrolling | For lists > 200 items |
700
+ | Image lazy loading | `loading="lazy"` on all non-critical images |
701
+
702
+ ---
703
+
704
+ ## 9. State Management Patterns
705
+
706
+ ### 9.1 State Type Decision Matrix
707
+
708
+ | State Type | When to Use | Technology |
709
+ |-----------|-------------|------------|
710
+ | Server state | API data, paginated lists, caches | TanStack Query |
711
+ | Global client state | Auth, theme, cart, app settings | Zustand |
712
+ | Feature/domain state | Domain-specific UI and data | Zustand (feature store) |
713
+ | Local component state | Form toggles, UI open/close | `useState` / `useReducer` |
714
+ | URL state | Filters, pagination, selected tab | TanStack Router search params |
715
+
716
+ ### 9.2 TanStack Query Defaults
717
+
718
+ ```typescript
719
+ const queryClient = new QueryClient({
720
+ defaultOptions: {
721
+ queries: {
722
+ staleTime: 60 * 1000, // 1 minute
723
+ refetchOnWindowFocus: false,
724
+ retry: 1,
725
+ },
726
+ },
727
+ });
728
+ ```
729
+
730
+ ### 9.3 Zustand Store Structure
731
+
732
+ ```typescript
733
+ // Feature store pattern
734
+ interface FeatureState {
735
+ // Domain data
736
+ items: Item[];
737
+ selectedItem: Item | null;
738
+
739
+ // UI state
740
+ loading: boolean;
741
+ error: string | null;
742
+
743
+ // Actions
744
+ setSelectedItem: (item: Item | null) => void;
745
+ clearError: () => void;
746
+ }
747
+ ```
748
+
749
+ ---
750
+
751
+ ## 10. Security & Input Handling
752
+
753
+ | Risk | Mitigation |
754
+ |------|------------|
755
+ | XSS | Never use `dangerouslySetInnerHTML`; sanitize all dynamic content |
756
+ | Sensitive data | Never store tokens/credentials in `localStorage` unencrypted |
757
+ | API keys | Never in frontend code — use server-side env variables only |
758
+ | User input | Always validate with Zod on submit before sending to API |
759
+
760
+ ---
761
+
762
+ ## 11. Naming Conventions
763
+
764
+ | Element | Convention | Example |
765
+ |---------|-----------|---------|
766
+ | Components | PascalCase | `ProductCard`, `UserList` |
767
+ | Component files | kebab-case | `product-card.tsx`, `user-list.tsx` |
768
+ | Directories | kebab-case | `user-management/` |
769
+ | Hooks | `use` + camelCase | `useProductStore`, `useAuth` |
770
+ | Zustand stores | `use{Feature}Store` | `useCartStore` |
771
+ | `data-testid` | kebab-case | `data-testid="product-card"` |
772
+ | CSS custom props | `--kebab-case` | `--color-primary-600` |
773
+ | Constants | SCREAMING_SNAKE_CASE | `MAX_PAGE_SIZE` |
774
+
775
+ ---
776
+
777
+ ## 12. Implementation Checklist
778
+
779
+ ### New Frontend Project
780
+
781
+ ```markdown
782
+ ## Design System
783
+ - [ ] TailwindCSS 4+ with extended brand color scales (primary, secondary, tertiary)
784
+ - [ ] Dark mode configured: class-based on `html`, `next-themes`
785
+ - [ ] Inter_18pt fonts (Light, Regular, Bold) loaded via `globals.css`
786
+ - [ ] Siesa logos in `assets/images/logos/` (4 SVG variants)
787
+ - [ ] `react-loading-skeleton` installed and configured (light/dark themes)
788
+ - [ ] `sonner` Toaster at `bottom-right` in root layout
789
+
790
+ ## Component Library
791
+ - [ ] `siesa-ui-kit` installed and verified for required components
792
+ - [ ] shadcn/ui added only for components not in siesa-ui-kit
793
+ - [ ] `MasterCrud` used for all master data management screens
794
+ - [ ] `LookupField` with `type: 'lookup'` for all backend record selectors
795
+ - [ ] `React Hook Form` + `Zod` for all form validation
796
+
797
+ ## Layout
798
+ - [ ] `_app.tsx` layout: `flex h-screen`, Sidebar + TopNav + main
799
+ - [ ] `_auth.tsx` layout: public pages (login, etc.)
800
+ - [ ] All pages use semantic HTML (`<main>`, `<nav>`, `<header>`)
801
+ - [ ] Error boundaries wrapping each major feature section
802
+
803
+ ## Accessibility
804
+ - [ ] WCAG 2.1 AA contrast ratios verified (4.5:1 normal, 3.1:1 large)
805
+ - [ ] Focus indicators visible (`ring-2 ring-primary-600`)
806
+ - [ ] Touch targets ≥ 44px
807
+ - [ ] All images have `alt` attributes
808
+ - [ ] Skip link "Saltar al contenido" before navigation
809
+ - [ ] Form inputs have associated `<label>` via `htmlFor`
810
+ - [ ] Single `<h1>` per page, headings in descending order
811
+
812
+ ## Language & Content
813
+ - [ ] All user-visible text in Spanish
814
+ - [ ] `MESSAGES` constant file for standard messages
815
+ - [ ] No mixed-language text in UI strings
816
+
817
+ ## Performance
818
+ - [ ] Bundle size < 500KB gzipped (initial)
819
+ - [ ] Skeleton screens for all async loading states
820
+ - [ ] `React.memo` on expensive list items
821
+ - [ ] Images have `loading="lazy"` where applicable
822
+ - [ ] Route-based code splitting (automatic with TanStack Router)
823
+
824
+ ## State Management
825
+ - [ ] TanStack Query for all server state (API calls)
826
+ - [ ] Zustand stores per feature (not global monolith)
827
+ - [ ] URL params for filters and pagination state
828
+
829
+ ## Security
830
+ - [ ] No `dangerouslySetInnerHTML` without sanitization
831
+ - [ ] No credentials or secrets in frontend code
832
+ - [ ] All user inputs validated with Zod before API submission
833
+ ```
834
+
835
+ ---
836
+
837
+ _This document is the base UX/UI specification. It is automatically applied when initializing new projects. Extend it using the `/create-ux-design` workflow for project-specific decisions._