Skip to content

Services

The backend is organized into vertical domains under backend/internal/services/<domain>/. Each domain package owns its full request path: store.go (persistence), service.go (business logic), handler.go (HTTP binding + response shaping), routes.go (route registration), and wire.go (Google Wire provider set). Multi-aggregate domains prefix files and types by aggregate (event_service.go / EventService); some carry deps.go for cross-domain interfaces and colocated *_test.go.

Constructors are named New<Thing>. Response shapes live inside each domain, but small cross-cutting summaries (models.UserSummary, models.EventSummary) are shared from the models package. Cross-cutting infrastructure lives in the platform/ bundle (cache, ws, email, audit, assets, taxonomy, llm, notify) and the boot-time drivers (internal/storage for S3, internal/database for Migrate). Domains are composed in internal/wiring/ (router.go mounts routes, Wire generates the object graph).

Each domain exposes RegisterRoutes(r chi.Router, handler, ...gates): JWT, optional-auth, rate limiters, and access.Require gates are passed in as func(http.Handler) http.Handler middleware, so routes.go never imports middleware or access packages. See Wiring.

Domain catalog

Domain Summary
auth Registration, login (password, Google, Apple, LINE, WebAuthn), OTP, sessions, JWT, API keys
user Lean user card, profile, preferences, denormalized stats, account lifecycle (deactivate + GDPR delete)
friend Friendship graph, requests, close friends, live friend-location sharing
event Event CRUD, participants, lifecycle state machine, promoted event-item snapshots
plan Collaborative planner: item board, capture pipeline, place/availability votes, promote-to-event
chat Event chat, 1:1 DM, group chat, reactions, disappearing messages, WebSocket transport
moment Ephemeral photo drops, likes, journaled vs. expiring
presence Heartbeat, active-location sharing sessions, check-ins
discovery Read-aggregation query surface: map, radar, unified search, location + profile detail, taxonomy
maps Map detail reads plus personalization (saves, dismissals, category affinity)
location Place search, autocomplete, geocode, reverse, resolve, dedup + merge
catalog seeding Generate + load the global place catalog (countries, cities, curated lists) from open data
content Curated catalog: stamp guide, curio store, challenges, per-catalog asset URLs
passport Earned state: append-only visit ledger, passport counts, progress, retroactive awards
gameengine Evaluates content rules against activity, writes earned passport progress
notification In-app and push notifications, push-token registration
media Direct-to-S3 upload starters, Klipy GIF/sticker proxy, SSRF-guarded link-preview proxy
payment Stripe checkout, billing portal, webhook subscription sync
admin Platform stats, user moderation, location merge, async queue (DLQ) operations
partner Multi-tenant scoping: Partner entity, memberships, per-partner role gating

Read this first

For the request lifecycle (handler → service → store) and dependency injection, see Wiring and Database.