Own your invoicing. VibeBooks is a self-hosted invoicing and time-tracking app for freelancers and small businesses — a FreshBooks alternative you run yourself, on your own hardware, with your data in a single SQLite file you can back up with cp.
Invoicing
- Invoices with line items, taxes, discounts, notes and terms
- Template builder with multiple designs, fonts and accent colors — deterministic PDF export
- Auto-incrementing, collision-safe invoice numbers (custom patterns supported)
- Recurring invoices with month-end-safe schedules and optional auto-send
- Public share links for clients — view online, no account needed
- Duplicate, archive, partial payments, overdue tracking
Estimates / Quotes
- Full lifecycle: draft → send → accepted / declined → convert to invoice
- Configurable document labels (e.g. "Quote", "Angebot") and validity windows
- Same templates, PDFs and public links as invoices
Get paid
- Bank sync: connect Mercury, Wise, or Slash — transactions import automatically
- Smart payment matching: incoming transactions are scored against open invoices and auto-matched or queued for one-click review
- Split matching: one bank transaction across multiple invoices
- Multi-currency with ECB rates (via Frankfurter), locked in at payment time
- Configurable payment reminders (on/off + day offsets per organization)
- Send from your own address: Gmail (OAuth) or any SMTP server
- Open tracking, reply detection (Gmail), full per-invoice conversation timeline
- Organization-wide email log: every invoice, estimate, message and reminder sent
Time tracking
- Billable hours per client/project, hour reports as PDF
- Generate invoices straight from unbilled time
Run your business
- Dashboard with customizable widgets: cash flow (received / outstanding / draft), revenue by client, aging, KPIs
- Clients & projects, CSV import (FreshBooks or generic) and CSV export (invoices, payments, clients, time)
- Multi-organization support with roles:
OWNER,ADMIN,EMPLOYEE(time-tracking only) - Complete audit log of every change — who, what, when
- Fully responsive — works on your phone
git clone https://github.com/C0RE1312/vibebooks.git
cd vibebooks
cp .env.example .env
# Generate secrets
echo "BETTER_AUTH_SECRET=\"$(openssl rand -base64 32)\"" >> .env
echo "ENCRYPTION_KEY=\"$(openssl rand -hex 32)\"" >> .env
echo "CRON_SECRET=\"$(openssl rand -hex 16)\"" >> .env
docker compose up -d --buildThe stack contains three containers:
| Container | Purpose |
|---|---|
vibebooks |
The app (Next.js standalone). Migrations apply automatically on boot. |
vibebooks-cron |
Calls /api/cron every 15 min — recurring invoices, reminders, bank sync, reply polling. |
ts-vibebooks |
Optional Tailscale sidecar serving the app privately over HTTPS inside your tailnet. |
Using Tailscale (default): set TS_AUTHKEY in .env and the app appears at https://vibebooks.<your-tailnet>.ts.net.
Not using Tailscale? Remove the ts-vibebooks service, drop network_mode: service:ts-vibebooks from the other two, add ports: ["3000:3000"] to the app, and put your own reverse proxy (Caddy, nginx, Traefik) in front. Set BETTER_AUTH_URL to your public URL.
Your entire state — SQLite database and uploads — lives in the vibebooks-data volume. Backup = copy that volume.
Requires Node 22+.
npm install
cp .env.example .env # add the three secrets as above
npx prisma migrate dev
npm run devSQLite path note: for local dev,
DATABASE_URLmust be an absolute path (e.g.file:/home/you/vibebooks/prisma/dev.db) — the Prisma CLI and the Next.js runtime resolve relative paths differently. Docker sets this for you.
| Variable | Required | Purpose |
|---|---|---|
DATABASE_URL |
✅ | SQLite file path (set automatically in Docker) |
BETTER_AUTH_SECRET |
✅ | Session signing — openssl rand -base64 32 |
BETTER_AUTH_URL |
✅ | Public URL of your instance |
ENCRYPTION_KEY |
✅ | AES-256-GCM key for bank/SMTP/Gmail credentials at rest — openssl rand -hex 32 |
CRON_SECRET |
✅ | Bearer token protecting POST /api/cron |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET |
— | Google sign-in + Gmail sending (setup) |
TS_AUTHKEY |
— | Tailscale sidecar auth key (Docker, optional) |
Sign-in with Google and sending via the Gmail API share one OAuth client. In Google Cloud Console:
- Create an OAuth 2.0 Client (Web application)
- Add
<BETTER_AUTH_URL>/api/auth/callback/googleas an authorized redirect URI - Enable the Gmail API
- Put the client ID/secret in
.env
src/app/(auth) login, signup
src/app/(app) the app — every query scoped by orgId
src/app/api auth, PDFs, exports, cron, bank discovery, tracking
src/app/public client-facing invoice/estimate pages (token-auth)
src/lib db, money (Decimal), fx, email, pdf, banking match engine
src/server/actions server actions, grouped by entity
src/server/guards.ts requireSession / requireOrg / requireOrgAdmin
prisma/ schema + hand-verified SQLite migrations
docs/ARCHITECTURE.md the full design
Design principles:
- Boring, durable stack: Next.js App Router + Prisma + SQLite. No queue, no Redis, no microservices — one container and a cron loop.
- Money is
Decimal, everywhere. Banker's rounding, per-line rounding before summing, FX locked at payment time. - Tenancy enforced in every query — all reads and writes are scoped by
orgIdat the query level, with role checks on top. - Secrets encrypted at rest (AES-256-GCM), 192-bit public tokens, security headers, role-gated API routes.
Full general-ledger accounting, expense tracking, payment-processor checkout (Stripe et al.), a public REST API, and full i18n are out of scope for now. The point is a sharp tool, not a suite.
Issues and PRs welcome. Open an issue first for non-trivial changes so scope stays tight — see non-goals above. Run docker build . to verify a change compiles (the build fails on type errors); docs/ARCHITECTURE.md is the source of truth for design decisions.
AGPL-3.0. VibeBooks should remain something you run — not something a SaaS reseller closes up and rents back to you. The AGPL guarantees hosted modifications flow back to the community.