refactor(db): replace sqlc with handwritten pgx repos

- Finish Paddle-to-Stripe billing migration; drop paddle/stripe libs
- Renumber migrations; add 00012 memberships+manage_token,
  00013 location_type_capacity
- Add tests: admin, auth, bookings customer service
- Remove graphify-out artifacts and stale env files

Authored By: TDvorak <[email protected]>

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Tomas DvorakandDevin committed 2026-09-17 20:21:34 +02:00
1 parent 2039669e2c
commit f2f7439050
93 files changed
+6987 -69060

No files matched your search

@@ -0,0 +1,50 @@
-- +goose Up
-- Tenant memberships keyed by the auth subject (Neon Auth `sub`).
-- The auth middleware resolves JWT subjects to memberships through users.neon_subject.
CREATE TABLE IF NOT EXISTS tenant_memberships (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id uuid NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
user_neon_subject text NOT NULL,
role text NOT NULL DEFAULT 'staff',
joined_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (tenant_id, user_neon_subject)
);
CREATE INDEX IF NOT EXISTS idx_tenant_memberships_subject ON tenant_memberships (user_neon_subject);
-- Unguessable per-booking management token used by /v1/public/bookings/:reference endpoints.
ALTER TABLE bookings
ADD COLUMN IF NOT EXISTS manage_token text;
CREATE UNIQUE INDEX IF NOT EXISTS idx_bookings_manage_token
ON bookings (manage_token)
WHERE manage_token IS NOT NULL;
-- Backfill tokens for pre-existing bookings.
UPDATE bookings
SET manage_token = replace(gen_random_uuid()::text, '-', '') || replace(gen_random_uuid()::text, '-', '')
WHERE manage_token IS NULL;
-- locations.updated_at is written by the repository update path.
ALTER TABLE locations
ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
-- Demo tenant membership so demo-owner resolves to Studio Atelier.
INSERT INTO tenant_memberships (tenant_id, user_neon_subject, role)
SELECT t.id, u.neon_subject, 'owner'
FROM tenants t
JOIN users u ON u.neon_subject = 'demo-owner'
WHERE t.slug = 'studio-atelier'
ON CONFLICT (tenant_id, user_neon_subject) DO NOTHING;
-- +goose Down
ALTER TABLE locations
DROP COLUMN IF EXISTS updated_at;
DROP INDEX IF EXISTS idx_bookings_manage_token;
ALTER TABLE bookings
DROP COLUMN IF EXISTS manage_token;
DROP TABLE IF EXISTS tenant_memberships;