{"id":50932023,"url":"https://github.com/kisaesdevlab/vibe-trial-balance","last_synced_at":"2026-06-17T05:04:42.047Z","repository":{"id":346260613,"uuid":"1189133317","full_name":"KisaesDevLab/Vibe-Trial-Balance","owner":"KisaesDevLab","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-10T12:46:09.000Z","size":3006,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-10T14:33:01.947Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KisaesDevLab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":"kisaes","thanks_dev":null,"custom":null}},"created_at":"2026-03-23T02:24:44.000Z","updated_at":"2026-05-10T12:46:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/KisaesDevLab/Vibe-Trial-Balance","commit_stats":null,"previous_names":["kisaesdevlab/vibe-trial-balance"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/KisaesDevLab/Vibe-Trial-Balance","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KisaesDevLab%2FVibe-Trial-Balance","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KisaesDevLab%2FVibe-Trial-Balance/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KisaesDevLab%2FVibe-Trial-Balance/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KisaesDevLab%2FVibe-Trial-Balance/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KisaesDevLab","download_url":"https://codeload.github.com/KisaesDevLab/Vibe-Trial-Balance/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KisaesDevLab%2FVibe-Trial-Balance/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34434498,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-17T02:00:05.408Z","response_time":127,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-17T05:04:27.681Z","updated_at":"2026-06-17T05:04:42.038Z","avatar_url":"https://github.com/KisaesDevLab.png","language":"TypeScript","funding_links":["https://buymeacoffee.com/kisaes"],"categories":[],"sub_categories":[],"readme":"# Vibe Trial Balance\n\nA self-hosted tax preparation and accounting workpaper application for small CPA firms. Manage trial balances, journal entries, bank transactions, tax code assignments, financial statements, and client engagements — with AI-powered diagnostics, classification, and PDF import.\n\n**License:** PolyForm Internal Use 1.0.0 ([full text](LICENSE)) — free for personal and internal firm use; distribution is not permitted. [Commercial license](COMMERCIAL_LICENSE.md) required for client-facing access. [FAQ](docs/LICENSING_FAQ.md)\n\n---\n\n## Table of Contents\n\n- [Features](#features)\n- [Architecture](#architecture)\n- [Environment Variables](#environment-variables)\n- [Development Setup (Windows)](#development-setup-windows)\n- [Deployment: Docker — Prebuilt Images](#deployment-docker--prebuilt-images) ← recommended\n- [Deployment: Raspberry Pi](#deployment-raspberry-pi)\n- [Deployment: Docker (Build from Source)](#deployment-docker-build-from-source)\n- [Deployment: Docker (Cloud / VPS)](#deployment-docker-cloud--vps)\n- [AI Provider Configuration](#ai-provider-configuration)\n- [Backup \u0026 Restore](#backup--restore)\n- [MCP Integration (Claude Desktop)](#mcp-integration-claude-desktop)\n- [License](#license)\n\n---\n\n## Features\n\n- Trial balance grid with inline editing, CSV/PDF import, prior year comparison\n- Book and tax adjusting journal entries with balance validation\n- Bank transaction import (OFX/CSV) with AI classification and reconciliation\n- Tax code management with AI auto-assignment (500+ seeded codes for 1040/1065/1120/1120S)\n- Financial statements: Income Statement, Balance Sheet, Cash Flow, Tax-Basis P\u0026L\n- Multi-period comparison with flux analysis and variance notes\n- Tax software exports: UltraTax, CCH, Lacerte, GoSystem, Generic CSV/Excel\n- Server-side PDF generation (pdfmake) for all report types\n- Workpaper package bundling with tickmarks and workpaper references\n- AI diagnostics, support chat, and scanned PDF vision-mode import\n- Document storage, backup/restore (.tbak archives), engagement checklists\n- MCP integration for Claude Desktop (18 tools, 8 resources, 5 prompts)\n- Multi-provider AI: Claude (Anthropic), Ollama (self-hosted), OpenAI-compatible (vLLM, LM Studio)\n\n---\n\n## Architecture\n\n```\nclient/          React 18 + TypeScript + Vite + Tailwind + TanStack Query/Table\nserver/          Node.js 20 + Express + TypeScript + Knex.js\ndatabase         PostgreSQL 16\nai               Anthropic SDK / OpenAI SDK (Ollama \u0026 OpenAI-compat)\npdf              pdfmake (server-side generation)\nhosting          Raspberry Pi 5 (8GB) / Docker / any Linux server\n```\n\n---\n\n## Environment Variables\n\nCreate a `.env` file in `server/` (or set these as system environment variables):\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `NODE_ENV` | *(none)* | Set to `production` for production deployments — enforces required env vars |\n| `PORT` | `3001` | Server listen port |\n| `DATABASE_URL` | *(none)* | **Preferred** — full Postgres connection string (e.g. `postgres://user:pw@host:5432/db`). Takes precedence over `DB_*` vars when set. |\n| `DB_HOST` | `127.0.0.1` | PostgreSQL host (deprecated — prefer `DATABASE_URL`) |\n| `DB_PORT` | `5432` | PostgreSQL port (deprecated — prefer `DATABASE_URL`) |\n| `DB_NAME` | `vibe_tb_db` | Database name (deprecated — prefer `DATABASE_URL`) |\n| `DB_USER` | `vibetb` | Database user (deprecated — prefer `DATABASE_URL`) |\n| `DB_PASSWORD` | `localdev123` | Database password (deprecated — prefer `DATABASE_URL`) |\n| `MIGRATIONS_AUTO` | `true` | When `false`, the server refuses to start with pending migrations. Set this in appliance/orchestrated deploys that run migrations as a separate step (`node dist/migrate.js`). |\n| `JWT_SECRET` | *(none)* | **Required everywhere** — must be ≥32 chars. Server refuses to start without it. Generate with `openssl rand -hex 32` |\n| `JWT_EXPIRY` | `8h` | JWT token lifetime |\n| `ALLOWED_ORIGIN` | `http://localhost:5173,http://localhost:3000` | **Required in production**. Comma-separated list. Entries wrapped in `/.../` are treated as regex (e.g. `/^https:\\/\\/.*\\.firm\\.com$/`). |\n| `ENCRYPTION_KEY` | *(falls back to JWT_SECRET in dev)* | **Required in production** — must be separate from JWT_SECRET. Generate with `openssl rand -hex 32` |\n| `ANTHROPIC_API_KEY` | *(none)* | Optional — can also be set in Admin \u003e Settings |\n| `APP_BASE_URL` | `http://localhost:3001` | Used in MCP integration for self-referencing URLs |\n| `STRICT_AI_URL_SAFETY` | `false` | Set to `true` to block outbound AI/OCR URLs that resolve to RFC1918 / loopback / link-local. Cloud-metadata IPs are always blocked regardless. |\n\n---\n\n## Development Setup\n\n### One-line install (Linux / macOS / Git Bash)\n```bash\ngit clone https://github.com/KisaesDevLab/Vibe-Trial-Balance.git \u0026\u0026 cd Vibe-Trial-Balance \u0026\u0026 bash setup.sh\n```\nClones the repo, installs all dependencies, starts PostgreSQL via Docker, runs migrations, and seeds demo data.\n\n### Quick start (Windows PowerShell)\n```powershell\n# PowerShell as Administrator\nSet-ExecutionPolicy Bypass -Scope Process -Force\n.\\setup.ps1       # One-time: installs Git, Node, Docker, deps, seeds DB\n.\\start.ps1       # Daily: starts backend (3001) + frontend (5173)\n```\n\n### Manual setup\n```bash\n# Prerequisites: Node.js 20+, Docker Desktop\ndocker compose up -d                         # Start PostgreSQL + pgAdmin\nnpm install                                  # Root dependencies\ncd server \u0026\u0026 npm install \u0026\u0026 cd ..\ncd client \u0026\u0026 npm install \u0026\u0026 cd ..\nnpm run migrate                              # Run all migrations\nnpm run seed                                 # Seed demo data\nnpm run dev                                  # Start both servers\n```\n\n**URLs:** Frontend http://localhost:5173 | API http://localhost:3001 | pgAdmin http://localhost:5050\n\n**First-time login:** username `admin`, password `admin1234`. The app forces you to pick a new password on first sign-in before you can reach anything else; new passwords require 8+ characters with uppercase, lowercase, and a number.\n\nSee [QUICKSTART.md](QUICKSTART.md) for detailed commands and troubleshooting.\n\n---\n\n## Deployment: Docker — Prebuilt Images\n\nThe fastest path to a running installation. Multi-arch images (`linux/amd64` and `linux/arm64`, so the same images run on a Pi) are published to GitHub Container Registry by the `Build and Publish Docker Images` workflow on every push to `main` and every `v*` tag.\n\n| Image | Pull command |\n|-------|--------------|\n| Server | `docker pull ghcr.io/kisaesdevlab/vibe-tb-server:latest` |\n| Client | `docker pull ghcr.io/kisaesdevlab/vibe-tb-client:latest` |\n\nAvailable tags:\n- `latest` — current main\n- `v1.2.3`, `v1.2`, `v1` — release tags\n- `sha-abcdef1` — specific commit (use for reproducible pins in production)\n\n### 1. Get the compose file and the env template\n\n```bash\n# Pick an install directory on the host\nmkdir -p /opt/vibe-tb \u0026\u0026 cd /opt/vibe-tb\n\ncurl -LO https://raw.githubusercontent.com/KisaesDevLab/Vibe-Trial-Balance/main/docker-compose.prod.yml\ncurl -LO https://raw.githubusercontent.com/KisaesDevLab/Vibe-Trial-Balance/main/.env.example\ncp .env.example .env\n```\n\n### 2. Fill in the required secrets\n\nEdit `.env` and set:\n\n```bash\nDB_PASSWORD=$(openssl rand -hex 24)\nJWT_SECRET=$(openssl rand -hex 32)\nENCRYPTION_KEY=$(openssl rand -hex 32)\nALLOWED_ORIGIN=http://YOUR_SERVER_IP_OR_HOSTNAME   # or https://tb.yourfirm.com\n# Optional: IMAGE_TAG=v1.2.3   — pin to a release instead of `latest`\n```\n\nCompose will refuse to start if any required value is missing.\n\n### 3. Start it\n\n```bash\ndocker compose -f docker-compose.prod.yml up -d\n```\n\nOn first boot the server runs migrations and seeds the default `admin` / `admin` account. **Change the admin password immediately after first login.**\n\n### 4. Verify\n\n```bash\ndocker compose -f docker-compose.prod.yml ps      # db, api, web all \"Up\"\ncurl http://localhost:3001/api/v1/health                 # {\"status\":\"ok\",\"database\":\"connected\",...}\n```\n\nOpen the app at `http://YOUR_SERVER_IP` (port 80).\n\n### 5. Update to a newer version\n\n```bash\ncd /opt/vibe-tb\ndocker compose -f docker-compose.prod.yml pull\ndocker compose -f docker-compose.prod.yml up -d\n```\n\nWith `IMAGE_TAG=latest`, `pull` fetches whatever `main` currently points to. For reproducible production, pin `IMAGE_TAG` to a specific `v*` tag or `sha-*` and bump it deliberately.\n\n### 6. Data persistence\n\nThree named volumes survive recreations and updates:\n\n- `pgdata` — the PostgreSQL data directory\n- `uploads` — documents uploaded through the app (`server/uploads`)\n- `backups` — `.tbak` archives written by the scheduled backup job (`server/backups`)\n\nBack these up at the host level (e.g., `docker run --rm -v pgdata:/src alpine tar …`) in addition to using the app's in-product backup.\n\n### Raspberry Pi note\n\nThe published images include `linux/arm64`, so the same `docker-compose.prod.yml` runs on a Pi 5 without any changes. Follow the steps above on the Pi — no compile step needed.\n\n### Single-app vs multi-app\n\nBy default the compose above runs Vibe TB in **single-app mode** — the SPA is served at `/`, the web container publishes port 80 to the host, and `ALLOWED_ORIGIN` points at the host's bare URL.\n\nWhen Vibe TB shares a host with other Vibe products (MyBooks, Connect, Payroll Time) behind a shared Caddy ingress, layer `docker-compose.grouped.yml` over the prod compose and set `VIBE_HOST` and `VITE_BASE_PATH=/tb/` in `.env`:\n\n```bash\ndocker network create vibe_ingress     # one-time per host\ndocker compose -f docker-compose.prod.yml -f docker-compose.grouped.yml up -d\n```\n\nThe same image runs in both modes — the web container substitutes `VITE_BASE_PATH` over the SPA assets at startup. The shared Caddy is provisioned by the [`vibe-installer`](https://github.com/KisaesDevLab/vibe-installer) repo; ad-hoc setups can stand up a Caddy attached to `vibe_ingress` with a single rule:\n\n```\nhandle_path /tb/* {\n    reverse_proxy web:80\n}\n```\n\nThat's enough — the web container's nginx already proxies `/api/*` to `api:3001` internally. `handle_path` strips the `/tb` prefix before forwarding, so the SPA's `/tb/api/v1/...` calls reach the backend as `/api/v1/...`.\n\n### Upgrading from `vibe-tb-api` / `vibe-tb-web` images\n\nThe image names changed from `vibe-tb-api`/`vibe-tb-web` to `vibe-tb-server`/`vibe-tb-client` to align with the Vibe Appliance manifest convention (see `.appliance/manifest.json`). Compose service names (`api`, `web`) are unchanged in `docker-compose.prod.yml` — only the image references changed. To upgrade:\n\n```bash\ndocker compose -f docker-compose.prod.yml down                                    # stop the old stack\ncurl -LO https://raw.githubusercontent.com/KisaesDevLab/Vibe-Trial-Balance/main/docker-compose.prod.yml\ndocker compose -f docker-compose.prod.yml up -d                                    # pulls vibe-tb-server / vibe-tb-client\n```\n\nExisting named volumes (`pgdata`, `uploads`, `backups`) are scoped by Compose project, not service, so the data carries across the rename. The previous `vibe-tb-api`/`vibe-tb-web` GHCR packages will continue to receive `latest` for one release cycle before being deprecated.\n\n### Deploying as part of Vibe Appliance\n\nFor multi-app deployments managed by the Vibe Appliance installer, this repo ships:\n\n- `docker-compose.appliance.yml` — appliance overlay (no bundled Postgres, no published ports, points at shared Postgres via `DATABASE_URL`).\n- `.appliance/manifest.json` — manifest the installer reads to wire up subdomains, env vars, migrations, and backup volumes.\n\nIn this mode, migrations and (on first install) seeds run as explicit one-shots before the API service starts:\n\n```bash\n# Always: apply pending migrations\ndocker compose run --rm vibe-tb-server node dist/migrate.js\n\n# First install only: load admin user, tax codes, COA templates\ndocker compose run --rm vibe-tb-server node dist/seed.js\n\n# Then bring the service up\ndocker compose -f docker-compose.appliance.yml up -d\n```\n\n`MIGRATIONS_AUTO=false` is set by the appliance overlay, which causes the entrypoint to skip both auto-migrate and auto-seed, AND the API refuses to start if a migration is still pending. The seed runner is idempotent (knex seed files use insert-ignore / on-conflict patterns) so it's safe to re-run if you're not sure whether the DB is fresh. The appliance's `enable-app.sh` handles this flow automatically; the manual commands above are for ad-hoc testing.\n\nEmergency-access mode (`http://\u003clan-ip\u003e:5172`) requires `ALLOWED_ORIGIN` to include that origin in the comma-separated list — the appliance synthesizes this; verify it if running the appliance compose by hand.\n\n---\n\n## Deployment: Raspberry Pi\n\nThe primary production target. Runs directly on the OS with Nginx as a reverse proxy and PM2 for process management.\n\n### Prerequisites\n- Raspberry Pi 5 (8GB recommended) with Raspberry Pi OS (64-bit)\n- External SSD recommended for database and uploads\n\n### 1. Initial setup\n```bash\n# Clone the repo\ngit clone https://github.com/kwkcp/vibe-tb.git /opt/vibe-tb\ncd /opt/vibe-tb\n\n# Run the automated setup (installs Node 20, PostgreSQL 16, Nginx, PM2)\nchmod +x deploy/setup-pi.sh\n./deploy/setup-pi.sh\n```\n\n### 2. Configure environment\n```bash\ncat \u003e /opt/vibe-tb/server/.env \u003c\u003c 'EOF'\nNODE_ENV=production\nPORT=3001\nDB_HOST=127.0.0.1\nDB_PORT=5432\nDB_NAME=vibe_tb_db\nDB_USER=vibetb\nDB_PASSWORD=YOUR_STRONG_PASSWORD_HERE\nJWT_SECRET=YOUR_RANDOM_SECRET_HERE\nENCRYPTION_KEY=YOUR_SEPARATE_RANDOM_SECRET_HERE\nALLOWED_ORIGIN=http://YOUR_PI_IP_OR_HOSTNAME\nEOF\n```\n\nUpdate the PostgreSQL password to match:\n```bash\nsudo -u postgres psql -c \"ALTER USER vibetb WITH PASSWORD 'YOUR_STRONG_PASSWORD_HERE';\"\n```\n\n### 3. Deploy\n```bash\nchmod +x deploy/deploy.sh\n./deploy/deploy.sh\n```\n\nThis builds the TypeScript server, builds the React client, copies the frontend to Nginx's web root, runs migrations, and starts/restarts PM2.\n\n### 4. Verify\n```bash\ncurl http://localhost:3001/api/v1/health   # Should return {\"status\":\"ok\"}\npm2 status                                  # Should show \"vibe-tb-server\" as online\nsudo nginx -t                               # Should show \"syntax is ok\"\n```\n\nAccess the app at `http://YOUR_PI_IP` (port 80 via Nginx).\n\n### 5. Auto-start on boot\n```bash\npm2 save\npm2 startup                                 # Follow the printed command\nsudo systemctl enable nginx\nsudo systemctl enable postgresql\n```\n\n### 6. Updates\n\nOne-line update:\n```bash\ncd /opt/vibe-tb \u0026\u0026 git pull \u0026\u0026 ./deploy/deploy.sh\n```\n\n### Optional: Scanned PDF support\n```bash\nsudo apt install poppler-utils              # Enables vision-mode PDF import\n```\n\n### Optional: Ollama for local AI\n```bash\ncurl -fsSL https://ollama.ai/install.sh | sh\nollama pull qwen3-vl:8b                     # Vision model for PDF extraction\nollama pull qwq:32b                         # Reasoning model for support chat\n# Then in app: Admin \u003e Settings \u003e AI Provider \u003e Ollama\n# Set Base URL to http://localhost:11434\n```\n\n---\n\n## Deployment: Docker (Build from Source)\n\nUse this path only when you need a local modification baked in. Otherwise the [prebuilt images](#deployment-docker--prebuilt-images) path above is faster and produces identical containers.\n\n### 1. Clone and prepare the environment\n\n```bash\ngit clone https://github.com/KisaesDevLab/Vibe-Trial-Balance.git /opt/vibe-tb\ncd /opt/vibe-tb\ncp .env.example .env\n# Edit .env — set DB_PASSWORD, JWT_SECRET, ENCRYPTION_KEY, ALLOWED_ORIGIN.\n```\n\n### 2. Build and run\n\n`docker-compose.prod.yml` itself only references prebuilt GHCR images. Layer `docker-compose.build.yml` on top to add `build:` directives that point at the in-repo `Dockerfile.server` / `Dockerfile.client`:\n\n```bash\ndocker compose -f docker-compose.prod.yml -f docker-compose.build.yml up -d --build\n```\n\nThe build overlay enforces `pull_policy: build` so Compose never tries to pull from GHCR when local sources are present. All required-secret env contracts from the prod compose still apply.\n\n### 3. Verify\n\n```bash\ndocker compose -f docker-compose.prod.yml -f docker-compose.build.yml ps\ncurl http://localhost:3001/api/v1/health\n```\n\n### 4. Updates\n\n```bash\ngit pull \u0026\u0026 docker compose -f docker-compose.prod.yml -f docker-compose.build.yml up -d --build\n```\n\n---\n\n## Deployment: Docker (Cloud / VPS)\n\nSame Docker setup as internal, with additional hardening for internet-facing deployments. Either the prebuilt-image path or the build-from-source path works; prefer the prebuilt images with `IMAGE_TAG` pinned to a `v*` release for reproducibility.\n\n### Additional steps for cloud\n\n#### 1. Add HTTPS with Let's Encrypt\n\nReplace the web container's nginx with a Certbot-enabled config, or use a reverse proxy like Caddy or Traefik.\n\n**Option A — Caddy (simplest, auto-HTTPS):**\n\nReplace the `web` service in `docker-compose.prod.yml`:\n\n```yaml\n  caddy:\n    image: caddy:2-alpine\n    restart: unless-stopped\n    depends_on:\n      - api\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n    volumes:\n      - ./Caddyfile:/etc/caddy/Caddyfile\n      - caddy_data:/data\n      - caddy_config:/config\n      - web_dist:/srv\n\nvolumes:\n  # ... existing volumes ...\n  caddy_data:\n  caddy_config:\n  web_dist:\n```\n\nCreate a `Caddyfile`:\n```\nyourdomain.com {\n    root * /srv\n    try_files {path} /index.html\n    file_server\n\n    handle /api/* {\n        reverse_proxy api:3001\n    }\n\n    handle /mcp/* {\n        reverse_proxy api:3001 {\n            flush_interval -1\n            transport http {\n                read_timeout 3600s\n            }\n        }\n    }\n}\n```\n\nBuild the SPA into a volume (uses the prebuilt `web` image's static assets):\n```bash\ndocker compose -f docker-compose.prod.yml run --rm \\\n  -v web_dist:/output web sh -c \"cp -r /usr/share/nginx/html/* /output/\"\n```\n\n**Option B — Nginx + Certbot:**\n```bash\nsudo apt install certbot python3-certbot-nginx\nsudo certbot --nginx -d yourdomain.com\n```\n\n#### 2. Set environment for cloud\n\n```bash\nALLOWED_ORIGIN=https://yourdomain.com\nAPP_BASE_URL=https://yourdomain.com\n```\n\n#### 3. Firewall\n\n```bash\n# Only allow HTTP, HTTPS, and SSH\nsudo ufw allow 22/tcp\nsudo ufw allow 80/tcp\nsudo ufw allow 443/tcp\nsudo ufw enable\n```\n\n#### 4. Database backups\n\nThe app has built-in backup (Admin \u003e Backup \u0026 Restore), but also set up external backups:\n\n```bash\n# Cron job for daily pg_dump\n0 2 * * * docker compose -f /path/to/docker-compose.prod.yml exec -T db \\\n  pg_dump -U vibetb vibe_tb_db | gzip \u003e /backups/tb-$(date +\\%Y\\%m\\%d).sql.gz\n```\n\n#### 5. Security checklist\n\n- [ ] Set `NODE_ENV=production` in `server/.env`\n- [ ] Change default `admin` / `admin` password immediately (new passwords require 8+ chars, uppercase, lowercase, number)\n- [ ] Set a strong `JWT_SECRET` (64+ random characters) — **server refuses to start without it in production**\n- [ ] Set a strong `ENCRYPTION_KEY` (separate from JWT_SECRET) — **server refuses to start without it in production**\n- [ ] Set `ALLOWED_ORIGIN` to your exact domain (no wildcards) — **server refuses to start without it in production**\n- [ ] Set a strong `DB_PASSWORD`\n- [ ] Configure HTTPS (Caddy, Certbot, or cloud load balancer)\n- [ ] Enable firewall (UFW, cloud security groups)\n- [ ] Set up external database backups\n- [ ] Regenerate your MCP token after upgrading (Admin \u003e Settings \u003e MCP Integration)\n- [ ] Review PolyForm Internal Use compliance: LICENSE file included, no third-party distribution of the software\n\n---\n\n## AI Provider Configuration\n\nThe app supports three AI backends. Configure at **Admin \u003e Settings \u003e AI Provider**.\n\n| Provider | Best For | Setup |\n|----------|----------|-------|\n| **Claude** (Anthropic) | Highest quality, native vision | Enter API key in Settings |\n| **Ollama** (self-hosted) | Full privacy, no cloud dependency | Install Ollama, pull models, enter server URL |\n| **OpenAI-compatible** | vLLM, LM Studio, text-generation-inference | Enter server URL and model name |\n\nAll AI features (diagnostics, tax auto-assign, bank classification, CSV/PDF import, support chat) work identically regardless of provider. See the in-app support chat or `server/knowledge/ai-providers.md` for detailed setup instructions.\n\n---\n\n## Backup \u0026 Restore\n\n- **In-app:** Admin \u003e Backup \u0026 Restore — create `.tbak` archives (full, client, period, or settings-only)\n- **Scheduled:** Nightly automatic backups via node-cron (configurable in Settings)\n- **Restore modes:** \"As new\" (creates new client), \"Replace\" (overwrites), \"Settings only\"\n- **External:** Use `pg_dump` for database-level backups (see cloud deployment section)\n\n---\n\n## MCP Integration (Claude Desktop)\n\nConnect Claude Desktop directly to the app for AI-assisted accounting workflows.\n\n1. Go to **Admin \u003e Settings \u003e MCP Integration**\n2. Generate an MCP token\n3. Copy the connection snippet (stdio or HTTP/SSE) into your Claude Desktop config\n4. Claude Desktop can now: read trial balances, create journal entries, run diagnostics, assign tax codes, and more\n\nSee `server/knowledge/mcp-integration.md` for the full tool/resource/prompt reference.\n\n---\n\n## License\n\nThis project is licensed under the **PolyForm Internal Use License 1.0.0**.\n\n- **Free for:** Personal use, internal firm use, self-hosting, and modification for your own internal business operations\n- **Not permitted:** Distributing the software (original or modified) to any third party in any form\n- **Requires commercial license:** Providing client-facing access (clients get their own login) or any other use beyond internal business operations\n- The [LICENSE](LICENSE) file contains the full PolyForm Internal Use 1.0.0 text. The canonical text is also at \u003chttps://polyformproject.org/licenses/internal-use/1.0.0\u003e.\n- See [COMMERCIAL_LICENSE.md](COMMERCIAL_LICENSE.md) for commercial licensing terms.\n- See [docs/LICENSING_FAQ.md](docs/LICENSING_FAQ.md) for common questions.\n- All dependencies are MIT/Apache-2.0/BSD/ISC compatible (verified via `./scripts/license-audit.sh`).\n- See `scripts/license-policy.json` for the complete dependency license policy.\n- Contact **licensing@kisaes.com** for commercial inquiries.\n\nRun `./scripts/license-audit.sh` before any release to verify compliance.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkisaesdevlab%2Fvibe-trial-balance","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkisaesdevlab%2Fvibe-trial-balance","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkisaesdevlab%2Fvibe-trial-balance/lists"}