openprompt-lang 0.3.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.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +663 -0
  3. package/bin/cli.js +110 -0
  4. package/bin/lint.js +50 -0
  5. package/docs/COMMANDS.md +229 -0
  6. package/docs/COMMITS/INDEX.md +11 -0
  7. package/docs/COMMITS/v0.1.0-existing.md +31 -0
  8. package/docs/COMMITS/v0.1.0-inicial.md +50 -0
  9. package/docs/COMMITS/v0.1.0-readme.md +24 -0
  10. package/docs/COMMITS/v0.2.0-strict-db-templates.md +50 -0
  11. package/docs/COMMITS/v0.3.0-parser-fixes-vscode.md +67 -0
  12. package/docs/COMMITS/v0.3.0-versioning-component.md +44 -0
  13. package/docs/DEPENDENCIES.md +45 -0
  14. package/docs/FRAMEWORK.md +1741 -0
  15. package/docs/SYNTAX.md +359 -0
  16. package/docs/VERSIONING.md +150 -0
  17. package/docs/referencia-metodologia/Anexos Finales Documentos de Respaldo y Estandarizaci/303/263n.md" +90 -0
  18. package/docs/referencia-metodologia/Cotizaciones.md +84 -0
  19. package/docs/referencia-metodologia/Example.md +1 -0
  20. package/docs/referencia-metodologia/ExtractorInformacion.py +78 -0
  21. package/docs/referencia-metodologia/Fase - 1 .- Desarrollo de la Metodolog/303/255a.md" +67 -0
  22. package/docs/referencia-metodologia/Fase - 2 .- Levantamiento de requisitos generales y traduccion a la IA.md +64 -0
  23. package/docs/referencia-metodologia/Fase - 3 .- Prototipado visual con IA (Figma Maker o equivalentes).md +64 -0
  24. package/docs/referencia-metodologia/Fase - 4 .- Especificacion de requisitos e iteracion con el cliente.md +58 -0
  25. package/docs/referencia-metodologia/Fase - 5 .- Estructuracion y maquetado de funciones (Scaffolding).md +118 -0
  26. package/docs/referencia-metodologia/Fase - 6 .- Estructuracion del backlog y division de tareas.md +48 -0
  27. package/docs/referencia-metodologia/Fase - 7 .- Desarrollo activo, pruebas y control de versiones.md +98 -0
  28. package/docs/referencia-metodologia/Fase - 8 .- Entrega, capacitaci/303/263n y mantenimiento.md" +55 -0
  29. package/docs/referencia-metodologia/Figma prompt template.md +130 -0
  30. package/docs/referencia-metodologia/Framework de Desarrollo Asistido por IA.md +1741 -0
  31. package/docs/referencia-metodologia/Indice General.md +83 -0
  32. package/docs/referencia-metodologia/Prompt refactorizar o creacion desde cero.md +50 -0
  33. package/docs/referencia-metodologia/docs/CONVENCIONES_DB.md +410 -0
  34. package/docs/referencia-metodologia/docs/CONVENCIONES_DOCUMENTACION.md +209 -0
  35. package/docs/referencia-metodologia/docs/PROMPTS/INDEX.md +73 -0
  36. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/01-hook-supabase.md +79 -0
  37. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/02-componente-ui.md +82 -0
  38. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/03-pagina-feature.md +70 -0
  39. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/04-comando-tauri.md +56 -0
  40. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/05-store-zustand.md +74 -0
  41. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/06-servicio-supabase.md +74 -0
  42. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/07-formulario-validacion.md +63 -0
  43. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/08-hook-capacitor.md +65 -0
  44. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/09-refactor-division.md +51 -0
  45. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/10-scaffolding-inicial.md +79 -0
  46. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/11-supabase-crud-service.md +114 -0
  47. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/12-supabase-hook-usetable.md +143 -0
  48. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/13-tauri-command-rust.md +84 -0
  49. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/14-tauri-wrapper-typescript.md +92 -0
  50. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/15-documentar-tabla-db.md +50 -0
  51. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/16-diagrama-arquitectura.md +60 -0
  52. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/17-documentar-api-rpc.md +56 -0
  53. package/docs/referencia-metodologia/docs/PROMPTS/STACK/ionic-capacitor.md +52 -0
  54. package/docs/referencia-metodologia/docs/PROMPTS/STACK/react-web-puro.md +46 -0
  55. package/docs/referencia-metodologia/docs/PROMPTS/STACK/tauri-desktop.md +53 -0
  56. package/package.json +56 -0
  57. package/schemas/prompt-lang.json +98 -0
  58. package/src/commands/component.js +326 -0
  59. package/src/commands/context.js +206 -0
  60. package/src/commands/figma.js +63 -0
  61. package/src/commands/init.js +373 -0
  62. package/src/commands/suggest.js +31 -0
  63. package/src/commands/validate.js +183 -0
  64. package/src/generators/figma-prompt.js +56 -0
  65. package/src/utils/ai.js +143 -0
  66. package/src/utils/annotations.js +510 -0
  67. package/src/utils/config.js +60 -0
  68. package/vscode-extension/README.md +31 -0
  69. package/vscode-extension/language-configuration.json +7 -0
  70. package/vscode-extension/package.json +62 -0
  71. package/vscode-extension/snippets/promptlang.json +105 -0
  72. package/vscode-extension/syntaxes/annotations.tmGrammar.json +39 -0
  73. package/vscode-extension/syntaxes/promptlang.tmGrammar.json +14 -0
@@ -0,0 +1,74 @@
1
+ ---
2
+ title: Servicio CRUD con Supabase
3
+ tags: [servicio, supabase, crud, api]
4
+ usado_en: []
5
+ fecha_creacion: 2026-05-13
6
+ ultima_modificacion: 2026-05-13
7
+ ---
8
+
9
+ ## Cuándo usar
10
+
11
+ Cuando necesites una capa de servicio para operaciones CRUD contra una tabla de Supabase. Separa la lógica de base de datos de los hooks/componentes.
12
+
13
+ ## Prompt
14
+
15
+ ```markdown
16
+ ## Contexto
17
+ Stack: TypeScript + Supabase.
18
+ Convenciones: servicios en src/services/supabase/, un archivo por tabla/entidad, máximo 150 líneas.
19
+ Patrón: servicio con métodos estáticos nombrados como verbo + entidad (createUser, getProductById).
20
+ Referencia: docs/Framework de Desarrollo Asistido por IA.md sección 2 (estructura services/).
21
+
22
+ ## Objetivo
23
+ Crear el servicio `{Entity}Service` para operaciones CRUD contra la tabla `{table_name}` de Supabase.
24
+
25
+ ## Especificaciones técnicas
26
+ - Archivo: `src/services/supabase/{entity}Service.ts`
27
+ - Cliente Supabase importado desde `src/services/supabase/client.ts`
28
+ - Métodos requeridos:
29
+ - `getAll(filters?)`: listar con filtros opcionales
30
+ - `getById(id: string)`: obtener por ID
31
+ - `create(data: CreateDTO)`: crear registro
32
+ - `update(id: string, data: UpdateDTO)`: actualizar
33
+ - `delete(id: string)`: eliminar (lógico si aplica)
34
+ - Tipos DTO en `src/services/supabase/types.ts` o local en el archivo
35
+
36
+ ## Reglas estrictas
37
+ - Cada método debe tener su tipo de entrada y salida definido
38
+ - Manejar errores con try/catch y devolver { data, error } siempre
39
+ - No exponer errores de Supabase al cliente (traducirlos)
40
+ - Si hay políticas RLS, el servicio debe recibir el userId como parámetro
41
+
42
+ ## Anti-patrones (prohibido)
43
+ - NO hacer llamadas a Supabase directamente desde componentes
44
+ - NO exponer errores internos de Supabase (code, hint, details)
45
+ - NO mezclar lógica de negocio con lógica de presentación
46
+
47
+ ## Ejemplo de estructura
48
+ ```typescript
49
+ interface CreateProductDTO {
50
+ name: string
51
+ price: number
52
+ category_id: string
53
+ }
54
+
55
+ interface Product {
56
+ id: string
57
+ name: string
58
+ price: number
59
+ created_at: string
60
+ }
61
+
62
+ export const productService = {
63
+ async getAll(): Promise<{ data: Product[]; error: string | null }> {
64
+ // implementación
65
+ },
66
+ async create(dto: CreateProductDTO): Promise<{ data: Product | null; error: string | null }> {
67
+ // implementación
68
+ },
69
+ }
70
+ ```
71
+
72
+ ## Formato de salida esperado
73
+ Archivo completo listo para `src/services/supabase/{entity}Service.ts`.
74
+ ```
@@ -0,0 +1,63 @@
1
+ ---
2
+ title: Formulario con validación (react-hook-form + zod)
3
+ tags: [formulario, validacion, react-hook-form, zod, typescript]
4
+ usado_en: []
5
+ fecha_creacion: 2026-05-13
6
+ ultima_modificacion: 2026-05-13
7
+ ---
8
+
9
+ ## Cuándo usar
10
+
11
+ Cuando necesites un formulario con validación en frontend. La combinación react-hook-form + zod es la más usada en proyectos React modernos por su tipado y rendimiento.
12
+
13
+ ## Prompt
14
+
15
+ ```markdown
16
+ ## Contexto
17
+ Stack: React 18 + TypeScript + Tailwind + react-hook-form + zod.
18
+ Convenciones: formularios en src/features/{feature}/components/, schema de validación junto al formulario o en types/.
19
+ Referencia: docs/Framework de Desarrollo Asistido por IA.md sección 7 (patrones de reutilización).
20
+
21
+ ## Objetivo
22
+ Crear el formulario `{FormName}` con validación usando react-hook-form + zod.
23
+
24
+ ## Especificaciones técnicas
25
+ - Archivo: `src/features/{feature}/components/{FormName}.tsx`
26
+ - Schema zod: definir las validaciones de cada campo
27
+ - hook-form con `zodResolver` para integración
28
+ - Campos del formulario:
29
+ - {campo 1: tipo, validación, placeholder}
30
+ - {campo 2: tipo, validación, placeholder}
31
+ - onSubmit: recibir callback `onSubmit(data: SchemaType) => void`
32
+ - Estados: idle, submitting, error, success
33
+ - Máximo 150 líneas
34
+
35
+ ## Reglas estrictas
36
+ - El schema zod debe definir tipos explícitos (z.string(), z.number(), etc.)
37
+ - Los mensajes de error deben estar en español
38
+ - Cada campo debe mostrar su error debajo del input
39
+ - Botón de submit deshabilitado mientras se envía
40
+ - Los inputs deben usar componentes de ui/ (Input, Select, etc.)
41
+
42
+ ## Anti-patrones (prohibido)
43
+ - NO usar any
44
+ - NO mezclar lógica de negocio (llamadas API) dentro del formulario
45
+ - NO usar useState para validación manual (para eso está hook-form)
46
+ - NO mostrar errores de API en los mensajes de validación de campo
47
+
48
+ ## Ejemplo de schema
49
+ ```typescript
50
+ import { z } from "zod"
51
+
52
+ export const {FormName}Schema = z.object({
53
+ email: z.string().email("Email inválido"),
54
+ password: z.string().min(8, "Mínimo 8 caracteres"),
55
+ name: z.string().min(2, "Mínimo 2 caracteres").max(50, "Máximo 50 caracteres"),
56
+ })
57
+
58
+ export type {FormName}SchemaType = z.infer<typeof {FormName}Schema>
59
+ ```
60
+
61
+ ## Formato de salida esperado
62
+ Archivo completo con schema + componente de formulario + exportaciones.
63
+ ```
@@ -0,0 +1,65 @@
1
+ ---
2
+ title: Hook para plugin nativo de Capacitor
3
+ tags: [capacitor, hook, nativo, camara, plugin]
4
+ usado_en: []
5
+ fecha_creacion: 2026-05-13
6
+ ultima_modificacion: 2026-05-13
7
+ ---
8
+
9
+ ## Cuándo usar
10
+
11
+ Cuando necesites acceder a funcionalidad nativa del dispositivo (cámara, GPS, notificaciones, almacenamiento) a través de plugins de Capacitor. El hook encapsula la lógica del plugin y expone una interfaz limpia para los componentes.
12
+
13
+ ## Prompt
14
+
15
+ ```markdown
16
+ ## Contexto
17
+ Stack: React 18 + TypeScript + Capacitor 6 + Ionic 8.
18
+ Convenciones: hooks de Capacitor en src/hooks/ con prefijo useCapacitor*, un hook por archivo, máximo 80 líneas.
19
+ NO mezclar con lógica de Tauri.
20
+ Referencia: docs/Framework de Desarrollo Asistido por IA.md sección 1 (convenciones Capacitor).
21
+
22
+ ## Objetivo
23
+ Crear el hook `useCapacitor{Feature}` que encapsule el plugin `@capacitor/{plugin}`.
24
+
25
+ ## Especificaciones técnicas
26
+ - Archivo: `src/hooks/useCapacitor{Feature}.ts`
27
+ - Plugin a usar: `@capacitor/{plugin}`
28
+ - Retornar: `{ result: {tipo} | null; execute: () => Promise<void>; error: string | null; loading: boolean }`
29
+ - Manejar permisos: verificar permiso antes de ejecutar, pedir si no está concedido
30
+ - Manejar error si el permiso es denegado permanentemente
31
+ - Máximo 70 líneas
32
+
33
+ ## Reglas estrictas
34
+ - Tipar todas las funciones con TypeScript
35
+ - Verificar permisos antes de ejecutar cualquier acción nativa
36
+ - Si el permiso es denegado, mostrar mensaje claro (no el error interno del plugin)
37
+ - El hook debe funcionar tanto en web (fallback) como en dispositivo real
38
+
39
+ ## Anti-patrones (prohibido)
40
+ - NO usar any
41
+ - NO poner lógica de UI en el hook
42
+ - NO mezclar con lógica de Tauri
43
+ - NO asumir que el plugin está disponible sin verificar
44
+
45
+ ## Ejemplo correcto
46
+ ```typescript
47
+ interface UseCapacitorCameraResult {
48
+ photo: string | null
49
+ takePhoto: () => Promise<void>
50
+ error: string | null
51
+ loading: boolean
52
+ }
53
+
54
+ export function useCapacitorCamera(): UseCapacitorCameraResult {
55
+ // 1. Verificar permiso con Camera.checkPermissions()
56
+ // 2. Si no concedido, pedir con Camera.requestPermissions()
57
+ // 3. Si denegado, setear error
58
+ // 4. Si concedido, ejecutar Camera.getPhoto({ resultType: CameraResultType.Uri })
59
+ // 5. Retornar { photo, takePhoto, error, loading }
60
+ }
61
+ ```
62
+
63
+ ## Formato de salida esperado
64
+ Archivo completo listo para `src/hooks/useCapacitor{Feature}.ts`.
65
+ ```
@@ -0,0 +1,51 @@
1
+ ---
2
+ title: Refactorizar componente grande en módulos pequeños
3
+ tags: [refactor, division, modularizacion, limites]
4
+ usado_en: []
5
+ fecha_creacion: 2026-05-13
6
+ ultima_modificacion: 2026-05-13
7
+ ---
8
+
9
+ ## Cuándo usar
10
+
11
+ Cuando un componente supera los límites definidos en el catálogo (120 líneas UI, 80 hooks, 200 páginas) y necesitas dividirlo siguiendo el protocolo de separación automática.
12
+
13
+ ## Prompt
14
+
15
+ ```markdown
16
+ ## Contexto
17
+ Stack: React 18 + TypeScript + Tailwind.
18
+ Convenciones: docs/Framework de Desarrollo Asistido por IA.md sección 6 (límites por archivo + reglas de separación automática).
19
+ Archivo a refactorizar: `{ruta/al/archivo.tsx}` ({cantidad} líneas actuales).
20
+
21
+ ## Objetivo
22
+ Dividir el archivo `{nombre}` en módulos más pequeños según los límites del catálogo.
23
+
24
+ ## Análisis del archivo actual
25
+ El archivo contiene:
26
+ 1. {sección 1}: {subcomponente o lógica identificable}
27
+ 2. {sección 2}: {subcomponente o lógica identificable}
28
+ 3. {sección 3}: {estados, lógica de negocio, etc.}
29
+
30
+ ## Plan de división propuesto
31
+ Crear los siguientes archivos:
32
+ - `{ruta}/components/{SubComponente1}.tsx` (estimado {N} líneas)
33
+ - `{ruta}/components/{SubComponente2}.tsx` (estimado {N} líneas)
34
+ - `{ruta}/hooks/use{Nombre}Logic.ts` (estimado {N} líneas)
35
+ - El archivo original debe quedar en máximo 120 líneas
36
+
37
+ ## Reglas estrictas
38
+ - NO cambiar la funcionalidad existente, solo mover código
39
+ - Mantener los mismos imports y tipos, solo reubicarlos
40
+ - El archivo original debe importar desde los nuevos archivos
41
+ - Actualizar barrel exports (index.ts) si existen
42
+ - No crear archivos de menos de 20 líneas (si es tan pequeño, fusionar)
43
+
44
+ ## Anti-patrones (prohibido)
45
+ - NO renombrar funciones o props a menos que sea necesario para claridad
46
+ - NO cambiar la lógica de negocio durante la refactorización
47
+ - NO crear dependencias circulares entre los nuevos archivos
48
+
49
+ ## Formato de salida esperado
50
+ Lista de archivos creados/modificados con el contenido de cada uno y los imports actualizados.
51
+ ```
@@ -0,0 +1,79 @@
1
+ ---
2
+ title: Scaffolding completo de un feature/módulo
3
+ tags: [scaffolding, feature, setup, estructura-inicial]
4
+ usado_en: []
5
+ fecha_creacion: 2026-05-13
6
+ ultima_modificacion: 2026-05-13
7
+ ---
8
+
9
+ ## Cuándo usar
10
+
11
+ Al iniciar un nuevo feature o módulo dentro del proyecto. Crea toda la estructura de archivos (esqueletos vacíos con contratos) para que luego solo haya que implementar la lógica.
12
+
13
+ ## Prompt
14
+
15
+ ```markdown
16
+ ## Contexto
17
+ Stack: React 18 + TypeScript + {Tailwind/Supabase/etc}.
18
+ Convenciones: scaffolding con contratos de método, throw new Error("pendiente"), un archivo por responsabilidad.
19
+ Referencia: docs/Framework de Desarrollo Asistido por IA.md sección 2 (estructura features/) y sección 6 (límites).
20
+
21
+ ## Objetivo
22
+ Crear el scaffolding completo del feature `{featureName}`.
23
+
24
+ ## Estructura a crear
25
+ ```
26
+ src/features/{featureName}/
27
+ ├── components/
28
+ │ ├── {Component1}.tsx
29
+ │ ├── {Component2}.tsx
30
+ │ └── index.ts
31
+ ├── hooks/
32
+ │ ├── use{FeatureName}.ts
33
+ │ └── index.ts
34
+ ├── services/
35
+ │ └── {featureName}Service.ts
36
+ ├── types/
37
+ │ └── index.ts
38
+ ├── {FeatureName}Page.tsx
39
+ └── index.ts
40
+ ```
41
+
42
+ ## Especificaciones técnicas
43
+
44
+ ### types/index.ts
45
+ - Interfaces de las entidades del feature
46
+ - DTOs de creación y actualización
47
+
48
+ ### services/{featureName}Service.ts
49
+ - Métodos CRUD con contrato de método (inputs, outputs, flujo, impacto, error handling)
50
+ - Cuerpo: `throw new Error("Lógica pendiente: {descripción}")`
51
+
52
+ ### hooks/use{FeatureName}.ts
53
+ - Hook que conecta el servicio con el estado del componente
54
+ - Estados: data, loading, error
55
+ - Acciones: fetch, create, update, delete
56
+
57
+ ### components/{Component1,Component2}.tsx
58
+ - Componentes visuales del feature
59
+ - Props tipadas con interfaces del feature
60
+ - Contrato de componente comentado
61
+
62
+ ### {FeatureName}Page.tsx
63
+ - Página principal que compone los componentes
64
+ - Máximo 200 líneas, idealmente < 100
65
+
66
+ ## Reglas estrictas
67
+ - Cada archivo debe tener su contrato de método completo como comentario
68
+ - throw new Error("pendiente") en toda función implementable
69
+ - NO implementar lógica de negocio real
70
+ - Los imports deben ser correctos entre los archivos del feature
71
+
72
+ ## Anti-patrones (prohibido)
73
+ - NO implementar lógica (solo scaffolding)
74
+ - NO crear archivos de más de 80 líneas en scaffolding
75
+ - NO olvidar los index.ts (barrel exports)
76
+
77
+ ## Formato de salida esperado
78
+ Todos los archivos del feature listos para copiar a src/features/{featureName}/.
79
+ ```
@@ -0,0 +1,114 @@
1
+ ---
2
+ title: Servicio CRUD con Supabase — operaciones batch + RLS + signed URLs
3
+ tags: [service, supabase, crud, rls, typescript]
4
+ usado_en: []
5
+ fecha_creacion: 2026-05-14
6
+ ultima_modificacion: 2026-05-14
7
+ ---
8
+
9
+ ## Cuándo usar
10
+
11
+ Cuando necesites un servicio CRUD completo para una tabla de Supabase con operaciones batch, RLS policies, signed URLs para archivos y manejo de errores por código PostgreSQL.
12
+
13
+ ## Prompt
14
+
15
+ ```markdown
16
+ ## Contexto
17
+ Stack: React 18 + TypeScript + Vite + Supabase.
18
+ Convenciones: servicios en src/services/, un archivo por entidad, máximo 150 líneas.
19
+ Referencia DB: docs/CONVENCIONES_DB.md (RLS, batch, signed URLs, error codes).
20
+ Tipos generados desde DB: src/types/supabase.ts (Database).
21
+
22
+ ## Objetivo
23
+ Crear el servicio CRUD `productService` para la tabla `products` con operaciones batch, RLS respetado desde el cliente, signed URLs para imágenes, y errores tipados por código PostgreSQL.
24
+
25
+ ## Especificaciones técnicas
26
+ - Archivo: `src/services/productService.ts`
27
+ - Cliente Supabase desde `src/services/supabase/client.ts`
28
+ - Tipos desde `src/types/supabase.ts`
29
+
30
+ Operaciones:
31
+ - `getAll(filters?)` — Listar con filtros opcionales, SELECT columnas específicas
32
+ - `getById(id)` — Obtener por ID
33
+ - `create(data)` — Insert con tipado estricto, capturar error 23505 (unique)
34
+ - `update(id, data)` — Update parcial
35
+ - `remove(id)` — Soft delete (columna deleted_at) con transacción
36
+ - `getImageUrl(productId)` — Signed URL expirable para imagen
37
+ - `batchCreate(items)` — Batch insert múltiple
38
+
39
+ Cada función debe:
40
+ - SELECT columnas específicas (nunca `*`)
41
+ - Usar tipos generados desde DB (Database['public']['Tables']['products']['Row'])
42
+ - Capturar errores PostgreSQL por código (23505, 23503, 42501)
43
+ - Respetar RLS (sin Service Role Key en frontend)
44
+
45
+ ## Reglas estrictas
46
+ - SELECT con columnas explícitas: `.select('id, name, price, category_id, created_at')`
47
+ - Errores capturados por código: `if (error?.code === '23505')` → mensaje amigable
48
+ - Soft delete con `deleted_at`, nunca hard delete
49
+ - Signed URLs con expiración máxima 1h (3600s)
50
+ - Batch insert con un solo `.insert([...])`, no loop
51
+ - Tipos desde Database generado, nunca interfaces manuales
52
+
53
+ ## Anti-patrones (prohibido)
54
+ - NO usar `select('*')`
55
+ - NO exponer Service Role Key en frontend
56
+ - NO hacer inserts en loop
57
+ - NO usar buckets públicos para imágenes
58
+ - NO borrar físicamente (hard delete)
59
+
60
+ ## Ejemplo correcto (parcial)
61
+ ```typescript
62
+ import { supabase } from './supabase/client'
63
+ import type { Database } from '../types/supabase'
64
+
65
+ type Product = Database['public']['Tables']['products']['Row']
66
+ type ProductInsert = Database['public']['Tables']['products']['Insert']
67
+
68
+ export async function getAll(filters?: { category_id?: string }) {
69
+ let query = supabase
70
+ .from('products')
71
+ .select('id, name, price, category_id, created_at')
72
+
73
+ if (filters?.category_id) {
74
+ query = query.eq('category_id', filters.category_id)
75
+ }
76
+
77
+ const { data, error } = await query
78
+ if (error) throw new Error(error.message)
79
+ return data as Product[]
80
+ }
81
+
82
+ export async function create(data: ProductInsert) {
83
+ const { data: product, error } = await supabase
84
+ .from('products')
85
+ .insert(data)
86
+ .select('id, name, price')
87
+ .single()
88
+
89
+ if (error?.code === '23505') {
90
+ throw new Error('Ya existe un producto con ese identificador')
91
+ }
92
+ if (error) throw new Error(error.message)
93
+
94
+ return product
95
+ }
96
+ ```
97
+
98
+ ## Ejemplo incorrecto
99
+ ```typescript
100
+ // ❌ SELECT *, sin tipos, sin manejo de errores
101
+ export async function getProducts() {
102
+ const { data } = await supabase.from('products').select('*')
103
+ return data
104
+ }
105
+
106
+ export async function deleteProduct(id: string) {
107
+ await supabase.from('products').delete().eq('id', id)
108
+ // Hard delete irreversible, sin soft delete
109
+ }
110
+ ```
111
+
112
+ ## Formato de salida esperado
113
+ Archivo completo `src/services/productService.ts` con todas las funciones CRUD implementadas.
114
+ ```
@@ -0,0 +1,143 @@
1
+ ---
2
+ title: Hook useSupabaseTable con keyset pagination y filtros
3
+ tags: [hook, supabase, pagination, keyset, typescript]
4
+ usado_en: []
5
+ fecha_creacion: 2026-05-14
6
+ ultima_modificacion: 2026-05-14
7
+ ---
8
+
9
+ ## Cuándo usar
10
+
11
+ Cuando necesites un hook que liste datos con paginación keyset (cursor-based), filtros combinados y ordenamiento. Ideal para tablas con muchos datos que deben escalar sin degradación.
12
+
13
+ ## Prompt
14
+
15
+ ```markdown
16
+ ## Contexto
17
+ Stack: React 18 + TypeScript + Vite + Supabase.
18
+ Convenciones: hooks en src/hooks/, un hook por archivo, máximo 80 líneas.
19
+ Referencia DB: docs/CONVENCIONES_DB.md (keyset pagination, partial indexes, columnas específicas).
20
+
21
+ ## Objetivo
22
+ Crear el hook `useSupabaseList<T>` que implemente keyset pagination (cursor-based), filtros combinados y ordenamiento. Escala a millones de filas sin degradación.
23
+
24
+ ## Especificaciones técnicas
25
+ - Archivo: `src/hooks/useSupabaseList.ts`
26
+ - Retornar: `{ data: T[]; loading: boolean; error: string | null; hasMore: boolean; loadMore: () => void; refetch: () => void }`
27
+ - Parámetros: `UseListOptions<T>`:
28
+ - `table: string` — Nombre de la tabla
29
+ - `select: string` — Columnas separadas por coma (nunca *)
30
+ - `filters?: Record<string, unknown>` — Filtros exactos (columna: valor)
31
+ - `search?: { column: string; value: string }` — Búsqueda textual
32
+ - `orderBy?: { column: keyof T; ascending: boolean }` — Ordenamiento
33
+ - `pageSize?: number` — Items por página (default: 25)
34
+ - `cursorColumn?: string` — Columna del cursor (default: 'id')
35
+
36
+ ## Reglas estrictas
37
+ - Paginación keyset: `WHERE cursorColumn > lastValue LIMIT pageSize`
38
+ - SELECT con columnas explícitas en `select`, nunca `*`
39
+ - `loading` debe iniciar en `true` en la primera carga
40
+ - `hasMore` se calcula: si la DB devuelve menos de `pageSize` filas, no hay más
41
+ - `loadMore` append los nuevos datos al array existente (no reemplazar)
42
+ - `refetch` reinicia el estado completo
43
+ - Los filtros deben ser estables (usar `useMemo` para construir la query)
44
+ - El cursor debe incluirse en `select` aunque no se muestre en UI
45
+
46
+ ## Anti-patrones (prohibido)
47
+ - NO usar `range()` / offset — usar keyset
48
+ - NO hacer fetch en el render, solo en `useEffect`
49
+ - NO mutar estado directamente (usar spread o inmutable)
50
+ - NO poner lógica de UI en el hook
51
+
52
+ ## Ejemplo correcto (parcial)
53
+ ```typescript
54
+ interface UseListOptions<T> {
55
+ table: string
56
+ select: string
57
+ filters?: Record<string, unknown>
58
+ orderBy?: { column: keyof T; ascending: boolean }
59
+ pageSize?: number
60
+ cursorColumn?: string
61
+ }
62
+
63
+ interface UseListResult<T> {
64
+ data: T[]
65
+ loading: boolean
66
+ error: string | null
67
+ hasMore: boolean
68
+ loadMore: () => void
69
+ refetch: () => void
70
+ }
71
+
72
+ export function useSupabaseList<T extends Record<string, unknown>>({
73
+ table,
74
+ select,
75
+ filters,
76
+ orderBy,
77
+ pageSize = 25,
78
+ cursorColumn = 'id',
79
+ }: UseListOptions<T>): UseListResult<T> {
80
+ const [data, setData] = useState<T[]>([])
81
+ const [loading, setLoading] = useState(true)
82
+ const [error, setError] = useState<string | null>(null)
83
+ const [cursor, setCursor] = useState<string | null>(null)
84
+ const [hasMore, setHasMore] = useState(true)
85
+
86
+ const fetchData = async (isLoadMore = false) => {
87
+ setLoading(true)
88
+ setError(null)
89
+
90
+ let query = supabase
91
+ .from(table)
92
+ .select(select)
93
+ .limit(pageSize)
94
+ .order(orderBy?.column || 'id', { ascending: orderBy?.ascending ?? true })
95
+
96
+ if (filters) {
97
+ Object.entries(filters).forEach(([key, value]) => {
98
+ query = query.eq(key, value)
99
+ })
100
+ }
101
+
102
+ if (isLoadMore && cursor) {
103
+ query = query.gt(cursorColumn, cursor)
104
+ }
105
+
106
+ const { data: result, error: err } = await query
107
+ if (err) { setError(err.message); setLoading(false); return }
108
+
109
+ setData(prev => isLoadMore ? [...prev, ...(result as T[])] : (result as T[]))
110
+ setHasMore(result.length === pageSize)
111
+ if (result.length > 0) {
112
+ setCursor(String(result[result.length - 1][cursorColumn]))
113
+ }
114
+ setLoading(false)
115
+ }
116
+
117
+ useEffect(() => { fetchData() }, [table, JSON.stringify(filters), orderBy?.column, orderBy?.ascending])
118
+ const loadMore = () => { if (hasMore && !loading) fetchData(true) }
119
+ const refetch = () => { setCursor(null); setHasMore(true); fetchData() }
120
+
121
+ return { data, loading, error, hasMore, loadMore, refetch }
122
+ }
123
+ ```
124
+
125
+ ## Ejemplo incorrecto
126
+ ```typescript
127
+ // ❌ Offset pagination, select *, sin hasMore
128
+ export function useProducts() {
129
+ const [data, setData] = useState<any[]>([])
130
+ const [page, setPage] = useState(0)
131
+
132
+ useEffect(() => {
133
+ supabase.from('products').select('*').range(page * 25, (page + 1) * 25).then(r => setData(r.data))
134
+ }, [page])
135
+
136
+ return { data, nextPage: () => setPage(p => p + 1) }
137
+ // Se degrada con datos grandes, any, mutación directa
138
+ }
139
+ ```
140
+
141
+ ## Formato de salida esperado
142
+ Archivo completo `src/hooks/useSupabaseList.ts` con hook genérico tipado.
143
+ ```
@@ -0,0 +1,84 @@
1
+ ---
2
+ title: Comando Tauri en Rust con validación de inputs
3
+ tags: [tauri, rust, command, backend]
4
+ usado_en: []
5
+ fecha_creacion: 2026-05-14
6
+ ultima_modificacion: 2026-05-14
7
+ ---
8
+
9
+ ## Cuándo usar
10
+
11
+ Cuando necesites crear un comando Tauri v2 en Rust con validación estricta de inputs, manejo de errores tipados, y path sanitization.
12
+
13
+ ## Prompt
14
+
15
+ ```markdown
16
+ ## Contexto
17
+ Stack: Tauri v2 + Rust + React + TypeScript.
18
+ Convenciones: comandos Rust en src-tauri/src/commands/, un archivo por comando.
19
+ Referencia: Tauri v2 IPC — #[tauri::command] con Result<T, String>.
20
+
21
+ ## Objetivo
22
+ Crear el comando Tauri `{command_name}` que {descripción del propósito} con validación de inputs, errores tipados y path sanitization.
23
+
24
+ ## Especificaciones técnicas
25
+ Archivos a crear:
26
+ - `src-tauri/src/commands/{module}.rs` — Implementación Rust
27
+ - `src-tauri/src/main.rs` — Registrar el módulo con `.invoke_handler()`
28
+ - `src/services/tauri/{module}.ts` — Wrapper TypeScript tipado
29
+
30
+ Comando Rust:
31
+ - `#[tauri::command]`
32
+ - `fn {nombre}({parametros}) -> Result<{output}, String>`
33
+ - Validar todos los inputs antes de ejecutar lógica
34
+ - Sanitizar paths para evitar path traversal
35
+ - Devolver error específico en español/inglés
36
+
37
+ ## Reglas estrictas
38
+ - Tipar con tipos concretos (String, no &str; u64, no i32 cuando no negativo)
39
+ - Sanitizar paths: rechazar `..`, `~`, y symlinks a directorios prohibidos
40
+ - No permitir path traversal — restringir a directorio de trabajo
41
+ - Error en String, no en custom enum (Tauri v2 IPC serializa String)
42
+ - Documentar cada error posible con su causa
43
+
44
+ ## Anti-patrones
45
+ - NO usar `std::fs::read_to_string` sin validar path
46
+ - NO exponer comandos inseguros sin autenticación
47
+ - NO usar `unwrap()` o `expect()` en producción
48
+ - NO mezclar lógica de negocio con lógica de UI
49
+
50
+ ## Ejemplo correcto (parcial)
51
+ ```rust
52
+ use std::path::{Path, PathBuf};
53
+ use tauri::Manager;
54
+
55
+ #[tauri::command]
56
+ fn read_file_content(app_handle: tauri::AppHandle, path: String) -> Result<String, String> {
57
+ let base = PathBuf::from(&app_handle.path().resource_dir().map_err(|e| e.to_string())?);
58
+ let requested = base.join(&path);
59
+
60
+ // Sanitize: rechazar path traversal
61
+ if !requested.starts_with(&base) {
62
+ return Err("Acceso denegado: path fuera del directorio permitido".into());
63
+ }
64
+
65
+ if !requested.exists() {
66
+ return Err(format!("Archivo no encontrado: {}", path));
67
+ }
68
+
69
+ std::fs::read_to_string(&requested).map_err(|e| format!("Error de lectura: {}", e))
70
+ }
71
+ ```
72
+
73
+ ## Ejemplo incorrecto
74
+ ```rust
75
+ // ❌ Sin validación de path, sin manejo de errores
76
+ #[tauri::command]
77
+ fn read_file(path: String) -> String {
78
+ std::fs::read_to_string(path).unwrap() // Panic en producción!
79
+ }
80
+ ```
81
+
82
+ ## Formato de salida esperado
83
+ Código Rust + registro en main.rs + wrapper TypeScript + instrucciones.
84
+ ```