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_SECRET environment 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

TableDescriptionTypical RowsCompressed Size
usersUser accounts74~3 KB
foodsFood items (user + dataset)7,006~2.5 MB
preferencesUser preferences43~3 KB
daysDaily nutrition logs863~139 KB
mealsMeal entries1,952~456 KB
meal_itemsFood items within meals5,301~1.4 MB
user_foodsUser's food library564~39 KB
meal_presetsSaved meal templates0~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

ComponentMethod
Cron endpointBearer token (CRON_SECRET)
SupabaseService role key (bypasses RLS)
GitHubPersonal Access Token with repo scope

Environment Variables

VariablePurposeLocation
CRON_SECRETAuthenticates cron requestsVercel
SUPABASE_URLSupabase project URLVercel
SUPABASE_SERVICE_ROLE_KEYFull database accessVercel
GITHUB_TOKENGitHub API authenticationVercel
GITHUB_OWNERGitHub usernameVercel
GITHUB_BACKUP_REPOTarget repository nameVercel

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-backups repo
  • โ—Each commit contains 8 .json.gz files
  • โ—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

ServiceCost
Vercel HobbyFree (includes cron)
Supabase FreeFree
GitHubFree (public repo)

Total: $0/month


Files Modified

nutrikit-website repository

  1. โ—app/api/backup/route.ts - Backup API endpoint
  2. โ—vercel.json - Cron job configuration
  3. โ—package.json - Added @supabase/supabase-js and @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