caterium-app/ops/supabase-selfhosted/scripts/05-storage-sync.sh
pavlov346346 88b7f55db4 Ops: add self-hosted Supabase stack for Timeweb Cloud migration
Full production-ready docker-compose stack (db, kong, auth, rest,
realtime, storage, imgproxy, meta, functions, studio) targeting
api.caterium.ru, plus bootstrap script for a fresh Cloud Server,
Caddy reverse-proxy config (HTTPS, WebSocket, upload limits), and
dump/restore/verify/storage-sync scripts for moving off the managed
Supabase project (cksuehzcimitsxmeloes). Does not touch public/ or
any live runtime behavior — frontend cutover is documented separately
in frontend-cutover.md and only applied after Etap 8 verification.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-11 16:20:45 +03:00

55 lines
2.3 KiB
Bash

#!/bin/bash
# Copies Storage objects (binary files) from the OLD managed Supabase project's Storage
# API to the new self-hosted Storage API, preserving bucket names, object paths and
# content-type. Bucket definitions + storage.objects METADATA rows are already restored
# by 02-restore-new.sh (they live in the `storage` schema, covered by schema.sql/data.sql)
# — this script only moves the actual binary blobs, which live outside Postgres.
set -euo pipefail
: "${OLD_SUPABASE_URL:?e.g. https://cksuehzcimitsxmeloes.supabase.co}"
: "${OLD_SERVICE_ROLE_KEY:?Old project's service_role key (Dashboard -> Project Settings -> API)}"
: "${NEW_SUPABASE_URL:?e.g. https://api.caterium.ru}"
: "${NEW_SERVICE_ROLE_KEY:?New stack's SERVICE_ROLE_KEY from .env}"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
echo "== Listing buckets on OLD project =="
BUCKETS=$(curl -sf "$OLD_SUPABASE_URL/storage/v1/bucket" \
-H "Authorization: Bearer $OLD_SERVICE_ROLE_KEY" \
-H "apikey: $OLD_SERVICE_ROLE_KEY" | jq -r '.[].id')
for bucket in $BUCKETS; do
echo "== Bucket: $bucket =="
OBJECTS=$(curl -sf -X POST "$OLD_SUPABASE_URL/storage/v1/object/list/$bucket" \
-H "Authorization: Bearer $OLD_SERVICE_ROLE_KEY" \
-H "apikey: $OLD_SERVICE_ROLE_KEY" \
-H "Content-Type: application/json" \
-d '{"limit": 1000, "offset": 0, "prefix": ""}' | jq -r '.[] | select(.id != null) | .name')
count=0
while IFS= read -r path; do
[ -z "$path" ] && continue
local_file="$TMP_DIR/$(basename "$path")"
curl -sf "$OLD_SUPABASE_URL/storage/v1/object/$bucket/$path" \
-H "Authorization: Bearer $OLD_SERVICE_ROLE_KEY" \
-H "apikey: $OLD_SERVICE_ROLE_KEY" \
-o "$local_file"
curl -sf -X POST "$NEW_SUPABASE_URL/storage/v1/object/$bucket/$path" \
-H "Authorization: Bearer $NEW_SERVICE_ROLE_KEY" \
-H "apikey: $NEW_SERVICE_ROLE_KEY" \
-H "x-upsert: true" \
--data-binary "@$local_file" > /dev/null
rm -f "$local_file"
count=$((count + 1))
echo " copied: $bucket/$path"
done <<< "$OBJECTS"
echo " -> $count object(s) copied for bucket $bucket"
done
echo ""
echo "Done. Spot-check: open a known photo URL under $NEW_SUPABASE_URL/storage/v1/object/public/<bucket>/<path>"
echo "and confirm it renders identically to the old one."