oden-forge 2.0.0
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/.claude/CLAUDE.md +75 -0
- package/.claude/commands/oden/architect.md +204 -0
- package/.claude/commands/oden/checklist.md +199 -0
- package/.claude/commands/oden/daily.md +223 -0
- package/.claude/commands/oden/debug.md +203 -0
- package/.claude/commands/oden/epic.md +224 -0
- package/.claude/commands/oden/git.md +259 -0
- package/.claude/commands/oden/help.md +304 -0
- package/.claude/commands/oden/init-agents.md +268 -0
- package/.claude/commands/oden/init-mcp.md +460 -0
- package/.claude/commands/oden/init.md +495 -0
- package/.claude/commands/oden/mcp.md +585 -0
- package/.claude/commands/oden/prd.md +134 -0
- package/.claude/commands/oden/research.md +207 -0
- package/.claude/commands/oden/review.md +146 -0
- package/.claude/commands/oden/spec.md +539 -0
- package/.claude/commands/oden/sync.md +286 -0
- package/.claude/commands/oden/tasks.md +156 -0
- package/.claude/commands/oden/test.md +200 -0
- package/.claude/commands/oden/work.md +791 -0
- package/.claude/epics/.gitkeep +0 -0
- package/.claude/hooks/README.md +130 -0
- package/.claude/hooks/bash-worktree-fix.sh +189 -0
- package/.claude/prds/.gitkeep +0 -0
- package/.claude/rules/agent-coordination.md +224 -0
- package/.claude/rules/branch-operations.md +147 -0
- package/.claude/rules/datetime.md +118 -0
- package/.claude/rules/frontmatter-operations.md +58 -0
- package/.claude/rules/github-operations.md +89 -0
- package/.claude/rules/oden-methodology.md +111 -0
- package/.claude/rules/path-standards.md +155 -0
- package/.claude/rules/standard-patterns.md +174 -0
- package/.claude/rules/strip-frontmatter.md +82 -0
- package/.claude/rules/worktree-operations.md +136 -0
- package/.claude/scripts/oden/blocked.sh +72 -0
- package/.claude/scripts/oden/epic-list.sh +101 -0
- package/.claude/scripts/oden/epic-show.sh +91 -0
- package/.claude/scripts/oden/epic-status.sh +90 -0
- package/.claude/scripts/oden/help.sh +71 -0
- package/.claude/scripts/oden/in-progress.sh +74 -0
- package/.claude/scripts/oden/init.sh +192 -0
- package/.claude/scripts/oden/next.sh +65 -0
- package/.claude/scripts/oden/prd-list.sh +89 -0
- package/.claude/scripts/oden/prd-status.sh +63 -0
- package/.claude/scripts/oden/search.sh +71 -0
- package/.claude/scripts/oden/standup.sh +89 -0
- package/.claude/scripts/oden/status.sh +42 -0
- package/.claude/scripts/oden/validate.sh +101 -0
- package/.claude/settings.json +27 -0
- package/MIGRATION.md +217 -0
- package/README.md +368 -0
- package/bin/install.js +155 -0
- package/bin/migrate.js +191 -0
- package/bin/oden-forge.js +114 -0
- package/bin/post-install.js +47 -0
- package/bin/pre-uninstall.js +108 -0
- package/install.sh +231 -0
- package/package.json +76 -0
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
---
|
|
2
|
+
allowed-tools: Bash, Read, Write, LS, Glob, Grep, Task, TodoWrite
|
|
3
|
+
description: Crear especificaciones detalladas por módulo (800-1200 líneas)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Oden Forge - Feature Specification Writer
|
|
7
|
+
|
|
8
|
+
Actúa como **Feature Specification Writer** para crear especificaciones técnicas detalladas.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
/oden:spec {nombre-modulo}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Ejemplos:
|
|
17
|
+
- `/oden:spec auth` - Especificación del módulo de autenticación
|
|
18
|
+
- `/oden:spec orders` - Especificación del módulo de órdenes
|
|
19
|
+
- `/oden:spec dashboard` - Especificación del dashboard
|
|
20
|
+
|
|
21
|
+
## Prerrequisitos
|
|
22
|
+
|
|
23
|
+
1. technical-decisions.md completo (`/oden:architect`)
|
|
24
|
+
2. User stories definidas (`/oden:analyze`)
|
|
25
|
+
|
|
26
|
+
## Responsabilidades
|
|
27
|
+
|
|
28
|
+
Como Spec Writer, debes crear:
|
|
29
|
+
|
|
30
|
+
1. **Especificación de 800-1200 líneas** para el módulo
|
|
31
|
+
2. **Diagrama de estados** si hay entidades con estados
|
|
32
|
+
3. **Todas las validaciones** con mensajes de error
|
|
33
|
+
4. **Flujos de UI/UX** completos
|
|
34
|
+
5. **Comportamiento offline** si aplica
|
|
35
|
+
6. **Matriz de permisos** por rol
|
|
36
|
+
|
|
37
|
+
## Proceso
|
|
38
|
+
|
|
39
|
+
### Paso 1: Análisis del Módulo
|
|
40
|
+
|
|
41
|
+
Lee technical-decisions.md y user-stories.md para entender:
|
|
42
|
+
- Qué entidades maneja el módulo
|
|
43
|
+
- Qué user stories cubre
|
|
44
|
+
- Dependencias con otros módulos
|
|
45
|
+
|
|
46
|
+
### Paso 2: Estructura de la Especificación
|
|
47
|
+
|
|
48
|
+
Crea `docs/reference/modules/{modulo}-spec.md`:
|
|
49
|
+
|
|
50
|
+
```markdown
|
|
51
|
+
# Especificación: {Nombre del Módulo}
|
|
52
|
+
|
|
53
|
+
**Estado:** 🟡 En Progreso
|
|
54
|
+
**Última actualización:** {fecha}
|
|
55
|
+
**Líneas:** ~{X} (target: 800-1200)
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 1. Overview
|
|
60
|
+
|
|
61
|
+
### 1.1 Propósito
|
|
62
|
+
{Por qué existe este módulo}
|
|
63
|
+
|
|
64
|
+
### 1.2 Alcance
|
|
65
|
+
**Incluye:**
|
|
66
|
+
- {funcionalidad 1}
|
|
67
|
+
- {funcionalidad 2}
|
|
68
|
+
|
|
69
|
+
**NO incluye:**
|
|
70
|
+
- {exclusión 1}
|
|
71
|
+
- {exclusión 2}
|
|
72
|
+
|
|
73
|
+
### 1.3 User Stories Relacionadas
|
|
74
|
+
- US-{X}: {título}
|
|
75
|
+
- US-{Y}: {título}
|
|
76
|
+
|
|
77
|
+
### 1.4 Dependencias
|
|
78
|
+
- Módulo {X}: {cómo depende}
|
|
79
|
+
- Servicio {Y}: {cómo depende}
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 2. Modelo de Datos
|
|
84
|
+
|
|
85
|
+
### 2.1 Entidad Principal
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
interface {Entidad} {
|
|
89
|
+
id: string;
|
|
90
|
+
// campos específicos
|
|
91
|
+
status: {Entidad}Status;
|
|
92
|
+
created_at: Date;
|
|
93
|
+
updated_at: Date;
|
|
94
|
+
created_by: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
enum {Entidad}Status {
|
|
98
|
+
DRAFT = 'draft',
|
|
99
|
+
ACTIVE = 'active',
|
|
100
|
+
COMPLETED = 'completed',
|
|
101
|
+
CANCELLED = 'cancelled',
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 2.2 Detalle de Campos
|
|
106
|
+
|
|
107
|
+
| Campo | Tipo | Requerido | Default | Validación | Descripción |
|
|
108
|
+
|-------|------|-----------|---------|------------|-------------|
|
|
109
|
+
| id | UUID | ✅ | auto | - | Identificador único |
|
|
110
|
+
| name | string | ✅ | - | 1-100 chars | Nombre del recurso |
|
|
111
|
+
| status | enum | ✅ | 'draft' | valores válidos | Estado actual |
|
|
112
|
+
| amount | decimal | ✅ | - | > 0 | Monto en MXN |
|
|
113
|
+
|
|
114
|
+
### 2.3 Relaciones
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
{Entidad} 1──────* {SubEntidad}
|
|
118
|
+
│
|
|
119
|
+
└──1 User (created_by)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 3. Estados y Transiciones
|
|
125
|
+
|
|
126
|
+
### 3.1 Diagrama
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
┌─────────┐
|
|
130
|
+
│ DRAFT │──────────────────────┐
|
|
131
|
+
└────┬────┘ │
|
|
132
|
+
│ submit() │ delete()
|
|
133
|
+
▼ ▼
|
|
134
|
+
┌─────────┐ reject() ┌─────────┐
|
|
135
|
+
│ PENDING │────────────────▶│ DELETED │
|
|
136
|
+
└────┬────┘ └─────────┘
|
|
137
|
+
│ approve()
|
|
138
|
+
▼
|
|
139
|
+
┌─────────┐ complete() ┌───────────┐
|
|
140
|
+
│ ACTIVE │────────────────▶│ COMPLETED │
|
|
141
|
+
└────┬────┘ └───────────┘
|
|
142
|
+
│ cancel()
|
|
143
|
+
▼
|
|
144
|
+
┌──────────┐
|
|
145
|
+
│CANCELLED │
|
|
146
|
+
└──────────┘
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 3.2 Tabla de Transiciones
|
|
150
|
+
|
|
151
|
+
| De | A | Acción | Condiciones | Side Effects |
|
|
152
|
+
|----|---|--------|-------------|--------------|
|
|
153
|
+
| DRAFT | PENDING | submit() | Campos válidos | Notificar revisor |
|
|
154
|
+
| DRAFT | DELETED | delete() | Owner o Admin | Soft delete |
|
|
155
|
+
| PENDING | ACTIVE | approve() | Rol: Admin | Log auditoría |
|
|
156
|
+
| PENDING | DRAFT | reject() | Rol: Admin | Notificar owner |
|
|
157
|
+
| ACTIVE | COMPLETED | complete() | Criterios met | Calcular totales |
|
|
158
|
+
| ACTIVE | CANCELLED | cancel() | Owner o Admin | Revertir cambios |
|
|
159
|
+
|
|
160
|
+
### 3.3 Acciones por Estado
|
|
161
|
+
|
|
162
|
+
| Estado | Acciones Disponibles |
|
|
163
|
+
|--------|---------------------|
|
|
164
|
+
| DRAFT | ver, editar, eliminar, submit |
|
|
165
|
+
| PENDING | ver, aprobar*, rechazar* |
|
|
166
|
+
| ACTIVE | ver, editar**, completar, cancelar |
|
|
167
|
+
| COMPLETED | ver |
|
|
168
|
+
| CANCELLED | ver, reactivar* |
|
|
169
|
+
|
|
170
|
+
*Solo Admin
|
|
171
|
+
**Solo campos específicos
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 4. Flujos de Usuario
|
|
176
|
+
|
|
177
|
+
### 4.1 Crear {Entidad}
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
181
|
+
│ FLUJO: CREAR {ENTIDAD} │
|
|
182
|
+
└─────────────────────────────────────────────────────────────┘
|
|
183
|
+
|
|
184
|
+
Usuario Sistema
|
|
185
|
+
│ │
|
|
186
|
+
│──[Click "Nuevo {entidad}"]────────▶│
|
|
187
|
+
│ │
|
|
188
|
+
│◀─[Muestra formulario vacío]────────│
|
|
189
|
+
│ │
|
|
190
|
+
│──[Completa campos requeridos]─────▶│
|
|
191
|
+
│ │
|
|
192
|
+
│──[Click "Guardar"]────────────────▶│
|
|
193
|
+
│ │
|
|
194
|
+
│ ┌─[Validar campos]─────────────│
|
|
195
|
+
│ │ │
|
|
196
|
+
│ ├─[Si válido] │
|
|
197
|
+
│ │ ├─[Guardar en BD] │
|
|
198
|
+
│ │ ├─[Crear audit log] │
|
|
199
|
+
│ │ └─[Retornar éxito] │
|
|
200
|
+
│ │ │
|
|
201
|
+
│◀────┴─[Redirect a detalle]─────────│
|
|
202
|
+
│ [Toast: "Creado exitosamente"]│
|
|
203
|
+
│ │
|
|
204
|
+
│ ├─[Si inválido] │
|
|
205
|
+
│ │ └─[Retornar errores] │
|
|
206
|
+
│ │ │
|
|
207
|
+
│◀────┴─[Mostrar errores inline]─────│
|
|
208
|
+
│ │
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### 4.2 Editar {Entidad}
|
|
212
|
+
|
|
213
|
+
[Flujo similar con validación de permisos]
|
|
214
|
+
|
|
215
|
+
### 4.3 Cambiar Estado
|
|
216
|
+
|
|
217
|
+
[Flujo para cada transición de estado]
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 5. Validaciones
|
|
222
|
+
|
|
223
|
+
### 5.1 Validaciones de Campo
|
|
224
|
+
|
|
225
|
+
| Campo | Regla | Código | Mensaje (ES) |
|
|
226
|
+
|-------|-------|--------|--------------|
|
|
227
|
+
| name | Requerido | REQUIRED | "El nombre es requerido" |
|
|
228
|
+
| name | Min 1 char | MIN_LENGTH | "El nombre debe tener al menos 1 carácter" |
|
|
229
|
+
| name | Max 100 chars | MAX_LENGTH | "El nombre no puede exceder 100 caracteres" |
|
|
230
|
+
| email | Formato válido | INVALID_FORMAT | "El formato del email no es válido" |
|
|
231
|
+
| amount | Mayor a 0 | MIN_VALUE | "El monto debe ser mayor a $0" |
|
|
232
|
+
| amount | Max 999999.99 | MAX_VALUE | "El monto máximo es $999,999.99" |
|
|
233
|
+
|
|
234
|
+
### 5.2 Validaciones de Negocio
|
|
235
|
+
|
|
236
|
+
| Código | Regla | Mensaje |
|
|
237
|
+
|--------|-------|---------|
|
|
238
|
+
| BR001 | No duplicar nombre activo | "Ya existe un {entidad} con este nombre" |
|
|
239
|
+
| BR002 | Solo owner puede submit | "Solo el creador puede enviar a revisión" |
|
|
240
|
+
| BR003 | No editar completado | "No se puede editar un {entidad} completado" |
|
|
241
|
+
|
|
242
|
+
### 5.3 Formato de Errores
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
// Error de validación
|
|
246
|
+
{
|
|
247
|
+
error: {
|
|
248
|
+
code: "VALIDATION_ERROR",
|
|
249
|
+
message: "Error de validación",
|
|
250
|
+
details: [
|
|
251
|
+
{ field: "name", code: "REQUIRED", message: "El nombre es requerido" },
|
|
252
|
+
{ field: "amount", code: "MIN_VALUE", message: "El monto debe ser mayor a $0" }
|
|
253
|
+
]
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Error de negocio
|
|
258
|
+
{
|
|
259
|
+
error: {
|
|
260
|
+
code: "BUSINESS_RULE_VIOLATION",
|
|
261
|
+
rule: "BR001",
|
|
262
|
+
message: "Ya existe un {entidad} con este nombre"
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## 6. API Endpoints
|
|
270
|
+
|
|
271
|
+
### 6.1 Lista de Endpoints
|
|
272
|
+
|
|
273
|
+
| Método | Endpoint | Descripción | Auth | Roles |
|
|
274
|
+
|--------|----------|-------------|------|-------|
|
|
275
|
+
| GET | /api/{entidades} | Listar | ✅ | All |
|
|
276
|
+
| GET | /api/{entidades}/:id | Obtener | ✅ | All |
|
|
277
|
+
| POST | /api/{entidades} | Crear | ✅ | All |
|
|
278
|
+
| PUT | /api/{entidades}/:id | Actualizar | ✅ | Owner/Admin |
|
|
279
|
+
| DELETE | /api/{entidades}/:id | Eliminar | ✅ | Admin |
|
|
280
|
+
| POST | /api/{entidades}/:id/submit | Enviar | ✅ | Owner |
|
|
281
|
+
| POST | /api/{entidades}/:id/approve | Aprobar | ✅ | Admin |
|
|
282
|
+
|
|
283
|
+
### 6.2 GET /api/{entidades}
|
|
284
|
+
|
|
285
|
+
**Query Parameters:**
|
|
286
|
+
| Param | Tipo | Default | Descripción |
|
|
287
|
+
|-------|------|---------|-------------|
|
|
288
|
+
| page | number | 1 | Página actual |
|
|
289
|
+
| limit | number | 20 | Items por página (max 100) |
|
|
290
|
+
| status | string | - | Filtrar por estado |
|
|
291
|
+
| search | string | - | Buscar por nombre |
|
|
292
|
+
| sort | string | -created_at | Campo de ordenamiento |
|
|
293
|
+
|
|
294
|
+
**Response 200:**
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"data": [
|
|
298
|
+
{
|
|
299
|
+
"id": "uuid",
|
|
300
|
+
"name": "string",
|
|
301
|
+
"status": "draft",
|
|
302
|
+
"created_at": "2024-01-15T10:30:00Z"
|
|
303
|
+
}
|
|
304
|
+
],
|
|
305
|
+
"meta": {
|
|
306
|
+
"total": 100,
|
|
307
|
+
"page": 1,
|
|
308
|
+
"limit": 20,
|
|
309
|
+
"totalPages": 5
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### 6.3 POST /api/{entidades}
|
|
315
|
+
|
|
316
|
+
**Request:**
|
|
317
|
+
```json
|
|
318
|
+
{
|
|
319
|
+
"name": "string",
|
|
320
|
+
"description": "string?",
|
|
321
|
+
"amount": "number"
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**Response 201:**
|
|
326
|
+
```json
|
|
327
|
+
{
|
|
328
|
+
"data": {
|
|
329
|
+
"id": "uuid",
|
|
330
|
+
"name": "string",
|
|
331
|
+
"status": "draft",
|
|
332
|
+
"created_at": "2024-01-15T10:30:00Z"
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Response 400:**
|
|
338
|
+
```json
|
|
339
|
+
{
|
|
340
|
+
"error": {
|
|
341
|
+
"code": "VALIDATION_ERROR",
|
|
342
|
+
"message": "Error de validación",
|
|
343
|
+
"details": [...]
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## 7. UI/UX
|
|
351
|
+
|
|
352
|
+
### 7.1 Componentes
|
|
353
|
+
|
|
354
|
+
| Componente | Descripción | Estados |
|
|
355
|
+
|------------|-------------|---------|
|
|
356
|
+
| {Entidad}List | Lista paginada | loading, empty, error, success |
|
|
357
|
+
| {Entidad}Card | Card individual | default, hover, selected |
|
|
358
|
+
| {Entidad}Form | Formulario CRUD | create, edit, view |
|
|
359
|
+
| {Entidad}Detail | Vista detalle | loading, error, success |
|
|
360
|
+
| {Entidad}StatusBadge | Badge de estado | por cada status |
|
|
361
|
+
|
|
362
|
+
### 7.2 Estados de UI
|
|
363
|
+
|
|
364
|
+
```
|
|
365
|
+
Loading:
|
|
366
|
+
┌────────────────────────────────────┐
|
|
367
|
+
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
|
|
368
|
+
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
|
|
369
|
+
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
|
|
370
|
+
└────────────────────────────────────┘
|
|
371
|
+
|
|
372
|
+
Empty:
|
|
373
|
+
┌────────────────────────────────────┐
|
|
374
|
+
│ │
|
|
375
|
+
│ 📭 Sin {entidades} │
|
|
376
|
+
│ │
|
|
377
|
+
│ Crea tu primer {entidad} │
|
|
378
|
+
│ │
|
|
379
|
+
│ [+ Crear {entidad}] │
|
|
380
|
+
│ │
|
|
381
|
+
└────────────────────────────────────┘
|
|
382
|
+
|
|
383
|
+
Error:
|
|
384
|
+
┌────────────────────────────────────┐
|
|
385
|
+
│ │
|
|
386
|
+
│ ❌ Error al cargar │
|
|
387
|
+
│ │
|
|
388
|
+
│ No se pudieron cargar los datos │
|
|
389
|
+
│ │
|
|
390
|
+
│ [Reintentar] │
|
|
391
|
+
│ │
|
|
392
|
+
└────────────────────────────────────┘
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### 7.3 Responsive
|
|
396
|
+
|
|
397
|
+
| Breakpoint | Layout |
|
|
398
|
+
|------------|--------|
|
|
399
|
+
| <640px | Stack vertical, cards full width |
|
|
400
|
+
| 640-1024px | 2 columnas |
|
|
401
|
+
| >1024px | Sidebar + content |
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## 8. Permisos
|
|
406
|
+
|
|
407
|
+
### 8.1 Matriz de Permisos
|
|
408
|
+
|
|
409
|
+
| Acción | Admin | Manager | User | Guest |
|
|
410
|
+
|--------|-------|---------|------|-------|
|
|
411
|
+
| Listar | Todos | Todos | Propios | ❌ |
|
|
412
|
+
| Ver | Todos | Todos | Propios | ❌ |
|
|
413
|
+
| Crear | ✅ | ✅ | ✅ | ❌ |
|
|
414
|
+
| Editar | Todos | Propios | Propios | ❌ |
|
|
415
|
+
| Eliminar | Todos | ❌ | ❌ | ❌ |
|
|
416
|
+
| Aprobar | ✅ | ✅ | ❌ | ❌ |
|
|
417
|
+
|
|
418
|
+
### 8.2 Row Level Security
|
|
419
|
+
|
|
420
|
+
```sql
|
|
421
|
+
-- Users can see their own records
|
|
422
|
+
CREATE POLICY "{entidades}_select_own" ON {entidades}
|
|
423
|
+
FOR SELECT USING (
|
|
424
|
+
auth.uid() = created_by
|
|
425
|
+
OR auth.jwt() ->> 'role' IN ('admin', 'manager')
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
-- Only creators can update their draft records
|
|
429
|
+
CREATE POLICY "{entidades}_update_own" ON {entidades}
|
|
430
|
+
FOR UPDATE USING (
|
|
431
|
+
(auth.uid() = created_by AND status = 'draft')
|
|
432
|
+
OR auth.jwt() ->> 'role' = 'admin'
|
|
433
|
+
);
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## 9. Offline Behavior
|
|
439
|
+
|
|
440
|
+
### 9.1 Funcionalidad Offline
|
|
441
|
+
|
|
442
|
+
| Acción | Offline | Sync Strategy |
|
|
443
|
+
|--------|---------|---------------|
|
|
444
|
+
| Ver lista | ✅ (cache) | Background refresh |
|
|
445
|
+
| Ver detalle | ✅ (cache) | Background refresh |
|
|
446
|
+
| Crear | ✅ (queue) | On reconnect |
|
|
447
|
+
| Editar | ✅ (queue) | Last-write-wins |
|
|
448
|
+
| Eliminar | ❌ | Requiere conexión |
|
|
449
|
+
| Aprobar | ❌ | Requiere conexión |
|
|
450
|
+
|
|
451
|
+
### 9.2 Indicadores
|
|
452
|
+
|
|
453
|
+
```
|
|
454
|
+
🟢 Sincronizado
|
|
455
|
+
🟡 Sincronizando... (2 pendientes)
|
|
456
|
+
🔴 Sin conexión (3 cambios locales)
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## 10. Edge Cases
|
|
462
|
+
|
|
463
|
+
| Caso | Comportamiento | Test |
|
|
464
|
+
|------|----------------|------|
|
|
465
|
+
| Nombre con emojis | Permitir, sanitizar XSS | ✅ |
|
|
466
|
+
| Doble click en submit | Deshabilitar botón | ✅ |
|
|
467
|
+
| Sesión expira durante edición | Guardar borrador local | ✅ |
|
|
468
|
+
| Otro usuario edita mismo recurso | Notificar conflicto | ✅ |
|
|
469
|
+
| Pérdida de conexión durante save | Queue y reintentar | ✅ |
|
|
470
|
+
|
|
471
|
+
---
|
|
472
|
+
|
|
473
|
+
## 11. Testing Checklist
|
|
474
|
+
|
|
475
|
+
### Unit Tests
|
|
476
|
+
- [ ] Validaciones de cada campo
|
|
477
|
+
- [ ] Transiciones de estado válidas
|
|
478
|
+
- [ ] Transiciones inválidas rechazadas
|
|
479
|
+
- [ ] Cálculos de negocio
|
|
480
|
+
|
|
481
|
+
### Integration Tests
|
|
482
|
+
- [ ] CRUD completo via API
|
|
483
|
+
- [ ] Permisos por rol
|
|
484
|
+
- [ ] Paginación y filtros
|
|
485
|
+
|
|
486
|
+
### E2E Tests
|
|
487
|
+
- [ ] Flujo crear → submit → aprobar
|
|
488
|
+
- [ ] Manejo de errores UI
|
|
489
|
+
- [ ] Responsive mobile
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
## 12. Métricas
|
|
494
|
+
|
|
495
|
+
### Eventos a Trackear
|
|
496
|
+
|
|
497
|
+
| Evento | Propiedades | Propósito |
|
|
498
|
+
|--------|-------------|-----------|
|
|
499
|
+
| {entidad}_created | id, user_id | Uso |
|
|
500
|
+
| {entidad}_submitted | id | Conversión |
|
|
501
|
+
| {entidad}_approved | id, approver | Workflow |
|
|
502
|
+
| {entidad}_error | code, context | Debug |
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
**Creado:** {fecha}
|
|
507
|
+
**Autor:** Spec Writer Agent
|
|
508
|
+
**Líneas:** {X}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
## Output
|
|
512
|
+
|
|
513
|
+
El archivo debe tener:
|
|
514
|
+
- [ ] 800-1200 líneas
|
|
515
|
+
- [ ] Todos los campos documentados
|
|
516
|
+
- [ ] Diagrama de estados (si aplica)
|
|
517
|
+
- [ ] Validaciones con mensajes en español
|
|
518
|
+
- [ ] Endpoints con request/response
|
|
519
|
+
- [ ] Permisos definidos
|
|
520
|
+
- [ ] Edge cases identificados
|
|
521
|
+
- [ ] Testing checklist
|
|
522
|
+
|
|
523
|
+
## Siguientes Pasos
|
|
524
|
+
|
|
525
|
+
Repetir para cada módulo principal:
|
|
526
|
+
```
|
|
527
|
+
/oden:spec auth
|
|
528
|
+
/oden:spec users
|
|
529
|
+
/oden:spec {modulo-principal}
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
Luego:
|
|
533
|
+
```
|
|
534
|
+
/oden:plan
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
## Referencia
|
|
538
|
+
|
|
539
|
+
Ver agente completo en: `.claude/agents/spec-writer.md`
|