Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesExports ImportsExports & Imports

Exports & Imports

Two complementary data movement pipelines:

  • Exports — owner-initiated CSV exports of organization data (members today, more entities planned). Async, R2-hosted, emailed when ready.
  • Imports — async ingestion of member/plan data from external systems. Two sources today: Arbox (FitKit’s primary competitor migration path) and generic CSV (header-mapped, preview-confirm workflow).

What

SurfaceEndpoint rootSource
Members exportPOST /organizations/:orgId/export/membersapps/api/src/export/
Analytics exportGET /organizations/:orgId/analytics/export?tab=...Synchronous CSV download from apps/api/src/analytics/.
Arbox importPOST /organizations/:orgId/importapps/api/src/import/ (Business API and Management API paths)
CSV importPOST /organizations/:orgId/import/csv/upload → preview → confirmapps/api/src/import/
Provider credentialsPOST /organizations/:orgId/import/provider-configEncrypted at rest.

Why

  • Customers leaving Excel / Squarespace / Arbox need a one-click way to bring their members in.
  • Owners need to push member data into accounting, marketing, or compliance tools and expect CSV.
  • Imports must be fault-tolerant — a 1500-row Arbox import shouldn’t fail because one row had a malformed email.

Who

  • Owner / admin — initiates imports + exports. Restricted by membership role inside the service (only owner / admin).
  • Member rows — created or updated by imports. No member action required for imports.
  • Email service — receives “Your export is ready” when an export completes.

Persona impact

PersonaImpact
OwnerMigrates from Arbox or a CSV in <10 min with idempotent retry. Exports member list to send to accountants.
MemberA correctly-imported row means their first login lands them in the right plan / membership state.

Capabilities

Exports

  • Asynchronous via BullMQ export queue → ExportProcessor.
  • Per-tab filtering for members (roles, statuses, custom fields).
  • CSV is UTF-8 with BOM (Excel-friendly Hebrew rendering).
  • Stored at exports/<orgId>/<jobId>.csv in R2.
  • Presigned download URL emailed to the requester when the job finishes.
  • Rate limit: 10 exports per minute per IP via @Throttle.

Arbox import

  • Two API surfaces: Business API (api key only) and Management API (email+password, fuller data).
  • Management API path runs both active + inactive reports in parallel and merges by user_fk.
  • Member rows fan out to a import-member queue (3 attempts, exponential backoff).
  • Optional enrichment phase (import-enrich) re-fetches Business API detail per member to fill fields the Management report doesn’t carry.
  • Whitelist support — restrict an import to specific emails (used in staged migrations).
  • Plan import runs inline (small batches) before member fan-out.

CSV import

  • Two-step UX: upload → header mapping preview → confirm + run.
  • 5 MB upload cap on the controller via MaxFileSizeValidator.
  • Heuristic header suggestion via CsvParseService.suggestMapping.
  • Plans + members + leads as separate entity targets.

Encryption at rest

  • Arbox credentials persisted via CredentialEncryptionService (shared with payments). Read-back returns only hasCredentials: true — never the plaintext.
  • r2 — file storage for exports and (indirectly) CSV uploads.
  • users-auth, memberships — imports create users and memberships.
  • plans — imports create plans linked to member rows.
  • notifications — email service delivers the export-ready notification.
  • leads-crm — CSV imports can target leads.

Status

  • Members CSV export: shipped.
  • Analytics tab CSV exports: shipped (synchronous).
  • Arbox import (Business + Management API): shipped.
  • CSV import (members + plans + leads): shipped.

Gaps

  • FIT-120 — Arbox import’s id-encryption flow has a known bug where credentials encrypted under an old key cannot be decrypted after a key rotation. Mitigation: re-enter credentials post-rotation.
  • Exports for non-member entities (workouts, payments) are CSV-only via the analytics tabs; no async export path.
  • No incremental imports — every Arbox run is a full pull-and-upsert.
  • No rollback / dry-run mode for imports. Owners must validate via the whitelist + a small batch first.
  • Failed member rows surface inside import_jobs.results.errors, but there’s no UI table to retry individual failures.
  • Export download URL TTL is 1h; if the email is opened later, the user must re-trigger the export. No long-lived signed link option.