Decision Register · v1.0

Prerequisites & Architecture
Decision Register

Technology choices, service dependencies, cost targets, and portability constraints for OneSummer — the Common App for summer camps. Every decision is traced to a capability need and sized against the MVP dependency budget of 4–5 services maximum.

Document Status
Approved — v1.0
Last Updated
April 2026
Platform Model
Two-sided marketplace
MVP Cost Target
$0–25 / month
Service Budget
4–5 services max
Deploy Target
Docker — run anywhere
01

Overview & Guiding Principles

OneSummer is a two-sided marketplace where parents discover, compare, and apply to summer camps while camps manage listings and accept applications. A Profile Vault stores child information once, reusable across all applications. The Calendar Planner provides scheduling and conflict detection.

The architecture decisions below follow a capability-first approach: every service added must answer a question that the existing stack cannot answer. The default question before adding anything new is "Can Postgres do this?"

Capability-First Principle: Add a new service only when the existing stack provably cannot satisfy the requirement. Postgres is the first line of defense. Defer infrastructure that is not needed at current scale. Optimize for portability and self-hosting from day one.
Docker as the portability primitive: The entire stack ships as a docker-compose.yml. Any developer can clone the repo and have a running local environment in one command. Production runs the same image. No environment-specific code paths.
MVP Dependency Budget — 4–5 services hard cap: Postgres, a Node/Bun runtime, and a reverse proxy count as one unit. Each additional service (Resend, Fly.io, Sentry) is counted separately. Exceeding 5 services requires explicit architectural review and a documented justification.
02

Scale & Growth Targets

Architecture decisions are anchored to concrete scale targets. Technology that is sufficient for Year 1 is preferred unless it creates a known migration cliff at Year 2 or Year 3.

YEAR 1
2,000
Families in one city. Single-region deployment. Minimal concurrent load. All infrastructure fits on a $6/mo VPS or a free PaaS tier.
Stack: Single Postgres instance, one app container, Resend free tier, Sentry free tier.
YEAR 2
25,000
Multi-city expansion. 12.5x growth. Search performance becomes critical. Postgres read replicas and connection pooling (PgBouncer) become necessary.
Delta: Add PgBouncer. Evaluate managed Postgres (Neon or RDS). CDN for static assets. Resend paid tier.
YEAR 3
200,000
National scale. 8x growth from Y2. Object storage (S3-compatible) for documents. Redis for session cache and rate limiting. Dedicated search layer evaluation.
Delta: Add S3 bucket, Redis (or Valkey). Evaluate pgvector vs. Elasticsearch for camp search.
Decision checkpoint rule: When monthly active families cross 10,000, re-evaluate the hosting and database decisions. When medical form uploads exceed 1 GB total, trigger the object storage migration. These are not today's problems — documenting the triggers prevents premature optimization.
03

MVP Dependency Budget

Five service slots. Each slot must be justified by a capability that no existing slot can provide.

Slot 1
Postgres
Slot 2
SvelteKit + Bun
Slot 3
Resend
Slot 4
Sentry
Slot 5
Reserved

Slot 5 is intentionally held open for the first real constraint that Postgres and the app runtime cannot solve. Current candidates when the trigger is hit: object storage (documents exceed 1 GB), PgBouncer (connection exhaustion), or a transactional SMS gateway (if camp operators require SMS alerts). Only one can occupy this slot at MVP scale.

04

Architecture Decision Records

ADR-001 · Hosting Strategy
ADR-001
Docker-Based Deployment on Fly.io (MVP)
Where does the application run, and how do we ensure it can move?
Decided
The primary goal is a Docker image that runs anywhere — local laptop, any VPS, any PaaS. Fly.io is the default MVP target because it offers a free tier sufficient for Year 1 scale, native Docker deployment, built-in Postgres provisioning, and automatic TLS. The application must not depend on any Fly.io-specific APIs so that migration to Railway, Render, or a bare VPS takes under one hour.
Options Considered
  • Fly.io — Docker-native PaaS, free tier, global edge
  • Vercel — serverless, poor fit for long-lived Postgres connections and background jobs
  • Railway — viable alternative, but Fly.io has more mature Postgres support at free tier
  • AWS ECS — over-engineered, high ops cost, no cost-free tier at this scale
Decision
Fly.io for MVP. App ships as a single Docker image. fly.toml is the only platform-specific artifact. Local dev runs docker-compose up.
Portability Constraints
No Fly.io SDK calls in application code. Secrets injected as environment variables. Postgres connection string is a single DATABASE_URL env var. To migrate: change DATABASE_URL, rebuild image, deploy elsewhere. Zero code changes required.
Trigger for Re-evaluation
Fly.io pricing change Need for GPU workloads Compliance requirements (SOC2/HIPAA) Year 2 scale: multi-region traffic
ADR-002 · Database
ADR-002
PostgreSQL — Single Instance with Native Extensions
Can Postgres do everything we need at MVP scale, and what does it replace?
Decided
Postgres is Slot 1 and is expected to shoulder capabilities that would normally require dedicated services. The capability map below (Section 5) details exactly what Postgres handles natively. At Year 1 scale (2,000 families), a single Postgres 16 instance on a 256 MB shared VPS handles all read/write load, full-text search, job queuing, and JSON document storage without additional services.
Key Postgres Features in Use
  • tsvector / tsquery — camp search & discovery
  • pg_cron — scheduled job execution
  • LISTEN / NOTIFY — real-time application events
  • JSONB — flexible form schemas, profile vault
  • bytea / large object — medical forms at MVP scale (deferred to S3 at Year 3)
  • Row-level security — camp data isolation
Decision
Postgres 16 with pg_cron. Managed via Fly.io Postgres at MVP. Migrate to Neon or self-managed at Year 2 if cost or connection limits demand it.
Trigger for Re-evaluation
Concurrent connections > 80 (add PgBouncer) Search result quality degrades (evaluate pgvector or Typesense) File storage > 1 GB (migrate to S3-compatible) Y2 multi-region reads (add read replica)
ADR-003 · Authentication
ADR-003
BetterAuth — Email/Password + Session Management
How do parents and camp operators authenticate? What is the session model?
Decided
Parents creating accounts for their children are the primary users. This audience does not reliably have a Google or Apple account linked to the email they use for camp administration. Email/password with email verification is the correct default. BetterAuth is a TypeScript-native auth library that owns its own schema and stores sessions in Postgres — no external auth service, no additional cost, no user data leaving the stack.
Options Considered
  • BetterAuth — TypeScript-native, Postgres-backed, no external SaaS
  • Clerk — $25+/mo at scale, user data in external SaaS, portability concern
  • Auth.js (NextAuth) — SvelteKit support incomplete, opinionated session model
  • Supabase Auth — pulls in an entire PaaS dependency
  • OAuth-only — wrong primary UX for parent demographic
Decision
BetterAuth with email/password. Sessions stored in Postgres. OAuth (Google) added as a secondary provider in Year 2 if signup drop-off data warrants it.
User Role Model
Three roles: parent, camp_admin, platform_admin. BetterAuth's organization plugin handles the camp_admin multi-seat use case. Role stored in Postgres, enforced server-side on every request. Row-level security in Postgres provides defense in depth.
Trigger for Re-evaluation
OAuth sign-up demand from parent user research SSO requirement from school district partnerships MFA requirement from enterprise camp operators
ADR-004 · Frontend Framework
ADR-004
SvelteKit — SSR-First Full-Stack Framework
What framework delivers the best parent and camp operator UX at lowest infrastructure cost?
Decided
SvelteKit collocates server-side rendering, API routes, and client-side interactivity in a single deployment unit. There is no separate API server. Form actions replace REST endpoints for mutations, eliminating client-side fetch boilerplate. The compiled output is small — critical for parents on mobile devices. The Node adapter ships as a Docker-compatible server.
Options Considered
  • SvelteKit — compiled, SSR-native, form actions, Node adapter for Docker
  • Next.js — React overhead, Vercel coupling, larger bundle, no form action model
  • Remix — compelling but smaller ecosystem, React runtime cost
  • SPA + separate API — two deployment units, CORS complexity, unnecessary at this scale
Decision
SvelteKit with Node adapter. Bun as the runtime for faster startup and native TypeScript execution. Single Docker image contains both SSR server and static assets.
Trigger for Re-evaluation
Native mobile app required (add Capacitor or separate React Native) Team grows >5 engineers with strong React preference Real-time camp dashboard requires WebSocket server separation
ADR-005 · Object Storage
ADR-005
Deferred — Medical Forms in Postgres at MVP Scale
Where do we store medical forms, permission slips, and profile photos? When does S3 become necessary?
Deferred
Medical form PDFs and permission slips are the primary file artifacts. At 2,000 families with an average of 2 children each, assuming 500 KB per document set, total storage is approximately 2 GB — well within what Postgres bytea or large objects can handle on a $6 VPS. Adding S3 at MVP introduces IAM credentials, pre-signed URL complexity, CORS configuration, and a service dependency for a problem that does not yet exist.
MVP Approach
  • Store document blobs in Postgres bytea column with metadata in separate table
  • Serve files through the SvelteKit server with auth middleware — no public URLs
  • AWS S3 / Cloudflare R2 — deferred to Year 3 trigger or 1 GB storage threshold
Deferred Until
Total document storage exceeds 1 GB, OR serving files creates measurable Postgres I/O latency, OR compliance audit requires immutable audit-logged storage.
Migration Path When Triggered
Abstract file access behind a StorageAdapter interface from day one. The MVP implementation writes to Postgres. The Year 3 implementation writes to Cloudflare R2 (S3-compatible, zero egress fees). No application code changes outside the adapter — only the implementation swaps. Design this interface before writing the first file upload handler.
Trigger for Migration
Document storage > 1 GB Postgres backup time > 5 minutes Camp profile photos added (Year 2 feature) File serving p99 latency > 800ms
ADR-006 · Background Jobs
ADR-006
Postgres-Based Job Queue — pg_cron + Job Table
How do we handle application deadline reminders, acceptance notifications, and scheduled reports without a dedicated job runner?
Decided
At Year 1 scale, background work consists of: deadline reminders (cron, daily), application status change emails (triggered, near-realtime), and waitlist notifications (event-driven). All three are satisfied by a job_queue table polled by the app server every 30 seconds, combined with pg_cron for scheduled triggers. This requires zero additional infrastructure.
Options Considered
  • pg_cron + job table polled by app — zero new services
  • BullMQ + Redis — requires Redis (a new service slot), overkill for <100 jobs/day
  • Inngest — SaaS dependency, adds latency, $0 tier insufficient at Year 2
  • Temporal — extraordinary over-engineering for this job volume
Decision
Postgres job table with FOR UPDATE SKIP LOCKED for safe concurrent dequeue. pg_cron inserts scheduled jobs. App server polls every 30 seconds with a single worker thread.
Job Table Schema (conceptual)
CREATE TABLE job_queue (
  id          uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  job_type    text NOT NULL,
  payload     jsonb NOT NULL,
  status      text NOT NULL DEFAULT 'pending',
  run_after   timestamptz NOT NULL DEFAULT now(),
  attempts    int NOT NULL DEFAULT 0,
  created_at  timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX ON job_queue (status, run_after)
  WHERE status = 'pending';
Trigger for Re-evaluation
Job volume > 1,000/day Jobs require sub-second latency Fan-out patterns needed (e.g., broadcast to 10K families) Redis already added for another reason
ADR-007 · Transactional Email
ADR-007
Resend — Developer-First Transactional Email
How do we send application confirmations, acceptance letters, and deadline reminders reliably?
Decided
Email is the primary communication channel between the platform, parents, and camp operators. It cannot fail silently. Self-hosted email (Postfix, etc.) requires SPF/DKIM/DMARC maintenance and has high deliverability risk. Resend provides 3,000 emails/month free, a TypeScript SDK, React Email template support, and excellent deliverability without per-email pricing at MVP volume.
Options Considered
  • Resend — 3,000/mo free, TypeScript SDK, React Email support
  • SendGrid — complex pricing, legacy API design, free tier deprecated
  • Postmark — excellent deliverability but $15/mo minimum, no free tier
  • SES (AWS) — $0.10/1K but requires AWS account, DNS config, IAM, no free tier for new accounts
  • Self-hosted SMTP — deliverability risk, maintenance burden
Decision
Resend with React Email templates. All sends queued through the Postgres job table first for retry safety. Abstract behind an EmailProvider interface for portability.
Email Types at MVP
Email verification, password reset, application submitted confirmation, application status change (accepted / waitlisted / declined), deadline reminder (D-7, D-1), camp operator digest (weekly application summary). All templates version-controlled in /emails directory using React Email.
Trigger for Re-evaluation
Monthly sends exceed 3,000 (upgrade to $20/mo plan) Marketing email needed (separate provider — never mix transactional & marketing) Deliverability SLA required by camp enterprise contract
ADR-008 · Error Tracking & Observability
ADR-008
Sentry — Exception Tracking (Free Tier)
How do we know when something breaks in production before a user reports it?
Decided
At MVP scale, the primary observability need is exception visibility — knowing when server actions throw unhandled errors, when email sends fail, and when database queries time out. Sentry's free tier (5,000 errors/month) covers this with zero cost. SvelteKit has an official Sentry integration. Logs are written to stdout and captured by Fly.io's built-in log aggregation — no additional log service needed at MVP.
Options Considered
  • Sentry — 5K errors/mo free, SvelteKit SDK, source maps, alerting
  • Datadog — $15+/mo minimum, full APM overkill for MVP
  • New Relic — complex setup, no relevant free tier
  • Self-hosted Glitchtip — additional service slot, maintenance overhead
Decision
Sentry free tier. Structured JSON logs to stdout captured by Fly.io. No dedicated log service until Year 2. Performance monitoring disabled at MVP to stay within free tier.
Trigger for Re-evaluation
Errors exceed 5K/mo (upgrade or self-host) Need distributed tracing (Year 2+) Compliance audit requires log retention > 30 days
05

Postgres Capability Map

Every capability listed below was evaluated with the question: "Can Postgres do this well enough that adding a dedicated service is unjustified at MVP scale?" Green rows are handled natively. Amber rows use a Postgres extension. Grey rows are deferred.

Capability Postgres Feature Status Replaces
Full-text camp search
Name, activity tags, location
tsvector, GIN index, ts_rank Native Algolia, Typesense, Elasticsearch
Structured document storage
Profile vault, form schemas, camp metadata
JSONB with GIN index Native MongoDB, DynamoDB
File storage (medical forms)
PDFs, permission slips — MVP only
bytea column Native S3, Cloudflare R2 (deferred to Y3)
Background job queue
Email dispatch, reminders, reports
job_queue table + FOR UPDATE SKIP LOCKED Native Redis + BullMQ, RabbitMQ
Scheduled triggers
Daily deadline reminders, weekly digests
pg_cron extension Extension Cron containers, Temporal, Inngest
Real-time application events
Status changes, new application notifications
LISTEN / NOTIFY Native Redis pub/sub, WebSocket service
Data isolation between camps
Camp operators see only their own applications
Row-level security (RLS) policies Native Application-layer tenant filtering
Geospatial camp discovery
Sort camps by distance from family ZIP code
PostGIS or earthdistance extension Extension Google Maps distance matrix, dedicated geo service
Session storage
BetterAuth session table
Standard table with TTL via pg_cron cleanup Native Redis sessions
Rate limiting
Login attempts, form submissions
rate_limit table + timestamp window query Native Redis sliding window, Upstash
Vector / semantic search
AI-powered camp recommendation matching
pgvector extension Deferred — Year 2+ Pinecone, Weaviate
Analytics / reporting
Camp operator dashboards, platform metrics
Materialized views, window functions Native ClickHouse, BigQuery, Redshift
06

Cost Projection

Target: $0–25/month at MVP scale (Year 1, 2,000 families, single city). The following projections are based on published free tier limits as of April 2026.

$0–10
Estimated monthly cost at MVP launch
Fly.io Hobby plan covers Postgres + app container. All other services within free tier.
Service Year 1 (MVP) Year 2 (25K) Year 3 (200K)
Fly.io — App + Postgres
Hobby: 3 shared-CPU VMs + 256 MB Postgres included free. Upgrade to dedicated at Y2.
$0 $25–50 $100–200
Resend — Transactional Email
Free: 3,000 emails/mo. Paid: $20/mo for 50K emails.
$0 $20 $20–40
Sentry — Error Tracking
Free: 5,000 errors/mo, 1 user. Team plan $26/mo for >1 developer.
$0 $0 $26
Domain + TLS
Cloudflare DNS (free) + Fly.io auto-TLS (free). Domain registration ~$12/yr.
$1 avg $1 avg $1 avg
Cloudflare R2 — Object Storage
Deferred. Free: 10 GB/mo. $0.015/GB/mo thereafter. Zero egress fees.
$0 (deferred) $0 $5–15
PgBouncer — Connection Pooling
Deferred. Run as sidecar container on same Fly.io VM — no additional cost.
$0 (deferred) $0 (sidecar) $0
Uptime Monitoring
Better Uptime / UptimeRobot free tier — 50 monitors, 3 min intervals.
$0 $0 $0
Total Monthly Estimate $1–5 $46–71 $152–282
MVP cost target achieved: Year 1 infrastructure runs at $1–5/month, well within the $0–25 target. The only non-free cost is the domain. All services remain within free tier limits at 2,000 families and typical usage patterns.
Year 2 cost driver: The Fly.io upgrade to a dedicated Postgres instance (for connection limits and reliability at 25K families) is the primary cost jump. Budget $50/mo from Year 2. This cost is justified by MRR from camp listing fees and parent premium features.
07

Portability Assessment

The primary portability goal is: any developer can run the full stack locally with docker-compose up in under three minutes. Production can be migrated away from Fly.io in under one day. No vendor-specific APIs in application code.

Hosting (Fly.io)
Excellent
Standard Docker image. The only Fly.io artifact is fly.toml. Migration: change one config file and redeploy.
Database (Postgres)
Excellent
Standard Postgres 16. Any hosted or self-managed Postgres works. Single DATABASE_URL env var. pg_cron available on all major managed providers.
Auth (BetterAuth)
Excellent
Self-hosted, schema in Postgres, open source. User data never leaves the stack. Migration: export Postgres table, schema compatible with any Postgres destination.
Frontend (SvelteKit)
Excellent
Node adapter builds a standard Node.js HTTP server. Runs in any container. No Vercel, Netlify, or Cloudflare-specific adapters used.
Email (Resend)
Good
Abstracted behind EmailProvider interface. Swap to SES, Postmark, or SMTP by replacing the provider implementation. React Email templates are provider-agnostic HTML.
Error Tracking (Sentry)
Good
Sentry is self-hostable (open source). Alternatively, swap to Glitchtip or remove entirely — error data does not affect application functionality.
File Storage (bytea/R2)
Excellent
StorageAdapter interface from day one. MVP writes to Postgres. Year 3 swaps implementation to any S3-compatible provider. Zero application changes required.
Local Dev Experience
Excellent
docker-compose up starts Postgres 16 + app in one command. No local dependencies beyond Docker. Seed script populates test data including camp listings and parent profiles.
Portability rule: Every external service dependency is accessed through an interface defined in the application. The implementation can be swapped without touching business logic. This applies to email, file storage, and (if added) SMS. It does not apply to Postgres — Postgres is the foundation, not a dependency.
08

Accounts & Credentials Checklist

Every account that must be created before the first production deployment. Sorted by dependency order — items marked Day 0 are blockers for initial deploy.

Fly.io — Hosting & Database
Required · Day 0
D0
Create Fly.io account at fly.io
Use the team's shared email, not a personal account. Enable 2FA immediately.
Free
D0
Install flyctl CLI and authenticate
brew install flyctl or download from fly.io/docs/hands-on/install-flyctl. Run fly auth login.
Free
D0
Create Fly.io app: fly apps create onesummer-prod
Also create onesummer-staging. Use the same organization.
Free
D0
Provision Fly Postgres: fly postgres create --name onesummer-db
Save the Postgres connection string as a Fly secret: fly secrets set DATABASE_URL=.... Never commit this value.
Free
D0
Add credit card to Fly.io account
Required to create Postgres volumes, even on the free tier. No charge until usage exceeds free limits.
Required
D1
Configure fly.toml with health check, port, and region
Set primary_region = "ord" (Chicago) for Year 1 single-city focus. Add [checks] block pointing to /health endpoint.
Free
Domain & DNS (Cloudflare)
Required · Day 0
D0
Register onesummer.com (or chosen domain)
Recommended: register at Cloudflare Registrar for lowest cost and native DNS management. ~$10–12/yr for .com.
~$12/yr
D0
Create Cloudflare account and add site
Enable "Full (strict)" SSL mode. Set nameservers to Cloudflare's. Enable HSTS via Cloudflare SSL settings.
Free
D1
Add CNAME for app.onesummer.com → Fly.io hostname
Run fly certs add app.onesummer.com to initiate TLS certificate provisioning via Let's Encrypt.
Free
D1
Configure SPF, DKIM, and DMARC records for email sending
Resend will provide the exact DNS records after domain verification. Add all three before sending the first transactional email. DMARC policy: p=none initially, upgrade to p=quarantine after 30 days of monitoring.
Free
Resend — Transactional Email
Required · Day 0
D0
Create Resend account at resend.com
Use the team's shared email. Free tier includes 3,000 emails/mo.
Free
D0
Generate Resend API key and store as Fly.io secret
fly secrets set RESEND_API_KEY=re_.... Never commit the key. Use a separate key for staging vs. production.
Free
D0
Add and verify sending domain in Resend dashboard
Add onesummer.com as a sending domain. Copy the DNS records Resend provides and add them to Cloudflare (DKIM TXT records).
Free
D1
Set from address: hello@onesummer.com for transactional, noreply@onesummer.com for automated
Verify both addresses in Resend. Use hello@ for emails that parents might reply to. Use noreply@ for system notifications.
Free
Sentry — Error Tracking
Required · Day 1
D1
Create Sentry account at sentry.io
Create organization: onesummer. Free tier: 5,000 errors/mo, 1 developer seat.
Free
D1
Create two Sentry projects: onesummer-web (SvelteKit) and onesummer-server (Node/Bun)
Separate DSNs for client-side and server-side errors. Store both as Fly secrets: SENTRY_DSN_CLIENT and SENTRY_DSN_SERVER.
Free
D1
Configure source maps upload in CI/CD pipeline
Install @sentry/sveltekit. Add SENTRY_AUTH_TOKEN to Fly.io and GitHub secrets. Source maps enable readable stack traces in production.
Free
D1
Set alert rules: notify on new error types, spike alerts (>100 errors/hour)
Configure email alerts to the team inbox. Optionally connect to a Slack channel for real-time alerts.
Free
GitHub — Source Control & CI/CD
Required · Day 0
D0
Create GitHub organization: onesummer-app
Free for public repos and up to 3 private repos with collaborators on the free tier.
Free
D0
Create repo: onesummer-app/platform as private
Monorepo structure: /app (SvelteKit), /emails (React Email templates), /db (migrations), /docker.
Free
D0
Add GitHub Actions secrets: FLY_API_TOKEN, SENTRY_AUTH_TOKEN
Get FLY_API_TOKEN from fly tokens create deploy. This enables CD: push to main → auto-deploy to Fly.io.
Free
D1
Set up branch protection on main: require PR review + passing CI
Enforce: 1 approving review, status checks must pass (typecheck, lint, test), no direct pushes.
Free
Better Uptime — Uptime Monitoring
Recommended · Day 1
D1
Create Better Uptime account at betteruptime.com
Free tier: 50 monitors, 3-minute check interval, unlimited team members. No credit card required.
Free
D1
Create monitors: https://app.onesummer.com/health and https://app.onesummer.com
The /health endpoint should return 200 and check Postgres connectivity. Alert via email + PagerDuty (or phone call) for >3 minute downtime.
Free
D1
Create public status page at status.onesummer.com
Better Uptime provides free hosted status pages. Add a CNAME for status.onesummer.com. Camp operators can check this during incidents.
Free
Environment Variables — Complete List
Reference · All environments
D0
DATABASE_URL
Postgres connection string. Set via fly secrets set. Never in .env committed to git.
D0
BETTER_AUTH_SECRET
32+ character random string for BetterAuth session signing. Generate: openssl rand -base64 32.
D0
BETTER_AUTH_URL
The canonical origin: https://app.onesummer.com in production, http://localhost:5173 in local dev.
D0
RESEND_API_KEY
Resend API key starting with re_. Separate keys for prod and staging.
D1
SENTRY_DSN
Sentry DSN for server-side error reporting. Safe to commit as a build-time variable (it is public by design).
D0
NODE_ENV / PUBLIC_APP_ENV
Set to production in Fly.io app config. Controls logging verbosity, error details, and dev-only routes.
D0
STORAGE_ADAPTER
Set to postgres at MVP. Future values: r2, s3. Controls which StorageAdapter implementation is injected at startup.