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:
/sandboxis 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/sandboxorlib/demo-dataover 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?