Back to PXL-829
PXL-829Documentation
NutriKit Supabase Backup System Documentation
For task: ๐พ Implement automated daily Supabase backup system
Overview
An automated daily backup system that exports all NutriKit Supabase database tables to GitHub, providing disaster recovery and data protection for production user data.
Architecture Diagram
DAILY CRON (3 AM UTC)
|
v
+------------------+ +-------------------+
| | | |
| Vercel Cron |------------->| /api/backup |
| (vercel.json) | trigger | (Next.js API) |
| | | |
+------------------+ +-------------------+
|
+---------------+---------------+
| |
v v
+------------------+ +------------------+
| | | |
| Supabase | | GitHub API |
| (Data Source) | | (Storage) |
| | | |
+------------------+ +------------------+
| |
| v
| +------------------+
| | nutrikit- |
+-------------------->| backups repo |
fetch all tables | (public) |
with pagination +------------------+
|
v
backups/
โโโ 2026-01-02/
โโโ users.json.gz
โโโ foods.json.gz
โโโ preferences.json.gz
โโโ days.json.gz
โโโ meals.json.gz
โโโ meal_items.json.gz
โโโ user_foods.json.gz
โโโ meal_presets.json.gz
Components
1. Vercel Cron Job
File: vercel.json
{
"crons": [
{
"path": "/api/backup",
"schedule": "0 3 * * *"
}
]
}
- โSchedule: Daily at 3:00 AM UTC
- โEndpoint:
/api/backup - โAuthentication: Uses
CRON_SECRETenvironment variable
2. Backup API Endpoint
File: app/api/backup/route.ts
Responsibilities:
- โAuthenticates requests using Bearer token
- โConnects to Supabase using service role key (bypasses RLS)
- โFetches all rows from each table with pagination (1000 rows per request)
- โFilters out sensitive fields from user data
- โCompresses data with gzip
- โUploads each table as a separate file to GitHub
- โTriggers cleanup of old backups
3. GitHub Repository
Repository: https://github.com/pxlshpr/nutrikit-backups
Structure:
nutrikit-backups/
โโโ backups/
โโโ .gitkeep
โโโ 2026-01-02/
โ โโโ users.json.gz
โ โโโ foods.json.gz
โ โโโ preferences.json.gz
โ โโโ days.json.gz
โ โโโ meals.json.gz
โ โโโ meal_items.json.gz
โ โโโ user_foods.json.gz
โ โโโ meal_presets.json.gz
โโโ 2026-01-03/
โโโ ...
Data Flow
Backup Process
1. Vercel Cron triggers /api/backup at 3 AM UTC
|
v
2. API validates CRON_SECRET in Authorization header
|
v
3. For each table (users, foods, preferences, days, meals, meal_items, user_foods, meal_presets):
|
+---> a. Fetch all rows with pagination (1000 per request)
|
+---> b. Filter sensitive fields (apple_user_id, cloudkit_id, device_ids)
|
+---> c. JSON stringify the data
|
+---> d. Compress with gzip
|
+---> e. Base64 encode for GitHub API
|
+---> f. Upload to GitHub: backups/{date}/{table}.json.gz
|
v
4. Cleanup old backups based on retention policy
|
v
5. Return success response with row counts and file sizes
Retention Policy
+------------------+-------------------+------------------+
| Age Range | Retention | Example |
+------------------+-------------------+------------------+
| 0-30 days | Keep ALL | 30 backups |
| 30-90 days | Keep 1/week | ~8 backups |
| 90+ days | Keep 1/month | ~12/year |
+------------------+-------------------+------------------+
Estimated annual storage: ~50 backup sets x 4.5 MB = ~225 MB
Well under GitHub's 1 GB soft limit
Tables Backed Up
| Table | Description | Typical Rows | Compressed Size |
|---|---|---|---|
users | User accounts | 74 | ~3 KB |
foods | Food items (user + dataset) | 7,006 | ~2.5 MB |
preferences | User preferences | 43 | ~3 KB |
days | Daily nutrition logs | 863 | ~139 KB |
meals | Meal entries | 1,952 | ~456 KB |
meal_items | Food items within meals | 5,301 | ~1.4 MB |
user_foods | User's food library | 564 | ~39 KB |
meal_presets | Saved meal templates | 0 | ~22 bytes |
Total compressed size: ~4.5 MB per backup
Security
Sensitive Data Handling
The following fields are excluded from backups:
- โ
users.apple_user_id- Apple Sign-In identifier - โ
users.cloudkit_id- CloudKit user identifier - โ
users.device_ids- User's device identifiers
Authentication
| Component | Method |
|---|---|
| Cron endpoint | Bearer token (CRON_SECRET) |
| Supabase | Service role key (bypasses RLS) |
| GitHub | Personal Access Token with repo scope |
Environment Variables
| Variable | Purpose | Location |
|---|---|---|
CRON_SECRET | Authenticates cron requests | Vercel |
SUPABASE_URL | Supabase project URL | Vercel |
SUPABASE_SERVICE_ROLE_KEY | Full database access | Vercel |
GITHUB_TOKEN | GitHub API authentication | Vercel |
GITHUB_OWNER | GitHub username | Vercel |
GITHUB_BACKUP_REPO | Target repository name | Vercel |
Restoring Data
Download a Backup
# Clone the repo
git clone https://github.com/pxlshpr/nutrikit-backups.git
cd nutrikit-backups
# Decompress a specific table
gunzip -k backups/2026-01-02/foods.json.gz
# View the data
cat backups/2026-01-02/foods.json | jq '.[0]'
Restore to Supabase
# Using Supabase CLI or direct SQL
# Example: Restore foods table
cat foods.json | jq -c '.[]' | while read row; do
# Insert each row via Supabase API or psql
done
Manual Backup Trigger
curl -H "Authorization: Bearer YOUR_CRON_SECRET" \
https://nutri-kit.vercel.app/api/backup
Response:
{
"success": true,
"timestamp": "2026-01-02",
"tables": [
{"table": "users", "rows": 74, "size": 2932},
{"table": "foods", "rows": 7006, "size": 2511670},
...
]
}
Monitoring
Success Indicators
- โDaily commits to
nutrikit-backupsrepo - โEach commit contains 8
.json.gzfiles - โResponse includes row counts matching production data
Failure Indicators
- โNo new commits for 24+ hours
- โAPI returns 500 error
- โMissing tables in backup folder
Vercel Logs
View function logs at: https://vercel.com/ahmed-khalafs-projects-75b160b9/nutrikit/logs
Cost
| Service | Cost |
|---|---|
| Vercel Hobby | Free (includes cron) |
| Supabase Free | Free |
| GitHub | Free (public repo) |
Total: $0/month
Files Modified
nutrikit-website repository
- โ
app/api/backup/route.ts- Backup API endpoint - โ
vercel.json- Cron job configuration - โ
package.json- Added@supabase/supabase-jsand@octokit/rest
New Repository
- โ
pxlshpr/nutrikit-backups- Public repo storing all backups
Future Improvements
- โ Email notification on backup failure
- โ Webhook to Slack/Discord on completion
- โ Backup verification (checksum validation)
- โ Point-in-time recovery documentation
- โ Automated restore testing
Created Jan 2, 2026, 5:33 PM ยท Updated Jan 2, 2026, 5:33 PM