@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.
- package/LICENSE +1 -1
- package/README.md +73 -47
- package/package.json +4 -4
- package/skills/supabase-advanced-troubleshooting/SKILL.md +404 -200
- package/skills/supabase-advanced-troubleshooting/references/errors.md +11 -0
- package/skills/supabase-advanced-troubleshooting/references/evidence-collection-framework.md +34 -0
- package/skills/supabase-advanced-troubleshooting/references/examples.md +11 -0
- package/skills/supabase-advanced-troubleshooting/references/rls-edge-functions-realtime.md +363 -0
- package/skills/supabase-advanced-troubleshooting/references/systematic-isolation.md +56 -0
- package/skills/supabase-advanced-troubleshooting/references/timing-analysis.md +35 -0
- package/skills/supabase-architecture-variants/SKILL.md +395 -216
- package/skills/supabase-architecture-variants/references/errors.md +11 -0
- package/skills/supabase-architecture-variants/references/examples.md +12 -0
- package/skills/supabase-architecture-variants/references/serverless-and-multi-tenant.md +251 -0
- package/skills/supabase-architecture-variants/references/variant-a-monolith-(simple).md +44 -0
- package/skills/supabase-architecture-variants/references/variant-b-service-layer-(moderate).md +72 -0
- package/skills/supabase-architecture-variants/references/variant-c-microservice-(complex).md +81 -0
- package/skills/supabase-auth-storage-realtime-core/SKILL.md +471 -37
- package/skills/supabase-ci-integration/SKILL.md +315 -67
- package/skills/supabase-ci-integration/references/errors.md +10 -0
- package/skills/supabase-ci-integration/references/examples.md +36 -0
- package/skills/supabase-ci-integration/references/implementation.md +54 -0
- package/skills/supabase-common-errors/SKILL.md +320 -62
- package/skills/supabase-common-errors/references/errors.md +53 -0
- package/skills/supabase-common-errors/references/examples.md +23 -0
- package/skills/supabase-cost-tuning/SKILL.md +365 -131
- package/skills/supabase-cost-tuning/references/cost-estimation.md +34 -0
- package/skills/supabase-cost-tuning/references/cost-reduction-strategies.md +40 -0
- package/skills/supabase-cost-tuning/references/errors.md +11 -0
- package/skills/supabase-cost-tuning/references/examples.md +15 -0
- package/skills/supabase-data-handling/SKILL.md +378 -145
- package/skills/supabase-data-handling/references/errors.md +11 -0
- package/skills/supabase-data-handling/references/examples.md +27 -0
- package/skills/supabase-data-handling/references/implementation.md +223 -0
- package/skills/supabase-data-handling/references/retention-and-backup.md +221 -0
- package/skills/supabase-debug-bundle/SKILL.md +267 -73
- package/skills/supabase-debug-bundle/references/errors.md +12 -0
- package/skills/supabase-debug-bundle/references/examples.md +24 -0
- package/skills/supabase-debug-bundle/references/implementation.md +54 -0
- package/skills/supabase-deploy-integration/SKILL.md +258 -147
- package/skills/supabase-deploy-integration/references/errors.md +11 -0
- package/skills/supabase-deploy-integration/references/examples.md +21 -0
- package/skills/supabase-deploy-integration/references/google-cloud-run.md +36 -0
- package/skills/supabase-deploy-integration/references/vercel-deployment.md +35 -0
- package/skills/supabase-enterprise-rbac/SKILL.md +327 -160
- package/skills/supabase-enterprise-rbac/references/api-scoping-and-enforcement.md +255 -0
- package/skills/supabase-enterprise-rbac/references/errors.md +11 -0
- package/skills/supabase-enterprise-rbac/references/examples.md +12 -0
- package/skills/supabase-enterprise-rbac/references/role-implementation.md +33 -0
- package/skills/supabase-enterprise-rbac/references/sso-integration.md +35 -0
- package/skills/supabase-hello-world/SKILL.md +160 -54
- package/skills/supabase-incident-runbook/SKILL.md +453 -131
- package/skills/supabase-incident-runbook/references/errors.md +11 -0
- package/skills/supabase-incident-runbook/references/examples.md +10 -0
- package/skills/supabase-incident-runbook/references/immediate-actions-by-error-type.md +41 -0
- package/skills/supabase-install-auth/SKILL.md +186 -50
- package/skills/supabase-install-auth/references/examples.md +102 -0
- package/skills/supabase-known-pitfalls/SKILL.md +411 -241
- package/skills/supabase-known-pitfalls/references/errors.md +11 -0
- package/skills/supabase-known-pitfalls/references/examples.md +12 -0
- package/skills/supabase-load-scale/SKILL.md +346 -217
- package/skills/supabase-load-scale/references/capacity-planning.md +47 -0
- package/skills/supabase-load-scale/references/errors.md +11 -0
- package/skills/supabase-load-scale/references/examples.md +26 -0
- package/skills/supabase-load-scale/references/load-testing-with-k6.md +59 -0
- package/skills/supabase-load-scale/references/scaling-patterns.md +65 -0
- package/skills/supabase-load-scale/references/table-partitioning.md +263 -0
- package/skills/supabase-local-dev-loop/SKILL.md +272 -73
- package/skills/supabase-local-dev-loop/references/errors.md +11 -0
- package/skills/supabase-local-dev-loop/references/examples.md +21 -0
- package/skills/supabase-local-dev-loop/references/implementation.md +60 -0
- package/skills/supabase-migration-deep-dive/SKILL.md +338 -177
- package/skills/supabase-migration-deep-dive/references/backfill-versioning-rollback.md +258 -0
- package/skills/supabase-migration-deep-dive/references/errors.md +11 -0
- package/skills/supabase-migration-deep-dive/references/examples.md +12 -0
- package/skills/supabase-migration-deep-dive/references/implementation-plan.md +80 -0
- package/skills/supabase-migration-deep-dive/references/pre-migration-assessment.md +39 -0
- package/skills/supabase-multi-env-setup/SKILL.md +393 -152
- package/skills/supabase-multi-env-setup/references/configuration-structure.md +59 -0
- package/skills/supabase-multi-env-setup/references/errors.md +11 -0
- package/skills/supabase-multi-env-setup/references/examples.md +11 -0
- package/skills/supabase-observability/SKILL.md +318 -196
- package/skills/supabase-observability/references/alert-configuration.md +40 -0
- package/skills/supabase-observability/references/errors.md +11 -0
- package/skills/supabase-observability/references/examples.md +13 -0
- package/skills/supabase-observability/references/metrics-collection.md +65 -0
- package/skills/supabase-performance-tuning/SKILL.md +304 -160
- package/skills/supabase-performance-tuning/references/caching-strategy.md +49 -0
- package/skills/supabase-performance-tuning/references/errors.md +11 -0
- package/skills/supabase-performance-tuning/references/examples.md +13 -0
- package/skills/supabase-policy-guardrails/SKILL.md +248 -221
- package/skills/supabase-policy-guardrails/references/ci-cost-security.md +484 -0
- package/skills/supabase-policy-guardrails/references/errors.md +11 -0
- package/skills/supabase-policy-guardrails/references/eslint-rules.md +46 -0
- package/skills/supabase-policy-guardrails/references/examples.md +10 -0
- package/skills/supabase-prod-checklist/SKILL.md +474 -84
- package/skills/supabase-prod-checklist/references/errors.md +63 -0
- package/skills/supabase-prod-checklist/references/examples.md +153 -0
- package/skills/supabase-prod-checklist/references/implementation.md +113 -0
- package/skills/supabase-rate-limits/SKILL.md +311 -98
- package/skills/supabase-rate-limits/references/errors.md +11 -0
- package/skills/supabase-rate-limits/references/examples.md +46 -0
- package/skills/supabase-rate-limits/references/implementation.md +66 -0
- package/skills/supabase-reference-architecture/SKILL.md +249 -182
- package/skills/supabase-reference-architecture/references/errors.md +29 -0
- package/skills/supabase-reference-architecture/references/examples.md +116 -0
- package/skills/supabase-reference-architecture/references/key-components.md +244 -0
- package/skills/supabase-reference-architecture/references/project-structure.md +109 -0
- package/skills/supabase-reliability-patterns/SKILL.md +229 -234
- package/skills/supabase-reliability-patterns/references/circuit-breaker.md +36 -0
- package/skills/supabase-reliability-patterns/references/dead-letter-queue.md +48 -0
- package/skills/supabase-reliability-patterns/references/errors.md +11 -0
- package/skills/supabase-reliability-patterns/references/examples.md +11 -0
- package/skills/supabase-reliability-patterns/references/idempotency-keys.md +36 -0
- package/skills/supabase-reliability-patterns/references/offline-degradation-health-dualwrite.md +489 -0
- package/skills/supabase-schema-from-requirements/SKILL.md +373 -34
- package/skills/supabase-sdk-patterns/SKILL.md +388 -99
- package/skills/supabase-sdk-patterns/references/errors.md +11 -0
- package/skills/supabase-sdk-patterns/references/examples.md +45 -0
- package/skills/supabase-sdk-patterns/references/implementation.md +67 -0
- package/skills/supabase-security-basics/SKILL.md +282 -102
- package/skills/supabase-security-basics/references/errors.md +10 -0
- package/skills/supabase-security-basics/references/examples.md +70 -0
- package/skills/supabase-security-basics/references/implementation.md +39 -0
- package/skills/supabase-upgrade-migration/SKILL.md +248 -66
- package/skills/supabase-upgrade-migration/references/errors.md +10 -0
- package/skills/supabase-upgrade-migration/references/examples.md +51 -0
- package/skills/supabase-upgrade-migration/references/implementation.md +29 -0
- package/skills/supabase-webhooks-events/SKILL.md +412 -138
- package/skills/supabase-webhooks-events/references/errors.md +55 -0
- package/skills/supabase-webhooks-events/references/event-handler-pattern.md +106 -0
- package/skills/supabase-webhooks-events/references/examples.md +133 -0
- 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
|
-
|
|
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
|
-
|
|
111
|
-
```markdown
|
|
112
|
-
# ADR-001: Supabase Client Initialization
|
|
6
|
+
library with reusable templates, table and column naming conventions,
|
|
113
7
|
|
|
114
|
-
|
|
115
|
-
Accepted
|
|
8
|
+
migration review process with CI checks, cost alert thresholds,
|
|
116
9
|
|
|
117
|
-
|
|
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
|
-
|
|
121
|
-
We will use the singleton pattern with lazy initialization.
|
|
12
|
+
Use when establishing Supabase standards across teams, creating RLS
|
|
122
13
|
|
|
123
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
20
|
+
"supabase naming convention", "supabase migration review",
|
|
160
21
|
|
|
161
|
-
|
|
162
|
-
# .github/workflows/supabase-policy.yml
|
|
163
|
-
name: Supabase Policy Check
|
|
22
|
+
"supabase cost alert", "supabase security audit", "supabase RLS template".
|
|
164
23
|
|
|
165
|
-
|
|
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
|
-
|
|
168
|
-
policy:
|
|
169
|
-
runs-on: ubuntu-latest
|
|
170
|
-
steps:
|
|
171
|
-
- uses: actions/checkout@v4
|
|
41
|
+
## Overview
|
|
172
42
|
|
|
173
|
-
|
|
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
|
-
|
|
181
|
-
run: |
|
|
182
|
-
npx ajv validate -s supabase-config.schema.json -d config/supabase/*.json
|
|
45
|
+
## Prerequisites
|
|
183
46
|
|
|
184
|
-
|
|
185
|
-
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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
|
-
|
|
217
|
-
|
|
218
|
-
### Step 1: Create ESLint Rules
|
|
219
|
-
Implement custom lint rules for Supabase patterns.
|
|
231
|
+
### Naming Convention Reference
|
|
220
232
|
|
|
221
|
-
|
|
222
|
-
|
|
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
|
-
|
|
225
|
-
Implement policy-as-code in CI pipeline.
|
|
245
|
+
## Step 2 — Migration Review Process with CI Checks
|
|
226
246
|
|
|
227
|
-
|
|
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
|
-
|
|
232
|
-
-
|
|
233
|
-
-
|
|
234
|
-
-
|
|
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
|
-
|
|
|
240
|
-
|
|
|
241
|
-
|
|
|
242
|
-
|
|
|
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
|
-
|
|
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
|
-
|
|
253
|
-
- [
|
|
254
|
-
- [
|
|
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
|
-
|
|
283
|
+
|
|
284
|
+
For architecture patterns across different app types, see `supabase-architecture-variants`.
|