Beyond the Schema: Crafting Robust E2E Tests and Safe PGVector Migrations
Join us as we navigate the complexities of implementing end-to-end tests for sensitive superadmin flows and devise a bulletproof strategy for `pgvector` database migrations with Prisma.
Just wrapped up a crucial design phase for an upcoming development sprint, and the insights are too valuable not to share. Our mission: fortify our superadmin flows with robust End-to-End (E2E) tests, ensure seamless multi-tenancy user experience, and, perhaps most critically, engineer a bulletproof database migration strategy for our pgvector columns.
The design is now with the user for final review, but the journey to get here was packed with explorations, a few "aha!" moments, and some critical lessons learned. Let's dive in.
Laying the Foundation: E2E Testing for Superadmin Flows
Our primary goal was to ensure that the superadmin experience, including the critical tenant switcher UX, is rock-solid. This meant a deep dive into our existing E2E setup and how to extend it for complex, multi-tenant scenarios.
E2E Exploration & Strategy
We use Playwright for our E2E tests, and the existing structure gave us a great starting point. We explored:
- Playwright Configuration: Understanding how our
playwright.config.tsis set up, especially for handling different environments. - Authentication Helper: The
tests/e2e/helpers/auth.tsfile is a gem. It allows us to programmatically inject a JWT cookie into the browser context, ensuring our tests start with a consistent, authenticated user state. For superadmin tests, this will be crucial for simulating different roles and tenant access. - Existing Test Patterns: Reviewing our current 4 spec files provided blueprints for interacting with the UI and asserting outcomes.
Deconstructing Multi-Tenancy & Superadmin Access
To effectively test superadmin flows, we needed to understand the underlying architecture:
- Tenant Switcher Component:
src/components/layout/tenant-switcher.tsxis the heart of our multi-tenancy UX. Testing this means verifying not just the UI interaction, but also the data isolation and correct context switching. - tRPC Routers:
src/server/trpc/routers/superadmin.tsandsrc/server/trpc/routers/teams.tsexpose the server-side logic for managing users, tenants, and teams. Our E2E tests will need to interact with or mock these endpoints. - Authentication & Authorization: The
auth.tsJWT callback logic is vital. It's where user roles andtenantIdare embedded into the token, dictating access. Our E2E auth helper will mimic this to simulate superadmin privileges.
Understanding how these pieces interlocked was essential to design tests that truly reflect real-world superadmin interactions and ensure data integrity across tenants.
The PGVector Migration Conundrum: A Critical Challenge
While powerful, our current database setup for pgvector introduced a unique challenge when it came to database migrations. We rely on pgvector for storing embedding vectors in tables like workflow_insights and document_chunks, and we use HNSW indexes for efficient similarity search.
The Problem: Prisma's db push and Unsupported Types
Our current setup doesn't use Prisma's migration engine (i.e., no migrations directory). Instead, we use prisma db push during development, and apply custom rls.sql scripts to add vector columns and HNSW indexes directly.
The critical issue arises when prisma db push is run on production. It attempts to DROP our embedding vector(1536) columns on workflow_insights and document_chunks because Prisma's introspection flags them as Unsupported types in the schema.
-- Example of what Prisma *wants* to do
ALTER TABLE "workflow_insights" DROP COLUMN "embedding";
This is a non-negotiable red flag. Running prisma db push --accept-data-loss on production would literally obliterate crucial vector data, leading to catastrophic data loss.
The Solution: Engineering a Safe Migration Script
To circumvent this, we've designed a custom, pgvector-safe migration script: scripts/db-migrate-safe.sh. The plan is:
- Generate Diff SQL: Use
prisma migrate diffto generate the raw SQL needed to bring the database schema up to date, based on the Prisma schema. - Filter Dangerous Operations: The script will then parse this generated SQL to identify and filter out any
DROP COLUMNstatements that target ourembeddingvector columns. - Apply Safe Changes: The filtered SQL will be applied to the production database using
psql. - Re-run RLS & Indexes: Finally, we'll re-run our
rls.sqlscript to ensure allpgvectorcolumns and HNSW indexes (which are not managed by Prisma's schema) are correctly in place.
This approach ensures we can evolve our Prisma schema safely without risking our valuable vector data.
A Quick Reminder: Edge Runtime Constraints
During our review, a critical lesson from a previous session (captured in commit 54933e0) resurfaced regarding our src/server/auth.ts file. This file runs in the Edge Runtime – a lightweight, performant environment often used in serverless functions.
The key takeaway: NEVER import Node.js-specific modules (like crypto, fs, path) into files intended for the Edge Runtime. This is because the Edge Runtime doesn't have access to the full Node.js API. While a quick win for performance, it's a sharp reminder to be mindful of module imports in these specific contexts.
The Path Forward: Bringing Design to Life
With our design approved by the user and potential pitfalls carefully charted, our path forward is clear. We're ready to transition from planning to implementation.
Immediate Next Steps:
- Get User Approval: Final sign-off on the 3-task design proposal.
- Develop Superadmin E2E Tests: Create
tests/e2e/superadmin.spec.ts, implementing E2E tests for superadmin flows, leveraging tRPC mocking where necessary. - Extend Auth Helper: Enhance
tests/e2e/helpers/auth.tswith aninjectSuperAdminCookie()helper to streamline superadmin test setup. - Implement Safe Migration Script: Create
scripts/db-migrate-safe.shto handlepgvector-safe migrations usingprisma migrate diff. - Verify E2E Tests: Run
npm run test:e2eto ensure all new and existing tests pass. - Validate Tenant Switcher UX: Confirm that the tenant switcher's functionality and data isolation are thoroughly covered by the new superadmin E2E tests.
This session reinforced the idea that modern web development isn't just about shipping features; it's about shipping them securely, reliably, and with an eye towards future maintainability and data integrity. Onwards to implementation!