Skip to content

Project Architecture

OpenQuok's architecture — project layout and key files for the social scheduler.

12 min read

Connect your agent today

Draft from chat, review in your calendar, and publish only what you approve.

Start for $0

Overview

The repository is a pnpm monorepo: the root holds the workspace manifest, shared tooling, and top-level packages.

The customer-facing SvelteKit app lives in web/. It serves the marketing site, and authenticated product UI. The docs runtime (content loading, navigation, search) lives under web/src/lib/docs/.

Tech stack

  • PNPM workspace
  • Supabase DB & Auth
  • Express.js
  • Svelte 5
  • Tailwind CSS
  • DaisyUI
  • Redis
  • Stripe
  • Resend
  • Sentry
  • Vercel

Runtime architecture

OpenQuok has three main services, programmatic clients, and four external systems. The web app and API talk over HTTP; with bullmq transport, the API enqueues Flowcraft runs to Redis and orchestrator workers execute them. External systems usually run outside the app process.

  • Web — SvelteKit UI; talks to the backend API.
  • Backend API — Express API, Supabase assets, and workflow enqueue.
  • Orchestrator — BullMQ workers for posts, email, and token refresh.
  • Programmatic clients — CLI, SDK, and MCP against the public API.
  • Supabase — Postgres, Auth, and optional Storage buckets.
  • Redis / BullMQ — Job queues and shared cache between API and workers.
  • Storage — User media (Supabase Storage, R2, or local disk in self-host).
  • Resend — Transactional email when EMAIL_ENABLED is enabled.

Maintenance mode — When MAINTENANCE_MODE=freeze_writes is set, mutations are blocked while public SEO pages stay live. See Maintenance mode.

Web

The web app is what users see in the browser — workspace, admin, and in-app docs.

Backend API

The backend coordinates product logic: REST API for the web and public clients, Supabase migrations and RLS, and uploads.

Orchestrator

Orchestrator workers run Flowcraft graphs backed by BullMQ. They handle:

  • Publishing scheduled content to social platforms
  • Refreshing OAuth tokens for connected integrations
  • Sending notification and digest email
  • Reconciling missing scheduled posts

See Orchestrator workflows.

Programmatic clients

The CLI, Node SDK, and hosted MCP server call /api/v1/public/*. The CLI may use the device-flow auth server in agent/server/ for login — see Auth server architecture.

Project Layout

Repository layout at the root:

  • LICENSE
  • README.md
  • .backups/
    • README.md
    • migration/
  • .cursor/
    • rules/
  • agent/
    • server/
    • skills/
    • src/
  • backend/
  • common/
  • infra/
    • self-host/
    • docker-compose.yml
  • orchestrator/
  • web/
  • sdk/
  • scripts/
  • package.json
  • pnpm-workspace.yaml
  • railway.toml
  • vercel.backend.json
  • vercel.web.json
  • agent/ — Published as @openquok/auto-cli: the programmatic CLI, agent skills under skills/, and the OAuth2 device-flow auth server in server/. See Getting Started - CLI and Configuration - Agent.
  • .backups/ See Supabase backup.
  • backend/ — Supabase project assets (migrations, RLS, modules) and the Express API that talks to Supabase (database + auth, and Storage).
  • common/ — Shared workspace package (`openquok-common`): types and small utilities imported by backend/ and orchestrator/ (for example notification email types).
  • .github/ — CI workflows (for example release automation under workflows/).
  • infra/ — Docker Compose and self-host env templates. Dev dependencies live in infra/docker-compose.yml; the full operator stack is under infra/self-host/. See Docker Compose.
  • orchestrator/ — Workspace package: Flowcraft blueprints, BullMQ adapters, and worker entrypoints. See Orchestrator workflows, Configuration - Worker, and Railway (workers).
  • .railway/ — Railway infrastructure-as-code (railway.ts); local CLI backups under this folder are gitignored. Worker deploy also uses per-flavor orchestrator/railpack.*.json configs.
  • sdk/ — Published as @openquok/node-sdk: a typed Node.js client for the programmatic API.
  • scripts/ — Monorepo automation: Vercel env sync/deploy helpers (vercelSync*.mjs, vercelDeploy*.mjs), Railway worker service setup (railwaySetupWorkerService.mjs), and prod-backup/ for Supabase export/restore scripts.
  • web/ — SvelteKit frontend; public static files live under web/static/.
  • .cursor/ — Cursor rules that encode repository conventions. Contributors and agents should follow the matching .cursor/rules/*.mdc files when editing code or using them as chat context in each area.

Key Directories

backend/

  • backend/
    • api/
    • handler/
    • app.ts
    • config/
    • connections/
    • controllers/
    • data/
    • emails/
    • errors/
    • guards/
    • integrations/
    • mcp/
    • middlewares/
    • public/
    • repositories/
    • routes/
      • publicApi/
    • scripts/
    • services/
    • supabase/
    • swagger/
    • tests/
    • types/
    • utils/
  • api/ and handler/ — HTTP entrypoints shaped or types for Vercel. Use them as the deployment shell.
  • services/ — Domain orchestration and use-cases; this layer is also where caching belongs when you need to reuse or shorten expensive work across requests (in-memory, keyed stores, or upstream cache). Services may also call `openquok-orchestrator` to enqueue Flowcraft runs.
  • supabase/ — Database source of truth: modular SQL under db/ tables, RLS, functions, seeds, and migration files.
  • integrations/ — Social provider adapters (OAuth, publish, analytics) consumed by services and orchestrator activities.
  • routes/publicApi/ — Programmatic API surface mounted at /api/v1/public/* (SDK, CLI, MCP clients).
  • mcp/ — Hosted MCP server tools and auth wired into the API process.
  • swagger/ — OpenAPI JSDoc sources merged into /api/v1/openapi.json for docs and SDK alignment.
  • repositories/, controllers/, routes/ — Persistence adapters, request/response handling, and route tables; prefer Supabase clients and SQL in migrations over ad hoc SQL in the web app.
  • middlewares/, errors/, connections/, config/, types/, utils/, data/, guards/ — Cross-cutting behavior (including maintenanceMode.ts write-freeze), Supabase/client wiring, shared types, helpers, and supporting data fixtures or reference payloads.
  • emails/ — Transactional templates and send flows.
  • scripts/ and tests/ — Migration aggregation (aggregate_migrations_all.mjs), one-off backend scripts, and automated tests.
  • Storage — User or system files go through Supabase Storage (buckets and policies live with the rest of the backend).

orchestrator/

  • orchestrator/
    • adapters/
    • activities/
    • blueprints/
    • flows/
    • nodes/
    • stores/
    • worker/
    • scripts/
    • index.ts
  • blueprints/ and nodes/ — Flowcraft graph definitions (scheduled social posts, notification email, integration token refresh).
  • flows/ — Workflow implementations and reconciliation helpers (for example missing scheduled post rescans).
  • adapters/ — BullMQ transport: enqueue helpers used from the API and worker bootstrap code.
  • worker/ — Process entrypoints plus health checks and Sentry init.
  • activities/ — Side-effecting steps invoked from flows (publish, email send, OAuth refresh).
  • stores/ — Redis-backed state for rate limits and notification digests.
  • scripts/ — Operator utilities (env validation, queue cleanup, Railway env setup).

When config/orchestratorFlows.ts keeps transport on in_process, the API runs flows inline; with bullmq, these workers execute jobs from Redis queues shared with the API.

agent/

  • agent/
    • src/
      • commands/
    • server/
      • app.ts
    • skills/
      • openquok-core/
    • tests/
    • package.json
    • tsup.config.ts
  • src/ — CLI implementation published as @openquok/auto-cli (`openquok` binary): auth, posts, integrations, analytics, uploads, and config commands.
  • server/ — Standalone OAuth2 device-flow auth server (Postgres-backed device codes, token polling). Deployed separately from the main API; the web app proxies browser routes under web/src/routes/(public)/cli/device.
  • skills/ — Agent skill packs (for example openquok-core) with channel recipes, provider settings, and command references for MCP clients.
  • tests/ — Vitest unit tests and CLI e2e helpers.

See Auth server architecture for the device-login sequence and endpoint map.

infra/

Docker and self-host operator assets:

  • infra/
    • docker-compose.yml
    • self-host/
      • docker-compose.yml
      • .env.example
  • infra/docker-compose.yml — Contributor development environment only.
  • infra/self-host/ — full stack: Redis, API, web, BullMQ workers, uploads volume; optional `cli` profile for Postgres + agent server. Default UI: http://localhost:4007.
  • infra/self-host/.env.example — Template for self-host env vars; operators copy to `.env` beside the Compose file.

User-facing bring-up steps live under Installation (especially Docker Compose — open the UI at http://localhost:4007 after up —build).

web/

The SvelteKit app root:

  • web/
    • package.json
    • web-config.json
    • static/
    • src/
      • content/
      • data/
        • docs.ts
        • icons.ts
      • lib/
        • area-admin/
        • area-protected/
        • area-public/
        • core/
        • ui/
      • params/
      • routes/
        • (auth)/
        • (docs)/
        • (legal)/
        • (protected)/
        • (public)/
        • maintenance/
      • styles/
      • tests/
  • src/routes/ — File-based routing. Route groups (public), (auth), (protected), (docs), (legal) share layouts and auth boundaries without affecting the URL prefix. maintenance/ is the write-freeze landing page when MAINTENANCE_MODE=freeze_writes (see src/lib/maintenance/ and hooks.server.ts).
  • src/data/ — Small typed registries and config imported from $data/…(e.g. `docs.ts`, `icons.ts`).
  • src/lib/core/ — HttpGateway, cookies, shared presenters that sit next to I/O. DTOs from the API are parsed here and in repositories, not in `.svelte` files.
  • src/lib/area-admin/, src/lib/area-protected/, src/lib/area-public/ — Page-level presenters, including admin console, signed-in app, public/marketing and etc. Routes import singletons from these indexes.
  • src/lib/ui/ — Reusable UI components (buttons, dialogs, docs chrome, DaisyUI-styled patterns). Feature routes pass view models and callbacks into these components.
  • Theming (DaisyUI) — Styling favors semantic DaisyUI + Tailwind tokens (bg-base-100, text-base-content, border-base-300, primary, and etc.) so theme presets swap via CSS variables instead of hand-maintained color pairs per component.
  • src/content/ — Markdown sources for the in-app docs site.
  • static/ — Public assets (favicon, PWA icons, README images).

Presenters, repositories, and tests

We keep Svelte focused on layout and inputs, and push behavior into layers you can test without the DOM or a real API:

LayerRoleTypical files
UI (Svelte)Render view models; forward user actions via callbacks. Parent routes own the page presenter.*.svelte under routes/ and $lib/ui/
PresenterView-specific state (status, toasts and etc), actions that call repositories.*.presenter.svelte.ts
RepositoryDomain state as programmer models; maps DTOs ↔ domain; calls the gateway.*.repository.svelte.ts
Gateway / infrastructureHTTP and other I/O; DTOs at the boundary.$lib/core/ (e.g. HttpGateway)

Why separate repository and presenter?

Repositories encode business rules and data shape (what the app believes is true). Presenters encode how a screen behaves (loading, errors, which *Vm the template sees).

Splitting them means you can unit test presenters with a stubbed repository and unit test repositories with a stubbed gateway—asserting on state and return values instead of rendering components or running end-to-end tests for every branch. That matches the goal: test view-model and domain behavior, not the DOM.

Convention reference: The full rules (page vs child components, toast wiring, *Pm / *Vm naming, Get* presenters) live in the repo at .cursor/rules/web-repository-presenter-architecture.mdc for contributors.

Document Directories

src/content/docs/

This is where in-app documentation markdown lives. Each .md file becomes a page; URLs follow the folder path.

Sidebar tabs and section order are declared in src/lib/docs/constants/config.ts as docsTabs: General, Cloud, Self-hosting, CLI, MCP, Public API, Contributing.

  • src/content/docs/
    • getting-started/
    • channels/
    • creating-posts/
    • posts-management/
    • settings/
    • platforms/
    • automations/
    • cloud/
    • getting-started-for-dev/
    • installation/
    • configuration-backend/
    • configuration-web/
    • configuration-worker/
    • configuration-agent/
    • admin/
    • social-integration/
    • getting-started-for-cli/
    • cli-usages/
    • cli-examples/
    • agent-setup-guides/
    • other-skills/
    • getting-started-for-mcp/
    • mcp-examples/
    • mcp-references/
    • mcp-setup-guides/
    • getting-started-for-public-api/
    • public-api-providers/
    • oauth2-for-apps/
    • apis-integrations/
    • apis-posts/
    • apis-analytics/
    • apis-notifications/
    • apis-uploads/
    • developer-guidelines/
    • contribution-opportunities/
    • publish-listings/
    • documentation-contribution/
  • General tab — Product usage under getting-started/, channels/, creating-posts/, posts-management/, settings/, platforms/, and automations/.
  • Self-hosting tab — Operator install and config: installation/ (including maintenance-mode.md), configuration-*, admin/, and social-integration/.
  • Public API tabgetting-started-for-public-api/, public-api-providers/, apis-*, and oauth2-for-apps/.
  • Contributing tabdeveloper-guidelines/, contribution-opportunities/, publish-listings/, and documentation-contribution/.

src/lib/docs/

The documentation engine:

  • constants/config.ts — Defines docs site metadata, docsTabs (General, Cloud, Self-hosting, CLI, MCP, Public API, Contributing), i18n, and assembles `docsConfig`
  • content.ts — Content loader that discovers and parses markdown files
  • navigation.ts — Generates sidebar navigation and maps paths/slugs to the active tab
  • types.ts — TypeScript types for docs, navigation, and config
  • utils/ui/tocState.svelte.ts — Table of contents state management

src/lib/ui/components/docs/

Documentation UI (layouts, MDX helpers, search, nav):

  • layout/ — Header, footers, sidebars
  • nav/ — Breadcrumbs, keyboard nav, social links
  • search/ — Command palette search
  • mdx/ — Callout, tabs, cards, and other markdown components

Configuration Files

Root (monorepo)

FilePurpose
package.jsonWorkspace scripts (pnpm filters), shared devDependencies, packageManager pin
pnpm-workspace.yamlWorkspace package globs
railway.tomlRailway deploy config for workers and related services
vercel.backend.json / vercel.web.jsonVercel project wiring templates for API and web packages
.dockerignoreExcludes local artifacts from Docker build context

Backend

FilePurpose
package.jsonScripts, dependencies, and workspace metadata for the API package
vercel.jsonVercel deployment: routes, builds, and serverless/function wiring
tsconfig.json / tsconfig.build.json / tsconfig.tsup.jsonTypeScript: editor vs production compile targets
tsup.config.tsBundles the deployable API surface
eslint.config.jsESLint rules for the backend source
jest.config.jsJest entry; see also jest.*.cjs / jest.*.js env files and babel.config.jest.cjs for test transforms

Orchestrator

FilePurpose
package.jsonWorker scripts and openquok-orchestrator package metadata
tsconfig.json / tsconfig.build.jsonTypeScript compile targets for workers
DockerfileProduction worker image (one image; Compose overrides command per queue)
railpack.*.jsonRailway buildpack configs per worker flavor
jest.config.js / jest.bullmq.config.jsUnit and BullMQ integration test entrypoints
babel.config.jest.cjsJest transform config

Agent

FilePurpose
package.jsonCLI package (@openquok/auto-cli) scripts and dependencies
tsconfig.jsonTypeScript for CLI sources
tsup.config.tsBundles the openquok CLI binary
vitest.config.mjs / run-vitest.mjsVitest runner for CLI tests
server/package.jsonAuth server dependencies and start scripts
server/tsconfig.jsonTypeScript for the device-flow server
server/vercel.jsonVercel deployment for the hosted auth server
server/DockerfileOptional self-host cli profile image

Common

FilePurpose
package.jsonopenquok-common workspace package metadata
tsconfig.jsonTypeScript compile settings for shared types and utilities

SDK

FilePurpose
package.json@openquok/node-sdk publish metadata and scripts
tsconfig.jsonTypeScript compile settings
tsup.config.tsBundles the published SDK entrypoint

Infra

FilePurpose
infra/docker-compose.ymlContributor Redis (+ optional CLI Postgres) for local dev
infra/self-host/docker-compose.ymlFull self-host stack (API, web, workers, Redis; optional cli profile)
infra/self-host/.env.exampleOperator env template (Supabase keys, Redis, OAuth apps, self-host defaults)

Web

FilePurpose
svelte.config.jsSvelteKit + MDSvex configuration
vite.config.tsVite + Tailwind CSS setup
package.jsonScripts and dependencies for the SvelteKit app
web-config.jsonWeb package metadata consumed by tooling
vercel.jsonVercel adapter and deployment settings
tsconfig.jsonTypeScript for the SvelteKit app
eslint.config.jsESLint rules for web sources
src/lib/docs/constants/config.tsDocs site title, sidebar tabs/sections, social links, locales; assembles docsConfig
src/data/docs.tsDocs site social URLs and shared docs data
Search documentation
Find a docs page
Discord Support