heymike.dev

Scaling and Evolving Arcturus: Architecture in Motion Published:

Picking Up Where We Left Off

Arcturus was originally designed around a few key principles: keep the business logic close to the data, expose as much as possible through a typed GraphQL API, and avoid writing one-off endpoints wherever possible. The system revolves around a set of modular, project-scoped concepts — footprints, collectibles, games, and taxonomy — each built with long-term flexibility in mind.

The database is split into clear schema boundaries: app_public for API-facing tables and functions, app_private for permission-checked logic, and app_hidden for internal mechanics. Permissions are managed through stable Postgres functions and RLS policies, often driven by session variables like user.id and user.permissions. Thanks to PostGraphile, most of the platform’s surface area comes straight from the database schema with stable, composable building blocks that reduce the need for backend boilerplate.

That approach worked well for getting things off the ground. But as Arcturus grew, both in terms of traffic and feature complexity, a few new requirements emerged that pushed the architecture further.

Scaling Without Reinventing the Stack

As Arcturus grew, the architecture stayed grounded in its original stack — Postgres, PostGraphile, and a handful of carefully chosen services. There was no need to introduce microservices, message queues, or background job systems. Most new features could be expressed as additional functions, views, or RLS rules inside the existing schema.

By leaning on stable database functions, the platform gained flexibility without losing structure. Stats, analytics, and even real-time behaviors like QR scans and gameplay logging are all driven by the same core primitives — tables, triggers, and SQL functions exposed through GraphQL. When something needs to change, it happens in one place: the schema.

That consistency has made it easier to ship new modules (like taxonomy and prizing) while keeping the rest of the system intact. The stack didn’t need to scale up — it just needed to scale out, using the same building blocks in new ways.

Keeping Complexity in Check

One of the core goals with Arcturus was to avoid letting complexity sprawl across layers of the stack. Most of the business logic lives in the database, expressed through stable, permission-aware functions that serve as the foundation of the GraphQL API. That decision has paid off, especially as more modules have been added.

The schema is split into three layers:

  • app_public: what clients see via GraphQL
  • app_private: where permission checks and core logic live
  • app_hidden: internal details like triggers and utility views

This structure helps keep responsibilities clear. When a new feature is added, it’s usually a matter of creating the right tables, writing a few stable functions, and exposing just what’s needed through app_public. There’s rarely a need for a custom resolver or REST endpoint.

PostGraphile’s plugin system fills in the gaps, but most of the time, the schema drives the API directly. That means faster iterations, fewer bugs, and less boilerplate, all without giving up control over what’s exposed.

That discipline at the schema level is only part of the story. Infrastructure also had to keep up, especially given how unpredictable usage patterns can be.

Scaling for Events, Not Always-On Traffic

One of the unique challenges with Arcturus is that usage isn’t constant. It spikes hard during live events and drops off completely between them. The system needs to scale up to handle tens of thousands of users in a short window, then scale down to nearly zero without wasting resources.

That’s where serverless infrastructure has been a good fit. The frontend Next.js app and GraphQL API layer both run on Vercel, which handles traffic bursts without any manual intervention. The database is hosted on Neon, which supports branching for testing and can pause inactive projects automatically to save costs.

This setup keeps the system responsive during peak usage but lightweight when idle. There’s no long-running server process to maintain, and no persistent fleet sitting around waiting for traffic. The platform scales based on activity, which is exactly what Arcturus needs.

Looking Ahead

Arcturus has grown from a tight schema and a handful of features into a full platform for powering interactive, real-world experiences. The architectural choices made early on — keeping logic close to the data, leaning on PostGraphile, and structuring the schema for long-term growth — have made that evolution feel manageable.

New modules continue to plug into the existing shape of the system without breaking it. And while new challenges have emerged, especially around observability and real-time feedback, the foundation has remained steady.

That’s what the next post will focus on: how the platform tracks activity across apps, games, and events — and how the observability stack came together to support it.