Ultra-fast, ultra-clean log aggregation. Grafana capabilities with Linear aesthetics.
- Frontend: React Router v7, Tailwind CSS, TanStack Query, Recharts
- Backend: Fastify 5, Drizzle ORM, Better Auth, BullMQ
- Database: TimescaleDB (PostgreSQL time-series extension)
- Cache/Queue: Redis
- Deploy: Docker Compose on Coolify VPS
piglog/
├── apps/
│ ├── api/ # Fastify backend (port 3001)
│ └── web/ # React Router frontend (port 3000/5173)
├── packages/
│ ├── contracts/ # Shared Zod schemas + types
│ └── db/ # Drizzle schema, migrations, client
├── ops/docker/ # Dev infrastructure compose
├── compose.prod.yml # Production stack
cp .env.dev.example .env.dev.env.dev is gitignored and contains local-only credentials. It's already pre-filled with sensible defaults for localhost development.
npm run dev:infraThis starts TimescaleDB (pg18-oss) and Redis in Docker with persistent volumes.
npm install
npm run db:migrateThis runs all .sql migrations in order and tracks them in a _migrations table.
You'll need 3 terminal sessions:
# Terminal 1 - API (port 3001)
npm run dev:api
# Terminal 2 - Background workers (alerts, webhooks)
npm run dev:worker
# Terminal 3 - Web dev server (port 5173)
npm run dev:webThe API and workers automatically load .env.dev via dotenv. The web app proxies /api requests to localhost:3001 and falls back to the same URL for API calls.
Client → POST /logs/ingest (API Key)
→ Validate source
→ Batch insert into TimescaleDB hypertable
→ Queue alert evaluation (BullMQ)
→ HTTP 202 Accepted
Browser → GET /logs/query?workspaceId=...&service=...
→ Auth session check
→ Drizzle query with time-based chunk exclusion
→ Return 500 rows max (virtualized on frontend)
BullMQ Worker (alert:evaluate)
→ Every minute or per-batch trigger
→ Count logs in time window
→ Compare against alert_rule threshold
→ If triggered: queue webhook notification
- Hypertables:
log_entrypartitioned by time - Compression: Enabled after 7 days, segmented by workspace/service/level
- Retention: Automatic cleanup after 90 days
- Chunk Exclusion: Fast time-range queries
cp .env.example .env.prod
# Fill in production values
docker compose -f compose.prod.yml --env-file .env.prod up -dServices:
timescaledb- Databaseredis- Cache & BullMQ brokermigrate- One-off database migrationsapi- Fastify HTTP APIworker- BullMQ background workersweb- React Router SSR/static served
For Dockerfile-based deploys on Coolify, run database migrations separately from the API container.
- The API image now starts the HTTP server only.
- Run migrations with the same image using:
node packages/db/dist/migrate.js - In Coolify, use a separate job/service for migrations before deploying the API app.
- Point the API app to port
3001unless you explicitly setPORTto something else.
This project reuses the following patterns from the original repo:
- Container structure (web + api + db + redis)
- Better Auth integration with workspace multi-tenancy
- Billing/Stripe scaffolding
- Notification engine
- Webhook delivery system with retries
- Docker production setup
- React Router framework mode configuration
- Tailwind + dark theme styling
Private