@intentsolutionsio/supabase-pack 1.0.0 → 1.0.3

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 (133) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +73 -47
  3. package/package.json +4 -4
  4. package/skills/supabase-advanced-troubleshooting/SKILL.md +404 -200
  5. package/skills/supabase-advanced-troubleshooting/references/errors.md +11 -0
  6. package/skills/supabase-advanced-troubleshooting/references/evidence-collection-framework.md +34 -0
  7. package/skills/supabase-advanced-troubleshooting/references/examples.md +11 -0
  8. package/skills/supabase-advanced-troubleshooting/references/rls-edge-functions-realtime.md +363 -0
  9. package/skills/supabase-advanced-troubleshooting/references/systematic-isolation.md +56 -0
  10. package/skills/supabase-advanced-troubleshooting/references/timing-analysis.md +35 -0
  11. package/skills/supabase-architecture-variants/SKILL.md +395 -216
  12. package/skills/supabase-architecture-variants/references/errors.md +11 -0
  13. package/skills/supabase-architecture-variants/references/examples.md +12 -0
  14. package/skills/supabase-architecture-variants/references/serverless-and-multi-tenant.md +251 -0
  15. package/skills/supabase-architecture-variants/references/variant-a-monolith-(simple).md +44 -0
  16. package/skills/supabase-architecture-variants/references/variant-b-service-layer-(moderate).md +72 -0
  17. package/skills/supabase-architecture-variants/references/variant-c-microservice-(complex).md +81 -0
  18. package/skills/supabase-auth-storage-realtime-core/SKILL.md +471 -37
  19. package/skills/supabase-ci-integration/SKILL.md +315 -67
  20. package/skills/supabase-ci-integration/references/errors.md +10 -0
  21. package/skills/supabase-ci-integration/references/examples.md +36 -0
  22. package/skills/supabase-ci-integration/references/implementation.md +54 -0
  23. package/skills/supabase-common-errors/SKILL.md +320 -62
  24. package/skills/supabase-common-errors/references/errors.md +53 -0
  25. package/skills/supabase-common-errors/references/examples.md +23 -0
  26. package/skills/supabase-cost-tuning/SKILL.md +365 -131
  27. package/skills/supabase-cost-tuning/references/cost-estimation.md +34 -0
  28. package/skills/supabase-cost-tuning/references/cost-reduction-strategies.md +40 -0
  29. package/skills/supabase-cost-tuning/references/errors.md +11 -0
  30. package/skills/supabase-cost-tuning/references/examples.md +15 -0
  31. package/skills/supabase-data-handling/SKILL.md +378 -145
  32. package/skills/supabase-data-handling/references/errors.md +11 -0
  33. package/skills/supabase-data-handling/references/examples.md +27 -0
  34. package/skills/supabase-data-handling/references/implementation.md +223 -0
  35. package/skills/supabase-data-handling/references/retention-and-backup.md +221 -0
  36. package/skills/supabase-debug-bundle/SKILL.md +267 -73
  37. package/skills/supabase-debug-bundle/references/errors.md +12 -0
  38. package/skills/supabase-debug-bundle/references/examples.md +24 -0
  39. package/skills/supabase-debug-bundle/references/implementation.md +54 -0
  40. package/skills/supabase-deploy-integration/SKILL.md +258 -147
  41. package/skills/supabase-deploy-integration/references/errors.md +11 -0
  42. package/skills/supabase-deploy-integration/references/examples.md +21 -0
  43. package/skills/supabase-deploy-integration/references/google-cloud-run.md +36 -0
  44. package/skills/supabase-deploy-integration/references/vercel-deployment.md +35 -0
  45. package/skills/supabase-enterprise-rbac/SKILL.md +327 -160
  46. package/skills/supabase-enterprise-rbac/references/api-scoping-and-enforcement.md +255 -0
  47. package/skills/supabase-enterprise-rbac/references/errors.md +11 -0
  48. package/skills/supabase-enterprise-rbac/references/examples.md +12 -0
  49. package/skills/supabase-enterprise-rbac/references/role-implementation.md +33 -0
  50. package/skills/supabase-enterprise-rbac/references/sso-integration.md +35 -0
  51. package/skills/supabase-hello-world/SKILL.md +160 -54
  52. package/skills/supabase-incident-runbook/SKILL.md +453 -131
  53. package/skills/supabase-incident-runbook/references/errors.md +11 -0
  54. package/skills/supabase-incident-runbook/references/examples.md +10 -0
  55. package/skills/supabase-incident-runbook/references/immediate-actions-by-error-type.md +41 -0
  56. package/skills/supabase-install-auth/SKILL.md +186 -50
  57. package/skills/supabase-install-auth/references/examples.md +102 -0
  58. package/skills/supabase-known-pitfalls/SKILL.md +411 -241
  59. package/skills/supabase-known-pitfalls/references/errors.md +11 -0
  60. package/skills/supabase-known-pitfalls/references/examples.md +12 -0
  61. package/skills/supabase-load-scale/SKILL.md +346 -217
  62. package/skills/supabase-load-scale/references/capacity-planning.md +47 -0
  63. package/skills/supabase-load-scale/references/errors.md +11 -0
  64. package/skills/supabase-load-scale/references/examples.md +26 -0
  65. package/skills/supabase-load-scale/references/load-testing-with-k6.md +59 -0
  66. package/skills/supabase-load-scale/references/scaling-patterns.md +65 -0
  67. package/skills/supabase-load-scale/references/table-partitioning.md +263 -0
  68. package/skills/supabase-local-dev-loop/SKILL.md +272 -73
  69. package/skills/supabase-local-dev-loop/references/errors.md +11 -0
  70. package/skills/supabase-local-dev-loop/references/examples.md +21 -0
  71. package/skills/supabase-local-dev-loop/references/implementation.md +60 -0
  72. package/skills/supabase-migration-deep-dive/SKILL.md +338 -177
  73. package/skills/supabase-migration-deep-dive/references/backfill-versioning-rollback.md +258 -0
  74. package/skills/supabase-migration-deep-dive/references/errors.md +11 -0
  75. package/skills/supabase-migration-deep-dive/references/examples.md +12 -0
  76. package/skills/supabase-migration-deep-dive/references/implementation-plan.md +80 -0
  77. package/skills/supabase-migration-deep-dive/references/pre-migration-assessment.md +39 -0
  78. package/skills/supabase-multi-env-setup/SKILL.md +393 -152
  79. package/skills/supabase-multi-env-setup/references/configuration-structure.md +59 -0
  80. package/skills/supabase-multi-env-setup/references/errors.md +11 -0
  81. package/skills/supabase-multi-env-setup/references/examples.md +11 -0
  82. package/skills/supabase-observability/SKILL.md +318 -196
  83. package/skills/supabase-observability/references/alert-configuration.md +40 -0
  84. package/skills/supabase-observability/references/errors.md +11 -0
  85. package/skills/supabase-observability/references/examples.md +13 -0
  86. package/skills/supabase-observability/references/metrics-collection.md +65 -0
  87. package/skills/supabase-performance-tuning/SKILL.md +304 -160
  88. package/skills/supabase-performance-tuning/references/caching-strategy.md +49 -0
  89. package/skills/supabase-performance-tuning/references/errors.md +11 -0
  90. package/skills/supabase-performance-tuning/references/examples.md +13 -0
  91. package/skills/supabase-policy-guardrails/SKILL.md +248 -221
  92. package/skills/supabase-policy-guardrails/references/ci-cost-security.md +484 -0
  93. package/skills/supabase-policy-guardrails/references/errors.md +11 -0
  94. package/skills/supabase-policy-guardrails/references/eslint-rules.md +46 -0
  95. package/skills/supabase-policy-guardrails/references/examples.md +10 -0
  96. package/skills/supabase-prod-checklist/SKILL.md +474 -84
  97. package/skills/supabase-prod-checklist/references/errors.md +63 -0
  98. package/skills/supabase-prod-checklist/references/examples.md +153 -0
  99. package/skills/supabase-prod-checklist/references/implementation.md +113 -0
  100. package/skills/supabase-rate-limits/SKILL.md +311 -98
  101. package/skills/supabase-rate-limits/references/errors.md +11 -0
  102. package/skills/supabase-rate-limits/references/examples.md +46 -0
  103. package/skills/supabase-rate-limits/references/implementation.md +66 -0
  104. package/skills/supabase-reference-architecture/SKILL.md +249 -182
  105. package/skills/supabase-reference-architecture/references/errors.md +29 -0
  106. package/skills/supabase-reference-architecture/references/examples.md +116 -0
  107. package/skills/supabase-reference-architecture/references/key-components.md +244 -0
  108. package/skills/supabase-reference-architecture/references/project-structure.md +109 -0
  109. package/skills/supabase-reliability-patterns/SKILL.md +229 -234
  110. package/skills/supabase-reliability-patterns/references/circuit-breaker.md +36 -0
  111. package/skills/supabase-reliability-patterns/references/dead-letter-queue.md +48 -0
  112. package/skills/supabase-reliability-patterns/references/errors.md +11 -0
  113. package/skills/supabase-reliability-patterns/references/examples.md +11 -0
  114. package/skills/supabase-reliability-patterns/references/idempotency-keys.md +36 -0
  115. package/skills/supabase-reliability-patterns/references/offline-degradation-health-dualwrite.md +489 -0
  116. package/skills/supabase-schema-from-requirements/SKILL.md +373 -34
  117. package/skills/supabase-sdk-patterns/SKILL.md +388 -99
  118. package/skills/supabase-sdk-patterns/references/errors.md +11 -0
  119. package/skills/supabase-sdk-patterns/references/examples.md +45 -0
  120. package/skills/supabase-sdk-patterns/references/implementation.md +67 -0
  121. package/skills/supabase-security-basics/SKILL.md +282 -102
  122. package/skills/supabase-security-basics/references/errors.md +10 -0
  123. package/skills/supabase-security-basics/references/examples.md +70 -0
  124. package/skills/supabase-security-basics/references/implementation.md +39 -0
  125. package/skills/supabase-upgrade-migration/SKILL.md +248 -66
  126. package/skills/supabase-upgrade-migration/references/errors.md +10 -0
  127. package/skills/supabase-upgrade-migration/references/examples.md +51 -0
  128. package/skills/supabase-upgrade-migration/references/implementation.md +29 -0
  129. package/skills/supabase-webhooks-events/SKILL.md +412 -138
  130. package/skills/supabase-webhooks-events/references/errors.md +55 -0
  131. package/skills/supabase-webhooks-events/references/event-handler-pattern.md +106 -0
  132. package/skills/supabase-webhooks-events/references/examples.md +133 -0
  133. package/skills/supabase-webhooks-events/references/signature-verification.md +165 -0
@@ -0,0 +1,255 @@
1
+ # API Key Scoping and Role Enforcement
2
+
3
+ Enforce roles at the application layer to complement RLS, and scope API operations by role.
4
+
5
+ **Server-side role enforcement middleware:**
6
+
7
+ ```typescript
8
+ import { createClient } from '@supabase/supabase-js';
9
+ import type { NextRequest } from 'next/server';
10
+
11
+ // Create a per-request client with the user's JWT
12
+ function createRequestClient(request: NextRequest) {
13
+ const token = request.headers.get('Authorization')?.replace('Bearer ', '');
14
+
15
+ return createClient(
16
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
17
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
18
+ {
19
+ global: {
20
+ headers: { Authorization: `Bearer ${token}` },
21
+ },
22
+ }
23
+ );
24
+ }
25
+
26
+ // Role enforcement for API routes
27
+ async function withRole(
28
+ request: NextRequest,
29
+ requiredRole: AppRole,
30
+ handler: (supabase: ReturnType<typeof createClient>, user: any) => Promise<Response>
31
+ ) {
32
+ const supabase = createRequestClient(request);
33
+
34
+ const { data: { user }, error } = await supabase.auth.getUser();
35
+ if (error || !user) {
36
+ return Response.json({ error: 'Unauthorized' }, { status: 401 });
37
+ }
38
+
39
+ const userRole = user.app_metadata?.role as AppRole;
40
+ if (!userRole || !hasRole(userRole, requiredRole)) {
41
+ return Response.json(
42
+ { error: `Forbidden: requires "${requiredRole}" role` },
43
+ { status: 403 }
44
+ );
45
+ }
46
+
47
+ return handler(supabase, user);
48
+ }
49
+
50
+ // Usage in Next.js App Router
51
+ export async function DELETE(request: NextRequest) {
52
+ return withRole(request, 'admin', async (supabase, user) => {
53
+ const projectId = request.nextUrl.searchParams.get('id');
54
+
55
+ const { error } = await supabase
56
+ .from('projects')
57
+ .delete()
58
+ .eq('id', projectId);
59
+
60
+ if (error) return Response.json({ error: error.message }, { status: 400 });
61
+ return Response.json({ deleted: true });
62
+ });
63
+ }
64
+ ```
65
+
66
+ **Admin panel — manage user roles:**
67
+
68
+ ```typescript
69
+ import { createClient } from '@supabase/supabase-js';
70
+
71
+ const adminClient = createClient(
72
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
73
+ process.env.SUPABASE_SERVICE_ROLE_KEY!,
74
+ { auth: { autoRefreshToken: false, persistSession: false } }
75
+ );
76
+
77
+ // List all users in an organization with their roles
78
+ async function listOrgMembers(orgId: string) {
79
+ const { data, error } = await adminClient
80
+ .from('team_members')
81
+ .select(`
82
+ user_id,
83
+ role,
84
+ created_at,
85
+ profiles!inner(email, full_name)
86
+ `)
87
+ .eq('org_id', orgId)
88
+ .order('created_at', { ascending: false });
89
+
90
+ if (error) throw error;
91
+ return data;
92
+ }
93
+
94
+ // Invite a user to an organization
95
+ async function inviteToOrg(
96
+ email: string,
97
+ orgId: string,
98
+ role: AppRole,
99
+ invitedBy: string
100
+ ) {
101
+ // Create or get the user
102
+ const { data: existingUsers } = await adminClient
103
+ .from('profiles')
104
+ .select('id')
105
+ .eq('email', email)
106
+ .single();
107
+
108
+ const userId = existingUsers?.id;
109
+ if (!userId) {
110
+ // Send invite email via Supabase Auth
111
+ const { error } = await adminClient.auth.admin.inviteUserByEmail(email, {
112
+ data: { org_id: orgId, role },
113
+ });
114
+ if (error) throw error;
115
+ return { status: 'invited' };
116
+ }
117
+
118
+ // Add existing user to org
119
+ const { error } = await adminClient.from('team_members').insert({
120
+ org_id: orgId,
121
+ user_id: userId,
122
+ role,
123
+ invited_by: invitedBy,
124
+ });
125
+
126
+ if (error) throw error;
127
+
128
+ // Update user's app_metadata with org and role
129
+ await setUserRole(userId, role, orgId);
130
+
131
+ return { status: 'added', userId };
132
+ }
133
+
134
+ // Change a user's role (admin only)
135
+ async function changeUserRole(
136
+ orgId: string,
137
+ targetUserId: string,
138
+ newRole: AppRole
139
+ ) {
140
+ // Update team_members table
141
+ const { error: dbError } = await adminClient
142
+ .from('team_members')
143
+ .update({ role: newRole })
144
+ .eq('org_id', orgId)
145
+ .eq('user_id', targetUserId);
146
+
147
+ if (dbError) throw dbError;
148
+
149
+ // Update JWT claims
150
+ await setUserRole(targetUserId, newRole, orgId);
151
+
152
+ console.log(`User ${targetUserId} role changed to "${newRole}" in org ${orgId}`);
153
+ }
154
+ ```
155
+
156
+ ## Output
157
+
158
+ After completing this skill, you will have:
159
+
160
+ - **Role assignment via app_metadata** — `admin.updateUserById()` sets role claims on user JWTs
161
+ - **JWT claim extraction** — `get_user_role()` and `get_user_org_id()` SQL helper functions
162
+ - **Role-based RLS policies** — SELECT/INSERT/UPDATE/DELETE scoped by role hierarchy (admin > editor > member > viewer)
163
+ - **Organization-scoped access** — multi-tenant isolation via `org_id` in JWT claims and RLS policies
164
+ - **Application-layer enforcement** — `withRole()` middleware for API routes with proper 401/403 responses
165
+ - **Admin panel operations** — list members, invite users, change roles with both database and JWT updates
166
+ - **Role hierarchy checking** — `hasRole()` function supporting role escalation comparison
167
+
168
+ ## Error Handling
169
+
170
+ | Error | Cause | Solution |
171
+ |-------|-------|----------|
172
+ | `app_metadata.role` is null in JWT | Role not set or user needs to re-login | Call `admin.updateUserById()` to set role; user must refresh their session |
173
+ | RLS policy returns empty results | JWT claims don't match policy conditions | Check `auth.jwt()` output in SQL Editor; verify `app_metadata` was set correctly |
174
+ | `permission denied for function` | Helper function not created or wrong schema | Create `get_user_role()` in the `public` schema with `SECURITY DEFINER` |
175
+ | User role changes not reflected | JWT cached with old claims | User must sign out and sign in again, or call `supabase.auth.refreshSession()` |
176
+ | `duplicate key value violates unique constraint` | User already in organization | Check `team_members` table for existing entry before inserting |
177
+ | `foreign key violation` on team_members | User or org doesn't exist | Verify both `user_id` and `org_id` exist before inserting membership |
178
+ | Role hierarchy bypass | Direct database access with service role | Service role bypasses RLS by design — restrict its use to server-side admin operations only |
179
+
180
+ ## Examples
181
+
182
+ **Example 1 — Quick role check in a component:**
183
+
184
+ ```typescript
185
+ import { createClient } from '@supabase/supabase-js';
186
+
187
+ const supabase = createClient(url, anonKey);
188
+
189
+ async function canEditProject(): Promise<boolean> {
190
+ const { data: { user } } = await supabase.auth.getUser();
191
+ const role = user?.app_metadata?.role;
192
+ return role === 'admin' || role === 'editor';
193
+ }
194
+ ```
195
+
196
+ **Example 2 — Verify RLS policies work correctly:**
197
+
198
+ ```sql
199
+ -- Test as an editor in org-123
200
+ SET request.jwt.claims = '{"sub": "user-uuid", "role": "authenticated", "app_metadata": {"role": "editor", "org_id": "org-123"}}';
201
+
202
+ -- Should return only org-123 projects
203
+ SELECT * FROM projects;
204
+
205
+ -- Should succeed (editors can create)
206
+ INSERT INTO projects (org_id, name, created_by) VALUES ('org-123', 'Test', 'user-uuid');
207
+
208
+ -- Should fail (editors cannot delete)
209
+ DELETE FROM projects WHERE id = 'some-project-id';
210
+
211
+ RESET request.jwt.claims;
212
+ ```
213
+
214
+ **Example 3 — Onboard a new organization:**
215
+
216
+ ```typescript
217
+ async function onboardOrganization(orgName: string, adminEmail: string) {
218
+ // 1. Create the organization
219
+ const { data: org } = await adminClient
220
+ .from('organizations')
221
+ .insert({ name: orgName, slug: orgName.toLowerCase().replace(/\s+/g, '-') })
222
+ .select('id')
223
+ .single();
224
+
225
+ // 2. Assign the creator as admin
226
+ const { data: { users } } = await adminClient.auth.admin.listUsers();
227
+ const adminUser = users.find((u) => u.email === adminEmail);
228
+
229
+ if (adminUser && org) {
230
+ await setUserRole(adminUser.id, 'admin', org.id);
231
+ await adminClient.from('team_members').insert({
232
+ org_id: org.id,
233
+ user_id: adminUser.id,
234
+ role: 'admin',
235
+ });
236
+ }
237
+
238
+ return org;
239
+ }
240
+ ```
241
+
242
+ ## Resources
243
+
244
+ - [Custom Claims and RBAC — Supabase Docs](https://supabase.com/docs/guides/database/postgres/custom-claims-and-role-based-access-control-rbac)
245
+ - [Auth Admin updateUserById — Supabase Docs](https://supabase.com/docs/reference/javascript/auth-admin-updateuserbyid)
246
+ - [Row Level Security — Supabase Docs](https://supabase.com/docs/guides/database/postgres/row-level-security)
247
+ - [auth.jwt() Function — Supabase Docs](https://supabase.com/docs/guides/database/postgres/row-level-security#helper-functions)
248
+ - [Multi-tenancy Patterns — Supabase Docs](https://supabase.com/docs/guides/getting-started/architecture#multi-tenancy)
249
+ - [inviteUserByEmail — Supabase Docs](https://supabase.com/docs/reference/javascript/auth-admin-inviteuserbyemail)
250
+
251
+ ## Next Steps
252
+
253
+ - For database migration patterns, see `supabase-migration-deep-dive`
254
+ - For security hardening and API key scoping, see `supabase-security-basics`
255
+ - For data handling and GDPR compliance, see `supabase-data-handling`
@@ -0,0 +1,11 @@
1
+ # Error Handling Reference
2
+
3
+ | Issue | Cause | Solution |
4
+ |-------|-------|----------|
5
+ | SSO login fails | Wrong callback URL | Verify IdP config |
6
+ | Permission denied | Missing role mapping | Update group mappings |
7
+ | Token expired | Short TTL | Refresh token logic |
8
+ | Audit gaps | Async logging failed | Check log pipeline |
9
+
10
+ ---
11
+ *[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*
@@ -0,0 +1,12 @@
1
+ ## Examples
2
+
3
+ ### Quick Permission Check
4
+
5
+ ```typescript
6
+ if (!checkPermission(user.role, 'write')) {
7
+ throw new ForbiddenError('Write permission required');
8
+ }
9
+ ```
10
+
11
+ ---
12
+ *[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*
@@ -0,0 +1,33 @@
1
+ # Role Implementation
2
+
3
+ ## Role Implementation
4
+
5
+ ```typescript
6
+ enum SupabaseRole {
7
+ Admin = 'admin',
8
+ Developer = 'developer',
9
+ Viewer = 'viewer',
10
+ Service = 'service',
11
+ }
12
+
13
+ interface SupabasePermissions {
14
+ read: boolean;
15
+ write: boolean;
16
+ delete: boolean;
17
+ admin: boolean;
18
+ }
19
+
20
+ const ROLE_PERMISSIONS: Record<SupabaseRole, SupabasePermissions> = {
21
+ admin: { read: true, write: true, delete: true, admin: true },
22
+ developer: { read: true, write: true, delete: false, admin: false },
23
+ viewer: { read: true, write: false, delete: false, admin: false },
24
+ service: { read: true, write: true, delete: false, admin: false },
25
+ };
26
+
27
+ function checkPermission(
28
+ role: SupabaseRole,
29
+ action: keyof SupabasePermissions
30
+ ): boolean {
31
+ return ROLE_PERMISSIONS[role][action];
32
+ }
33
+ ```
@@ -0,0 +1,35 @@
1
+ # Sso Integration
2
+
3
+ ## SSO Integration
4
+
5
+ ### SAML Configuration
6
+
7
+ ```typescript
8
+ // Supabase SAML setup
9
+ const samlConfig = {
10
+ entryPoint: 'https://idp.company.com/saml/sso',
11
+ issuer: 'https://supabase.com/saml/metadata',
12
+ cert: process.env.SAML_CERT,
13
+ callbackUrl: 'https://app.yourcompany.com/auth/supabase/callback',
14
+ };
15
+
16
+ // Map IdP groups to Supabase roles
17
+ const groupRoleMapping: Record<string, SupabaseRole> = {
18
+ 'Engineering': SupabaseRole.Developer,
19
+ 'Platform-Admins': SupabaseRole.Admin,
20
+ 'Data-Team': SupabaseRole.Viewer,
21
+ };
22
+ ```
23
+
24
+ ### OAuth2/OIDC Integration
25
+
26
+ ```typescript
27
+ import { OAuth2Client } from '@supabase/supabase-js';
28
+
29
+ const oauthClient = new OAuth2Client({
30
+ clientId: process.env.SUPABASE_OAUTH_CLIENT_ID!,
31
+ clientSecret: process.env.SUPABASE_OAUTH_CLIENT_SECRET!,
32
+ redirectUri: 'https://app.yourcompany.com/auth/supabase/callback',
33
+ scopes: read, write, realtime,
34
+ });
35
+ ```
@@ -1,96 +1,202 @@
1
1
  ---
2
2
  name: supabase-hello-world
3
- description: |
4
- Create a minimal working Supabase example.
5
- Use when starting a new Supabase integration, testing your setup,
6
- or learning basic Supabase API patterns.
7
- Trigger with phrases like "supabase hello world", "supabase example",
8
- "supabase quick start", "simple supabase code".
9
- allowed-tools: Read, Write, Edit
3
+ description: "Run your first Supabase query \u2014 insert a row and read it back.\n\
4
+ Use when starting a new Supabase project, verifying your connection works,\nor learning\
5
+ \ the basic insert-then-select pattern with @supabase/supabase-js.\nTrigger with\
6
+ \ phrases like \"supabase hello world\", \"first supabase query\",\n\"supabase quick\
7
+ \ start\", \"test supabase connection\", \"supabase insert and select\".\n"
8
+ allowed-tools: Read, Write, Edit, Bash(npm:*), Bash(npx:*), Bash(supabase:*)
10
9
  version: 1.0.0
11
10
  license: MIT
12
11
  author: Jeremy Longshore <jeremy@intentsolutions.io>
12
+ tags:
13
+ - saas
14
+ - supabase
15
+ - database
16
+ - getting-started
17
+ compatibility: Designed for Claude Code, also compatible with Codex and OpenClaw
13
18
  ---
14
-
15
- # Supabase Hello World
19
+ # Supabase Hello World — First Query
16
20
 
17
21
  ## Overview
18
- Minimal working example demonstrating core Supabase functionality.
22
+
23
+ Execute your first real Supabase query: create a `todos` table in the dashboard, insert a row with the JS client, and read it back. This validates that your project URL, anon key, and Row Level Security are configured correctly before you build anything else.
19
24
 
20
25
  ## Prerequisites
21
- - Completed `supabase-install-auth` setup
22
- - Valid API credentials configured
23
- - Development environment ready
26
+
27
+ - Completed `supabase-install-auth` setup (project URL + anon key in `.env`)
28
+ - `@supabase/supabase-js` v2+ installed (`npm install @supabase/supabase-js`)
29
+ - A Supabase project at [supabase.com/dashboard](https://supabase.com/dashboard)
24
30
 
25
31
  ## Instructions
26
32
 
27
- ### Step 1: Create Entry File
28
- Create a new file for your hello world example.
33
+ ### Step 1: Create the `todos` Table
34
+
35
+ Open your Supabase dashboard SQL Editor and run:
36
+
37
+ ```sql
38
+ -- Create a simple todos table
39
+ create table public.todos (
40
+ id bigint generated always as identity primary key,
41
+ task text not null,
42
+ is_complete boolean default false,
43
+ inserted_at timestamptz default now()
44
+ );
45
+
46
+ -- Enable Row Level Security (required for anon key access)
47
+ alter table public.todos enable row level security;
48
+
49
+ -- Allow anyone with the anon key to read and insert
50
+ -- (permissive for hello-world; lock down before production)
51
+ create policy "Allow public read" on public.todos
52
+ for select using (true);
53
+
54
+ create policy "Allow public insert" on public.todos
55
+ for insert with check (true);
56
+ ```
57
+
58
+ Verify the table appears under **Table Editor** in the dashboard before continuing.
59
+
60
+ ### Step 2: Insert a Row
29
61
 
30
- ### Step 2: Import and Initialize Client
31
62
  ```typescript
32
- import { SupabaseClient } from '@supabase/supabase-js';
63
+ import { createClient } from '@supabase/supabase-js'
64
+
65
+ const supabase = createClient(
66
+ process.env.SUPABASE_URL!,
67
+ process.env.SUPABASE_ANON_KEY!
68
+ )
69
+
70
+ // Insert a row and return it with .select()
71
+ const { data, error } = await supabase
72
+ .from('todos')
73
+ .insert({ task: 'Hello from Supabase!' })
74
+ .select()
75
+
76
+ if (error) {
77
+ console.error('Insert failed:', error.message)
78
+ // e.g. "new row violates row-level security policy"
79
+ process.exit(1)
80
+ }
33
81
 
34
- const client = new SupabaseClient({
35
- apiKey: process.env.SUPABASE_API_KEY,
36
- });
82
+ console.log('Inserted:', data)
83
+ // [{ id: 1, task: "Hello from Supabase!", is_complete: false, inserted_at: "2026-03-22T..." }]
37
84
  ```
38
85
 
39
- ### Step 3: Make Your First API Call
86
+ Key detail: `.insert()` alone returns `{ data: null }`. You must chain `.select()` to get the inserted row back.
87
+
88
+ ### Step 3: Read It Back
89
+
40
90
  ```typescript
41
- async function main() {
42
- const result = await supabase.from('todos').insert({ task: 'Hello!' }).select(); console.log(result.data);
91
+ // Select all rows from todos
92
+ const { data: todos, error: selectError } = await supabase
93
+ .from('todos')
94
+ .select('*')
95
+
96
+ if (selectError) {
97
+ console.error('Select failed:', selectError.message)
98
+ process.exit(1)
43
99
  }
44
100
 
45
- main().catch(console.error);
101
+ console.log('Todos:', todos)
102
+ // [{ id: 1, task: "Hello from Supabase!", is_complete: false, inserted_at: "2026-03-22T..." }]
103
+
104
+ // Verify the round-trip
105
+ if (todos && todos.length > 0) {
106
+ console.log('Round-trip verified — row exists in database')
107
+ } else {
108
+ console.error('No rows returned. Check RLS policies.')
109
+ }
46
110
  ```
47
111
 
112
+ Open the **Table Editor** in the Supabase dashboard to visually confirm the row is there.
113
+
48
114
  ## Output
49
- - Working code file with Supabase client initialization
50
- - Successful API response confirming connection
51
- - Console output showing:
52
- ```
53
- Success! Your Supabase connection is working.
54
- ```
115
+
116
+ - `todos` table created with RLS enabled
117
+ - One row inserted via the JS client
118
+ - Same row read back with `.select('*')`
119
+ - Dashboard confirms the data round-trip
55
120
 
56
121
  ## Error Handling
122
+
57
123
  | Error | Cause | Solution |
58
124
  |-------|-------|----------|
59
- | Import Error | SDK not installed | Verify with `npm list` or `pip show` |
60
- | Auth Error | Invalid credentials | Check environment variable is set |
61
- | Timeout | Network issues | Increase timeout or check connectivity |
62
- | Rate Limit | Too many requests | Wait and retry with exponential backoff |
125
+ | `relation "public.todos" does not exist` | Table not created | Run the Step 1 SQL in the dashboard SQL Editor |
126
+ | `new row violates row-level security policy` | RLS blocks the insert | Add the permissive insert policy from Step 1 |
127
+ | `Invalid API key` | Wrong anon key in `.env` | Copy from Settings > API in the dashboard |
128
+ | `FetchError: request to https://... failed` | Wrong project URL | Verify `SUPABASE_URL` matches dashboard URL |
129
+ | `data` is `null` after insert | Missing `.select()` chain | Add `.select()` after `.insert()` |
130
+ | Empty array returned from select | RLS blocks reads | Add the select policy from Step 1 |
63
131
 
64
132
  ## Examples
65
133
 
66
- ### TypeScript Example
67
- ```typescript
68
- import { SupabaseClient } from '@supabase/supabase-js';
69
-
70
- const client = new SupabaseClient({
71
- apiKey: process.env.SUPABASE_API_KEY,
72
- });
134
+ ### TypeScript (Complete Script)
73
135
 
74
- async function main() {
75
- const result = await supabase.from('todos').insert({ task: 'Hello!' }).select(); console.log(result.data);
136
+ ```typescript
137
+ import { createClient } from '@supabase/supabase-js'
138
+
139
+ const supabase = createClient(
140
+ process.env.SUPABASE_URL!,
141
+ process.env.SUPABASE_ANON_KEY!
142
+ )
143
+
144
+ async function helloSupabase() {
145
+ // Insert
146
+ const { data: inserted, error: insertErr } = await supabase
147
+ .from('todos')
148
+ .insert({ task: 'Hello from TypeScript!' })
149
+ .select()
150
+ .single()
151
+
152
+ if (insertErr) throw new Error(`Insert: ${insertErr.message}`)
153
+ console.log('Inserted:', inserted)
154
+
155
+ // Read back
156
+ const { data: rows, error: selectErr } = await supabase
157
+ .from('todos')
158
+ .select('*')
159
+ .order('inserted_at', { ascending: false })
160
+ .limit(5)
161
+
162
+ if (selectErr) throw new Error(`Select: ${selectErr.message}`)
163
+ console.log('Recent todos:', rows)
76
164
  }
77
165
 
78
- main().catch(console.error);
166
+ helloSupabase().catch(console.error)
79
167
  ```
80
168
 
81
- ### Python Example
82
- ```python
83
- from supabase import SupabaseClient
84
-
85
- client = SupabaseClient()
169
+ ### Python
86
170
 
87
- response = supabase.table('todos').insert({'task': 'Hello!'}).execute(); print(response.data)
171
+ ```python
172
+ from supabase import create_client
173
+ import os
174
+
175
+ supabase = create_client(
176
+ os.environ["SUPABASE_URL"],
177
+ os.environ["SUPABASE_ANON_KEY"]
178
+ )
179
+
180
+ # Insert a row
181
+ result = supabase.table("todos").insert({"task": "Hello from Python!"}).execute()
182
+ print("Inserted:", result.data)
183
+ # [{"id": 2, "task": "Hello from Python!", "is_complete": False, ...}]
184
+
185
+ # Read it back
186
+ result = supabase.table("todos").select("*").execute()
187
+ print("All todos:", result.data)
88
188
  ```
89
189
 
190
+ Install the Python client with: `pip install supabase`
191
+
90
192
  ## Resources
91
- - [Supabase Getting Started](https://supabase.com/docs/getting-started)
92
- - [Supabase API Reference](https://supabase.com/docs/api)
93
- - [Supabase Examples](https://supabase.com/docs/examples)
193
+
194
+ - [Supabase Getting Started](https://supabase.com/docs/guides/getting-started)
195
+ - [JS Client — Insert](https://supabase.com/docs/reference/javascript/insert)
196
+ - [JS Client — Select](https://supabase.com/docs/reference/javascript/select)
197
+ - [Python Client](https://supabase.com/docs/reference/python/introduction)
198
+ - [Row Level Security](https://supabase.com/docs/guides/database/postgres/row-level-security)
94
199
 
95
200
  ## Next Steps
96
- Proceed to `supabase-local-dev-loop` for development workflow setup.
201
+
202
+ Proceed to `supabase-local-dev-loop` for local development workflow with the Supabase CLI.