ActivityFox Dev

Architecture

Multi-service design, data flow, publish pipeline, and service boundaries for the ActivityFox platform.

ActivityFox — Technical Documentation

Developer-focused documentation covering architecture, data models, APIs, and integration guides.

System Architecture

%%{init: {'theme': 'neutral'}}%%
graph TB
    Browser["React SPA<br/>(shadcn/ui + Tailwind + Redux)"]
    Express["Express.js API Server"]
    ST["Sharetribe<br/>Users · Listings · Transactions"]
    SB["Supabase<br/>Activities · Sessions · Preferences"]
    Davis["Davis CalDAV<br/>Calendars · Events"]
    Meili["Meilisearch<br/>Search Indexes"]
    n8n["n8n<br/>Sync Workflows"]

    Browser -->|"Redux thunks"| Express
    Browser -->|"Marketplace SDK"| ST
    Express -->|"Integration SDK"| ST
    Express -->|"Service role"| SB
    Express -->|"tsdav + ical.js"| Davis
    Express -->|"meilisearch client"| Meili
    n8n -->|"Supabase → Meili sync"| Meili
    n8n -->|"Seat tracking"| SB
    n8n -->|"Webhooks"| ST

ActivityFox is a multi-service platform. Each service owns a specific domain; the Express.js API server orchestrates between them.

Service Boundaries

%%{init: {'theme': 'neutral'}}%%
graph LR
    subgraph Frontend
        SPA["React SPA<br/>shadcn/ui · Tailwind · Redux"]
    end

    subgraph "Express.js API"
        API["API Router<br/>server/apiRouter.js"]
    end

    subgraph "External Services"
        ST["Sharetribe<br/>Users · Listings<br/>Transactions · Payments"]
        SB["Supabase Cloud<br/>Activities · Sessions<br/>Preferences · Vendor Signups"]
        Davis["Davis CalDAV<br/>Calendars · Events<br/>Recurrence (rrule)"]
        Meili["Meilisearch<br/>sessions index<br/>activities index"]
        n8n["n8n Workflows<br/>Sync · Seat Tracking<br/>Like Counts"]
    end

    SPA --> API
    SPA -->|"Marketplace SDK"| ST
    API -->|"Integration SDK"| ST
    API -->|"@supabase/supabase-js"| SB
    API -->|"tsdav + ical.js"| Davis
    API -->|"meilisearch client"| Meili
    n8n --> SB
    n8n --> Meili
    n8n --> ST

What Lives Where

ServiceData OwnedWhy
SharetribeUser accounts, marketplace listings, transactions, paymentsCore marketplace primitives — auth, payments, trust
SupabaseActivities, sessions, child preferences (likes, connections, interests), vendor signupsRelational data that doesn't fit Sharetribe's publicData/privateData model
Davis (CalDAV)Calendars, events, recurrence rulesStandard calendar protocol with native rrule support
MeilisearchSearch indexes (sessions, activities)Fast faceted search with geo, compatible with Algolia InstantSearch
n8nWorkflow definitionsBackground sync jobs — no persistent data

Data Flow

Session Publish Pipeline

When a vendor publishes a draft session, four systems are updated in a single API call:

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Vendor as Vendor Browser
    participant API as Express API
    participant SB as Supabase
    participant ST as Sharetribe
    participant Davis as Davis CalDAV
    participant MS as Meilisearch

    Vendor->>API: POST /api/sessions/publish
    API->>SB: Read session + parent activity
    SB-->>API: Session and activity data

    API->>ST: Create listing<br/>(stock, price, publicData)
    ST-->>API: listingId

    API->>SB: Update session<br/>(listing_id, status=published)

    API->>Davis: Create calendar +<br/>WEEKLY recurring events
    Davis-->>API: calendarId
    API->>SB: Update session<br/>(caldav_calendar_id)

    API->>MS: Index to sessions +<br/>activities indexes
    API-->>Vendor: 200 OK

Data Derivation

Supabase is the source of truth for activity and session data. Other systems hold derived copies:

%%{init: {'theme': 'neutral'}}%%
graph TD
    SB["Supabase<br/>(source of truth)"]
    ST["Sharetribe Listing<br/>(bookable copy)"]
    Davis["CalDAV Calendar<br/>(schedule copy)"]
    MS["Meilisearch Index<br/>(searchable copy)"]

    SB -->|"on publish"| ST
    SB -->|"on publish"| Davis
    SB -->|"on publish / n8n sync"| MS

Background Sync (n8n)

WorkflowTriggerFlow
Full index syncCron scheduleSupabase → read all published sessions → rebuild Meilisearch indexes
Seat trackingSharetribe transaction webhookTransaction event → update seats_remaining in Supabase → update Meilisearch
Like countCron scheduleAggregate child_likes per activity → update likeCount in Meilisearch activities index

Server Utilities

FilePurpose
server/api-util/supabaseClient.jsSupabase client with requireSupabase() factory
server/api-util/meilisearchClient.jsMeilisearch client with index initialization
server/api-util/davisClient.jstsdav client factory, ICS parsing/building, vendor provisioning
server/api-util/integrationSdk.jsSharetribe Integration SDK singleton
server/api-util/childOwnership.jsBidirectional parent-child ownership verification
server/api-util/crypto.jsAES-256-GCM encryption for child credentials

Key Design Decisions

DecisionChoiceRationale
Session storageSupabase CloudSharetribe publicData won't scale for structured session queries
Listing modelOne Sharetribe listing per sessionClean stock/availability tracking, no publicData overflow
SearchMeilisearch + Algolia InstantSearch adapterAPI-compatible with Algolia client libraries, self-hosted
Component strategyNever modify Sharetribe originalsCreate replacements and swap at route level for upstream rebase safety
Data flowRedux ducks onlyNo fetch() in components — consistency and testability
CalDAV vendor accountsAuto-provision on first session publishZero vendor friction

On this page