A full-featured accounting system built to replace QuickBooks Online for a small Georgia CPA firm (2-5 staff, 26-50 clients). Runs entirely local -- no cloud subscriptions, no third-party dependencies at runtime.
All 38 backend modules across 8 phases are built, tested, and deployed. The frontend has 27 pages covering every workflow. Security hardened and running in production.
- 900 tests passing (pytest)
- 59 database tables with audit triggers
- 34 routers / 257+ API endpoints
- 27 frontend pages
- 50+ ORM models
- Deployed via nginx HTTPS + launchd services
| Phase | Modules | Description |
|---|---|---|
| 0 - Migration | M1-M7 | QBO CSV parser, client splitter, CoA mapper, transaction/invoice/payroll importers, audit report |
| 1 - Foundation | F1-F5 | Database schema, chart of accounts, general ledger, client management, JWT auth |
| 2 - Transactions | T1-T4 | Accounts payable, accounts receivable, bank reconciliation, approval workflow |
| 3 - Documents | D1-D3 | Upload, viewer, search |
| 4 - Payroll | P1-P6 | Employee records, GA withholding (G-4), GA SUTA, federal tax/FICA/FUTA, pay stubs, approval gate |
| 5 - Tax Exports | X1-X11 | GA G-7, Form 500/600, ST-3, Schedule C, 1120-S/1120/1065, checklist, W-2, 1099-NEC |
| 6 - Reporting | R1-R7 | P&L, balance sheet, cash flow, PDF export, firm dashboard, AR/AP aging |
| 7 - Operations | O1-O4 | Audit trail, automated backup, restore, health check |
| 8 - Feature Gaps | FG1-FG4 | W-2 generation, 1099-NEC generation, AR/AP aging reports, check printing |
| Layer | Technology | Purpose |
|---|---|---|
| Backend | Python 3.14 + FastAPI | Async API server with rate limiting |
| Frontend | React 18.3 + Vite 6 | 27-page internal dashboard (React Query, React Router 6) |
| Database | PostgreSQL | 59 tables, ACID-compliant, audit triggers on all tables |
| Auth | JWT + RBAC + TOTP 2FA | CPA_OWNER and ASSOCIATE roles, defense-in-depth |
| WeasyPrint | Pay stubs, tax forms, financial reports, checks | |
| Encryption | Fernet (AES-128-CBC) | PII at rest (SSN, tax ID) |
| Migration | Custom CSV parser | Imports QuickBooks Online exports |
| Deploy | nginx + launchd | HTTPS reverse proxy, auto-start services, nightly backup |
| Backup | GPG (AES-256) | Encrypted nightly database backups, 30-day retention |
tax/
├── backend/
│ ├── app/
│ │ ├── auth/ # JWT auth, RBAC, 2FA (TOTP)
│ │ ├── models/ # SQLAlchemy ORM (50+ models)
│ │ ├── schemas/ # Pydantic request/response schemas
│ │ ├── routers/ # 34 FastAPI route handlers
│ │ ├── services/ # Business logic layer
│ │ │ ├── migration/ # QBO import pipeline (M1-M7)
│ │ │ ├── payroll/ # Tax calculators, pay stubs, W-2, NACHA
│ │ │ └── tax_filing/ # GA FSET XML, TaxBandits
│ │ ├── middleware/ # Security headers, request size limits, audit
│ │ ├── crypto.py # Fernet PII encryption
│ │ ├── config.py # Environment settings (no default secrets)
│ │ ├── database.py # Async SQLAlchemy engine
│ │ └── main.py # FastAPI app entry point
│ ├── db/migrations/ # SQL migrations (004-006)
│ ├── scripts/ # seed_test_data.py, migrate_encrypt_pii.py
│ └── tests/ # 900 tests (pytest + pytest-asyncio)
├── frontend/
│ ├── src/
│ │ ├── pages/ # 27 page components
│ │ ├── components/ # 11 shared components
│ │ ├── hooks/ # useApi, useAuth, useToast, useUnsavedChanges
│ │ ├── utils/ # format.js (currency, dates, entity types)
│ │ └── styles/ # Single CSS file (index.css)
│ └── package.json
├── deploy/
│ ├── setup.sh # Full install (nginx, launchd, certs)
│ ├── teardown.sh # Uninstall everything
│ ├── backup.sh # GPG-encrypted pg_dump
│ ├── restore.sh # Restore from encrypted backup
│ ├── logrotate.sh # Daily log rotation
│ ├── dbmaint.sh # Weekly VACUUM/REINDEX
│ ├── nginx.conf # HTTPS reverse proxy config
│ ├── com.gacpa.*.plist # 4 launchd service definitions
│ └── windows-trust.md # LAN client cert trust instructions
├── ARCHITECTURE.md # Module dependency map
├── OPEN_ISSUES.md # 11 open compliance flags (rate verification)
└── AGENT_LOG.md # Build session history
- Python 3.14+
- PostgreSQL (local instance)
- Node.js 18+
- pango (for PDF generation):
brew install pango - nginx (for deployment):
brew install nginx
cd backend
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtCreate backend/.env with required secrets (the app will crash on startup if any are missing):
DATABASE_URL=postgresql+asyncpg://postgres:YOUR_PASSWORD@localhost:5432/ga_cpa
JWT_SECRET=your-secret-key-here
ENCRYPTION_KEY=your-fernet-key-here
DEBUG=falseGenerate a Fernet key: python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
# Create the database
psql -U postgres -c "CREATE DATABASE ga_cpa;"
# Run migrations (004-006 are incremental)
psql -U postgres -d ga_cpa -f backend/db/migrations/004_audit_pii_redaction.sql
psql -U postgres -d ga_cpa -f backend/db/migrations/005_recurring_templates.sql
psql -U postgres -d ga_cpa -f backend/db/migrations/006_password_reset_tokens.sql
# Seed test data (optional -- creates 4 clients with all entity types)
cd backend && .venv/bin/python scripts/seed_test_data.py
# Use --reset flag to wipe and reseedNote: The initial schema (tables, triggers, seed data) is created automatically by SQLAlchemy on first startup via create_all().
cd frontend
npm install
npm run build # Production build# Terminal 1: Backend
cd backend
source .venv/bin/activate
uvicorn app.main:app --reload
# Terminal 2: Frontend
cd frontend
npm run devbash deploy/setup.shThis installs nginx with HTTPS (self-signed cert), creates launchd services for the backend, nightly backup, log rotation, and DB maintenance.
| Method | URL |
|---|---|
| Local | https://localhost |
| LAN | https://192.168.1.104 (or your machine's IP) |
| Dev frontend | http://localhost:5173 |
| Dev backend | http://localhost:8000 |
Default credentials: edward@755mortgage.com / admin123 (CPA_OWNER role)
LAN clients (Windows/Mac) need to trust the self-signed certificate. See deploy/windows-trust.md.
cd backend
.venv/bin/python -m pytest --tb=short -q
# 900 passedAll endpoints are prefixed with /api/v1. Authentication via httpOnly JWT cookie (set on login).
| Group | Prefix | Key Endpoints |
|---|---|---|
| Auth | /auth |
Login, 2FA setup/verify/disable, password reset |
| Clients | /clients |
CRUD, archive, restore, entity type |
| Chart of Accounts | /clients/{id}/accounts |
CRUD, Georgia standard categories |
| Journal Entries | /clients/{id}/journal-entries |
Double-entry GL, approval workflow |
| Vendors | /clients/{id}/vendors |
CRUD |
| Bills (AP) | /clients/{id}/bills |
Create, pay, void, check printing |
| Invoices (AR) | /clients/{id}/invoices |
Create, approve, record payment, void, PDF |
| Bank Reconciliation | /clients/{id}/bank-accounts |
Import, match, reconcile |
| Documents | /clients/{id}/documents |
Upload, view, search |
| Employees | /clients/{id}/employees |
CRUD, terminate |
| Payroll | /clients/{id}/payroll |
Create run, submit, finalize, pay stub PDF |
| Approvals | /approvals |
Queue, batch approve/reject |
| Reports | /reports |
P&L, balance sheet, cash flow, AR/AP aging, PDF/CSV/Excel export |
| Tax Exports | /tax |
GA G-7, 500, 600, ST-3, federal forms, W-2, 1099-NEC |
| Statements | /clients/{id}/statements |
Client account statements, email |
| Recurring | /clients/{id}/recurring-templates |
Recurring transaction templates |
| Bulk Import | /clients/{id}/bulk-import |
CSV upload for bills/invoices (5,000 row cap) |
| Search | /search |
Global search across clients, transactions, documents |
| Year-End | /clients/{id}/year-end |
Year-end close process |
| Time Tracking | /clients/{id}/time-entries |
Billable hours tracking |
| Service Billing | /clients/{id}/service-invoices |
Firm billing to clients |
| Engagements | /clients/{id}/engagements |
Engagement management |
| Contacts | /clients/{id}/contacts |
Client contact records |
| Workflows | /workflows |
Task/workflow management |
| Portal | /portal |
Client portal messages |
| Fixed Assets | /clients/{id}/fixed-assets |
Asset tracking, depreciation |
| Budgets | /clients/{id}/budgets |
Budget creation and tracking |
| Check Sequence | /clients/{id}/check-sequence |
Auto-increment check numbers |
| Firm Analytics | /firm-analytics |
Cross-client metrics and trends |
| Operations | /operations |
Backup, restore, health check |
| Audit Log | /audit-log |
Immutable change history |
The system has been through a full security audit (11 findings, all fixed):
- Password hashing: bcrypt with timing-attack mitigation
- Authentication: httpOnly + Secure + SameSite=Strict cookies, JWT (30-min expiry)
- 2FA: TOTP via pyotp, rate-limited (5/min), valid_window=0
- Encryption at rest: Fernet for PII (SSN, tax ID)
- Security headers: HSTS, X-Frame-Options, Content-Security-Policy, X-Content-Type-Options
- SQL injection: SQLAlchemy parameterized queries throughout
- XSS: React auto-escapes, no dangerouslySetInnerHTML
- Rate limiting: Login (per-IP and per-email), 2FA endpoints
- Request size limits: Middleware-enforced body size cap
- Bulk import cap: 5,000 rows per CSV upload
- Audit trail: Immutable PostgreSQL trigger-based logging of all changes
- Encrypted backups: GPG AES-256, passphrase via fd (not visible in ps)
- No default secrets: App crashes on startup if DATABASE_URL, JWT_SECRET, or ENCRYPTION_KEY missing
- Production mode: DEBUG=false disables /docs, /redoc, /openapi.json
This system handles real financial data under Georgia tax law. Key enforcement:
- Double-entry: Every transaction balances debits and credits (DB-level CHECK constraint)
- Audit trail: No hard deletes anywhere. All changes logged with old/new values, user, timestamp
- Client isolation: Every table with client data has
client_idas non-nullable FK; every query filters by it - Approval workflow: Associates enter drafts (
PENDING_APPROVAL); only CPA_OWNER can approve/post to GL - Payroll gate: Finalization verified at both route level (
require_role) and function level (verify_role) - Tax rate sourcing: Every rate constant cites its Georgia DOR / IRS source document and review date
See OPEN_ISSUES.md for 11 open rate-verification flags for TY2026.
The system runs on macOS with these launchd services:
| Service | Plist | Schedule |
|---|---|---|
| Backend (uvicorn) | com.gacpa.backend |
Always running, auto-restart |
| Nightly backup | com.gacpa.backup |
2:00 AM daily, 30-day retention |
| Log rotation | com.gacpa.logrotate |
Daily |
| DB maintenance | com.gacpa.dbmaint |
Weekly VACUUM/REINDEX |
nginx serves as an HTTPS reverse proxy with a self-signed certificate (10-year validity).
# Install everything
bash deploy/setup.sh
# Uninstall everything
bash deploy/teardown.sh
# Manual backup
bash deploy/backup.sh
# Restore from backup
bash deploy/restore.sh /path/to/backup.sql.gpg- CPA_OWNER compliance review -- Verify 11 open tax rate flags in
OPEN_ISSUES.md - End-to-end integration testing with real QuickBooks Online export data
- Team onboarding -- Create ASSOCIATE accounts, migrate first real client
- Trust self-signed cert on team machines (see
deploy/windows-trust.md) - Deferred features -- Plaid bank feeds (paid API), document OCR (Tesseract)
- Frontend pages -- Recurring templates manager, year-end close UI