Skip to content

Repo layout

Bun workspaces monorepo. Apps split into backend/ and frontend/; packages split into business/, infra/, clients/, and frontend/.

  • Directoryapps/
    • Directorybackend/
      • Directoryapi/ tRPC + Elysia HTTP server. BullMQ producer.
      • Directoryworker/ BullMQ consumer. Every async job runs here.
      • Directorydata-provider/ Centralised outbound 3rd-party calls.
    • Directoryfrontend/
      • Directoryapp/ React + Vite SPA.
      • Directorydocs/ This Starlight docs site.
  • Directorypackages/
    • Directorybusiness/ Domain logic + the wire contract.
      • Directorydomain/ Services, repositories, use cases.
      • Directoryjobs/ Async-job catalog: descriptors, schedules.
      • Directoryshared/ Frontend-safe contract (zod DTOs, Decimal).
    • Directoryinfra/ System concerns. No business knowledge.
      • Directorydb/ Drizzle schema, migrations, BaseRepository.
      • Directoryqueue/ BullMQ framework (queue, worker, scheduler).
      • Directoryemail/ Fastmail JMAP / SMTP.
      • Directorylogging/ Structured logging (pino).
      • Directorysecurity/ AES-256-GCM credential encryption.
      • Directorystorage/ S3-compatible object storage.
      • Directoryrealtime/ SSE / Redis pub-sub.
      • Directoryrate-limiter/ Per-provider rate limit + circuit breakers.
      • Directoryconfig/ Env-validation primitives.
    • Directoryclients/ Outbound network adapters.
      • Directoryproviders/ Unified 3rd-party integration package.
      • Directorycloud-client/ Typed tRPC client for the data-provider.
    • Directoryfrontend/
      • Directoryui/ Design system + shared client plumbing (@scani/ui).
  • Directoryscripts/ Workspace scripts (sync-env, …).
  • docker-compose.yml Local dev stack.
  • docker-compose.prod.yml Production-flavour compose.
  • .env.example Annotated env vars.
  • CLAUDE.md Canonical engineering spec.
  • CONTRIBUTING.md Contributor on-ramp.

tRPC over Elysia. Owns per-user credentialed integrations (exchange API keys, brokerage tokens). The api decrypts and uses those credentials on its own machine; they never leave the tenant boundary. Acts as the BullMQ producer — every user action that needs async work enqueues into Redis from here.

Routes live in apps/backend/api/src/presentation/routers/.

The BullMQ consumer. Every scheduled job (pricing, balance syncs, historical backfills, transfer linking, APY payouts, …) and every user-initiated job (screenshot parse, exchange import, wallet import, file import, …) runs here in one binary.

Processors live in apps/backend/worker/src/processors/. The cron-lock helper is in apps/backend/worker/src/lib/cron-lock.ts.

tRPC service that centralises every outbound third-party call (CoinGecko, Finnhub, DeFiLlama, OpenAI, Etherscan, Helius, …) and the email transport. The api and worker call it over tRPC rather than hitting upstream APIs directly. This is the seam between tiers — in Tier 1 it’s a sidecar on localhost:8082; in Tier 2/3 it’s a hosted endpoint.

Routers live in apps/backend/data-provider/src/presentation/.

The main React + Vite SPA. End-to-end type-safe with the api via tRPC. Source under src/v2/. Locales under src/i18n/locales/.

This site. Astro + Starlight. Pages under src/content/docs/. Custom CSS in src/styles/custom.css. scripts/generate-llms-txt.ts runs before astro build to emit public/llms.txt and public/llms-full.txt.

Things that change when the product changes.

The bulk of business logic — services, repositories, use cases. Class-field DI (see DI pattern). Tests in mirrored tests/ directories.

Per-job descriptors (payload schemas, retry policies, jobId strategies, summarisers), repeatable schedules, and the @scani/queue mirror/lock impls. The wire-name catalogue is job-names.ts.

Frontend-safe contract: zod DTOs (the tRPC wire), the project-configured Decimal.js instance, UI helpers (formatCurrency, formatRelative, emailSchema, …). Strict rule: no Node-only APIs reachable from the barrel. The frontend must be able to import any of it.

Pure system concerns. No business knowledge; reusable in any TypeScript backend.

PackageRole
@scani/dbDrizzle schema, migrations, postgres.js connection, BaseRepository.
@scani/queueAsync-coordination framework on BullMQ. Abstract bases + concrete @Service() impls.
@scani/emailFastmail JMAP / SMTP. Owns FASTMAIL_API_TOKEN / SMTP_URL.
@scani/loggingStructured logging (pino). Owns LOG_*.
@scani/securityAES-256-GCM credential encryption. Owns ENCRYPTION_KEY.
@scani/storageS3-compatible object storage. Owns S3_*.
@scani/realtimeRealtime / SSE pub-sub via Redis.
@scani/rate-limiterRate limiting + circuit breakers for upstream calls.
@scani/configEnv-validation primitives (requiredInProd, httpsUrlInProduction, …).

Outbound network adapters.

@scani/providers (packages/clients/providers)

Section titled “@scani/providers (packages/clients/providers)”

The unified 3rd-party integration package. One directory per provider under src/providers/ (CoinGecko, DeFiLlama, Kraken, Binance, IBKR, Wise, OpenAI, Solana, …). Capability-based interfaces (PriceProvider, BalanceProvider, TransactionProvider, TokenIdentityProvider, AIProvider).

See Adding a provider and Provider matrix.

@scani/cloud-client (packages/clients/cloud-client)

Section titled “@scani/cloud-client (packages/clients/cloud-client)”

Typed tRPC client for the data-provider. The api + worker call the data-provider through this rather than reaching for HTTP directly.

Design system + shared client plumbing for the SPA. Tailwind preset + CSS tokens, the full shadcn primitive set, ThemeContext, ErrorBoundary, UpdateBanner, MagicCodeInput, the useAppUpdate hook, PWA helpers, createScaniAuthClient / createTrpcProvider factories.

apps/frontend/app is the canonical source of truth for shared primitives — when promoting a new primitive into the library, copy from there.

WhatWhere
tRPC routersapps/backend/api/src/presentation/routers/
Queue names + enqueue helperspackages/infra/queue/src/{queue-names,enqueue}.ts
Worker processorsapps/backend/worker/src/processors/
Repeatable schedulespackages/business/jobs/src/scheduled-jobs/
Domain services / repos / use casespackages/business/domain/src/
DB schemapackages/infra/db/src/schema/
Drizzle migrationspackages/infra/db/src/migrations/
Provider registrypackages/clients/providers/src/
Data-provider routersapps/backend/data-provider/src/presentation/
Test preloadpackages/business/domain/test-preload.ts