Skip to content

owittek/avisio

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,570 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Avisio — The Cashflow CFO

Bookkeeping tells you what you earned. Your bank tells you the balance. Neither tells you the number you actually care about: how much can you spend this month without running short on taxes later?

Avisio answers that. It's a financial planning tool for freelancers and small service businesses in Germany. Connect your accounts, set your tax and reserve rules once, and it keeps a running figure for what's safely spendable ("Verfügbarer Betrag"), alongside reserve coverage, net worth, and a year-end tax projection.

It is not a bookkeeping tool. No invoices, no receipt scanning, no VAT pre-registration. That's Lexware's job. Avisio sits on top and plans the future instead of documenting the past.

The built-in agent, Navi, works on your real numbers rather than generic advice. It explains why a figure moved, simulates a decision before you commit to it, flags risks like client concentration or a shrinking runway, and can build a dashboard widget on the spot when the standard view doesn't show what you need.

The full product vision lives in docs/VISION.md.

Tech Stack

Bun is the only package manager and runtime. The app is Next.js 16 (App Router) with React 19.

  • Database: PostgreSQL on Neon, accessed through Drizzle ORM. We run a vendored drizzle-kit fork (vendor/drizzle-kit/) for virtual generated columns and non-interactive migrations.
  • API: tRPC for everything internal. REST is reserved for auth, webhooks, cron, OAuth, SSE streaming, and uploads. See docs/CLAUDE.md for the full list.
  • Auth: Better Auth, including its OAuth provider.
  • AI (Navi): Vercel AI SDK across Anthropic, Google, OpenAI, and Moonshot, plus MCP. Max-tier users bring their own API keys, encrypted with AES-256-GCM.
  • Billing: Stripe, with Free, Pro, and Max tiers.
  • Banking: Enable Banking for live balances and recurring-transaction detection.
  • Accounting: Lexware sync for plan-versus-actual comparison.
  • Money: NUMERIC(15,2) columns and Decimal.js arithmetic. Never floats.
  • i18n: next-intl, with German as the source locale and English alongside it.
  • Testing: Vitest for unit and integration, Playwright for e2e.
  • Observability: Sentry, PostHog, Pino.

Prerequisites

  • Bun 1.3 or newer
  • Docker, running, for the local Postgres database
  • psql and jq on your PATH. The setup scripts call both.

Setup

1. Environment file

.env is checked in as a documented template. Copy it and fill in the gaps:

cp .env .env.local

Everything reads from .env.local. The template lists every variable with a comment, but most are optional and only switch on a specific integration. The four below are validated at startup by lib/env.ts, so the server refuses to boot without them:

Variable Notes
DATABASE_URL Postgres connection string. The local-DB script fills this in for you (see step 2).
BETTER_AUTH_SECRET Generate one with openssl rand -base64 32.
BETTER_AUTH_URL http://localhost:3000 for local work.
NEXT_PUBLIC_APP_URL Same URL as above. Must be a valid URL or the parse fails.

Everything else is optional and gates a feature when set. Leave it blank and that feature stays off:

Group Variables What it unlocks
Encryption MASTER_KEY_B64, MASTER_KEY_ID BYOAI key storage. Needed before a user can save their own AI key.
AI DEFAULT_AI_API_KEY Platform-managed Navi on the lower tiers.
Email RESEND_API_KEY, EMAIL_FROM Transactional email. Without it, verification mails are skipped.
Billing NEXT_PUBLIC_BILLING_ENABLED, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, the STRIPE_PRICE_* set Stripe checkout and the subscription pages. Run bun scripts/seed-stripe-products.ts to create the prices.
Banking ENABLE_BANKING_ENABLED, ENABLE_BANKING_APP_ID, ENABLE_BANKING_PRIVATE_KEY Live bank connections.
Google login GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET The Google social provider. Redirect URI is $BETTER_AUTH_URL/api/auth/callback/google.
Observability NEXT_PUBLIC_SENTRY_DSN, SENTRY_AUTH_TOKEN, NEXT_PUBLIC_POSTHOG_KEY, NEXT_PUBLIC_POSTHOG_HOST Sentry and PostHog.
Cron / Lexware CRON_SECRET, LEXWARE_WEBHOOK_URL Scheduled jobs and the Lexware webhook.

2. Local database

The fastest path is the bootstrap script. It allocates a port for your branch, starts the Docker containers, points .env.local at the local DB, and runs migrations in one go:

bun install
bash scripts/local-db-init.sh

The script saves your current .env.local as .env.cloud the first time it runs, so keep your non-DB config (auth secret, API keys) in .env.local before running it. After that, the two files are how the env switcher tells local and cloud apart:

bun env:local      # rewrite .env.local to use local Docker Postgres
bun env:prod        # restore the cloud config from .env.cloud
bun env:status      # show which one is active

If you'd rather wire it up by hand, the Docker stack is a Postgres 18 container plus a local Neon HTTP proxy (the app talks to Postgres over @neondatabase/serverless):

bun docker:up      # start Postgres + neon-proxy
bun db:setup       # pre-migrate SQL, migrations, post-migrate SQL

Local Postgres has no role separation, so DATABASE_URL, DATABASE_URL_APP, and DATABASE_URL_SECRETS all point at the same database. In the cloud, DATABASE_URL_APP connects as a restricted role with row-level security enforced.

3. Run it

bun dev

bun dev runs behind portless on the avisio.lvh hostname, so open the URL it prints (https://avisio.lvh.me) rather than localhost:3000.

Common Commands

Command What it does
bun dev Dev server
bun build / bun start Production build, then serve
bun typecheck tsc --noEmit
bun test <file> Run tests for the files you touched
bun test:unit / bun test:integration Targeted runs
bun test:e2e Playwright
bun lint ESLint
bun i18n:check Catch missing translations
bun knip Find unused code and dependencies

Database

Command What it does
bun db:generate Generate migration SQL from the schema
bun db:migrate Apply migrations
bun db:setup Pre-migrate SQL, migrate, post-migrate SQL
bun db:studio Open Drizzle Studio
bun db:branch / bun db:branch:delete Manage Neon branches

To change the schema: edit lib/db/schema/index.ts, run bun db:generate, review the SQL, then bun db:migrate. Migrations have to be idempotent. The vendored drizzle-kit is documented in docs/VENDORED_DRIZZLE_KIT.md.

Project Structure

app/            Next.js App Router. Pages under app/[locale]/, routes under app/api/
components/     React components
lib/            Core logic: db, auth, ai, financial-core, calculations,
                reserves, trpc, stripe, enable-banking, mcp, and more
messages/       Translation catalogs (de.json, en.json)
docs/           Vision, architecture, plans, runbooks
scripts/        DB setup, env switching, key rotation, seeding
vendor/         The drizzle-kit fork

Conventions

Some of these are enforced by hooks in .claude/hooks/. The rest live in CLAUDE.md.

  • Money is NUMERIC(15,2) plus Decimal.js, never floats.
  • Deletes are soft, via deleted_at. Nothing is ever hard-deleted.
  • Every mutation filters on userId in its WHERE clause.
  • Financial mutations are audit-logged, for GoBD compliance.
  • UI text goes through t('key'). No hardcoded strings.
  • Before building a component, check the shadcn registries for one that already exists.

Documentation

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages