nyxcore-systems
5 min read

From Handoff to High-Five: Deploying Phase 1 of Our Project Sync Feature

A deep dive into successfully deploying Phase 1 of our Project Sync feature, covering the full-stack implementation, validating data integrity, and crucial lessons learned from navigating complex production database migrations.

prismadeploymentproductiondatabase-migrationfull-stackssetrpcdockerdevopslessons-learned

Just a few days ago, we hit a major milestone: Phase 1 of our Project Sync feature is live in production! This wasn't just another deployment; it was a full-stack symphony, a dance with databases, and a critical lesson in the realities of production environments. Coming out of the session, I wanted to capture not just what we accomplished, but how we did it, and more importantly, the hard-won wisdom from the challenges we faced.

The Mission: Project Sync Phase 1

Our goal for this session was ambitious: fully integrate and deploy Phase 1 of Project Sync. This feature is designed to keep projects in sync with their external repositories, starting with branch selection capabilities. It involved touching almost every layer of our application:

  • Database Schema: Introducing new tables and columns to track project sync configurations.
  • Backend Service: Building the core logic to manage sync operations.
  • Real-time Updates: Implementing Server-Sent Events (SSE) to provide instant feedback to users on sync status.
  • API Layer: Extending our tRPC API to expose the new sync functionalities.
  • Frontend Components: Crafting intuitive UI elements for users to configure and monitor their project syncs.

After what felt like a marathon, I'm thrilled to report: all 13 tasks for Phase 1 are complete, tested, and deployed to production at nyxcore.cloud!

The "Done" List: A Full-Stack Victory

Getting this feature out the door involved a comprehensive effort across the stack:

  • Full Project Sync Feature Implementation: From the foundational database schema to the interactive frontend components, including the backend service, real-time SSE updates, and tRPC endpoints, every piece is now integrated and functional.
  • Production Deployment: This was the big one. We successfully applied the new schema to our production database, rebuilt and deployed the application, and critically, ensured all existing data remained intact.
  • Backfill Endpoint: An earlier-session task, the backfill endpoint, was also deployed, playing a crucial role in validating data integrity post-migration.

The best part? All 382 existing embeddings – a critical part of our application's intelligence – remained perfectly intact. The new project_syncs table and its associated columns are live and kicking.

The "Lessons Learned" Log: Navigating Production Perils

While the deployment was a success, the path was not without its bumps. These "pain points" are now invaluable lessons that I want to share, especially regarding database migrations in production:

1. The prisma db push --accept-data-loss Trap

NEVER, ever, use prisma db push --accept-data-loss on a production environment. I cannot stress this enough. While incredibly convenient for development, in production, it will literally drop columns that are not part of your current schema definition, even if they contain vital data. In our case, this would have wiped out our precious embedding column, leading to catastrophic data loss.

bash
# DO NOT RUN THIS ON PRODUCTION!
prisma db push --accept-data-loss

This command is a data-loss bomb waiting to explode in production. It's a stark reminder that convenience in dev can be catastrophe in prod.

2. Manual SQL Migration: The Only Safe Path for Production

For any schema changes in production, manual SQL migration is the only safe approach. This means carefully crafting ALTER TABLE statements and executing them directly. It's slower, more meticulous, but it gives you granular control and prevents accidental data destruction.

For example, adding a new column might look something like this:

sql
ALTER TABLE "Project"
ADD COLUMN "syncEnabled" BOOLEAN NOT NULL DEFAULT FALSE;

Always review, test on staging, and then execute with extreme caution.

3. SSH and Heredocs: A Quoting Nightmare

When applying SQL changes via SSH to a Dockerized database, I initially tried using a heredoc for multi-line SQL commands. The idea was to pass a block of SQL directly to psql. However, escaping quotes within the heredoc proved to be an absolute nightmare, leading to syntax errors and frustration.

bash
# This approach proved problematic with quote escaping
ssh user@host <<EOF
  docker compose exec db psql -U user -d database -c "
    ALTER TABLE "Project"
    ADD COLUMN "syncEnabled" BOOLEAN NOT NULL DEFAULT FALSE;
  "
EOF

The simpler, more robust solution? Execute individual commands. Break down your SQL script into single statements and pass them one by one, or create a .sql file and pipe it in.

4. docker compose run --rm for Prisma Commands: Tricky Quotes

Similarly, running Prisma CLI commands within a Docker Compose setup using docker compose run --rm can be tricky due to shell quoting rules. While it works, escaping arguments correctly, especially for commands that take string parameters, requires careful attention.

bash
# Example of running a Prisma command via docker compose
docker compose run --rm backend prisma migrate deploy

This is generally fine for simple commands, but for more complex ones, consider packaging your migration scripts or using a dedicated CI/CD pipeline that handles these nuances.

What's Next?

With Phase 1 successfully deployed, our sights are already set on the horizon:

  1. Real-world Testing: The immediate next step is to rigorously test the sync feature with a real GitHub repository to ensure it performs as expected under actual usage conditions.
  2. Phase 2 Planning: We're already gearing up for Phase 2, which will delve into more advanced capabilities like code analysis and documentation regeneration based on synced repositories.
  3. RLS for project_syncs: To enhance security and data isolation, we need to consider adding Row-Level Security (RLS) policies for the new project_syncs table.

Conclusion

Deploying a complex feature like Project Sync Phase 1 is always a monumental effort, but it's also incredibly rewarding. The success isn't just in the code that's running, but in the lessons we learn along the way. Understanding the nuances of production database migrations and the pitfalls of convenience tools is invaluable knowledge that strengthens our development process for the future. Here's to more successful deployments and smarter development!