The create-user action in src/actions/admin/users.ts was written
against a richer admin_users schema than the one that landed in
0001_init.sql. The 0001 schema has just `name` plus the role-derived
can_manage_<X> columns; the action also references display_name,
phone_number, brand_id, can_manage_pickup/messages/refunds/users,
active, must_change_password, auth_provider, auth_subject, and
last_login. Result: 'column "display_name" of relation
"admin_users" does not exist' on any create-user submit.
Migration 0043 adds the missing columns with sensible defaults
(ADD COLUMN IF NOT EXISTS, so re-runnable). The four extra
can_manage_* flags are vestigial — getAdminUser() in
lib/admin-permissions.ts derives per-user permissions from the role
via permissionsForRole() and never reads them — but they exist so
the create-user form's per-user toggles persist, and the migration
header documents the cleanup target.
The db/schema/brands.ts Drizzle adminUsers definition is extended
in lockstep so the inferred TS types stay in sync with the table.
brand_id is left as a denormalized column (the link table
admin_user_brands is the source of truth and is what
getAdminUser() reads); getAdminUsers() in the action joins on
au.brand_id so keeping the column avoids rewriting the SELECT.
Gitea CI runs scripts/migrate.js before the build, so this lands
on prod automatically on the next push.
- Add MinIO/S3-compatible storage client (src/lib/storage.ts) with uploadObject,
deleteObject, presigned URL helpers, and BUCKETS constant
- Wire product images, brand logos, and water log photos to MinIO via the
new storage client
- Migrate forgot-password to Neon Auth (remove Supabase /auth/v1/recover call)
- Migrate send-scheduled cron to direct Postgres + Resend (remove Supabase Edge
Function proxy)
- Add logoUrl to email types (OrderReceipt, Welcome, PasswordReset) and pass
brand_settings.logo_url from all call sites
- Update email templates to use dynamic logoUrl instead of hardcoded Supabase
bucket URLs
- Remove hardcoded Supabase URLs from TuxedoVideoHero, TuxedoAboutPage,
TimeTrackingFieldClient; use brand_settings props + local public/ fallback
- Download brand logos (3) and tuxedo-hero.mp4 (36MB) from Supabase bucket to
public/ for local development
- Add MinIO env vars to .env.example (endpoint, access key, secret, buckets)
- Fix TimeTrackingFieldClient to destructure logoUrl and brandAccent props
- Fix admin/users.ts logoUrl type (null → undefined for optional string)
- Remove stale sb- cookie from wholesale-auth
- Migrate tuxedo/about page to remove supabase import and use pool query for
wholesale_settings lookup