openprompt-lang 1.2.4 → 1.2.7

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/docs/FRAMEWORK.md CHANGED
@@ -186,6 +186,37 @@ npx openPrompt-Lang work-context learn
186
186
  npx openPrompt-Lang work-context report
187
187
  ```
188
188
 
189
+ ### Plan y Modo (Planificación Ágil)
190
+ ```
191
+ opl plan → Cambiar a modo PLAN (bloquea tools de escritura)
192
+ opl execute → Cambiar a modo EXECUTE (requiere plan aprobado)
193
+ opl mode → Mostrar modo actual (plan/execute)
194
+ opl workflow discovery → E.1 — Wizard de descubrimiento (8 bloques, 29 preguntas)
195
+ opl workflow specification → E.2 — Generar documentos y diagramas Mermaid
196
+ opl workflow delivery → E.3 — Iniciar desarrollo por tickets
197
+ opl workflow close → E.4 — Cerrar sesión y documentar aprendizajes
198
+ ```
199
+
200
+ ### Teaching (Enseñanza Adaptativa)
201
+ ```
202
+ opl teach progress → Dashboard de progreso
203
+ opl teach template <id> → Lección desde template @teachMe
204
+ opl teach assess → Diagnosticar nivel de dominio
205
+ opl teach study → Unidad pedagógica adaptada
206
+ opl teach project-guide → Ruta de aprendizaje con tickets
207
+ ```
208
+
209
+ ### Ticket, Memoria y Diagnóstico
210
+ ```
211
+ opl ticket create --title "..." → Crear ticket de trabajo
212
+ opl ticket list → Listar tickets (--status ready|backlog|done)
213
+ opl ticket close <id> → Cerrar ticket
214
+ opl recall "consulta" → Búsqueda en memoria del proyecto
215
+ opl doctor → Diagnóstico del sistema OPL
216
+ opl fix → Auto-corrección de errores
217
+ opl rebuild → Reconstrucción de configuración
218
+ ```
219
+
189
220
  ### QA, Extracción y AI
190
221
  ```
191
222
  npx openPrompt-Lang qa-gen [--lang L] [--source DIR] [--output DIR] [--dry-run] [--no-scan]
@@ -197,6 +228,12 @@ npx openPrompt-Lang db-rules [--list] [--id ID] [--tag TAG]
197
228
  npx openPrompt-Lang scaffold folders FRAMEWORK [--name N] [--force]
198
229
  ```
199
230
 
231
+ ### MCP Servers
232
+ ```
233
+ npx openPrompt-Lang mcp → Iniciar servidor MCP principal (tools OPL)
234
+ npx openPrompt-Lang mcp-plan → Iniciar servidor MCP de planificación (tools plan_*)
235
+ ```
236
+
200
237
  ### MCP Server
201
238
  ```
202
239
  npx openPrompt-Lang mcp
@@ -234,6 +271,21 @@ npx openPrompt-Lang mcp
234
271
  | `work_context_start` | Iniciar sesión con tracking | `task` (req), `domain?` |
235
272
  | `work_context_status` | Estado actual de la sesión | — |
236
273
  | `work_context_close` | Cerrar sesión y registrar métricas | `summary` (req) |
274
+ | `teach_progress` | Mostrar progreso de aprendizaje | `userId?`, `domain?` |
275
+ | `teach_assess` | Diagnosticar nivel de dominio | `conceptId` (req), `domain?` |
276
+ | `teach_study` | Generar unidad pedagógica adaptada | `conceptId` (req), `level?`, `includeExercises?` |
277
+
278
+ ### Servidor OPL-Plan (tools adicionales)
279
+
280
+ | Herramienta | Descripción | Parámetros |
281
+ |------------|-------------|------------|
282
+ | `plan_recommend_stack` | Analizar proyecto y recomendar stack | `description` (req) |
283
+ | `plan_wizard` | Wizard interactivo de configuración | `project_name` (req), `context` (req) |
284
+ | `plan_create` | Crear plan formal @workflow | `project_name` (req), `language` (req), `stack` (req) |
285
+ | `plan_validate` | Validar que el plan esté completo | `plan_id?` |
286
+ | `plan_status` | Mostrar estado del plan actual | `plan_id?` |
287
+ | `plan_switch_mode` | Cambiar a EXECUTE mode | `plan_id?` |
288
+ | `plan_knowledge_filter` | Filtrar biblioteca por dominio | `domain` (req), `features?` |
237
289
 
238
290
  ## 11. Reglas Estrictas
239
291
 
@@ -0,0 +1,504 @@
1
+ # 📋 Auditoría OPL — AppMobilSaaSEcommerce
2
+
3
+ > **Generado:** 2026-05-23
4
+ > **Propósito:** Documentar todos los errores, problemas de anotaciones, y deuda técnica encontrada en el proyecto para resolverlos sistemáticamente.
5
+
6
+ ---
7
+
8
+ ## 📊 Resumen del proyecto
9
+
10
+ | Aspecto | Valor |
11
+ |---------|-------|
12
+ | Stack | React 18 + Vite 6 + TypeScript 5.9 + Tailwind 3 |
13
+ | Mobile | Ionic 8 + Capacitor 7 (Android/iOS) |
14
+ | Backend | Supabase (Auth, DB, Realtime, Storage, Edge Functions) |
15
+ | Archivos totales | ~90+ archivos fuente |
16
+ | Componentes UI | 31 componentes de página + 49 shadcn/ui |
17
+ | Hooks | 10 hooks personalizados |
18
+ | Archivos con anotaciones OPL | **3 de 50+** (✅ `useOfflineQueue`, `useCapacitorLifecycle`, `DeliveryZones`, `pushNotifications`) |
19
+ | Archivos sin anotaciones OPL | **~46 archivos** |
20
+ | Tests unitarios | **0** |
21
+
22
+ ---
23
+
24
+ ## 🚨 CATEGORÍA 1: Anotaciones OPL faltantes
25
+
26
+ ### 1.1 — `src/App.tsx` — Sin anotaciones OPL
27
+ **Archivo:** `src/App.tsx` (266 líneas)
28
+
29
+ ```typescript
30
+ // @use(kind, contract, limit, deps)
31
+ // @kind(page)
32
+ // @contract(in: void -> out: JSX.Element)
33
+ // @limit(lines: 300, deps: 10)
34
+ // @deps(@external: [react, sonner, lucide-react], @internal: [
35
+ // ./components/Login, ./components/Dashboard, ./components/Catalog,
36
+ // ./components/Reports, ./components/BottomNav, ./components/Settings,
37
+ // ./components/Notifications, ./components/QueueModal,
38
+ // ./components/OfferExecutionModal, ./components/CalendarModal,
39
+ // ./components/OfflineRestrictionModal, ./components/PinPadModal,
40
+ // ./hooks/useAuth, ./hooks/useAppData, ./hooks/useOfflineQueue,
41
+ // ./hooks/useCapacitorLifecycle, ./hooks/useRealtimeSync,
42
+ // ./hooks/useProducts, ./hooks/useOrders, ./hooks/useOffers,
43
+ // ./hooks/useMetrics, ./services/pushNotifications
44
+ // ])
45
+ ```
46
+
47
+ ### 1.2 — `src/main.tsx` — Sin anotaciones OPL
48
+ **Archivo:** `src/main.tsx` (11 líneas)
49
+
50
+ ```typescript
51
+ // @use(kind, deps)
52
+ // @kind(entry)
53
+ // @deps(@external: [react-dom, @ionic/react], @internal: [./App])
54
+ ```
55
+
56
+ ### 1.3 — `src/hooks/useAuth.ts` — Sin anotaciones OPL
57
+ **Archivo:** `src/hooks/useAuth.ts` (98 líneas)
58
+
59
+ ```typescript
60
+ // @use(kind, contract, limit, deps)
61
+ // @kind(hook)
62
+ // @contract(in: void -> out: UseAuthReturn)
63
+ // @limit(lines: 100)
64
+ // @deps(@external: [react, sonner, @supabase/supabase-js], @internal: [../lib/supabase])
65
+ ```
66
+
67
+ ### 1.4 — `src/hooks/useAppData.ts` — Sin anotaciones OPL
68
+ **Archivo:** `src/hooks/useAppData.ts` (199 líneas)
69
+
70
+ ```typescript
71
+ // @use(kind, contract, limit, deps)
72
+ // @kind(hook)
73
+ // @contract(in: void -> out: UseAppDataReturn)
74
+ // @limit(lines: 200, params: 0)
75
+ // @deps(@external: [react, sonner, @supabase/supabase-js], @internal: [
76
+ // ../lib/supabase, ../lib/cache, ../utils/mappers, ../types
77
+ // ])
78
+ ```
79
+
80
+ ### 1.5 — `src/hooks/useOrders.ts` — Sin anotaciones OPL
81
+ **Archivo:** `src/hooks/useOrders.ts` (97 líneas)
82
+
83
+ ```typescript
84
+ // @use(kind, contract, limit, deps)
85
+ // @kind(hook)
86
+ // @contract(in: UseOrdersOptions -> out: UseOrdersReturn)
87
+ // @limit(lines: 100)
88
+ // @deps(@external: [react, sonner, @supabase/supabase-js], @internal: [../lib/supabase, ../types])
89
+ ```
90
+
91
+ ### 1.6 — `src/hooks/useProducts.ts` — Sin anotaciones OPL
92
+ **Archivo:** `src/hooks/useProducts.ts` (256 líneas)
93
+
94
+ ```typescript
95
+ // @use(kind, contract, limit, deps)
96
+ // @kind(hook)
97
+ // @contract(in: UseProductsOptions -> out: UseProductsReturn)
98
+ // @limit(lines: 260, params: 1)
99
+ // @deps(@external: [react, sonner, @supabase/supabase-js], @internal: [
100
+ // ../lib/supabase, ../lib/cache, ../types/product, ../types
101
+ // ])
102
+ ```
103
+
104
+ ### 1.7 — `src/hooks/useOffers.ts` — Sin anotaciones OPL
105
+ **Archivo:** `src/hooks/useOffers.ts` (60 líneas)
106
+
107
+ ```typescript
108
+ // @use(kind, contract, limit, deps)
109
+ // @kind(hook)
110
+ // @contract(in: UseOffersOptions -> out: UseOffersReturn)
111
+ // @limit(lines: 60)
112
+ // @deps(@external: [react, sonner, @supabase/supabase-js], @internal: [../lib/supabase, ../lib/cache, ../types])
113
+ ```
114
+
115
+ ### 1.8 — `src/hooks/useRealtimeSync.ts` — Sin anotaciones OPL
116
+ **Archivo:** `src/hooks/useRealtimeSync.ts` (102 líneas)
117
+
118
+ ```typescript
119
+ // @use(kind, contract, limit, deps)
120
+ // @kind(hook)
121
+ // @contract(in: UseRealtimeSyncOptions -> out: void)
122
+ // @limit(lines: 105)
123
+ // @deps(@external: [react, sonner, @supabase/supabase-js], @internal: [
124
+ // ../lib/supabase, ../types, ../types/product, ../utils/mappers
125
+ // ])
126
+ ```
127
+
128
+ ### 1.9 — `src/hooks/useMetrics.ts` — Sin anotaciones OPL
129
+ **Archivo:** `src/hooks/useMetrics.ts` (154 líneas)
130
+
131
+ ```typescript
132
+ // @use(kind, contract, limit, deps)
133
+ // @kind(hook)
134
+ // @contract(in: orders: Order[], products: Product[], reviews: any[], userMetrics -> out: { metrics, isCrunching })
135
+ // @limit(lines: 155)
136
+ // @deps(@external: [react], @internal: [../types, ../types/product])
137
+ ```
138
+
139
+ ### 1.10 — `src/hooks/useDeliveryZones.ts` — TIENE anotaciones (bien)
140
+ ✅ Archivo ya tiene `// @use(kind, contract, limit, deps)` correctamente.
141
+
142
+ ### 1.11 — `src/lib/supabase.ts` — Sin anotaciones OPL
143
+ **Archivo:** `src/lib/supabase.ts` (27 líneas)
144
+
145
+ ```typescript
146
+ // @use(kind, contract, limit, deps)
147
+ // @kind(lib)
148
+ // @contract(in: void -> out: SupabaseClient)
149
+ // @limit(lines: 30)
150
+ // @deps(@external: [@supabase/supabase-js])
151
+ ```
152
+
153
+ ### 1.12 — `src/lib/cache.ts` — Sin anotaciones OPL
154
+ **Archivo:** `src/lib/cache.ts` (59 líneas)
155
+
156
+ ```typescript
157
+ // @use(kind, contract, limit)
158
+ // @kind(service)
159
+ // @contract(in: setCache(key, data, ttl) -> void | getCache(key) -> T | null)
160
+ // @limit(lines: 60)
161
+ ```
162
+
163
+ ### 1.13 — `src/lib/queue.ts` — Sin anotaciones OPL
164
+ **Archivo:** `src/lib/queue.ts` (65 líneas)
165
+
166
+ ```typescript
167
+ // @use(kind, contract, limit)
168
+ // @kind(service)
169
+ // @contract(in: QueueItem -> out: void)
170
+ // @limit(lines: 65)
171
+ ```
172
+
173
+ ### 1.14 — `src/lib/storage.ts` — Sin anotaciones OPL
174
+ **Archivo:** `src/lib/storage.ts` (91 líneas)
175
+
176
+ ```typescript
177
+ // @use(kind, contract, limit, deps)
178
+ // @kind(service)
179
+ // @contract(in: files: File[], productId: string -> out: string[])
180
+ // @limit(lines: 95)
181
+ // @deps(@external: [@supabase/supabase-js], @internal: [./supabase])
182
+ ```
183
+
184
+ ### 1.15 — `src/lib/sanitizer.ts` — Sin anotaciones OPL
185
+ **Archivo:** `src/lib/sanitizer.ts` (27 líneas)
186
+
187
+ ```typescript
188
+ // @use(kind, contract, limit)
189
+ // @kind(util)
190
+ // @contract(in: text: string | undefined | null -> out: string)
191
+ // @limit(lines: 30)
192
+ // @forbidden(any)
193
+ ```
194
+
195
+ ### 1.16 — `src/lib/supabaseLogger.ts` — Sin anotaciones OPL
196
+ **Archivo:** `src/lib/supabaseLogger.ts` (172 líneas)
197
+
198
+ ```typescript
199
+ // @use(kind, contract, limit, deps)
200
+ // @kind(service)
201
+ // @contract(in: supabaseUrl: string -> out: class SupabaseLogger)
202
+ // @limit(lines: 175)
203
+ // @deps(@external: [crypto])
204
+ ```
205
+
206
+ ---
207
+
208
+ ## 🔴 CATEGORÍA 2: Componentes sin anotaciones OPL
209
+
210
+ ### 2.1 — Componentes de página (todos sin anotaciones)
211
+
212
+ | Archivo | Líneas | Anotaciones |
213
+ |---------|--------|-------------|
214
+ | `src/components/Dashboard.tsx` | 148 | ❌ Faltan |
215
+ | `src/components/Catalog.tsx` | 379 | ❌ Faltan |
216
+ | `src/components/Login.tsx` | 294 | ❌ Faltan |
217
+ | `src/components/Reports.tsx` | 388 | ❌ Faltan |
218
+ | `src/components/Settings.tsx` | 402 | ❌ Faltan |
219
+ | `src/components/BottomNav.tsx` | 57 | ❌ Faltan |
220
+ | `src/components/Notifications.tsx` | 167 | ❌ Faltan |
221
+ | `src/components/OrderDetail.tsx` | 391 | ❌ Faltan |
222
+ | `src/components/OrderCard.tsx` | 92 | ❌ Faltan |
223
+ | `src/components/ProductCard.tsx` | 183 | ❌ Faltan |
224
+ | `src/components/ProductForm.tsx` | 468 | ❌ Faltan (**MUY GRANDE**, debe dividirse) |
225
+ | `src/components/UserManagement.tsx` | 238 | ❌ Faltan |
226
+ | `src/components/ReviewModeration.tsx` | 171 | ❌ Faltan |
227
+ | `src/components/InboxTab.tsx` | 31 | ❌ Faltan |
228
+ | `src/components/ActiveOrdersTab.tsx` | 31 | ❌ Faltan |
229
+ | `src/components/HistoryTab.tsx` | — | ❌ Faltan |
230
+ | `src/components/DeliveryZones.tsx` | 272 | ✅ **TIENE** anotaciones |
231
+
232
+ ### 2.2 — Modales (todos sin anotaciones)
233
+
234
+ | Archivo | Líneas | Anotaciones |
235
+ |---------|--------|-------------|
236
+ | `src/components/PinPadModal.tsx` | 176 | ❌ Faltan |
237
+ | `src/components/OfferBuilderModal.tsx` | 202 | ❌ Faltan |
238
+ | `src/components/OfferExecutionModal.tsx` | — | ❌ Faltan |
239
+ | `src/components/QueueModal.tsx` | — | ❌ Faltan |
240
+ | `src/components/StockModal.tsx` | — | ❌ Faltan |
241
+ | `src/components/RejectModal.tsx` | — | ❌ Faltan |
242
+ | `src/components/DelayedConfirmModal.tsx` | — | ❌ Faltan |
243
+ | `src/components/CalendarModal.tsx` | — | ❌ Faltan |
244
+ | `src/components/ChangePasswordModal.tsx` | — | ❌ Faltan |
245
+ | `src/components/CategoryPickerModal.tsx` | — | ❌ Faltan |
246
+ | `src/components/AboutModal.tsx` | — | ❌ Faltan |
247
+ | `src/components/OfflineRestrictionModal.tsx` | — | ❌ Faltan |
248
+ | `src/components/ConnectionDebugModal.tsx` | — | ❌ Faltan (código muerto) |
249
+ | `src/components/DebugPanel.tsx` | — | ❌ Faltan (código muerto) |
250
+
251
+ ### 2.3 — Servicios
252
+
253
+ | Archivo | Líneas | Anotaciones |
254
+ |---------|--------|-------------|
255
+ | `src/services/pushNotifications.ts` | 93 | ✅ **TIENE** anotaciones |
256
+
257
+ ### 2.4 — Utils
258
+
259
+ | Archivo | Líneas | Anotaciones |
260
+ |---------|--------|-------------|
261
+ | `src/utils/mappers.ts` | 46 | ❌ Faltan |
262
+ | `src/utils/imageUtils.ts` | 73 | ❌ Faltan |
263
+
264
+ ### 2.5 — Web/Theme
265
+
266
+ | Archivo | Líneas | Anotaciones |
267
+ |---------|--------|-------------|
268
+ | `src/web/ThemeContext.tsx` | 62 | ❌ Faltan |
269
+ | `src/web/themes.ts` | — | ❌ Faltan |
270
+
271
+ ---
272
+
273
+ ## 🟡 CATEGORÍA 3: Errores de diseño y código detectados
274
+
275
+ ### 3.1 — 🔴 Overfetching masivo de Supabase
276
+ **Archivo:** `src/hooks/useAppData.ts` (líneas 101-124)
277
+ ```typescript
278
+ // ❌ Se traen TODAS las columnas de 5 tablas
279
+ const ordersPromise = supabase.from('orders').select('*, order_items(*)').range(0, 99);
280
+ const productsPromise = supabase.from('products').select('*');
281
+ ```
282
+ **Impacto:** $40-80/mes extra en ancho de banda de Supabase.
283
+
284
+ ### 3.2 — 🔴 3 canales Realtime en vez de 1
285
+ **Archivo:** `src/hooks/useRealtimeSync.ts` (líneas 28-93)
286
+ ```typescript
287
+ // ❌ 3 suscripciones separadas
288
+ supabase.channel('public:orders')...
289
+ supabase.channel('public:offer_reminders')...
290
+ supabase.channel('public:products')...
291
+ ```
292
+ **Impacto:** $20-50/mes extra. Debe ser un solo canal.
293
+
294
+ ### 3.3 — 🔴 Efecto colateral dentro de setState
295
+ **Archivo:** `src/hooks/useProducts.ts` (líneas 140-191)
296
+ ```typescript
297
+ setProducts(prevProducts => {
298
+ // ❌ Llamada a Supabase DENTRO del updater de setState
299
+ supabase.from('products').update(updates).eq('id', productId).then(...)
300
+ return prevProducts.map(...)
301
+ });
302
+ ```
303
+ **Impacto:** Anti-pattern grave. Causa doble ejecución en StrictMode.
304
+
305
+ ### 3.4 — 🔴 Sin RLS en tablas principales
306
+ **Archivo:** `supabase/migrations/`
307
+ - ✅ `admin_push_tokens` → RLS implementado
308
+ - ✅ `event_logs` → RLS implementado
309
+ - ❌ `orders` → SIN RLS
310
+ - ❌ `products` → SIN RLS
311
+ - ❌ `order_items` → SIN RLS
312
+ - ❌ `product_reviews` → SIN RLS
313
+ - ❌ `offer_reminders` → SIN RLS
314
+ - ❌ `delivery_zones` → SIN RLS
315
+ - ❌ `user_profiles` → SIN RLS
316
+
317
+ **Impacto:** Cualquiera con la anon key puede leer/modificar/borrar datos.
318
+
319
+ ### 3.5 — 🔴 `.env` comiteado en Git
320
+ **Archivo:** `.env`
321
+ ```env
322
+ VITE_SUPABASE_URL=https://cszlktmntlyqeslilpnu.supabase.co
323
+ VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIs...
324
+ ```
325
+ **Impacto:** Credenciales expuestas permanentemente en el historial de Git.
326
+
327
+ ### 3.6 — 🔴 PIN secreto hardcodeado
328
+ **Archivo:** `src/components/Login.tsx` (línea 9)
329
+ ```typescript
330
+ const CREATION_SECRET_PIN = '738250';
331
+ ```
332
+ **Impacto:** Cualquiera que lea el código sabe el PIN para crear cuentas admin.
333
+
334
+ ### 3.7 — 🟡 N+1 queries en bulk offer
335
+ **Archivo:** `src/hooks/useProducts.ts` (líneas 221-228)
336
+ ```typescript
337
+ // ❌ N updates individuales en vez de 1 batch
338
+ const uparts = updates.map(u => supabase.from('products').update({...}).eq('id', u.id));
339
+ await Promise.all(uparts);
340
+ ```
341
+
342
+ ### 3.8 — 🟡 `useMemo` usado como `useEffect`
343
+ **Archivo:** `src/App.tsx` (líneas 102-106)
344
+ ```typescript
345
+ // ❌ useMemo es para valores computados, no efectos
346
+ useMemo(() => { registerPushNotifications(user.id) }, [user?.id]);
347
+ ```
348
+
349
+ ### 3.9 — 🟡 JSON.stringify como dependencias de useEffect
350
+ **Archivo:** `src/hooks/useMetrics.ts` (líneas 144-151)
351
+ ```typescript
352
+ // ❌ Serialización completa en cada render
353
+ useEffect(() => { ... }, [JSON.stringify(orders.map(...))]);
354
+ ```
355
+
356
+ ### 3.10 — 🟡 Hook monstruo useAppData
357
+ **Archivo:** `src/hooks/useAppData.ts` (199 líneas)
358
+ **Problema:** Maneja 11 estados + 7 setters de 5 dominios diferentes (products, orders, reviews, reminders, metrics, dbStatus, loading).
359
+
360
+ ### 3.11 — 🟡 ProductForm de 468 líneas
361
+ **Archivo:** `src/components/ProductForm.tsx` (468 líneas)
362
+ **Problema:** Supera el límite recomendado de 200-250 líneas. Debe dividirse en subcomponentes.
363
+
364
+ ### 3.12 — 🟡 Caché inconsistente
365
+ **Archivo:** `src/hooks/useAppData.ts` (líneas 81-136)
366
+ **Problema:** `setCache` guarda datos crudos de Supabase, pero `getCache` consume datos mapeados. Hay doble transformación.
367
+
368
+ ### 3.13 — 🟡 fetchRole llamado dos veces en useAuth
369
+ **Archivo:** `src/hooks/useAuth.ts` (líneas 46-69)
370
+ **Problema:** `getSession()` dispara fetchRole y `onAuthStateChange` también lo dispara para el evento INITIAL_SESSION.
371
+
372
+ ### 3.14 — 🟡 handleDeleteUser solo elimina perfil, no auth user
373
+ **Archivo:** `src/components/UserManagement.tsx` (línea 103)
374
+ ```typescript
375
+ await supabase.from('user_profiles').delete().eq('id', id);
376
+ // ❌ auth.users sigue existiendo
377
+ ```
378
+
379
+ ### 3.15 — 🟡 Código muerto: ConnectionDebugModal, DebugPanel
380
+ **Archivos:** `src/components/ConnectionDebugModal.tsx`, `src/components/DebugPanel.tsx`
381
+ **Problema:** Componentes que existen pero no se importan ni usan en App.tsx.
382
+
383
+ ### 3.16 — 🟡 49 componentes shadcn/ui instalados, muchos sin usar
384
+ **Archivo:** `src/components/ui/` (49 archivos)
385
+ **Problema:** Se instaló shadcn/ui completo pero muchos componentes (carousel, chart, command, context-menu, hover-card, input-otp, menubar, navigation-menu, pagination, resizable, scroll-area, sidebar, slider, toggle-group, tooltip, etc.) no se usan.
386
+
387
+ ### 3.17 — 🟡 16 CSS modulares + Tailwind duplicados
388
+ **Archivo:** `src/styles/*.css` (16 archivos)
389
+ **Problema:** Se mezcla Tailwind (`@apply`) con CSS clásico, duplicando estilos y aumentando el bundle.
390
+
391
+ ### 3.18 — 🟡 sanitizer.ts rompe caracteres UTF-8
392
+ **Archivo:** `src/lib/sanitizer.ts` (líneas 16-20)
393
+ ```typescript
394
+ .replace(/'/g, '’') // ❌ Rompe "Don's Special" → "Don’s Special"
395
+ .replace(/"/g, '”') // ❌ Rompe comillas válidas
396
+ ```
397
+
398
+ ### 3.19 — 🟡 Edge Functions no integradas con frontend
399
+ **Archivos:** `supabase/functions/` (4 funciones)
400
+ **Problema:** `apply-queue` duplica lógica del frontend, `sync-snapshot` nunca se llama, `new-order` solo logea.
401
+
402
+ ### 3.20 — 🟡 16 parámetros en useCapacitorLifecycle
403
+ **Archivo:** `src/hooks/useCapacitorLifecycle.ts` (líneas 12-31)
404
+ **Problema:** Demasiadas propiedades en el options object (code smell).
405
+
406
+ ### 3.21 — 🟡 Alias @/ configurado pero no usado
407
+ **Archivos:** `vite.config.ts:51`, `tsconfig.json:23-24`
408
+ ```json
409
+ "paths": { "@/*": ["./src/*"] }
410
+ ```
411
+ **Problema:** Ningún archivo importa con `@/`, todos usan rutas relativas como `../`.
412
+
413
+ ### 3.22 — 🟡 edge functions `_shared/` con secretos hardcodeados potenciales
414
+ **Archivo:** `supabase/functions/notify-admin/index.ts`
415
+ **Problema:** Usa `Deno.env.get()` para credenciales de Firebase, pero no hay validación de que existan.
416
+
417
+ ### 3.23 — 🟢 Duplicación de scrollbar-hide y hide-scrollbar
418
+ **Archivo:** `src/index.css` (líneas 90-104)
419
+ **Problema:** Dos utility classes con el mismo propósito.
420
+
421
+ ### 3.24 — 🟢 Variables CSS --brand-* duplican propósito de Tailwind
422
+ **Archivo:** `src/index.css` (líneas 37-41)
423
+ **Problema:** Las variables CSS solo se usan en los CSS modulares, no en Tailwind.
424
+
425
+ ### 3.25 — 🟢 Sin tests unitarios
426
+ **Problema:** No hay ningún archivo de test (`*.test.ts`, `*.spec.ts`). No se puede verificar regresión.
427
+
428
+ ---
429
+
430
+ ## 💰 Impacto económico estimado en Supabase
431
+
432
+ | Problema | Costo/mes | Solución |
433
+ |----------|-----------|----------|
434
+ | Overfetching (SELECT *) | $40-80 | Columnas específicas |
435
+ | 3 canales Realtime | $20-50 | 1 canal |
436
+ | N+1 queries bulk offers | $5-15 | Batch `.in()` |
437
+ | Sin RLS (riesgo de abuso) | $100+ | RLS policies |
438
+ | Sin paginación real | $10-30 | Cursor-based |
439
+ | **Total evitable** | **~$75-175/mes** | |
440
+
441
+ ---
442
+
443
+ ## 📋 Checklist de resolución
444
+
445
+ ### 🔴 Prioridad 1 — Seguridad (HACER AHORA)
446
+
447
+ - [ ] **P1.1** Agregar `@use()`, `@kind`, `@contract`, `@deps` a TODOS los archivos
448
+ - [ ] **P1.2** Implementar RLS en todas las tablas (orders, products, order_items, product_reviews, offer_reminders, delivery_zones, user_profiles)
449
+ - [ ] **P1.3** Agregar `.env` a `.gitignore` y rotar la anon key
450
+ - [ ] **P1.4** Mover PIN secreto a variable de entorno
451
+ - [ ] **P1.5** Fix: handleToggleSale — sacar efecto colateral de setState
452
+
453
+ ### 🔴 Prioridad 2 — Performance (HACER PRONTO)
454
+
455
+ - [ ] **P2.1** Optimizar fetchData con columnas específicas + paginación cursor-based
456
+ - [ ] **P2.2** Reducir de 3 a 1 canal Realtime con filtros por tabla
457
+ - [ ] **P2.3** Cambiar N+1 queries a batch update con `.in()`
458
+ - [ ] **P2.4** Reemplazar `useMemo` por `useEffect` en push notifications
459
+
460
+ ### 🟡 Prioridad 3 — Refactor (PLAZO MEDIO)
461
+
462
+ - [ ] **P3.1** Separar `useAppData` en hooks por dominio
463
+ - [ ] **P3.2** Dividir ProductForm en subcomponentes (< 250 líneas c/u)
464
+ - [ ] **P3.3** Unificar CSS: eliminar 16 CSS modulares, usar solo Tailwind
465
+ - [ ] **P3.4** Limpiar shadcn/ui no utilizados
466
+ - [ ] **P3.5** Eliminar código duplicado (compressImage, scrollbar classes)
467
+ - [ ] **P3.6** Eliminar código muerto (ConnectionDebugModal, DebugPanel)
468
+ - [ ] **P3.7** Usar alias @/ en imports
469
+ - [ ] **P3.8** Revisar/fix sanitizer.ts (no romper UTF-8)
470
+ - [ ] **P3.9** Integrar Edge Functions reales con frontend
471
+ - [ ] **P3.10** Agregar test unitarios (mínimo 1 por hook)
472
+
473
+ ### 🟢 Prioridad 4 — Deuda técnica menor
474
+
475
+ - [ ] **P4.1** Crear @learn-error por cada bug fijo
476
+ - [ ] **P4.2** Configurar `prompt-lang.json` con strict mode
477
+ - [ ] **P4.3** Establecer dominio en `prompt-lang.json`
478
+ - [ ] **P4.4** Ejecutar `npx openprompt-lang qa-gen` para generar tests
479
+
480
+ ---
481
+
482
+ ## 📌 Archivos con anotaciones OPL ya existentes (para referencia)
483
+
484
+ ✅ Estos archivos ya tienen anotaciones y sirven como modelo:
485
+
486
+ 1. `src/hooks/useOfflineQueue.ts`
487
+ 2. `src/hooks/useCapacitorLifecycle.ts`
488
+ 3. `src/hooks/useDeliveryZones.ts`
489
+ 4. `src/services/pushNotifications.ts`
490
+ 5. `src/components/DeliveryZones.tsx`
491
+
492
+ ---
493
+
494
+ ## 🏁 Notas finales
495
+
496
+ Este documento debe actualizarse a medida que se resuelvan los problemas.
497
+ Cada vez que se corrija un error, agregar:
498
+ ```typescript
499
+ // @learn-error id=XXX input='...' expected=200 actual=500 fix='...'
500
+ ```
501
+
502
+ ---
503
+
504
+ *Documento generado durante sesión de auditoría OPL — 2026-05-23*
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openprompt-lang",
3
- "version": "1.2.4",
3
+ "version": "1.2.7",
4
4
  "description": "PromptLang CLI — Context Engine de anotaciones para desarrollo asistido por IA",
5
5
  "type": "module",
6
6
  "main": "./bin/cli.js",
@@ -6,7 +6,9 @@
6
6
  export function register(program) {
7
7
  const workContext = program
8
8
  .command("work-context")
9
- .description("Gestionar contexto de trabajo, planes, logs y aprendizajes")
9
+ .description(
10
+ "Gestionar contexto de trabajo (integrado con 'opl workflow' — start≈delivery, close≈close)"
11
+ )
10
12
 
11
13
  workContext
12
14
  .command("init")
@@ -15,7 +15,8 @@ export async function init(options) {
15
15
  const dryRun = options.dryRun || false
16
16
 
17
17
  const cwd = process.cwd()
18
- const isInitialized = existsSync(join(cwd, "prompt-lang.json")) || existsSync(join(cwd, ".openprompt"))
18
+ const isInitialized =
19
+ existsSync(join(cwd, "prompt-lang.json")) || existsSync(join(cwd, ".openprompt"))
19
20
 
20
21
  if (interactive && !options.existing && !options.name && !options.preset && !options.stack) {
21
22
  console.log(chalk.cyan("\n🧙 openPrompt-Lang — Inicialización\n"))
@@ -23,7 +24,10 @@ export async function init(options) {
23
24
  const choices = []
24
25
 
25
26
  if (isInitialized) {
26
- choices.push({ name: chalk.yellow(" Actualizar/Reconstruir la integración (Rebuild)"), value: "rebuild" })
27
+ choices.push({
28
+ name: chalk.yellow(" Actualizar/Reconstruir la integración (Rebuild)"),
29
+ value: "rebuild",
30
+ })
27
31
  choices.push(new inquirer.Separator())
28
32
  }
29
33
 
@@ -41,7 +45,9 @@ export async function init(options) {
41
45
  {
42
46
  type: "list",
43
47
  name: "projectType",
44
- message: isInitialized ? "Este proyecto ya tiene OPL. ¿Qué deseas hacer?" : "¿Qué tipo de proyecto?",
48
+ message: isInitialized
49
+ ? "Este proyecto ya tiene OPL. ¿Qué deseas hacer?"
50
+ : "¿Qué tipo de proyecto?",
45
51
  choices,
46
52
  },
47
53
  ])
@@ -137,9 +143,14 @@ export async function init(options) {
137
143
  // ── Handoff a la IA ──
138
144
  console.log(chalk.cyan("\n✨ OPL Init: Estructura base lista."))
139
145
  console.log(chalk.yellow("OPL delega ahora la inicialización estratégica a tu Agente IA."))
140
- console.log(chalk.white("Copia y pega el siguiente prompt en tu chat con la IA (ej. Cline, Cursor, OpenCode, etc.):\n"))
141
-
142
- console.log(chalk.bgGray.white(`
146
+ console.log(
147
+ chalk.white(
148
+ "Copia y pega el siguiente prompt en tu chat con la IA (ej. Cline, Cursor, OpenCode, etc.):\n"
149
+ )
150
+ )
151
+
152
+ console.log(
153
+ chalk.bgGray.white(`
143
154
  "Asume el rol de Arquitecto Principal OPL. Acabo de ejecutar opl init para un proyecto NUEVO llamado '${finalName}'.
144
155
 
145
156
  Tu proceso obligatorio es:
@@ -149,7 +160,8 @@ Tu proceso obligatorio es:
149
160
  4. Usa 'init_project' y 'scaffold_project' para configurar el proyecto.
150
161
  5. Genera los archivos canónicos: AGENTS.md, prompt-lang.json, .openprompt/FRAMEWORK.md.
151
162
  6. Confirma explícitamente que el proyecto quedó estabilizado e indícame el siguiente paso operativo."
152
- `))
163
+ `)
164
+ )
153
165
 
154
166
  return finalBaseDir
155
167
  }