nextjs-hackathon-stack 0.1.40 → 0.1.42

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 (174) hide show
  1. package/dist/index.js +3 -63
  2. package/package.json +1 -1
  3. package/template/.claude/agents/backend.md +54 -0
  4. package/template/.claude/agents/business-analyst.md +195 -0
  5. package/template/.claude/agents/code-reviewer.md +76 -0
  6. package/template/.claude/agents/frontend.md +85 -0
  7. package/template/.claude/agents/security-researcher.md +54 -0
  8. package/template/.claude/agents/technical-lead.md +92 -0
  9. package/template/.claude/agents/test-qa.md +85 -0
  10. package/template/.claude/rules/architecture.mdc +48 -0
  11. package/template/.claude/rules/coding-standards.mdc +120 -0
  12. package/template/.claude/rules/components.mdc +49 -0
  13. package/template/.claude/rules/data-fetching.mdc +115 -0
  14. package/template/.claude/rules/forms.mdc +100 -0
  15. package/template/.claude/rules/general.mdc +54 -0
  16. package/template/.claude/rules/migrations.mdc +11 -0
  17. package/template/.claude/rules/nextjs.mdc +71 -0
  18. package/template/.claude/rules/security.mdc +108 -0
  19. package/template/.claude/rules/supabase.mdc +70 -0
  20. package/template/.claude/rules/testing.mdc +136 -0
  21. package/template/.claude/settings.json +16 -0
  22. package/template/.claude/skills/build-feature/SKILL.md +198 -0
  23. package/template/.claude/skills/build-feature/references/server-action-test-template.md +103 -0
  24. package/template/.claude/skills/create-api-route/SKILL.md +62 -0
  25. package/template/.claude/skills/discover-feature/SKILL.md +200 -0
  26. package/template/.claude/skills/memory/SKILL.md +208 -0
  27. package/template/.claude/skills/review-branch/SKILL.md +43 -0
  28. package/template/.claude/skills/review-branch/references/review-checklist.md +36 -0
  29. package/template/.claude/skills/security-audit/SKILL.md +40 -0
  30. package/template/.claude/skills/security-audit/references/audit-steps.md +41 -0
  31. package/template/.claude/skills/supabase/SKILL.md +105 -0
  32. package/template/.claude/skills/supabase/assets/feedback-issue-template.md +17 -0
  33. package/template/.claude/skills/supabase/references/skill-feedback.md +17 -0
  34. package/template/.claude/skills/supabase-postgres-best-practices/SKILL.md +65 -0
  35. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp__contributing.md +170 -0
  36. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp__sections.md +39 -0
  37. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp__template.md +34 -0
  38. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_advanced-full-text-search.md +55 -0
  39. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_advanced-jsonb-indexing.md +49 -0
  40. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_conn-idle-timeout.md +46 -0
  41. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_conn-limits.md +44 -0
  42. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_conn-pooling.md +41 -0
  43. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_conn-prepared-statements.md +46 -0
  44. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_data-batch-inserts.md +54 -0
  45. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_data-n-plus-one.md +53 -0
  46. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_data-pagination.md +50 -0
  47. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_data-upsert.md +50 -0
  48. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_lock-advisory.md +56 -0
  49. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_lock-deadlock-prevention.md +68 -0
  50. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_lock-short-transactions.md +50 -0
  51. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_lock-skip-locked.md +54 -0
  52. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_monitor-explain-analyze.md +45 -0
  53. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_monitor-pg-stat-statements.md +55 -0
  54. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_monitor-vacuum-analyze.md +55 -0
  55. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_query-composite-indexes.md +44 -0
  56. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_query-covering-indexes.md +40 -0
  57. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_query-index-types.md +48 -0
  58. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_query-missing-indexes.md +43 -0
  59. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_query-partial-indexes.md +45 -0
  60. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_schema-constraints.md +80 -0
  61. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_schema-data-types.md +46 -0
  62. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_schema-foreign-key-indexes.md +59 -0
  63. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_schema-lowercase-identifiers.md +55 -0
  64. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_schema-partitioning.md +55 -0
  65. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_schema-primary-keys.md +61 -0
  66. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_security-privileges.md +54 -0
  67. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_security-rls-basics.md +50 -0
  68. package/template/.claude/skills/supabase-postgres-best-practices/references/pgbp_security-rls-performance.md +57 -0
  69. package/template/.cursor/agents/business-analyst.md +197 -0
  70. package/template/.cursor/agents/technical-lead.md +3 -3
  71. package/template/.cursor/mcp.json +6 -2
  72. package/template/.cursor/skills/build-feature/SKILL.md +20 -21
  73. package/template/.cursor/skills/discover-feature/SKILL.md +118 -29
  74. package/template/.cursor/skills/supabase/SKILL.md +104 -0
  75. package/template/.cursor/skills/supabase/assets/feedback-issue-template.md +17 -0
  76. package/template/.cursor/skills/supabase/references/skill-feedback.md +17 -0
  77. package/template/.cursor/skills/supabase-postgres-best-practices/SKILL.md +64 -0
  78. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp__contributing.md +170 -0
  79. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp__sections.md +39 -0
  80. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp__template.md +34 -0
  81. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_advanced-full-text-search.md +55 -0
  82. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_advanced-jsonb-indexing.md +49 -0
  83. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_conn-idle-timeout.md +46 -0
  84. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_conn-limits.md +44 -0
  85. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_conn-pooling.md +41 -0
  86. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_conn-prepared-statements.md +46 -0
  87. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_data-batch-inserts.md +54 -0
  88. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_data-n-plus-one.md +53 -0
  89. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_data-pagination.md +50 -0
  90. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_data-upsert.md +50 -0
  91. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_lock-advisory.md +56 -0
  92. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_lock-deadlock-prevention.md +68 -0
  93. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_lock-short-transactions.md +50 -0
  94. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_lock-skip-locked.md +54 -0
  95. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_monitor-explain-analyze.md +45 -0
  96. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_monitor-pg-stat-statements.md +55 -0
  97. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_monitor-vacuum-analyze.md +55 -0
  98. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_query-composite-indexes.md +44 -0
  99. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_query-covering-indexes.md +40 -0
  100. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_query-index-types.md +48 -0
  101. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_query-missing-indexes.md +43 -0
  102. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_query-partial-indexes.md +45 -0
  103. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_schema-constraints.md +80 -0
  104. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_schema-data-types.md +46 -0
  105. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_schema-foreign-key-indexes.md +59 -0
  106. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_schema-lowercase-identifiers.md +55 -0
  107. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_schema-partitioning.md +55 -0
  108. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_schema-primary-keys.md +61 -0
  109. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_security-privileges.md +54 -0
  110. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_security-rls-basics.md +50 -0
  111. package/template/.cursor/skills/supabase-postgres-best-practices/references/pgbp_security-rls-performance.md +57 -0
  112. package/template/.mcp.json +16 -0
  113. package/template/.opencode/agents/backend.md +72 -0
  114. package/template/.opencode/agents/business-analyst.md +153 -0
  115. package/template/.opencode/agents/code-reviewer.md +80 -0
  116. package/template/.opencode/agents/frontend.md +84 -0
  117. package/template/.opencode/agents/security-researcher.md +58 -0
  118. package/template/.opencode/agents/technical-lead.md +131 -0
  119. package/template/.opencode/agents/test-qa.md +103 -0
  120. package/template/.opencode/memory/architecture-snapshot.md +127 -0
  121. package/template/.opencode/skills/build-feature/SKILL.md +208 -0
  122. package/template/.opencode/skills/create-api-route/SKILL.md +63 -0
  123. package/template/.opencode/skills/discover-feature/SKILL.md +194 -0
  124. package/template/.opencode/skills/memory/SKILL.md +199 -0
  125. package/template/.opencode/skills/review-branch/SKILL.md +43 -0
  126. package/template/.opencode/skills/security-audit/SKILL.md +40 -0
  127. package/template/.opencode/skills/supabase/SKILL.md +105 -0
  128. package/template/.opencode/skills/supabase/assets/feedback-issue-template.md +17 -0
  129. package/template/.opencode/skills/supabase/references/skill-feedback.md +17 -0
  130. package/template/.opencode/skills/supabase-postgres-best-practices/SKILL.md +65 -0
  131. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp__contributing.md +170 -0
  132. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp__sections.md +39 -0
  133. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp__template.md +34 -0
  134. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_advanced-full-text-search.md +55 -0
  135. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_advanced-jsonb-indexing.md +49 -0
  136. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_conn-idle-timeout.md +46 -0
  137. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_conn-limits.md +44 -0
  138. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_conn-pooling.md +41 -0
  139. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_conn-prepared-statements.md +46 -0
  140. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_data-batch-inserts.md +54 -0
  141. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_data-n-plus-one.md +53 -0
  142. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_data-pagination.md +50 -0
  143. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_data-upsert.md +50 -0
  144. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_lock-advisory.md +56 -0
  145. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_lock-deadlock-prevention.md +68 -0
  146. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_lock-short-transactions.md +50 -0
  147. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_lock-skip-locked.md +54 -0
  148. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_monitor-explain-analyze.md +45 -0
  149. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_monitor-pg-stat-statements.md +55 -0
  150. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_monitor-vacuum-analyze.md +55 -0
  151. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_query-composite-indexes.md +44 -0
  152. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_query-covering-indexes.md +40 -0
  153. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_query-index-types.md +48 -0
  154. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_query-missing-indexes.md +43 -0
  155. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_query-partial-indexes.md +45 -0
  156. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_schema-constraints.md +80 -0
  157. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_schema-data-types.md +46 -0
  158. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_schema-foreign-key-indexes.md +59 -0
  159. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_schema-lowercase-identifiers.md +55 -0
  160. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_schema-partitioning.md +55 -0
  161. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_schema-primary-keys.md +61 -0
  162. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_security-privileges.md +54 -0
  163. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_security-rls-basics.md +50 -0
  164. package/template/.opencode/skills/supabase-postgres-best-practices/references/pgbp_security-rls-performance.md +57 -0
  165. package/template/.requirements/README.md +1 -1
  166. package/template/AGENTS.md +1 -1
  167. package/template/CLAUDE.md +1 -1
  168. package/template/Dockerfile.memory +7 -0
  169. package/template/README.md +15 -2
  170. package/template/_gitignore +3 -0
  171. package/template/docker-compose.yml +28 -0
  172. package/template/ia-flow.md +341 -0
  173. package/template/opencode.json +23 -0
  174. package/template/.cursor/agents/business-intelligence.md +0 -83
@@ -0,0 +1,108 @@
1
+ ---
2
+ description: Security rules (OWASP, auth, RLS, XSS, CSP). Applied to server code, API routes, actions, auth, and config.
3
+ globs: ["src/**/actions/**", "src/**/api/**", "src/**/lib/supabase/**", "src/app/**/route.ts", "src/app/**/proxy.ts", "*.config.*"]
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Security Rules
8
+
9
+ ## OWASP Top 10 Awareness
10
+ 1. **Injection** — use Drizzle parameterized queries, never string concatenation
11
+ 2. **Broken Auth** — Supabase Auth only, no custom auth
12
+ 3. **Sensitive Data** — HTTPS-only cookies, no secrets in code
13
+ 4. **XSS** — never use `dangerouslySetInnerHTML`, escape user input
14
+ 5. **Broken Access Control** — RLS on all tables, auth check in all protected routes
15
+ 6. **Security Misconfiguration** — CSP, HSTS, X-Frame-Options in `next.config.ts`
16
+ 7. **Insecure Dependencies** — run `pnpm audit` regularly
17
+ 8. **SSRF** — validate URLs before fetch
18
+
19
+ ## Environment Variables
20
+ ```
21
+ NEXT_PUBLIC_* → client-safe (Supabase URL, anon key only)
22
+ No prefix → server-only (DB URL, secret keys)
23
+ ```
24
+
25
+ Never use `NEXT_PUBLIC_` for secret keys.
26
+
27
+ ## Supabase RLS
28
+ - Enable RLS on EVERY table
29
+ - Write explicit allow/deny policies
30
+ - Test RLS policies — never assume they work
31
+
32
+ ## Auth in API Routes and Server Actions
33
+
34
+ Every Server Action and API route that accesses data must verify auth via `getUser()` before any data access. RLS provides row-level enforcement, but `getUser()` at the action level is required as defense-in-depth — never rely on RLS alone.
35
+
36
+ ```typescript
37
+ export async function POST(request: Request) {
38
+ const supabase = await createClient();
39
+ const { data: { user } } = await supabase.auth.getUser();
40
+ if (!user) return Response.json({ error: "Unauthorized" }, { status: 401 });
41
+ // ...
42
+ }
43
+ ```
44
+
45
+ Every mutation Server Action must:
46
+ 1. Call `getUser()` and return an error result if no user
47
+ 2. Scope all queries to `user.id` (even with RLS active)
48
+
49
+ ```typescript
50
+ export async function deleteItemAction(id: string): Promise<ActionResult> {
51
+ const supabase = await createClient();
52
+ const { data: { user } } = await supabase.auth.getUser();
53
+ if (!user) return { status: "error", message: "No autenticado" };
54
+
55
+ const { error } = await supabase.from("items").delete().eq("id", id).eq("user_id", user.id);
56
+ if (error) return { status: "error", message: "Error al eliminar" };
57
+
58
+ revalidatePath("/");
59
+ return { status: "success", message: "Eliminado" };
60
+ }
61
+ ```
62
+
63
+ ## Open Redirect Prevention
64
+
65
+ Validate all redirect targets — ensure `next`/`redirect` params start with `/` and not `//`. Never redirect to user-controlled URLs without validation.
66
+
67
+ ```typescript
68
+ // ✅ Safe redirect validation
69
+ const next = rawNext.startsWith("/") && !rawNext.startsWith("//") ? rawNext : "/";
70
+
71
+ // ❌ Unsafe — allows protocol-relative redirects (//evil.com)
72
+ const next = searchParams.get("next") ?? "/";
73
+ ```
74
+
75
+ ## Input Validation
76
+ - Validate ALL external input with Zod at the boundary
77
+ - Validate in Server Actions AND API routes
78
+ - Never trust client-side validation alone
79
+
80
+ ## Rate Limiting
81
+ - Apply rate limiting to all AI routes
82
+ - Apply rate limiting to auth endpoints
83
+ - Use Vercel's built-in rate limiting or `@upstash/ratelimit`
84
+
85
+ ## Content Security Policy
86
+
87
+ `script-src` must not include `'unsafe-eval'`. Avoid `'unsafe-inline'` for scripts — prefer nonce-based CSP. `'unsafe-inline'` is acceptable for `style-src` only.
88
+
89
+ ```typescript
90
+ // ✅ Ideal — nonce-based CSP (no unsafe-inline for scripts)
91
+ `script-src 'self' 'nonce-${nonce}'`,
92
+ "style-src 'self' 'unsafe-inline'",
93
+
94
+ // ✅ Acceptable intermediate — add a TODO to migrate to nonce-based
95
+ "script-src 'self' 'unsafe-inline'", // TODO: replace with nonce-based CSP
96
+ "style-src 'self' 'unsafe-inline'",
97
+
98
+ // ✅ Dev-only — unsafe-eval for React debugging features (silences installHook.js warning)
99
+ `script-src 'self' 'unsafe-inline'${isDev ? " 'unsafe-eval'" : ""}`,
100
+
101
+ // ❌ Never — unsafe-eval unconditionally in production
102
+ "script-src 'self' 'unsafe-eval' 'unsafe-inline'",
103
+ ```
104
+
105
+ ## Cookies
106
+ - `httpOnly: true` for auth tokens (Supabase handles this)
107
+ - `secure: true` in production
108
+ - `sameSite: "lax"` minimum
@@ -0,0 +1,70 @@
1
+ ---
2
+ description: Supabase + Drizzle rules. Schema changes require migration — never edit migration files directly.
3
+ globs: ["src/shared/db/**", "src/shared/lib/supabase/**"]
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Supabase + Drizzle Rules (Risk 2: Zod Schema Drift)
8
+
9
+ ## Drizzle: Schema + Migrations ONLY
10
+ ```typescript
11
+ // ✅ Use Drizzle for schema definition
12
+ export const users = pgTable("users", {
13
+ id: uuid("id").primaryKey(),
14
+ email: text("email").notNull(),
15
+ });
16
+
17
+ // ✅ Auto-generate Zod from Drizzle — zero manual Zod for DB types
18
+ export const insertUserSchema = createInsertSchema(users);
19
+ export const selectUserSchema = createSelectSchema(users);
20
+
21
+ // ❌ NEVER write Zod schemas manually for DB types
22
+ const userSchema = z.object({ id: z.string(), email: z.string() }); // WRONG
23
+ ```
24
+
25
+ ## Runtime Reads: Repository Pattern (RLS active)
26
+
27
+ All reads go through the feature's `queries/` module — never call `supabase.from().select()` inline in pages or actions.
28
+
29
+ ```typescript
30
+ // ✅ Read via repository function
31
+ import { getUserById } from "@/features/users/queries/users.queries";
32
+ const { data, error } = await getUserById(supabase, userId);
33
+
34
+ // ✅ Repository module — receives supabase client as parameter (DI)
35
+ // src/features/users/queries/users.queries.ts
36
+ import type { createClient } from "@/shared/lib/supabase/server";
37
+ type Client = Awaited<ReturnType<typeof createClient>>;
38
+
39
+ export async function getUserById(supabase: Client, userId: string) {
40
+ return supabase.from("users").select("*").eq("id", userId).single();
41
+ }
42
+
43
+ // ❌ Never inline a SELECT in a page or action
44
+ const { data } = await supabase.from("users").select("*").eq("id", userId); // WRONG in page/action
45
+
46
+ // ❌ Never use Drizzle for runtime queries
47
+ const users = await db.select().from(usersTable); // WRONG — bypasses RLS
48
+ ```
49
+
50
+ ## RLS Mandate
51
+ - Enable RLS on ALL tables in Supabase dashboard
52
+ - Every table must have explicit policies — RLS is not a post-step
53
+ - Default policy template: `CREATE POLICY "users_own_rows" ON <table> FOR ALL USING (user_id = auth.uid());`
54
+
55
+ ## Migrations
56
+
57
+ Files in `src/shared/db/migrations/` are **auto-generated** by Drizzle CLI — never create, edit, or delete them directly.
58
+
59
+ | Command | Purpose |
60
+ |---|---|
61
+ | `pnpm db:generate` | Generate migration SQL from schema changes |
62
+ | `pnpm db:migrate` | Apply pending migrations to the database |
63
+ | `pnpm db:push` | Push schema directly to DB (dev only, no migration file) |
64
+
65
+ Workflow: edit `src/shared/db/<table>.schema.ts` → `pnpm db:generate` → review SQL → `pnpm db:migrate`
66
+
67
+ ## Environment Variables
68
+ - `NEXT_PUBLIC_SUPABASE_URL` + `NEXT_PUBLIC_SUPABASE_ANON_KEY` — client-safe, used in browser + server
69
+ - `DATABASE_URL` — server-only, used by Drizzle for migrations (`drizzle.config.ts`)
70
+ - See `.env.example` for all required variables
@@ -0,0 +1,136 @@
1
+ ---
2
+ description: TDD, Vitest, and Playwright testing standards.
3
+ globs: ["**/*.test.*", "**/e2e/**"]
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Testing Standards
8
+
9
+ ## Iron Rules (Non-Negotiable)
10
+ 1. **NEVER modify a test to make it pass** — always fix the implementation code. Tests define the contract. If a test fails, the code is wrong, not the test.
11
+ 2. **Tests are immutable during GREEN phase** — only modify tests in RED phase (writing new ones) or REFACTOR phase (improving structure, never weakening assertions)
12
+ 3. **Coverage thresholds** — 95% statements/functions/lines, 90% branches. Use `/* v8 ignore next */` only for genuinely unreachable defensive branches
13
+ 4. **Every edge case gets a test** — null/undefined, empty string, empty array, boundary values, error responses, timeout, concurrent calls
14
+ 5. **AAA is mandatory** — every test uses Arrange-Act-Assert with labeled comments
15
+
16
+ ## TDD Cycle
17
+ 1. **RED**: Write failing test describing desired behavior
18
+ 2. **GREEN**: Write minimum code to make it pass
19
+ 3. **REFACTOR**: Clean up while keeping tests green
20
+
21
+ ## AAA Pattern (Arrange-Act-Assert)
22
+
23
+ Every test MUST follow the Arrange-Act-Assert structure. No exceptions.
24
+
25
+ ```typescript
26
+ it("shows error message on invalid credentials", async () => {
27
+ // Arrange
28
+ const user = userEvent.setup();
29
+ mockSignIn.mockResolvedValue({ error: { message: "Invalid credentials" } });
30
+ render(<LoginForm />);
31
+
32
+ // Act
33
+ await user.type(screen.getByLabelText(/email/i), "test@example.com");
34
+ await user.type(screen.getByLabelText(/password/i), "password123");
35
+ await user.click(screen.getByRole("button", { name: /sign in/i }));
36
+
37
+ // Assert
38
+ expect(await screen.findByRole("alert")).toHaveTextContent("Invalid credentials");
39
+ });
40
+ ```
41
+
42
+ Rules:
43
+ - **Arrange**: set up state, mocks, render
44
+ - **Act**: perform the single action being tested
45
+ - **Assert**: verify outcome — one logical assertion per test
46
+ - Add blank lines between sections when all three are non-trivial
47
+ - Never skip a section — if Act is empty, you are testing the wrong thing
48
+
49
+ ## Vitest (Unit + Integration)
50
+ - Mock external dependencies only (HTTP calls, Supabase, DB)
51
+ - Test behavior, not implementation details
52
+ - Colocate tests with source: `features/auth/__tests__/`
53
+ - Coverage thresholds are non-negotiable (95% statements/functions/lines, 90% branches — see Iron Rule #3)
54
+
55
+ ```typescript
56
+ // ✅ AAA — tests behavior
57
+ it("shows error message on invalid credentials", async () => {
58
+ // Arrange
59
+ mockSignIn.mockResolvedValue({ error: { message: "Invalid credentials" } });
60
+ render(<LoginForm />);
61
+
62
+ // Act
63
+ await userEvent.click(screen.getByRole("button", { name: /sign in/i }));
64
+
65
+ // Assert
66
+ expect(await screen.findByRole("alert")).toBeInTheDocument();
67
+ });
68
+
69
+ // ❌ No AAA — tests implementation details, brittle
70
+ it("calls signInWithPassword with correct args", () => { ... });
71
+ ```
72
+
73
+ ## Playwright (E2E)
74
+ - **Always use `data-testid` attributes for element selection** — never use visible text or translated labels. Text-based selectors break when copy or i18n changes.
75
+ - Page Object Pattern for complex flows
76
+ - Every user flow needs an e2e test
77
+
78
+ ```typescript
79
+ // ✅ Stable — decoupled from i18n
80
+ await page.getByTestId("submit-button").click();
81
+
82
+ // ❌ Brittle — breaks if language changes or copy is updated
83
+ await page.getByRole("button", { name: /sign in/i }).click();
84
+ await page.getByLabel(/email/i).fill("...");
85
+ ```
86
+
87
+ ```typescript
88
+ test("user can log in", async ({ page }) => {
89
+ // Arrange
90
+ await page.goto("/login");
91
+
92
+ // Act
93
+ await page.getByTestId("email-input").fill("user@example.com");
94
+ await page.getByTestId("password-input").fill("password123");
95
+ await page.getByTestId("sign-in-button").click();
96
+
97
+ // Assert
98
+ await expect(page).toHaveURL("/");
99
+ });
100
+ ```
101
+
102
+ ## Edge Case Checklist
103
+ For every function, ask: what happens with...
104
+ - null / undefined input
105
+ - empty string / empty array / empty object
106
+ - boundary values (0, -1, MAX_SAFE_INTEGER)
107
+ - invalid types (wrong shape, missing fields)
108
+ - API error responses (4xx, 5xx, network failure)
109
+ - Loading / pending states
110
+ - Concurrent calls / race conditions
111
+ - Auth expired / missing session
112
+
113
+ If any of these apply, write a test for it. No exceptions.
114
+
115
+ ## jsdom Known Limitations (avoid rework cycles)
116
+
117
+ jsdom does not implement all browser APIs. Hitting these in tests causes failures that require full component rewrites — avoid them upfront:
118
+
119
+ - **No `HTMLDialogElement` methods** — `dialog.showModal()` and `dialog.close()` throw in jsdom. Use state-controlled visibility (`isOpen` prop / conditional render) instead of the native `<dialog>` API.
120
+ - **No portal-based components in unit tests** — components like `<Toaster>` (sonner), `<Tooltip>`, `<Popover>` render outside the React tree and are unreliable in jsdom. Exclude their wrapper files from coverage; test toast behavior indirectly via the action's `ActionResult`.
121
+ - **Run `pnpm lint` before finishing** — do not leave lint errors to a separate pass. Fix inline as you go.
122
+
123
+ ## Coverage Thresholds
124
+ ```typescript
125
+ // vitest.config.ts
126
+ coverage: {
127
+ thresholds: {
128
+ branches: 90,
129
+ functions: 95,
130
+ lines: 95,
131
+ statements: 95,
132
+ },
133
+ }
134
+ ```
135
+
136
+ Use `/* v8 ignore next */` for genuinely unreachable defensive branches (e.g., exhaustive `switch` default arms, type narrowing guards that cannot be hit at runtime).
@@ -0,0 +1,16 @@
1
+ {
2
+ "mcpServers": {
3
+ "memory": {
4
+ "type": "http",
5
+ "url": "http://localhost:8765/mcp"
6
+ },
7
+ "shadcn": {
8
+ "command": "npx",
9
+ "args": ["-y", "shadcn@latest", "mcp"]
10
+ },
11
+ "supabase": {
12
+ "type": "http",
13
+ "url": "https://mcp.supabase.com/mcp?features=docs"
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,198 @@
1
+ ---
2
+ name: build-feature
3
+ description: Plan and implement a new feature following TDD — tech-lead planning, backend + frontend in parallel, review gate, and memory sync. Run in a fresh conversation after /discover-feature. Triggers: 'build feature', 'implement feature', 'start building', 'build from requirements'. NOT for: bug fixes, refactors, or API-only routes (use /create-api-route).
4
+ ---
5
+
6
+ # Build Feature Skill
7
+
8
+ > **Invoke as:** `/build-feature @.requirements/<feature-name>-<timestamp>.md`
9
+ > Run in **Agent mode** in a **fresh conversation** (not the same one where you ran `/discover-feature`).
10
+
11
+ ## IMPORTANT: Fresh Conversation Required
12
+
13
+ If this conversation already contains requirements gathering, **start a new conversation** first. Reusing the same context risks hitting the token limit mid-implementation.
14
+
15
+ If context usage exceeds 60% at any point, stop and tell the user to continue in a new conversation referencing the current step.
16
+
17
+ ---
18
+
19
+ ## Process
20
+
21
+ ### 1. Read the Requirements
22
+
23
+ Read `.requirements/<feature-name>-<timestamp>.md`. Confirm the file exists and contains both a **Functional Task List** (with acceptance criteria) and a **Technical Task List** (with Parallel Execution Plan groups A/B/C) before proceeding.
24
+
25
+ - If no spec exists → tell the user to run `/discover-feature <description>` first
26
+ - If the file only has functional tasks (old format) → use the `technical-lead` subagent to produce the Technical Task List before continuing
27
+
28
+ ### 2. Load Architecture Context via MCP Memory
29
+
30
+ Load project context with targeted queries (token-efficient):
31
+
32
+ 1. Read `package.json` to get the project name (`<project-name>`)
33
+ 2. `search_memory` with `tags: ["project:<project-name>", "domain:ui"]` — installed shadcn/ui components
34
+ 3. `search_memory` with `tags: ["project:<project-name>", "domain:database"]` — existing schema
35
+ 4. `search_memory` with `tags: ["project:<project-name>", "domain:features"]` — existing features and paths
36
+ 5. `search_memory` with `tags: ["project:<project-name>", "domain:patterns"]` — canonical pattern references
37
+ 6. `search_memory` with `tags: ["project:<project-name>", "domain:rules"]` — active lint/TS rules
38
+
39
+ **Fallback**: if memory service is unavailable or returns no results, read `.cursor/memory/architecture-snapshot.md` directly.
40
+
41
+ **Also read `eslint.config.ts` and `tsconfig.json`** to confirm active rules and compiler flags before writing any code.
42
+
43
+ **Dependency pre-flight:**
44
+ ```bash
45
+ pnpm ls drizzle-orm # Confirm installed version
46
+ pnpm typecheck # Confirm baseline passes — fix pre-existing errors first
47
+ ```
48
+
49
+ ### 3. Planning (Tech Lead)
50
+
51
+ The requirements file already contains a Technical Task List with parallel execution groups produced during `/discover-feature`. The TL should:
52
+
53
+ 1. **Read the Parallel Execution Plan** from the requirements file (Groups A/B/C + Review Gate)
54
+ 2. **Verify against current codebase state** — confirm referenced patterns, schemas, and components still exist
55
+ 3. **Identify reuse** from MCP memory:
56
+ - Which canonical patterns to copy
57
+ - Which shadcn components are already installed vs need installing
58
+ - Which shared utilities apply (`formFieldText`, `firstZodIssueMessage`, etc.)
59
+ 4. **Plan the test structure**:
60
+ - One `describe` block per acceptance criterion
61
+ - Which mocks are needed (`makeSupabaseMock`, HTTP mocks, etc.)
62
+ - Which edge cases map to test cases from the Functional Task List
63
+ 5. **Present a brief implementation summary to the user** and wait for approval before proceeding to Step 4.
64
+
65
+ > Summary: execution order (which groups run in parallel), which files will be created/modified, any risks or deviations from the plan.
66
+
67
+ ### 4. Create Feature Structure
68
+
69
+ ```
70
+ src/features/<feature-name>/
71
+ ├── components/
72
+ ├── actions/
73
+ ├── queries/
74
+ ├── hooks/
75
+ ├── api/
76
+ ├── lib/
77
+ └── __tests__/
78
+ ```
79
+
80
+ ### 5. Pre-Test Setup
81
+
82
+ Update `vitest.config.ts` to exclude files that cannot be meaningfully tested in jsdom:
83
+ - Drizzle schema file(s) (`src/shared/db/*.schema.ts`)
84
+ - Pure type-only files
85
+ - Portal/browser-API-dependent UI wrappers (e.g., `src/shared/components/ui/sonner.tsx`)
86
+
87
+ ```typescript
88
+ // vitest.config.ts — add to coverage.exclude before writing tests
89
+ exclude: [
90
+ "src/shared/db/*.schema.ts",
91
+ "src/shared/components/ui/sonner.tsx",
92
+ ]
93
+ ```
94
+
95
+ ### 6. TDD: RED Phase
96
+
97
+ Write ALL test files first — zero implementation code at this stage:
98
+ - `__tests__/<component>.test.tsx` — component tests
99
+ - `__tests__/use-<feature>.test.ts` — hook tests (if applicable)
100
+ - `__tests__/<action>.action.test.ts` — action tests (see `references/server-action-test-template.md`)
101
+ - `__tests__/<feature>.queries.test.ts` — query tests
102
+
103
+ Import mock helpers from `@/shared/test-utils/supabase-mock` — do not inline mock chains.
104
+
105
+ **Coverage guidance:** Threshold is 95% statements/functions/lines and 90% branches. Use `/* v8 ignore next */` for genuinely unreachable defensive branches.
106
+
107
+ **For standard CRUD features**: write tests and implementation per module (queries test+impl → actions test+impl → UI test+impl) instead of strict all-RED-then-all-GREEN.
108
+
109
+ **BLOCKING GATE — do not proceed until this passes:**
110
+ Run `pnpm test:unit` and paste the output. All new tests must **FAIL** (red). If any new test passes without implementation, the test is wrong — fix it before continuing.
111
+
112
+ ### 7. TDD: GREEN Phase
113
+
114
+ Follow the **Parallel Execution Plan** from the requirements file:
115
+
116
+ - **Group A**: run first (foundation — schema, shared types, no dependencies)
117
+ - **Group B**: launch `backend` and `frontend` subagents **in parallel** after Group A completes
118
+ - **Group C**: run after Group B (integration, polish)
119
+
120
+ Typical assignment:
121
+
122
+ | backend handles | frontend handles |
123
+ |-----------------|-------------------|
124
+ | `actions/` | `components/` |
125
+ | `queries/` | `page.tsx` |
126
+ | `schema.ts` changes | shadcn component installs |
127
+ | RLS policies | Loading/empty states |
128
+
129
+ **Do NOT run intermediate verification between sub-tasks.** Complete all GREEN phase work, then run a single verification pass in Step 9.
130
+
131
+ **BLOCKING GATE — do not proceed until this passes:**
132
+ Run `pnpm test:unit` and paste the output. All tests must **PASS** (green).
133
+
134
+ ### 8. Refactor
135
+
136
+ Clean up while keeping tests green.
137
+
138
+ ### 9. Verify & Self-Check
139
+
140
+ Run all three **together** (single pass) and paste output:
141
+ ```bash
142
+ pnpm test:coverage # Must meet thresholds: 95% statements/functions/lines, 90% branches
143
+ pnpm lint # Must pass with 0 warnings
144
+ pnpm typecheck # Must pass with 0 errors
145
+ ```
146
+
147
+ If issues are found, fix **all** of them, then run the full trio again once.
148
+
149
+ Before moving to the review gate, verify manually:
150
+ - [ ] No `any` types: `grep -r ": any" src/features/<feature>/`
151
+ - [ ] No `eslint-disable` comments
152
+ - [ ] All UI text in Spanish, all `it()`/`describe()` text in English
153
+ - [ ] No file over 200 lines
154
+ - [ ] No function over 20 lines
155
+ - [ ] AAA pattern (`// Arrange`, `// Act`, `// Assert`) in every test
156
+ - [ ] `ActionResult` returned from every Server Action mutation
157
+ - [ ] Toast feedback (`toast.success` / `toast.error`) for every mutation
158
+ - [ ] RLS policies written for every new table
159
+
160
+ ### 10. Review Gate
161
+
162
+ Run @code-reviewer and @security-researcher **in parallel** on the changed files. Fix any findings before marking the feature complete.
163
+
164
+ This step is not optional. The feature is not done until both reviewers pass.
165
+
166
+ > **Note for time-critical work:** if the user explicitly says to skip the review gate, you may proceed — but flag the skipped step so it can be done as a follow-up.
167
+
168
+ ### 11. Update Architecture Snapshot & MCP Memory
169
+
170
+ Update `.cursor/memory/architecture-snapshot.md`:
171
+ - Add new DB tables to the schema table
172
+ - Add new shadcn components to the installed list
173
+ - Add the new feature to the Existing Features table
174
+ - Add any new canonical pattern references that differ from existing ones
175
+
176
+ Then run `/memory sync` to persist all changes to MCP memory so future sessions load context efficiently.
177
+
178
+ ---
179
+
180
+ ## Common Issues
181
+
182
+ | Problem | Cause | Fix |
183
+ |---------|-------|-----|
184
+ | MCP memory returns no results | Memory not synced yet | Run `/memory sync` first, then retry |
185
+ | Test passes without implementation (RED fails) | Test asserts on falsy/default values | Ensure the test expects a specific truthy result that only a real implementation can produce |
186
+ | `pnpm typecheck` fails on schema file | Schema imported in test without mock | Add the schema file to `coverage.exclude` in `vitest.config.ts` |
187
+ | Context exceeds 60% mid-build | Feature too large for one conversation | Stop, note the current step, start a new conversation referencing it |
188
+ | `lint-staged` blocks commit | ESLint warnings treated as errors | Fix all warnings; never use `eslint-disable` inline — fix the code |
189
+
190
+ ---
191
+
192
+ ## Guardrails
193
+ - NEVER start implementation before the user approves the plan (Step 3)
194
+ - NEVER start implementation before the RED gate is confirmed with actual test output
195
+ - Coverage threshold: 95% statements/functions/lines, 90% branches
196
+ - Follow `features/* → shared/*` dependency direction
197
+ - RLS is mandatory for every new table — not a post-step
198
+ - Write lint-compliant code from the start — read the Strict Rules Reference before the first line of code
@@ -0,0 +1,103 @@
1
+ # Server Action Testing Pattern
2
+
3
+ Test Server Actions by mocking `createClient`, asserting on the returned `ActionResult`, and verifying side effects.
4
+
5
+ ## Setup
6
+
7
+ ```typescript
8
+ import { vi, it, expect, describe, beforeEach } from "vitest";
9
+ import { createClient } from "@/shared/lib/supabase/server";
10
+ import { revalidatePath } from "next/cache";
11
+ import { makeChain, makeSupabaseMock } from "@/shared/test-utils/supabase-mock";
12
+ import { myAction } from "@/features/example/actions/my.action";
13
+
14
+ vi.mock("@/shared/lib/supabase/server", () => ({ createClient: vi.fn() }));
15
+ vi.mock("next/cache", () => ({ revalidatePath: vi.fn() }));
16
+
17
+ beforeEach(() => {
18
+ vi.clearAllMocks();
19
+ });
20
+ ```
21
+
22
+ ## Unauthenticated case (required in every action test)
23
+
24
+ ```typescript
25
+ it("returns error when user is not authenticated", async () => {
26
+ // Arrange
27
+ const { mockClient } = makeSupabaseMock({ user: null });
28
+ vi.mocked(createClient).mockResolvedValue(mockClient as never);
29
+ const formData = new FormData();
30
+
31
+ // Act
32
+ const result = await myAction(formData);
33
+
34
+ // Assert
35
+ expect(result).toEqual({ status: "error", message: "No autenticado" });
36
+ expect(revalidatePath).not.toHaveBeenCalled();
37
+ });
38
+ ```
39
+
40
+ ## Happy path (insert example)
41
+
42
+ ```typescript
43
+ it("returns success and revalidates on valid input", async () => {
44
+ // Arrange
45
+ const { mockClient, mockFrom } = makeSupabaseMock({ user: { id: "user-1" } });
46
+ vi.mocked(createClient).mockResolvedValue(mockClient as never);
47
+ mockFrom.mockReturnValue(makeChain({ error: null }));
48
+ const formData = new FormData();
49
+ formData.set("title", "My item");
50
+
51
+ // Act
52
+ const result = await myAction(formData);
53
+
54
+ // Assert
55
+ expect(result).toEqual({ status: "success", message: expect.any(String) });
56
+ expect(revalidatePath).toHaveBeenCalledWith("/");
57
+ });
58
+ ```
59
+
60
+ ## DB error case
61
+
62
+ ```typescript
63
+ it("returns error when db insert fails", async () => {
64
+ // Arrange
65
+ const { mockClient, mockFrom } = makeSupabaseMock({ user: { id: "user-1" } });
66
+ vi.mocked(createClient).mockResolvedValue(mockClient as never);
67
+ mockFrom.mockReturnValue(makeChain({ error: { message: "db error" } }));
68
+ const formData = new FormData();
69
+ formData.set("title", "My item");
70
+
71
+ // Act
72
+ const result = await myAction(formData);
73
+
74
+ // Assert
75
+ expect(result).toEqual({ status: "error", message: expect.any(String) });
76
+ expect(revalidatePath).not.toHaveBeenCalled();
77
+ });
78
+ ```
79
+
80
+ ## Validation error case
81
+
82
+ ```typescript
83
+ it("returns error when required field is missing", async () => {
84
+ // Arrange
85
+ const { mockClient } = makeSupabaseMock({ user: { id: "user-1" } });
86
+ vi.mocked(createClient).mockResolvedValue(mockClient as never);
87
+ const formData = new FormData(); // no fields set
88
+
89
+ // Act
90
+ const result = await myAction(formData);
91
+
92
+ // Assert
93
+ expect(result).toEqual({ status: "error", message: expect.any(String) });
94
+ });
95
+ ```
96
+
97
+ ## Key Rules
98
+
99
+ - Always import `makeChain` and `makeSupabaseMock` from `@/shared/test-utils/supabase-mock`
100
+ - Every action test must cover: unauthenticated, validation error, DB error, happy path
101
+ - `mockFrom` returns a chain — each chained method (`.select()`, `.insert()`, etc.) returns the same chain object
102
+ - `then` on the chain resolves with the value you pass to `makeChain()`
103
+ - Never use `mockReturnThis()` — it does not match Supabase's actual chaining API