The Problem

Freelancers must juggle invoicing, time‑tracking, receipt reconciliation, file storage and financial reporting across many SaaS tools. Switching between Stripe, Plaid, Supabase, email, and a custom UI creates context‑switch cost and data inconsistency.

What This Does

midday is a monorepo that bundles the back‑end API, a Next.js dashboard, a Tauri desktop client and supporting libraries into a single code base.

  • The API lives under apps/api/src/ – e.g. apps/api/src/ai/agents/main.ts wires AI‑driven assistants, while apps/api/src/rest/routers/* expose REST endpoints for invoices, bank accounts, and file vaults.
  • The dashboard UI is in apps/dashboard/ and uses React, Tailwind, and the shared UI primitives from packages/ui/.
  • Core business logic (invoice templates, DB queries, notification helpers) resides in packages/ and is imported by both API and UI layers.

How It Is Wired

Execution starts at the API entry point apps/api/src/index.ts, which creates a Bun server, registers middleware (apps/api/src/rest/middleware/*) and mounts the tRPC router defined in apps/api/src/trpc/routers/_app.ts.

  • Request flow – A typical request (e.g. GET /api/invoices) hits the router in apps/api/src/rest/routers/invoices.ts, which calls service functions in apps/api/src/services/supabase.ts. The Supabase client (createClient) is defined in apps/api/src/services/supabase.ts (3 functions, called from 8 places). This client performs the only database write/read observed (packages/supabase/src/queries/index.ts).
  • AI agents – Calls to apps/api/src/ai/agents/* are triggered from the same API entry point via the main.ts agent dispatcher. Each agent ultimately uses utility functions such as getUserContext (apps/api/src/ai/utils/get-user-context.ts) and tool-helpers to fetch data from Supabase or external APIs.
  • File I/O – The only filesystem interaction is in apps/dashboard/src/components/bank-connect-button.tsx (reads/writes a file for the “Connect Bank” flow).
  • Cryptographic work – A single secret‑generation helper lives in packages/ui/src/utils/cn.ts (used by 25 files).
  • High‑impact hubs – packages/ui/src/utils/index is imported by 50 modules (instability 0.04), making it a low‑risk but critical utility surface. Conversely, apps/api/src/trpc/routers/_app imports 29 other modules (instability 0.97) and is a change‑sensitive hub.
  • Call concentration – The function cn is called from 25 files; createClient from 11 places; set from 10 places. These are the narrowest blast‑radius points that, if altered, affect many downstream components.

No circular import cycles were detected, and the internal call graph contains 109 resolved edges, indicating a relatively flat dependency structure.

How To Use It

# Clone the repo
git clone https://github.com/moses-y/midday.git
cd midday

# Install dependencies (Bun is the package manager used)
bun install

# Build and run the API container
docker build -f apps/api/Dockerfile -t midday-api .
docker run -p 3000:3000 midday-api

# Start the dashboard locally
cd apps/dashboard
bun dev   # uses next.config.ts and tailwind.config.ts
  • Env files – apps/api/.env-template lists required variables (Supabase keys, OpenAI/Gemini tokens, Resend API). Copy to .env before starting.
  • Database – The API expects a Supabase instance; the schema is defined in apps/api/src/schemas/*.ts.
  • Desktop client – Build with Tauri: cd apps/desktop && bun tauri dev (requires Rust toolchain, see apps/desktop/src-tauri/Cargo.toml).

If any of these files are missing (e.g., a concrete docker-compose.yml), the steps above reflect the only documented build paths.

Real‑World Use

A freelancer runs the API on Fly.io, the dashboard on Vercel, and connects their bank via Plaid. When a new receipt lands in the inbox, the API webhook (apps/api/src/rest/routers/webhooks/*) stores the file, triggers apps/api/src/ai/agents/transactions.ts to classify it, and updates the Supabase transactions table via packages/supabase/src/queries/index.ts. The dashboard instantly reflects the new entry thanks to Supabase realtime.

Code Health & Issues

SeverityIssueLocation
HighPin third‑party GitHub Actions to a commit SHA.github/workflows/*
HighCI does not run the test suite.github/workflows/*
MediumLeast‑privilege GITHUB_TOKEN permissions missing.github/workflows/beta-dashboard.yaml
MediumNo Dependabot/Renovate configurationRepository root
MediumDocker base image not pinned by digestapps/api/Dockerfile
MediumNo dependency‑vulnerability scan in CI.github/workflows/*
MediumLarge binary (notification-center.gif) stored in repoapps/website/public/images/
MediumDockerfile runs as rootapps/api/Dockerfile
LowMissing convention files (.editorconfig, .gitattributes)Repository root

These findings come directly from the static analysis pipeline; no additional subjective issues are listed.

The Bottom Line

midday delivers a full‑stack freelance‑business platform with a clear separation of API, UI and shared libraries, and its code base is reasonably modular aside from a few high‑instability hubs. Production readiness is hampered by CI gaps, unpinned dependencies and container hardening omissions. Teams comfortable managing Supabase, Bun and Docker can adopt it, but should address the highlighted health items before scaling.