Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesLocationsLocations

Locations

What is this

A location is a studio branch or physical space within an organization. It carries an address, city, country, latitude/longitude (used for GPS check-in), capacity, and an is_active flag. Class sessions optionally reference a location (class_sessions.location_id). Multi-branch studios use multiple location rows; single-studio orgs typically have one.

Who uses it

PersonaWhy
OwnerAdds/edits branches; sets coordinates to enable GPS check-in.
AdminSame as owner.
CoachReads; selects a location at session-create.
MemberReads location name + map (minisite has an embed); GPS check-in uses lat/lng but the member doesn’t see the coordinates.

Persona impact

  • Tier-gated: LocationsService.create checks checkTierLimit(platformTier, 'maxLocations', currentCount)lite orgs can’t add unlimited branches.
  • GPS check-in (POST /sessions/:id/self-checkin with method=gps) reads location.latitude and location.longitude. If either is null when a member tries GPS check-in, the booking flow throws BadRequestException('Session location coordinates are not configured').

High-level capabilities

  1. CRUD — create, list, get, update, deactivate (soft via is_active=false).
  2. Tier enforcementmaxLocations checked at create time; exceeds raises 403 with upgrade copy.
  3. Geo metadatalatitude/longitude (doublePrecision) used by self-checkin Haversine distance.
  4. Capacity hintlocation.capacity is informational only (not enforced against class session capacity).
  5. Minisite integration — public minisites can render a map embed for the location (see i18n minisite.locations*).

Relationship to other features

  • scheduling-bookingsclass_sessions.location_id FKs here. GPS check-in resolves session.location.latitude/longitude.
  • organizationslocations.organization_id is the direct org boundary (unlike class_types, no parent indirection).
  • Platform tiers / billing — see apps/api/src/platform-tiers/ + @fitkit/shared.checkTierLimit. maxLocations limit varies per tier.

Current status

Shipped. The schema column address is a free-text text field (not normalized). Coordinates are populated either manually by owners or via the AddressAutocomplete component during onboarding (Google Places, see apps/web/src/components/onboarding/address-autocomplete.tsx).

Known gaps

  • No bulk-import for multi-branch studios; each location added one-at-a-time.
  • No “default location” flag on the org — when a session is created without location_id, none is chosen automatically.
  • location.capacity is informational; not enforced anywhere in booking logic.