@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
@@ -1,257 +1,284 @@
1
1
  ---
2
2
  name: supabase-policy-guardrails
3
- description: |
4
- Implement Supabase lint rules, policy enforcement, and automated guardrails.
5
- Use when setting up code quality rules for Supabase integrations, implementing
6
- pre-commit hooks, or configuring CI policy checks for Supabase best practices.
7
- Trigger with phrases like "supabase policy", "supabase lint",
8
- "supabase guardrails", "supabase best practices check", "supabase eslint".
9
- allowed-tools: Read, Write, Edit, Bash(npx:*)
10
- version: 1.0.0
11
- license: MIT
12
- author: Jeremy Longshore <jeremy@intentsolutions.io>
13
- ---
14
-
15
- # Supabase Policy & Guardrails
16
-
17
- ## Overview
18
- Automated policy enforcement and guardrails for Supabase integrations.
19
-
20
- ## Prerequisites
21
- - ESLint configured in project
22
- - Pre-commit hooks infrastructure
23
- - CI/CD pipeline with policy checks
24
- - TypeScript for type enforcement
25
-
26
- ## ESLint Rules
27
-
28
- ### Custom Supabase Plugin
29
- ```javascript
30
- // eslint-plugin-supabase/rules/no-hardcoded-keys.js
31
- module.exports = {
32
- meta: {
33
- type: 'problem',
34
- docs: {
35
- description: 'Disallow hardcoded Supabase API keys',
36
- },
37
- fixable: 'code',
38
- },
39
- create(context) {
40
- return {
41
- Literal(node) {
42
- if (typeof node.value === 'string') {
43
- if (node.value.match(/^sk_(live|test)_[a-zA-Z0-9]{24,}/)) {
44
- context.report({
45
- node,
46
- message: 'Hardcoded Supabase API key detected',
47
- });
48
- }
49
- }
50
- },
51
- };
52
- },
53
- };
54
- ```
55
-
56
- ### ESLint Configuration
57
- ```javascript
58
- // .eslintrc.js
59
- module.exports = {
60
- plugins: ['supabase'],
61
- rules: {
62
- 'supabase/no-hardcoded-keys': 'error',
63
- 'supabase/require-error-handling': 'warn',
64
- 'supabase/use-typed-client': 'warn',
65
- },
66
- };
67
- ```
68
-
69
- ## Pre-Commit Hooks
70
-
71
- ```yaml
72
- # .pre-commit-config.yaml
73
- repos:
74
- - repo: local
75
- hooks:
76
- - id: supabase-secrets-check
77
- name: Check for Supabase secrets
78
- entry: bash -c 'git diff --cached --name-only | xargs grep -l "sk_live_" && exit 1 || exit 0'
79
- language: system
80
- pass_filenames: false
81
-
82
- - id: supabase-config-validate
83
- name: Validate Supabase configuration
84
- entry: node scripts/validate-supabase-config.js
85
- language: node
86
- files: '\.supabase\.json$'
87
- ```
88
-
89
- ## TypeScript Strict Patterns
90
-
91
- ```typescript
92
- // Enforce typed configuration
93
- interface SupabaseStrictConfig {
94
- apiKey: string; // Required
95
- environment: 'development' | 'staging' | 'production'; // Enum
96
- timeout: number; // Required number, not optional
97
- retries: number;
98
- }
99
-
100
- // Disallow any in Supabase code
101
- // @ts-expect-error - Using any is forbidden
102
- const client = new Client({ apiKey: any });
103
-
104
- // Prefer this
105
- const client = new SupabaseClient(config satisfies SupabaseStrictConfig);
106
- ```
107
-
108
- ## Architecture Decision Records
3
+ description: 'Enforce organizational governance for Supabase projects: shared RLS
4
+ policy
109
5
 
110
- ### ADR Template
111
- ```markdown
112
- # ADR-001: Supabase Client Initialization
6
+ library with reusable templates, table and column naming conventions,
113
7
 
114
- ## Status
115
- Accepted
8
+ migration review process with CI checks, cost alert thresholds,
116
9
 
117
- ## Context
118
- We need to decide how to initialize the Supabase client across our application.
10
+ and security audit scripts scanning for common misconfigurations.
119
11
 
120
- ## Decision
121
- We will use the singleton pattern with lazy initialization.
12
+ Use when establishing Supabase standards across teams, creating RLS
122
13
 
123
- ## Consequences
124
- - Pro: Single client instance, connection reuse
125
- - Pro: Easy to mock in tests
126
- - Con: Global state requires careful lifecycle management
14
+ policy templates, setting up migration review workflows, or auditing
127
15
 
128
- ## Enforcement
129
- - ESLint rule: supabase/use-singleton-client
130
- - CI check: grep for "new SupabaseClient(" outside allowed files
131
- ```
16
+ existing projects for security and cost issues.
132
17
 
133
- ## Policy-as-Code (OPA)
134
-
135
- ```rego
136
- # supabase-policy.rego
137
- package supabase
138
-
139
- # Deny production API keys in non-production environments
140
- deny[msg] {
141
- input.environment != "production"
142
- startswith(input.apiKey, "sk_live_")
143
- msg := "Production API keys not allowed in non-production environment"
144
- }
145
-
146
- # Require minimum timeout
147
- deny[msg] {
148
- input.timeout < 10000
149
- msg := sprintf("Timeout too low: %d < 10000ms minimum", [input.timeout])
150
- }
151
-
152
- # Require retry configuration
153
- deny[msg] {
154
- not input.retries
155
- msg := "Retry configuration is required"
156
- }
157
- ```
18
+ Trigger with phrases like "supabase governance", "supabase policy library",
158
19
 
159
- ## CI Policy Checks
20
+ "supabase naming convention", "supabase migration review",
160
21
 
161
- ```yaml
162
- # .github/workflows/supabase-policy.yml
163
- name: Supabase Policy Check
22
+ "supabase cost alert", "supabase security audit", "supabase RLS template".
164
23
 
165
- on: [push, pull_request]
24
+ '
25
+ allowed-tools: Read, Write, Edit, Bash(supabase:*), Bash(psql:*), Bash(npx:*), Grep
26
+ version: 1.0.0
27
+ license: MIT
28
+ author: Jeremy Longshore <jeremy@intentsolutions.io>
29
+ tags:
30
+ - saas
31
+ - supabase
32
+ - governance
33
+ - security
34
+ - rls
35
+ - naming-conventions
36
+ - cost-management
37
+ compatibility: Designed for Claude Code, also compatible with Codex and OpenClaw
38
+ ---
39
+ # Supabase Policy Guardrails
166
40
 
167
- jobs:
168
- policy:
169
- runs-on: ubuntu-latest
170
- steps:
171
- - uses: actions/checkout@v4
41
+ ## Overview
172
42
 
173
- - name: Check for hardcoded secrets
174
- run: |
175
- if grep -rE "sk_(live|test)_[a-zA-Z0-9]{24,}" --include="*.ts" --include="*.js" .; then
176
- echo "ERROR: Hardcoded Supabase keys found"
177
- exit 1
178
- fi
43
+ Organizational governance for Supabase at scale: a **shared RLS policy library** (reusable templates for common access patterns), **naming conventions** (tables, columns, functions, policies), **migration review process** (CI checks ensuring RLS, preventing destructive operations, enforcing naming), **cost alert configuration** (billing thresholds and usage monitoring), and **security audit scripts** (scanning for exposed keys, missing RLS, overly permissive policies). All patterns use real `createClient` from `@supabase/supabase-js` and Supabase CLI commands.
179
44
 
180
- - name: Validate configuration schema
181
- run: |
182
- npx ajv validate -s supabase-config.schema.json -d config/supabase/*.json
45
+ ## Prerequisites
183
46
 
184
- - name: Run ESLint Supabase rules
185
- run: npx eslint --plugin supabase --rule 'supabase/no-hardcoded-keys: error' src/
47
+ - Supabase project with `supabase` CLI installed and linked
48
+ - `@supabase/supabase-js` v2+ installed
49
+ - CI/CD pipeline (GitHub Actions recommended)
50
+ - Database access via `psql` or Supabase SQL Editor
51
+ - Pro plan recommended for cost alerts and usage API
52
+
53
+ ## Step 1 — Shared RLS Policy Library and Naming Conventions
54
+
55
+ ### RLS Policy Templates
56
+
57
+ Create reusable RLS policy templates that teams apply to new tables. This prevents each developer from writing ad-hoc policies and ensures consistent access control.
58
+
59
+ ```sql
60
+ -- supabase/migrations/00000000000000_rls_policy_library.sql
61
+ -- Shared RLS policy library — apply these templates to new tables
62
+
63
+ -- ============================================================
64
+ -- Template 1: Owner-only access (user owns the row)
65
+ -- Usage: tables with a user_id column (todos, profiles, settings)
66
+ -- ============================================================
67
+ CREATE OR REPLACE FUNCTION public.rls_owner_only(table_name text, user_column text DEFAULT 'user_id')
68
+ RETURNS void AS $$
69
+ BEGIN
70
+ EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', table_name);
71
+
72
+ EXECUTE format(
73
+ 'CREATE POLICY "owner_select" ON public.%I FOR SELECT USING (%I = auth.uid())',
74
+ table_name, user_column
75
+ );
76
+ EXECUTE format(
77
+ 'CREATE POLICY "owner_insert" ON public.%I FOR INSERT WITH CHECK (%I = auth.uid())',
78
+ table_name, user_column
79
+ );
80
+ EXECUTE format(
81
+ 'CREATE POLICY "owner_update" ON public.%I FOR UPDATE USING (%I = auth.uid())',
82
+ table_name, user_column
83
+ );
84
+ EXECUTE format(
85
+ 'CREATE POLICY "owner_delete" ON public.%I FOR DELETE USING (%I = auth.uid())',
86
+ table_name, user_column
87
+ );
88
+ END;
89
+ $$ LANGUAGE plpgsql;
90
+
91
+ -- ============================================================
92
+ -- Template 2: Organization-scoped access (user is member of org)
93
+ -- Usage: tables with org_id referencing org_members
94
+ -- ============================================================
95
+ CREATE OR REPLACE FUNCTION public.rls_org_scoped(
96
+ table_name text,
97
+ org_column text DEFAULT 'org_id',
98
+ allow_delete boolean DEFAULT false
99
+ )
100
+ RETURNS void AS $$
101
+ BEGIN
102
+ EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', table_name);
103
+
104
+ EXECUTE format(
105
+ 'CREATE POLICY "org_select" ON public.%I FOR SELECT USING (
106
+ %I IN (SELECT org_id FROM public.org_members WHERE user_id = auth.uid())
107
+ )', table_name, org_column
108
+ );
109
+ EXECUTE format(
110
+ 'CREATE POLICY "org_insert" ON public.%I FOR INSERT WITH CHECK (
111
+ %I IN (SELECT org_id FROM public.org_members WHERE user_id = auth.uid())
112
+ )', table_name, org_column
113
+ );
114
+ EXECUTE format(
115
+ 'CREATE POLICY "org_update" ON public.%I FOR UPDATE USING (
116
+ %I IN (SELECT org_id FROM public.org_members WHERE user_id = auth.uid() AND role IN (''admin'', ''editor''))
117
+ )', table_name, org_column
118
+ );
119
+
120
+ IF allow_delete THEN
121
+ EXECUTE format(
122
+ 'CREATE POLICY "org_delete" ON public.%I FOR DELETE USING (
123
+ %I IN (SELECT org_id FROM public.org_members WHERE user_id = auth.uid() AND role = ''admin'')
124
+ )', table_name, org_column
125
+ );
126
+ END IF;
127
+ END;
128
+ $$ LANGUAGE plpgsql;
129
+
130
+ -- ============================================================
131
+ -- Template 3: Public read, authenticated write
132
+ -- Usage: blog posts, product listings, public content
133
+ -- ============================================================
134
+ CREATE OR REPLACE FUNCTION public.rls_public_read_auth_write(
135
+ table_name text,
136
+ owner_column text DEFAULT 'created_by'
137
+ )
138
+ RETURNS void AS $$
139
+ BEGIN
140
+ EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', table_name);
141
+
142
+ EXECUTE format(
143
+ 'CREATE POLICY "public_select" ON public.%I FOR SELECT USING (true)',
144
+ table_name
145
+ );
146
+ EXECUTE format(
147
+ 'CREATE POLICY "auth_insert" ON public.%I FOR INSERT WITH CHECK (auth.uid() IS NOT NULL)',
148
+ table_name
149
+ );
150
+ EXECUTE format(
151
+ 'CREATE POLICY "owner_update" ON public.%I FOR UPDATE USING (%I = auth.uid())',
152
+ table_name, owner_column
153
+ );
154
+ EXECUTE format(
155
+ 'CREATE POLICY "owner_delete" ON public.%I FOR DELETE USING (%I = auth.uid())',
156
+ table_name, owner_column
157
+ );
158
+ END;
159
+ $$ LANGUAGE plpgsql;
160
+
161
+ -- Apply templates to tables:
162
+ -- SELECT public.rls_owner_only('todos');
163
+ -- SELECT public.rls_org_scoped('projects', 'org_id', true);
164
+ -- SELECT public.rls_public_read_auth_write('blog_posts', 'author_id');
186
165
  ```
187
166
 
188
- ## Runtime Guardrails
189
-
190
- ```typescript
191
- // Prevent dangerous operations in production
192
- const BLOCKED_IN_PROD = ['deleteAll', 'resetData', 'migrateDown'];
193
-
194
- function guardSupabaseOperation(operation: string): void {
195
- const isProd = process.env.NODE_ENV === 'production';
196
-
197
- if (isProd && BLOCKED_IN_PROD.includes(operation)) {
198
- throw new Error(`Operation '${operation}' blocked in production`);
199
- }
200
- }
201
-
202
- // Rate limit protection
203
- function guardRateLimits(requestsInWindow: number): void {
204
- const limit = parseInt(process.env.SUPABASE_RATE_LIMIT || '100');
205
-
206
- if (requestsInWindow > limit * 0.9) {
207
- console.warn('Approaching Supabase rate limit');
208
- }
209
-
210
- if (requestsInWindow >= limit) {
211
- throw new Error('Supabase rate limit exceeded - request blocked');
212
- }
213
- }
167
+ ### Naming Conventions
168
+
169
+ ```sql
170
+ -- supabase/migrations/00000000000001_naming_convention_check.sql
171
+ -- Validation function that checks naming conventions at migration time
172
+
173
+ CREATE OR REPLACE FUNCTION public.validate_naming_conventions()
174
+ RETURNS TABLE(issue text, object_name text, suggestion text) AS $$
175
+ BEGIN
176
+ -- Tables must be snake_case, plural
177
+ RETURN QUERY
178
+ SELECT
179
+ 'Table name should be plural snake_case'::text,
180
+ t.tablename::text,
181
+ regexp_replace(t.tablename, '([A-Z])', '_\1', 'g')::text
182
+ FROM pg_tables t
183
+ WHERE t.schemaname = 'public'
184
+ AND (
185
+ t.tablename ~ '[A-Z]' -- contains uppercase
186
+ OR t.tablename ~ '-' -- contains hyphens
187
+ OR t.tablename !~ 's$' -- not plural (heuristic)
188
+ )
189
+ AND t.tablename NOT LIKE '\_%'; -- skip internal tables
190
+
191
+ -- Columns must be snake_case
192
+ RETURN QUERY
193
+ SELECT
194
+ 'Column name should be snake_case'::text,
195
+ (c.table_name || '.' || c.column_name)::text,
196
+ regexp_replace(c.column_name, '([A-Z])', '_\1', 'g')::text
197
+ FROM information_schema.columns c
198
+ WHERE c.table_schema = 'public'
199
+ AND (c.column_name ~ '[A-Z]' OR c.column_name ~ '-');
200
+
201
+ -- Foreign key columns should end with _id
202
+ RETURN QUERY
203
+ SELECT
204
+ 'Foreign key column should end with _id'::text,
205
+ (tc.table_name || '.' || kcu.column_name)::text,
206
+ (kcu.column_name || '_id')::text
207
+ FROM information_schema.table_constraints tc
208
+ JOIN information_schema.key_column_usage kcu
209
+ ON tc.constraint_name = kcu.constraint_name
210
+ WHERE tc.constraint_type = 'FOREIGN KEY'
211
+ AND tc.table_schema = 'public'
212
+ AND kcu.column_name NOT LIKE '%_id';
213
+
214
+ -- Boolean columns should start with is_ or has_
215
+ RETURN QUERY
216
+ SELECT
217
+ 'Boolean column should start with is_ or has_'::text,
218
+ (c.table_name || '.' || c.column_name)::text,
219
+ ('is_' || c.column_name)::text
220
+ FROM information_schema.columns c
221
+ WHERE c.table_schema = 'public'
222
+ AND c.data_type = 'boolean'
223
+ AND c.column_name NOT LIKE 'is_%'
224
+ AND c.column_name NOT LIKE 'has_%';
225
+ END;
226
+ $$ LANGUAGE plpgsql;
227
+
228
+ -- Run: SELECT * FROM public.validate_naming_conventions();
214
229
  ```
215
230
 
216
- ## Instructions
217
-
218
- ### Step 1: Create ESLint Rules
219
- Implement custom lint rules for Supabase patterns.
231
+ ### Naming Convention Reference
220
232
 
221
- ### Step 2: Configure Pre-Commit Hooks
222
- Set up hooks to catch issues before commit.
233
+ | Object | Convention | Example |
234
+ |--------|-----------|---------|
235
+ | Tables | Plural snake_case | `user_profiles`, `order_items` |
236
+ | Columns | snake_case | `created_at`, `full_name` |
237
+ | Foreign keys | `{referenced_table_singular}_id` | `user_id`, `order_id` |
238
+ | Booleans | `is_` or `has_` prefix | `is_active`, `has_verified_email` |
239
+ | Timestamps | `_at` suffix | `created_at`, `updated_at`, `deleted_at` |
240
+ | RLS policies | `{scope}_{operation}` | `owner_select`, `org_insert` |
241
+ | Functions | `verb_noun` | `create_user`, `get_dashboard_metrics` |
242
+ | Indexes | `idx_{table}_{columns}` | `idx_orders_user_id_created_at` |
243
+ | Migrations | `{timestamp}_{verb}_{description}` | `20250322000000_create_orders_table.sql` |
223
244
 
224
- ### Step 3: Add CI Policy Checks
225
- Implement policy-as-code in CI pipeline.
245
+ ## Step 2 Migration Review Process with CI Checks
226
246
 
227
- ### Step 4: Enable Runtime Guardrails
228
- Add production safeguards for dangerous operations.
247
+ See [CI checks, cost alerts, and security audits](references/ci-cost-security.md) for GitHub Actions migration guardrails (RLS enforcement, naming checks, destructive operation blocks), pre-commit hooks, cost monitoring with Slack alerts, security audit scripts, and scheduled Edge Function audits.
229
248
 
230
249
  ## Output
231
- - ESLint plugin with Supabase rules
232
- - Pre-commit hooks blocking secrets
233
- - CI policy checks passing
234
- - Runtime guardrails active
250
+
251
+ - Shared RLS policy library with owner-only, org-scoped, and public-read templates
252
+ - Naming convention validation function checking tables, columns, FKs, and booleans
253
+ - CI pipeline enforcing RLS, naming, and destructive operation controls
254
+ - Pre-commit hook blocking hardcoded secrets and tables without RLS
255
+ - Cost monitoring script with configurable thresholds and Slack alerting
256
+ - Security audit script detecting missing RLS, permissive policies, and missing indexes
257
+ - Scheduled Edge Function for continuous security monitoring
235
258
 
236
259
  ## Error Handling
260
+
237
261
  | Issue | Cause | Solution |
238
262
  |-------|-------|----------|
239
- | ESLint rule not firing | Wrong config | Check plugin registration |
240
- | Pre-commit skipped | --no-verify | Enforce in CI |
241
- | Policy false positive | Regex too broad | Narrow pattern match |
242
- | Guardrail triggered | Actual issue | Fix or whitelist |
263
+ | CI RLS check fails on new table | Migration missing `ENABLE ROW LEVEL SECURITY` | Add `ALTER TABLE` after `CREATE TABLE` in same migration |
264
+ | Naming convention false positive | Table is intentionally singular (e.g., `config`) | Add to exclusion list in validation function |
265
+ | Cost alert not firing | Missing `SUPABASE_ACCESS_TOKEN` | Generate token at supabase.com/dashboard/account/tokens |
266
+ | Security audit times out | Too many tables to scan | Run audit on specific schemas or paginate results |
267
+ | Pre-commit blocks legitimate JWT in test | Test fixture contains JWT-like string | Add test file path to exclusion pattern |
268
+ | RLS template function not found | Migration not applied | Run `supabase db reset` or apply migration manually |
243
269
 
244
270
  ## Examples
245
271
 
246
- ### Quick ESLint Check
247
- ```bash
248
- npx eslint --plugin supabase --rule 'supabase/no-hardcoded-keys: error' src/
249
- ```
272
+ See [CI, cost, and security reference](references/ci-cost-security.md) for full examples including applying RLS templates, running security audits, and checking naming conventions.
250
273
 
251
274
  ## Resources
252
- - [ESLint Plugin Development](https://eslint.org/docs/latest/extend/plugins)
253
- - [Pre-commit Framework](https://pre-commit.com/)
254
- - [Open Policy Agent](https://www.openpolicyagent.org/)
275
+
276
+ - [Supabase Row Level Security](https://supabase.com/docs/guides/database/postgres/row-level-security)
277
+ - [Supabase CLI Migrations](https://supabase.com/docs/guides/cli/managing-environments)
278
+ - [Supabase Management API](https://supabase.com/docs/reference/api/introduction)
279
+ - [Supabase Pricing](https://supabase.com/pricing)
280
+ - [PostgreSQL Naming Conventions](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS)
255
281
 
256
282
  ## Next Steps
257
- For architecture blueprints, see `supabase-architecture-variants`.
283
+
284
+ For architecture patterns across different app types, see `supabase-architecture-variants`.