Migrate backend services to Neon - #43
Open
andrelandgraf wants to merge 6 commits into
Open
andrelandgraf wants to merge 6 commits into
andrelandgraf wants to merge 6 commits into
Conversation
|
@andrelandgraf is attempting to deploy a commit to the James Singleton's projects Team on Vercel. A member of the Team first needs to authorize it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Move Project Aqua's database and object storage from Supabase to Neon while keeping existing accounts, team data and coach workflows usable. Contributors also need one schema migration path and commands for setup, branch development and cutover.
The current application already uses Better Auth and Drizzle through the Next.js backend. Supabase still owns the SQL migration history and logo/avatar storage. Switching connection strings alone would leave those dependencies and existing image URLs behind.
Implementation
The backend uses Drizzle with postgres.js for Lakebase Postgres on Neon and the AWS S3 SDK for Neon Object Storage. Better Auth stays in the application.
Authorization remains in the existing Next.js session, team membership, role and plan checks. On
origin/main, the RLS request-binding helpers have no callers outside their definitions and exports; the default database handle falls back todbAdmin. This PR replaces that wrapper with onedbhandle and removes the Supabase SQL policies and role setup from the target schema.Drizzle owns the application schema, migrations and snapshots. The migrations create 52 tables, 31 enums and the 134-event swim catalog. Schema definitions now include details previously held only in SQL, including
account.issuer, the one-current-season constraint, relay-result uniqueness with null rounds, the theme check, template timestamps and missing foreign keys and indexes.Setup and development
Run from the repository root with Node.js 24+ and pnpm 11.22.0:
pnpm install cp .env.example .env.local npm i -g neon neon auth neon link --no-env-pull neon deploy neon env pull --file .env.local openssl rand -base64 32 # Set BETTER_AUTH_SECRET in .env.local to the generated value. pnpm db:migrate pnpm dev:adminOpen
http://localhost:3001, sign up and create a team.neon.tsdeclares theteam-logosanduser-avatarspublic-read buckets. The root.env.localsupplies database, storage and application configuration to development, build and migration commands.DATABASE_URLPOSTGRES_URLfallbackDATABASE_URL_UNPOOLEDAWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEYAWS_ENDPOINT_URL_S3,AWS_REGIONStop the app before switching branches, then restart it to load the new credentials:
After editing
packages/db/src/schema/, generate and commit the SQL and snapshots:Deployment has separate infrastructure, schema and application steps:
Deploy the Next.js apps through the application host with the selected branch's environment variables.
neon deployapplies the bucket configuration; the application host still runs Next.js.Existing installations
Back up the source database and objects, stop application writes and provision a fresh target through the setup commands above. Keep the existing
BETTER_AUTH_SECRETand application URLs. SetSOURCE_DATABASE_URLto the source's direct connection in.env.local, then run:The importer requires
pg_dump,pg_restoreandpsql. It copiespublictable data into the Drizzle-created schema and compares every table's row count and content fingerprint. The comparison excludesorganization.logoanduser.image, which the image step rewrites.The initial import requires a target without users or teams. A populated target can resume image migration only when its non-image data matches the source. The image step copies referenced logos and avatars into the target buckets and stores
/api/storage/paths. Completed image rows are skipped on a rerun.Existing images must remain anonymously readable over HTTP(S) and meet the application's image validation rules. Private image origins require an explicit, exact-origin entry in
IMAGE_IMPORT_ALLOWED_ORIGINS. Download or validation failures stop the command.Keep the source read-only until the deployed application's smoke test passes. This is a data cutover into a fresh schema; the command does not upgrade older source schemas or apply Drizzle's initial migration over an existing installation.
Images and existing callers
The roster, meet, workout, attendance and calendar routes retain their existing interfaces. Logo and avatar uploads retain their server-action arguments and result shapes. Their returned image values become same-origin paths:
The public route serves image bytes from the configured branch endpoint. Successful requests return
200; unknown buckets return404and storage HTTP failures retain their upstream status. Responses include a sandboxed content security policy andnosniff.Logo changes retain the owner/admin/head-coach check. Avatar changes require team membership and update the signed-in user's image. JPEG, PNG, WebP, AVIF and SVG remain supported up to 2 MiB; validation now measures the supplied bytes rather than trusting the optional size field.
Also in here
pnpm neon:mcpfor project-local Cursor and Claude Code OAuth configuration.pnpm db:migrate.Verification
Run against
b1b88f7, compared withorigin/mainatf2b84bb:Added coverage checks encoded object-key round trips, external/other-bucket URL handling, actual image byte limits and download address restrictions. The download tests include a real local HTTP server for an explicitly allowed private origin.
git diff --check origin/main...HEADalso passed.These checks do not establish end-to-end compatibility. No live cutover, storage upload/delete, branch checkout, browser journey or deployment was run for this description. The full build, lint and workspace test suite were not run here.
For your attention