Docs Developers
Development setup
Tech stack, project layout, and contributor flow. For install instructions see Installing SlowBooks Pro; for the public security policy and disclosure process see SECURITY.md; for internal hardening notes see Security hardening.
Tech Stack
| Component | Technology |
|---|---|
| Backend | Python 3.13 + FastAPI (89 routers, 735 API operations on 588 paths in 2.31.4) |
| Database | SQLite company files (desktop, Server Edition) or PostgreSQL 17 + SQLAlchemy 2.0 |
| Migrations | Alembic; every table and column change needs one (see below) |
| Frontend | Vanilla HTML/CSS/JS (no framework) + self-hosted Chart.js 4.4.6 for analytics |
| WeasyPrint 70.0 + Jinja2 | |
| Bank feeds and imports | SimpleFIN, Mercury; ofxparse (OFX/QFX), CSV |
| Payments | Stripe Checkout, PayPal and Square (hosted pages), one abstraction in app/services/payments/ |
| Auth | Named users in four roles, sessions, scoped API tokens |
| Port | 3001 |
Project Structure
SlowBooks-Pro-2026/
โโโ .env.example # Environment config template
โโโ requirements.txt # Python dependencies (production)
โโโ requirements-dev.txt # Test + lint deps
โโโ run.py # Uvicorn entry point (port 3001)
โโโ alembic.ini # Alembic config
โโโ migrations/ # Alembic database migrations (script_location in alembic.ini)
โโโ app/
โ โโโ main.py # FastAPI app + the routers, role policy, startup checks
โ โโโ config.py # Environment-based settings (CORS, origins)
โ โโโ database.py # SQLAlchemy engine + session + table auto-creation
โ โโโ models/ # 60 model modules (105 tables)
โ โ โโโ accounts.py # Chart of Accounts (self-referencing)
โ โ โโโ contacts.py # Customers + Vendors
โ โ โโโ items.py # Products, services, materials, labor
โ โ โโโ invoices.py # Invoices + line items
โ โ โโโ estimates.py # Estimates + line items
โ โ โโโ payments.py # Payments + allocations
โ โ โโโ transactions.py # Journal entries (double-entry core)
โ โ โโโ banking.py # Bank accounts, transactions, reconciliations
โ โ โโโ settings.py # Key-value company settings
โ โ โโโ audit.py # Audit log
โ โ โโโ purchase_orders.py # Purchase orders + lines
โ โ โโโ bills.py # Bills + lines + payments + allocations
โ โ โโโ credit_memos.py # Credit memos + lines + applications
โ โ โโโ recurring.py # Recurring invoices + lines
โ โ โโโ email_log.py # Email delivery log
โ โ โโโ tax.py # Tax category mappings
โ โ โโโ backups.py # Backup records
โ โ โโโ companies.py # Multi-company records
โ โ โโโ payroll.py # Employees, pay runs, pay stubs, bank accounts
โ โ โโโ hr.py # HR module: onboarding, time entries, PTO, deductions
โ โ โโโ pto.py # PTO policies, requests, accruals
โ โ โโโ time_entries.py # Time entry tracking with approval workflow
โ โ โโโ deductions.py # Deduction types, employee deductions, garnishments
โ โ โโโ qbo_mapping.py # what an earlier QuickBooks Online import left behind
โ โ โโโ attachments.py # File attachments
โ โ โโโ bank_rules.py # Bank transaction categorization rules
โ โ โโโ budgets.py # Budget tracking by account/period
โ โ โโโ document_audit.py # a SHA-256 hash per generated tax-form PDF
โ โ โโโ portal_access.py # Portal access audit log
โ โ โโโ reseller_permit.py # Per-entity reseller permits
โ โ โโโ email_templates.py # Customizable email templates
โ โโโ schemas/ # Pydantic request/response models
โ โโโ routes/ # FastAPI routers (89; payroll and reports are packages)
โ โโโ services/
โ โ โโโ accounting.py # Double-entry journal entry engine
โ โ โโโ analytics.py # Business intelligence aggregates (8 methods)
โ โ โโโ audit.py # SQLAlchemy after_flush audit hooks
โ โ โโโ closing_date.py # Closing date enforcement guard
โ โ โโโ payroll_service.py # Withholding calculations
โ โ โโโ recurring_service.py # Recurring invoice generation
โ โ โโโ email_service.py # SMTP email delivery
โ โ โโโ csv_export.py # CSV export (5 entity types)
โ โ โโโ csv_import.py # CSV import with error handling
โ โ โโโ ofx_import.py # OFX/QFX bank feed parser
โ โ โโโ tax_export.py # Schedule C data + CSV export
โ โ โโโ backup_service.py # backups: pg_dump on PostgreSQL, a file copy on SQLite
โ โ โโโ company_service.py # Multi-company DB management
โ โ โโโ iif_export.py # IIF export (8 export functions)
โ โ โโโ iif_import.py # IIF parser + import + validation
โ โ โโโ pdf_service.py # WeasyPrint PDF generation
โ โ โโโ payments/ # stripe, paypal, square, recorder, clearing
โ โ โโโ qbo_export_import.py # QuickBooks Online's Export data zip โ Migrate Data
โ โ โโโ auth.py # Users, roles, sessions, API tokens
โ โ โโโ rate_limit.py # slowapi rate limiting
โ โ โโโ settings_service.py # Settings CRUD with sensitive key filtering
โ โ โโโ encryption.py # Fernet encryption + versioned ciphertext + rewrap CLI
โ โ โโโ crypto.py # Master key resolution
โ โโโ templates/ # Jinja2 templates (PDF, email, checks, collection letters)
โ โโโ seed/ # Chart of Accounts seed data
โ โโโ static/
โ โโโ css/
โ โ โโโ style.css # QB2003 "Default Blue" skin
โ โ โโโ dark.css # Dark mode CSS overrides
โ โโโ js/ # SPA router, API wrapper, 40+ page modules
โ โโโ app.js # Main SPA router (76 routes)
โ โโโ api.js # HTTP wrapper (API.get/post/put/del)
โ โโโ employees.js # Employee CRUD + Details modal
โ โโโ onboarding.js # Onboarding checklists + e-signature
โ โโโ time_entries.js # Time tracking + approve/reject workflow
โ โโโ pto.js # PTO policies + request workflow
โ โโโ deductions.js # Deduction types, employee deductions, garnishments
โ โโโ tax_forms.js # W-2, W-3, 940, 941 form generation UI
โ โโโ [30+ more pages] # Invoices, customers, reports, analytics, etc.
โโโ scripts/
โ โโโ seed_database.py # Seed the Chart of Accounts
โ โโโ seed_irs_mock_data.py # IRS Pub 583 mock data
โ โโโ run_recurring.py # Cron script for recurring invoices + auto-enter memorized transactions
โ โโโ backup.sh # PostgreSQL backup with rotation
โโโ screenshots/ # README + docs images
โโโ cloudflare/ # Self-hosted Cloudflare Worker AI gateway
โ โโโ worker.js # Hardened proxy (model allowlist, rate limiting, security headers)
โ โโโ wrangler.toml # Deployment config
โ โโโ README.md # Setup guide
โโโ tests/ # ~7,200 pytest tests (auth, security, posting, reporting, imports, payroll, HR, browser tests under Playwright, the wiring, schema, autoescape, rounding, race-condition, N+1, closing-date, secret-redaction, void-symmetry, IIF round-trip and shell-injection audits)
โโโ index.html # SPA shell
Where things go when you add code
- New HTTP endpoint โ drop into
app/routes/<domain>.py. Define anAPIRouter(prefix="/api/...", tags=[...]), attach@router.get/@router.post/ etc., thenapp.include_router(router)inapp/main.py. Group by domain โ add to the smallest existing router file, or create a new one for a new feature area. - New DB table or column โ model goes in
app/models/<name>.pyand an Alembic migration inmigrations/versions/(alembic revision -m "...", thenalembic upgrade head). Both are required: the app refuses to start against a database behind the migration head, andtests/test_gate_290_fixes.pyfails on a table onlycreate_all()makes. - New Pydantic shape โ
app/schemas/<domain>.py. Beware thedate: datefield-shadows-type collision โ see CONTRIBUTING.md โ Schema conventions. - New SPA page โ
app/static/js/<name>.jsexporting a module object with arender()method; register the hash route inapp/static/js/app.js. Talk to the backend throughAPI.get/post/ put/del(thedelspelling matters โ notdelete). - Tests โ
tests/test_<area>.py. The wiring audit (tests/test_wiring.py) will fail CI if your new endpoint has no SPA caller AND isn't on the_INTENTIONAL_BACKEND_ONLYallowlist.
Running tests
pip install -r requirements.txt -r requirements-dev.txt
pytest # the full suite, about 7,200 tests; 40 minutes on one machine
pytest tests/test_wiring.py # under a second: the JS <-> backend wiring audit
pytest -k "audit or portal" # subset by keyword
The browser tests need Playwright's Chromium (playwright install chromium) and skip without it; the PostgreSQL-only tests run when
SLOWBOOKS_TEST_POSTGRES_URL names a database. To run the app while you
work: cp .env.example .env, set APP_DEBUG=true, APP_HOST=127.0.0.1 and
a PAYROLL_ENCRYPTION_SECRET, then python run.py and open
http://localhost:3001 (INSTALL.md, Option 2, has the whole setup). The
desktop window is python desktop_launcher.py.
The wiring audit is also a boot-time tripwire in
docker-entrypoint.sh: a container that has pytest installed (the
Dockerfile installs requirements.txt only, so add requirements-dev.txt
in a debug image) fails to start if any JS API call points at a removed
route. Production images skip the boot check silently โ CI already gates
the same condition before the image is built.
Manual end-to-end smoke test
scripts/integration_test_frontend.py is a live-HTTP integration
script (deliberately not under tests/ so the pytest collector
skips it). It covers the HR and payroll pages against a fresh
database at 127.0.0.1:8000, confirming the pages and their API calls
answer over real HTTP. Run it against a server started for it when
you've touched those pages:
uvicorn app.main:app --port 8000 &
python scripts/integration_test_frontend.py
Lint + format
pip install "black>=24.8.0" "ruff>=0.6.0"
black --check app/ tests/ scripts/ # what CI runs
ruff check app/ tests/ scripts/
CI lints the whole tree (.github/workflows/ci.yml); both pass on every
release tag.
Contributor flow
See CONTRIBUTING.md for the full guide. The short version:
- Branch off
main - Make changes; add/update tests
pytestgreen locally- Open a PR โ CI runs lint, the full suite on Linux and Windows, pip-audit, CodeQL and the Docker build; the installer and DMG build on their own workflows
- Reviewer merges once green
The PR template prompts for: summary, test plan, security/perf notes, and any docs updates.