@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
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Data Handling Reference
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Handle sensitive data correctly when integrating with Supabase.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- Understanding of GDPR/CCPA requirements
|
|
10
|
+
- Supabase SDK with data export capabilities
|
|
11
|
+
- Database for audit logging
|
|
12
|
+
- Scheduled job infrastructure for cleanup
|
|
13
|
+
|
|
14
|
+
## Data Classification
|
|
15
|
+
|
|
16
|
+
| Category | Examples | Handling |
|
|
17
|
+
|----------|----------|----------|
|
|
18
|
+
| PII | Email, name, phone | Encrypt, minimize |
|
|
19
|
+
| Sensitive | API keys, tokens | Never log, rotate |
|
|
20
|
+
| Business | Usage metrics | Aggregate when possible |
|
|
21
|
+
| Public | Product names | Standard handling |
|
|
22
|
+
|
|
23
|
+
## PII Detection
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
const PII_PATTERNS = [
|
|
27
|
+
{ type: 'email', regex: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g },
|
|
28
|
+
{ type: 'phone', regex: /\d{3}[-.]?\d{3}[-.]?\d{4}/g },
|
|
29
|
+
{ type: 'ssn', regex: /\d{3}-\d{2}-\d{4}/g },
|
|
30
|
+
{ type: 'credit_card', regex: /\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}/g },
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
function detectPII(text: string): { type: string; match: string }[] {
|
|
34
|
+
const findings: { type: string; match: string }[] = [];
|
|
35
|
+
|
|
36
|
+
for (const pattern of PII_PATTERNS) {
|
|
37
|
+
const matches = text.matchAll(pattern.regex);
|
|
38
|
+
for (const match of matches) {
|
|
39
|
+
findings.push({ type: pattern.type, match: match[0] });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return findings;
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Data Redaction
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
function redactPII(data: Record<string, any>): Record<string, any> {
|
|
51
|
+
const sensitiveFields = ['email', 'phone', 'ssn', 'password', 'apiKey'];
|
|
52
|
+
const redacted = { ...data };
|
|
53
|
+
|
|
54
|
+
for (const field of sensitiveFields) {
|
|
55
|
+
if (redacted[field]) {
|
|
56
|
+
redacted[field] = '[REDACTED]';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return redacted;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Use in logging
|
|
64
|
+
console.log('Supabase request:', redactPII(requestData));
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Data Retention Policy
|
|
68
|
+
|
|
69
|
+
### Retention Periods
|
|
70
|
+
|
|
71
|
+
| Data Type | Retention | Reason |
|
|
72
|
+
|-----------|-----------|--------|
|
|
73
|
+
| API logs | 30 days | Debugging |
|
|
74
|
+
| Error logs | 90 days | Root cause analysis |
|
|
75
|
+
| Audit logs | 7 years | Compliance |
|
|
76
|
+
| PII | Until deletion request | GDPR/CCPA |
|
|
77
|
+
|
|
78
|
+
### Automatic Cleanup
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
async function cleanupSupabaseData(retentionDays: number): Promise<void> {
|
|
82
|
+
const cutoff = new Date();
|
|
83
|
+
cutoff.setDate(cutoff.getDate() - retentionDays);
|
|
84
|
+
|
|
85
|
+
await db.supabaseLogs.deleteMany({
|
|
86
|
+
createdAt: { $lt: cutoff },
|
|
87
|
+
type: { $nin: ['audit', 'compliance'] },
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Schedule daily cleanup
|
|
92
|
+
cron.schedule('0 3 * * *', () => cleanupSupabaseData(30));
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## GDPR/CCPA Compliance
|
|
96
|
+
|
|
97
|
+
### Data Subject Access Request (DSAR)
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
async function exportUserData(userId: string): Promise<DataExport> {
|
|
101
|
+
const supabaseData = await supabaseClient.getUserData(userId);
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
source: 'Supabase',
|
|
105
|
+
exportedAt: new Date().toISOString(),
|
|
106
|
+
data: {
|
|
107
|
+
profile: supabaseData.profile,
|
|
108
|
+
activities: supabaseData.activities,
|
|
109
|
+
// Include all user-related data
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Right to Deletion
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
async function deleteUserData(userId: string): Promise<DeletionResult> {
|
|
119
|
+
// 1. Delete from Supabase
|
|
120
|
+
await supabaseClient.deleteUser(userId);
|
|
121
|
+
|
|
122
|
+
// 2. Delete local copies
|
|
123
|
+
await db.supabaseUserCache.deleteMany({ userId });
|
|
124
|
+
|
|
125
|
+
// 3. Audit log (required to keep)
|
|
126
|
+
await auditLog.record({
|
|
127
|
+
action: 'GDPR_DELETION',
|
|
128
|
+
userId,
|
|
129
|
+
service: 'supabase',
|
|
130
|
+
timestamp: new Date(),
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return { success: true, deletedAt: new Date() };
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Data Minimization
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// Only request needed fields
|
|
141
|
+
const user = await supabaseClient.getUser(userId, {
|
|
142
|
+
fields: ['id', 'name'], // Not email, phone, address
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Don't store unnecessary data
|
|
146
|
+
const cacheData = {
|
|
147
|
+
id: user.id,
|
|
148
|
+
name: user.name,
|
|
149
|
+
// Omit sensitive fields
|
|
150
|
+
};
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Instructions
|
|
154
|
+
|
|
155
|
+
### Step 1: Classify Data
|
|
156
|
+
|
|
157
|
+
Categorize all Supabase data by sensitivity level.
|
|
158
|
+
|
|
159
|
+
### Step 2: Implement PII Detection
|
|
160
|
+
|
|
161
|
+
Add regex patterns to detect sensitive data in logs.
|
|
162
|
+
|
|
163
|
+
### Step 3: Configure Redaction
|
|
164
|
+
|
|
165
|
+
Apply redaction to sensitive fields before logging.
|
|
166
|
+
|
|
167
|
+
### Step 4: Set Up Retention
|
|
168
|
+
|
|
169
|
+
Configure automatic cleanup with appropriate retention periods.
|
|
170
|
+
|
|
171
|
+
## Output
|
|
172
|
+
|
|
173
|
+
- Data classification documented
|
|
174
|
+
- PII detection implemented
|
|
175
|
+
- Redaction in logging active
|
|
176
|
+
- Retention policy enforced
|
|
177
|
+
|
|
178
|
+
## Error Handling
|
|
179
|
+
|
|
180
|
+
| Issue | Cause | Solution |
|
|
181
|
+
|-------|-------|----------|
|
|
182
|
+
| PII in logs | Missing redaction | Wrap logging with redact |
|
|
183
|
+
| Deletion failed | Data locked | Check dependencies |
|
|
184
|
+
| Export incomplete | Timeout | Increase batch size |
|
|
185
|
+
| Audit gap | Missing entries | Review log pipeline |
|
|
186
|
+
|
|
187
|
+
## Examples
|
|
188
|
+
|
|
189
|
+
### Quick PII Scan
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
const findings = detectPII(JSON.stringify(userData));
|
|
193
|
+
if (findings.length > 0) {
|
|
194
|
+
console.warn(`PII detected: ${findings.map(f => f.type).join(', ')}`);
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Redact Before Logging
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
const safeData = redactPII(apiResponse);
|
|
202
|
+
logger.info('Supabase response:', safeData);
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### GDPR Data Export
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
const userExport = await exportUserData('user-123');
|
|
209
|
+
await sendToUser(userExport);
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Resources
|
|
213
|
+
|
|
214
|
+
- GDPR Developer Guide
|
|
215
|
+
- [CCPA Compliance Guide](https://oag.ca.gov/privacy/ccpa)
|
|
216
|
+
- Supabase Privacy Guide
|
|
217
|
+
|
|
218
|
+
## Next Steps
|
|
219
|
+
|
|
220
|
+
For enterprise access control, see `supabase-enterprise-rbac`.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
*[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# Retention Policies and Backup/Restore
|
|
2
|
+
|
|
3
|
+
Automate data retention with `pg_cron` scheduled jobs and configure backup/restore using Supabase's point-in-time recovery.
|
|
4
|
+
|
|
5
|
+
**Automated retention policies with pg_cron:**
|
|
6
|
+
|
|
7
|
+
```sql
|
|
8
|
+
-- Enable pg_cron extension (Supabase Pro plan)
|
|
9
|
+
CREATE EXTENSION IF NOT EXISTS pg_cron;
|
|
10
|
+
|
|
11
|
+
-- Retention policy: delete API logs older than 30 days
|
|
12
|
+
SELECT cron.schedule(
|
|
13
|
+
'cleanup-api-logs',
|
|
14
|
+
'0 3 * * *', -- Run at 3 AM UTC daily
|
|
15
|
+
$$DELETE FROM public.api_logs
|
|
16
|
+
WHERE created_at < now() - interval '30 days'$$
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
-- Retention policy: delete error logs older than 90 days
|
|
20
|
+
SELECT cron.schedule(
|
|
21
|
+
'cleanup-error-logs',
|
|
22
|
+
'0 4 * * *', -- Run at 4 AM UTC daily
|
|
23
|
+
$$DELETE FROM public.error_logs
|
|
24
|
+
WHERE created_at < now() - interval '90 days'$$
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
-- Retention policy: anonymize inactive user profiles after 2 years
|
|
28
|
+
SELECT cron.schedule(
|
|
29
|
+
'anonymize-inactive-users',
|
|
30
|
+
'0 5 * * 0', -- Run weekly on Sunday at 5 AM UTC
|
|
31
|
+
$$UPDATE public.profiles
|
|
32
|
+
SET email = 'anonymized-' || id || '@deleted.local',
|
|
33
|
+
full_name = 'Deleted User',
|
|
34
|
+
phone = NULL,
|
|
35
|
+
avatar_url = NULL,
|
|
36
|
+
anonymized_at = now()
|
|
37
|
+
WHERE last_active_at < now() - interval '2 years'
|
|
38
|
+
AND anonymized_at IS NULL$$
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
-- View scheduled jobs
|
|
42
|
+
SELECT jobid, schedule, command, nodename
|
|
43
|
+
FROM cron.job
|
|
44
|
+
ORDER BY jobid;
|
|
45
|
+
|
|
46
|
+
-- Monitor job execution history
|
|
47
|
+
SELECT jobid, start_time, end_time, status, return_message
|
|
48
|
+
FROM cron.job_run_details
|
|
49
|
+
ORDER BY start_time DESC
|
|
50
|
+
LIMIT 20;
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Retention tracking from the SDK:**
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { createClient } from '@supabase/supabase-js';
|
|
57
|
+
|
|
58
|
+
const supabase = createClient(
|
|
59
|
+
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
|
60
|
+
process.env.SUPABASE_SERVICE_ROLE_KEY!,
|
|
61
|
+
{ auth: { autoRefreshToken: false, persistSession: false } }
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Get retention policy status
|
|
65
|
+
async function getRetentionStatus() {
|
|
66
|
+
const policies = [
|
|
67
|
+
{ table: 'api_logs', retentionDays: 30 },
|
|
68
|
+
{ table: 'error_logs', retentionDays: 90 },
|
|
69
|
+
{ table: 'audit_logs', retentionDays: null }, // Never delete
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
for (const policy of policies) {
|
|
73
|
+
const { count } = await supabase
|
|
74
|
+
.from(policy.table)
|
|
75
|
+
.select('*', { count: 'exact', head: true });
|
|
76
|
+
|
|
77
|
+
let expiredCount = 0;
|
|
78
|
+
if (policy.retentionDays) {
|
|
79
|
+
const cutoff = new Date();
|
|
80
|
+
cutoff.setDate(cutoff.getDate() - policy.retentionDays);
|
|
81
|
+
|
|
82
|
+
const { count: expired } = await supabase
|
|
83
|
+
.from(policy.table)
|
|
84
|
+
.select('*', { count: 'exact', head: true })
|
|
85
|
+
.lt('created_at', cutoff.toISOString());
|
|
86
|
+
|
|
87
|
+
expiredCount = expired ?? 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log(`${policy.table}: ${count} total, ${expiredCount} expired, retention=${policy.retentionDays ?? 'forever'}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Backup and restore:**
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Point-in-time recovery (PITR) — available on Pro plan
|
|
99
|
+
# Configured in Supabase Dashboard → Database → Backups
|
|
100
|
+
|
|
101
|
+
# Manual backup via pg_dump (for migration or offline backup)
|
|
102
|
+
pg_dump "postgres://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:5432/postgres" \
|
|
103
|
+
--format=custom \
|
|
104
|
+
--no-owner \
|
|
105
|
+
--no-privileges \
|
|
106
|
+
--file=backup-$(date +%Y%m%d).dump
|
|
107
|
+
|
|
108
|
+
# Restore to a different project (e.g., staging)
|
|
109
|
+
pg_restore \
|
|
110
|
+
--dbname="postgres://postgres.<staging-ref>:<password>@aws-0-<region>.pooler.supabase.com:5432/postgres" \
|
|
111
|
+
--no-owner \
|
|
112
|
+
--no-privileges \
|
|
113
|
+
--clean \
|
|
114
|
+
backup-20260322.dump
|
|
115
|
+
|
|
116
|
+
# Export specific tables as CSV for DSAR compliance
|
|
117
|
+
psql "postgres://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:5432/postgres" \
|
|
118
|
+
-c "\COPY (SELECT * FROM profiles WHERE id = 'user-uuid') TO 'user-export.csv' CSV HEADER"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Output
|
|
122
|
+
|
|
123
|
+
After completing this skill, you will have:
|
|
124
|
+
|
|
125
|
+
- **RLS tenant isolation** — row-level security policies ensuring users only access their own data
|
|
126
|
+
- **PII column registry** — documented and classified PII columns across all tables
|
|
127
|
+
- **PII scanner** — SDK-based pattern detection for emails, phones, SSNs, and IPs in text columns
|
|
128
|
+
- **User deletion pipeline** — complete `auth.admin.deleteUser()` flow with cascade table deletion, storage cleanup, and audit logging
|
|
129
|
+
- **Data export** — DSAR-compliant export of all user data from tables and storage
|
|
130
|
+
- **GDPR audit log** — immutable log of all deletion and export operations with legal basis
|
|
131
|
+
- **Automated retention** — `pg_cron` jobs for 30/90/730-day retention tiers
|
|
132
|
+
- **Backup/restore** — `pg_dump`/`pg_restore` commands and PITR configuration
|
|
133
|
+
|
|
134
|
+
## Error Handling
|
|
135
|
+
|
|
136
|
+
| Error | Cause | Solution |
|
|
137
|
+
|-------|-------|----------|
|
|
138
|
+
| `auth.admin.deleteUser()` returns 404 | User already deleted or wrong ID | Check `auth.users` table; may have been deleted by another process |
|
|
139
|
+
| `violates foreign key constraint` during deletion | Child rows reference user | Delete in cascade order (comments → orders → profiles) or use `ON DELETE CASCADE` |
|
|
140
|
+
| `permission denied for function cron.schedule` | `pg_cron` not enabled or wrong plan | Enable `pg_cron` extension; requires Supabase Pro plan |
|
|
141
|
+
| `pg_dump: connection refused` | Using wrong port or pooler URL | Use direct connection (port 5432), not pooler (port 6543) for `pg_dump` |
|
|
142
|
+
| `RLS policy blocks admin operations` | Service role key not used | Use `createClient` with `SUPABASE_SERVICE_ROLE_KEY` to bypass RLS |
|
|
143
|
+
| Audit log entries missing | Table has RLS blocking inserts | Use `SECURITY DEFINER` function or service role for audit writes |
|
|
144
|
+
| Retention job not running | `pg_cron` job disabled or errored | Check `cron.job_run_details` for error messages |
|
|
145
|
+
|
|
146
|
+
## Examples
|
|
147
|
+
|
|
148
|
+
**Example 1 — Handle a GDPR deletion request:**
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { createClient } from '@supabase/supabase-js';
|
|
152
|
+
|
|
153
|
+
const supabase = createClient(url, serviceRoleKey, {
|
|
154
|
+
auth: { autoRefreshToken: false, persistSession: false },
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// API endpoint for GDPR deletion
|
|
158
|
+
async function handleDeletionRequest(userId: string) {
|
|
159
|
+
// Verify the request is legitimate (e.g., authenticated user or admin)
|
|
160
|
+
const result = await deleteUserData(userId);
|
|
161
|
+
|
|
162
|
+
console.log(`User ${userId} deleted:`, {
|
|
163
|
+
tables: result.tablesProcessed.join(', '),
|
|
164
|
+
files: result.storageFilesDeleted,
|
|
165
|
+
auth: result.authDeleted,
|
|
166
|
+
auditId: result.auditLogId,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// GDPR requires completion within 30 days
|
|
170
|
+
return { status: 'completed', auditId: result.auditLogId };
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Example 2 — Quick PII audit:**
|
|
175
|
+
|
|
176
|
+
```sql
|
|
177
|
+
-- Count rows with email-like patterns in unexpected columns
|
|
178
|
+
SELECT 'profiles' AS table_name, 'bio' AS column_name,
|
|
179
|
+
count(*) AS rows_with_email
|
|
180
|
+
FROM public.profiles
|
|
181
|
+
WHERE bio ~ '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
|
|
182
|
+
UNION ALL
|
|
183
|
+
SELECT 'orders', 'notes',
|
|
184
|
+
count(*)
|
|
185
|
+
FROM public.orders
|
|
186
|
+
WHERE notes ~ '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}';
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Example 3 — Verify retention job execution:**
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
import { createClient } from '@supabase/supabase-js';
|
|
193
|
+
|
|
194
|
+
const supabase = createClient(url, serviceRoleKey, {
|
|
195
|
+
auth: { autoRefreshToken: false, persistSession: false },
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
async function checkRetentionJobs() {
|
|
199
|
+
const { data, error } = await supabase.rpc('get_cron_status');
|
|
200
|
+
if (error) throw error;
|
|
201
|
+
|
|
202
|
+
for (const job of data ?? []) {
|
|
203
|
+
console.log(`Job "${job.jobname}": last_run=${job.last_run}, status=${job.status}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Resources
|
|
209
|
+
|
|
210
|
+
- [Row Level Security — Supabase Docs](https://supabase.com/docs/guides/database/postgres/row-level-security)
|
|
211
|
+
- [Auth Admin deleteUser — Supabase Docs](https://supabase.com/docs/reference/javascript/auth-admin-deleteuser)
|
|
212
|
+
- [Database Backups — Supabase Docs](https://supabase.com/docs/guides/platform/backups)
|
|
213
|
+
- [pg_cron Extension — Supabase Docs](https://supabase.com/docs/guides/database/extensions/pg_cron)
|
|
214
|
+
- GDPR Developer Guide
|
|
215
|
+
- [CCPA Compliance Guide](https://oag.ca.gov/privacy/ccpa)
|
|
216
|
+
|
|
217
|
+
## Next Steps
|
|
218
|
+
|
|
219
|
+
- For enterprise role-based access control, see `supabase-enterprise-rbac`
|
|
220
|
+
- For security hardening and API key scoping, see `supabase-security-basics`
|
|
221
|
+
- For observability and audit trail monitoring, see `supabase-observability`
|