Skip to content

Repo Separation & Access Model

Two repositories, two access tiers, one clean boundary.


The Model at a Glance

Repo What it owns Access tier
christensen-digital/relay-platform MCP server, REST API, database, auth, billing, admin console, all server-side infrastructure ๐Ÿ”ด Restricted โ€” EC + select platform keyholders
christensen-digital/relay-app Web app, mobile app, Slack bot, shared client types, design tokens ๐ŸŸก Broader โ€” platform team + app contributors

The rule: App contributors have relay-app access only. No app contributor gets relay-platform access โ€” not even read. Platform keyholders may contribute to both.


What Each Repo Owns

relay-platform (restricted)

Everything that runs server-side or touches data directly:

  • MCP server (mcp.relayctx.com) โ€” src/relay/mcp/ โ€” all tool definitions, nudges, manicure, display
  • REST API (api.relayctx.com) โ€” src/relay/app.py, routes/, handlers/, services/
  • Database layer โ€” src/relay/db.py, migrations/ โ€” all SQL queries, schema
  • Auth, billing, legal, storage โ€” src/relay/auth.py, billing.py, legal.py, storage.py
  • Server-side integrations โ€” Stripe, SendGrid, Freshdesk, Dub (src/relay/integrations/)
  • Notification delivery โ€” src/relay/channels/ (email, push, Slack notify, web)
  • Admin console (console.relayctx.com) โ€” relay-console/ (TypeScript/Vite, operator-only surface)
  • Deployment config โ€” Dockerfile, deploy/ (systemd), .github/workflows/

relay-app (broader access)

Everything user-facing that consumes platform tooling:

  • Web SPA (app.relayctx.com) โ€” web/ โ€” TypeScript, Vite, no framework
  • Mobile app โ€” mobile/ โ€” Expo 51, React Native, Expo Router
  • Slack bot โ€” integration-slack branch โ†’ slack/ once extracted
  • Shared types + API client โ€” shared/ โ€” typed fetch client, all domain types
  • Design system tokens โ€” packages/ui/ โ€” CSS-only, no JS

Edge Cases & Decisions

Admin console stays in relay-platform. relay-console/ is an internal operator tool tightly coupled to admin API routes that only platform keyholders should touch. Keeping it in the platform repo enforces that access naturally. It is not a user-facing surface.

Slack bot belongs in relay-app. The Slack integration is a user-facing surface that calls platform MCP tools via API โ€” same pattern as the web and mobile apps. It belongs in relay-app.

Marketing/landing web assets in platform (short-term). web/relayctx/ serves static HTML from the same server as the API. Fine for now; candidate for extraction to its own repo if the landing site grows significantly.


How App Talks to Platform

App code communicates with platform exclusively over the public API surface:

Channel Endpoint Used for
REST API https://api.relayctx.com Auth, transfers, series, orgs, billing, user management
MCP server https://mcp.relayctx.com All MCP tool calls (relay_transfer_create, relay_pulse_active, etc.)

No app code imports from platform. No shared module. No monorepo link. No direct database access. The boundary is enforced structurally โ€” separate repositories with separate deploy pipelines.


Access Model

                relay-platform              relay-app
                โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€           โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Tier            Restricted                  Broader

GitHub teams    platform-core               platform-core
                                            app-contributors

Who             EC + ~3 platform            Platform team +
                engineers max               app contributors

Deploy path     GitHub Actions only         GitHub Actions only
                (never SSH to server)       

Enforcement rules:

  1. The app-contributors GitHub team has access to relay-app only โ€” never add to relay-platform.
  2. Any new contributor touching web/mobile/Slack: relay-app only.
  3. Any new contributor touching MCP server, API, or DB: requires platform keyholder vetting before any repo access.
  4. If you're unsure which repo a piece of work belongs in โ€” if it runs server-side or touches data, it's platform; if it's consumed by an end user or operator UI, it's app.

Branch & Deploy Rules (Both Repos)

  • Never push directly to main. Every push to main auto-deploys to production.
  • All changes go via branch โ†’ PR โ†’ review โ†’ merge.
  • Each distinct change gets its own branch off main โ€” don't pile onto an existing feature branch.
  • Always syntax-check before anything that could reach the server: python3 -m compileall -q src/relay/

Platform Cleanup Items

The Jun 2026 audit identified these minor housekeeping items in relay-platform โ€” none are boundary violations, all are internal tidiness:

Item Path Action
Shadow module directory platform/relay/ Remove โ€” legacy layout, not part of installed package
Consent JS duplication relay-consent.js (root), relay-console/relay-consent.js Delete both; canonical is src/relay/static/consent.js
Patch script at root patch_restore_rich_card_display.py Move to scripts/ or archive/ once applied
CF Pages worker cf-pages-notify.worker.js Move to .github/

relay-app is clean โ€” no boundary violations. Root-level Python patch scripts (patch_entity_prefixes.py etc.) are one-off migration helpers from the monolith-to-Vite TS transition; remove once applied.


Last updated: 2026-06-14 ยท Audit: relay-platform + relay-app