Skip to content

Architecture Overview

Repository Structure

Butler Series consists of 3 repositories:

RepositoryRoleTech
butler-platformAuth, billing, admin, docsNext.js + FastAPI
butler-taxAccounting SaaSVue.js + FastAPI
butler-lawLegal Q&A (tax/labor)Next.js + FastAPI

Technology Stack

Butler Tax

  • Frontend: Vue.js 3 (Composition API) + Vite (port 3001)
  • Backend: FastAPI (port 8001)
  • Business Data: MongoDB (butler_tax database)
  • PII Data: Firestore (company_profiles, bank_accounts, clients)
  • Auth: Firebase Auth via Butler Platform
  • AI Chat: Anthropic Claude Sonnet 4.6
  • OCR: Gemini 2.5 Flash

Butler Platform

  • Auth Frontend: Next.js (port 3003)
  • Studio Admin: Next.js (port 3004)
  • Platform API: FastAPI (port 8003)
  • Database: MongoDB (butler_platform) + Firebase Admin SDK

Butler Law

  • Frontend: Next.js (port 3002)
  • Backend: FastAPI (port 8002)
  • Database: MongoDB (butler_law) — also used as vector store via numpy cosine similarity
  • Embedding model: paraphrase-multilingual-mpnet-base-v2 (local)

Data Architecture

MongoDB Collections (Business Data — Butler Tax)

CollectionPurpose
corporatesCorporate entity profiles
employeesEmployee records
receiptsExpense receipts
invoicesIssued & received invoices
transactionsBank transactions
matchesReconciliation records
audit_logsOperation audit trail
approval_rulesApproval workflow configurations
matching_rulesReconciliation rules
journal_rulesJournal entry rules
permission_settingsDynamic role-based permissions

Firestore Collections (PII Data — Butler Tax)

CollectionPurpose
company_profilesCompany profiles with PII (address, phone, registration number)
bank_accountsBank account details (account number, holder name)
clientsClient/vendor master with contact info

All Firestore documents include a firebase_uid field for scoping.

Key Design Patterns

CorporateContext

All Butler Tax API routes use Depends(get_corporate_context) to scope data access to the authenticated corporate entity. The context exposes:

  • corporate_id — MongoDB document ID
  • firebase_uid — Firebase Auth UID
  • role — employee role (staff / approver / accounting / manager / admin)
  • db — MongoDB connection
  • fs — Firestore client (lazy-initialized)
  • is_tax_firm_proxy — true during tax firm impersonation
  • actual_uid — original tax firm UID during impersonation

Tax Firm Impersonation

Tax firms can act on behalf of their client companies via the ?as_corporate={firebase_uid} query parameter. The backend validates the advising_tax_firm_id relationship and fixes the role to accounting. All proxy actions are recorded in audit_logs with is_tax_firm_proxy: true.

Role Hierarchy

RoleRankAccess Level
staff1Basic access, submit documents
approver2Approve documents within scope
group_leader2Same rank as approver
manager3Department-level management
accounting4Full accounting access
admin5Full administrative access

Lazy Firestore Initialization

The Firestore client is wrapped in LazyFirestore so that firestore.client() is only called on the first .collection() access. Routes that don't touch PII data continue to work even when Firebase credentials are not configured locally.

Butler Chat Format

Butler Chat uses an embedded text format for tool calls:

[[TOOL:tool_name]]
human-readable confirmation message
[[/TOOL]]
[[TOOL_PAYLOAD:{"key":"value"}]]

The frontend parses this and renders a confirmation UI before calling POST /advisor/tools/{tool_name} with confirmed: true. Migration to Anthropic's native Tool Use API is a future task.

Butler Series — Saikoku Studio