Skip to main content

Application Architecture

Blue North is moving from prototype to production, so new work should follow clear domain boundaries. A large app is maintainable when every file has an obvious home and every feature owns a small, coherent slice of the product.

Principles

  • Organize product code by domain before file type.
  • Keep shared infrastructure small and boring.
  • Keep Supabase access behind focused modules instead of scattering database calls through UI components.
  • Keep sandbox/demo behavior clearly separated from production campaign behavior.
  • Prefer many small files with clear ownership over large files with mixed concerns.
  • Add abstractions only when they reduce real duplication or clarify a domain boundary.

Current Domains

Use platform/features/* for new production-facing feature code.

platform/features/auth
platform/features/campaigns
platform/features/dashboard
platform/features/voters
platform/features/turf
platform/features/canvassing
platform/features/knowledge
platform/features/admin
platform/features/sandbox

Not every domain exists yet. Create a feature directory when new work has enough code to own UI, server logic, types, or tests.

App Routes

platform/app should stay thin. Routes should compose feature modules rather than becoming the main place where business logic lives.

Good:

import { AuthHome } from "@/features/auth/components/auth-home"

export default function Page() {
return <AuthHome />
}

Avoid:

export default function Page() {
// hundreds of lines of form state, data loading, and business rules
}

Shared Code

Shared primitives belong in a few stable places:

  • platform/components/ui: reusable UI primitives with no campaign-specific business logic.
  • platform/components/shell: app chrome, navigation, header, command palette.
  • platform/lib: shared runtime infrastructure, pure utilities, stores, and third-party clients.
  • platform/lib/supabase: Supabase client creation and session plumbing.
  • platform/lib/data: legacy/static data loaders while we migrate to Supabase.

If a shared module starts accumulating product-specific behavior, move that behavior into a feature folder.

Sandbox Boundary

The Anakin Skywalker for Congress demo is useful for sales, QA, and public exploration. It should remain clearly labeled as sandbox data.

Rules:

  • /sandbox is the public demo entry into the existing app shell.
  • Production auth and campaign onboarding should not depend on sandbox localStorage data.
  • Demo-specific data assumptions should move toward features/sandbox or lib/demo-data over time.

File Size Guideline

When a file approaches 300-500 lines, pause before adding more. Split by responsibility:

  • page/container
  • form
  • table
  • detail panel
  • data access
  • types
  • pure helper logic

This is a guideline, not a hard rule. Some complex UI files may stay larger temporarily, but new code should bias toward smaller feature-owned modules.

Review Checklist

Before adding new code, ask:

  • Which product domain owns this?
  • Is this route thin?
  • Is Supabase access hidden behind a helper/repository?
  • Is this sandbox-only or production behavior?
  • Will another developer know where to put the next related file?