Skip to content

bryanmig/modash

Repository files navigation

Modash

Modash is a local dashboard and proxy for LLM-compatible API traffic. It sits between your application and an upstream API server, forwards requests, records usage metadata in Postgres, and exposes a live React dashboard for usage, throughput, model breakdowns, and recent requests.

Modash Dashboard

The current server tracks:

  • Request count, in-flight requests, latency, and per-request throughput.
  • Prompt, completion, and total token counts when the upstream response includes usage data.
  • Streaming and non-streaming request metadata.
  • Per-model token volume and tokens-per-second throughput.
  • Live dashboard refresh events over Server-Sent Events.

Repository Layout

  • apps/server: Node HTTP server, proxy, Effect services, RPC handlers, and SSE event stream.
  • apps/web: React/Vite dashboard UI.
  • packages/db: Drizzle schema, migrations, Postgres client, and usage repository.
  • packages/rpc: Shared Effect RPC procedures, schemas, DTOs, and typed errors.

Runtime Architecture

The server exposes three kinds of routes:

  • /rpc: Effect RPC endpoint used by the dashboard to fetch analytics.
  • /events: Server-Sent Events endpoint used by the dashboard to refresh when usage or request state changes.
  • All other paths: proxied to UPSTREAM_URL.

The Vite dev server runs the dashboard on port 3000 and proxies /rpc and /events to the server on port 4005. Application/API traffic should be pointed at the server port, not the Vite port.

Requirements

  • Node.js 22 or newer.
  • pnpm 10.8.1. The repo uses Corepack-compatible package metadata.
  • Docker, if you want the local Postgres service or container image.
  • A Postgres database.
  • An upstream LLM-compatible API server, for example a local OpenAI-compatible server on http://localhost:1234.

Configuration

Copy the example environment file:

cp .env.example .env

Supported environment variables:

DATABASE_URL=postgresql://modash:modash@localhost:5433/modash
UPSTREAM_URL=http://localhost:1234
PORT=4005
  • DATABASE_URL is required by the server and Drizzle migrations.
  • UPSTREAM_URL is the target that proxied requests are forwarded to.
  • PORT controls the server listen port and defaults to 4005.

The server and Drizzle config explicitly load the repo-root .env when it exists, so commands can be run from either the repo root or package directories. In containers, you can inject environment variables directly without copying a .env file.

Local Development

Install dependencies:

pnpm install

Start Postgres:

docker compose up -d postgres

Run migrations:

pnpm db:migrate

Start the app:

pnpm dev

This starts package dev tasks through Turbo:

  • Server: apps/server, usually available at http://localhost:4005.
  • Web dashboard: apps/web, available at http://localhost:3000.

Use the proxy by sending LLM API requests to the server, for example http://localhost:4005/v1/chat/completions. The server forwards the request to UPSTREAM_URL/v1/chat/completions, records usage metadata, and emits live dashboard refresh events.

Database Workflow

The schema lives in packages/db/src/schema.ts, and migrations are generated into packages/db/drizzle.

Generate a migration after changing the schema:

pnpm db:generate

Apply migrations:

pnpm db:migrate

Open Drizzle Studio:

pnpm db:studio

The default compose database is:

postgresql://modash:modash@localhost:5433/modash

Common Development Commands

Run all type checks:

pnpm type-check

Run tests:

pnpm test

Run lint:

pnpm lint

Format code:

pnpm format

Build all packages:

pnpm build

The web build currently emits a Vite chunk-size warning because the dashboard bundle is larger than 500 kB after minification. That warning does not fail the build.

Package-Specific Commands

Run only the server:

pnpm --filter @modash/server dev

Run only the dashboard:

pnpm --filter @modash/web dev

Run only database tests:

pnpm --filter @modash/db test

Run only server tests:

pnpm --filter @modash/server test

Docker Image

Build the image from the repo root:

docker build -t modash:local .

The GitHub Actions workflow in .github/workflows/docker.yml builds the image for pull requests and publishes it to GitHub Container Registry on pushes to main, version tags like v1.2.3, and manual workflow dispatches. Published images use these tags:

ghcr.io/bryanmig/modash:latest
ghcr.io/bryanmig/modash:main
ghcr.io/bryanmig/modash:sha-<commit-sha>
ghcr.io/bryanmig/modash:v1.2.3

GitHub Actions pushes with the built-in GITHUB_TOKEN, so no Docker Hub credentials are required. If the image package does not appear public after the first push, change the package visibility in GitHub under Packages -> modash -> Package settings -> Change visibility.

Run it against the compose Postgres database and a host-machine upstream service:

docker run --rm \
  --name modash \
  --network host \
  -e DATABASE_URL=postgresql://modash:modash@localhost:5433/modash \
  -e UPSTREAM_URL=http://localhost:1234 \
  -e PORT=4005 \
  modash:local

On Docker Desktop for macOS or Windows, --network host may not behave the same as Linux. Use host.docker.internal for services running on the host:

docker run --rm \
  --name modash \
  -p 4005:4005 \
  -e DATABASE_URL=postgresql://modash:modash@host.docker.internal:5433/modash \
  -e UPSTREAM_URL=http://host.docker.internal:1234 \
  -e PORT=4005 \
  modash:local

If Postgres is running in Docker Compose and the Modash container should join that Compose network, first find the network name:

docker network ls

Then run with that network and use the Compose service name postgres:

docker run --rm \
  --name modash \
  --network modash_default \
  -p 4005:4005 \
  -e DATABASE_URL=postgresql://modash:modash@postgres:5432/modash \
  -e UPSTREAM_URL=http://host.docker.internal:1234 \
  -e PORT=4005 \
  modash:local

The Docker image starts the server on PORT by running the @modash/server start script. It does not currently serve the built React dashboard as static files from the Node server; run the web app separately in development or serve apps/web/dist with your preferred static host if you need the UI in a containerized deployment.

API and Dashboard Endpoints

  • GET /healthz: Health check endpoint for Kubernetes liveness and readiness probes. Returns {"status":"ok"}.
  • GET /events: SSE stream. Emits connected, usage-updated, and request-state-updated.
  • POST /rpc: Effect RPC endpoint for dashboard analytics.
  • Any other path: proxied to the configured upstream.

The shared RPC package defines these dashboard procedures:

  • UsageSummary
  • UsageTimeseries
  • ThroughputTimeseries
  • ModelBreakdown
  • RecentRequests

RecentRequests validates page as an integer greater than or equal to 1, and pageSize as an integer between 1 and 100.

Implementation Notes

  • Effect is used for service wiring, typed effects, RPC, PubSub, and SubscriptionRef-based live state.
  • Drizzle owns the database schema and query layer.
  • The server records usage after upstream responses complete. Streaming responses are parsed from SSE payloads when possible.
  • RPC errors are tagged as shared schema values. Database-backed dashboard failures are returned as { _tag: "DatabaseError", message }.
  • The public @modash/db package surface intentionally exports only UsageRepository and repository-level types.

Troubleshooting

If the server fails on startup with a missing database URL, confirm .env exists and contains DATABASE_URL.

If migrations fail to connect, confirm Postgres is running:

docker compose ps

If the dashboard loads but shows no data, confirm the web dev server can reach the server through Vite proxy and that the server is running on PORT.

If proxied API calls fail with 502, confirm UPSTREAM_URL points at a reachable upstream server and includes only the origin, not the final request path.

If Docker cannot reach services on the host, use host.docker.internal on Docker Desktop or put the container on the same Docker network as the service.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors