Finance & Accounting App – Modular Enterprise Suite
Enterprise modular accounting suite decomposed into 7 composable Vue 3 / Vite packages for multi-tenant financial reporting and double-entry ledgers.
Delivered a comprehensive double-entry accounting suite for multi-tenant organizations [X] by decomposing PennyPerfect into 7 independently publishable Vue packages covering chart of accounts, transactions, balance sheets, P&L statements, reports, and settings [Y], achieving 6 auto-discovered production menu surfaces under /penny-perfect/* backed by standardized Vue provide/inject abstractions and Laravel Sanctum multi-tenant APIs [Z].
My contribution
Core contributorDelivered a comprehensive double-entry accounting suite for multi-tenant organizations [X] by decomposing PennyPerfect into 7 independently publishable Vue packages covering chart of accounts, transactions, balance sheets, P&L statements, reports, and settings [Y], achieving 6 auto-discovered production menu surfaces under /penny-perfect/* backed by standardized Vue provide/inject abstractions and Laravel Sanctum multi-tenant APIs [Z].
What I owned
- Feature scope vs. maintainability in a monorepo with nested git repos
- Inconsistent HTTP client patterns across packages (raw Axios vs @itc/coreservice callApi)
- Legacy branch API (/loanapp/branchs) missing in Supercards backend
- Reports had duplicate route definitions (src/routes.ts vs src/router/routes.ts)
- Print/PDF export without server-side rendering
Product context
Enterprise Finance Teams, Multi-Tenant SaaS Organizations & Accounting LeadsDelivered a comprehensive double-entry accounting suite for multi-tenant organizations [X] by decomposing PennyPerfect into 7 independently publishable Vue packages covering chart of accounts, transactions, balance sheets, P&L statements, reports, and settings [Y], achieving 6 auto-discovered production menu surfaces under /penny-perfect/* backed by standardized Vue provide/inject abstractions and Laravel Sanctum multi-tenant APIs [Z].
Core challenge
Finance teams inside Supercards tenants needed in-app accounting—accounts, journal entries, tax-aware income/expense, and standard financial reports—without bolting on a separate ERP. Legacy PennyPerfect UIs assumed a monolithic loan-app API (e.g. /loanapp/branchs, cashbook import/export) and wrong default API hosts, causing broken branch filters, failed imports, and session logout when tax endpoints 401'd on page load.
Value proposition
Monolithic Frontend Bloat Across Accounting Modules — Integrating double-entry accounting into host applications traditionally bloated frontend bundles and coupled financial code with unrelated core app logic.
7 Composable Autonomous Vue Library Packages — Decomposed the suite into independently versioned packages (@itc/pennyperfect-*) orchestrated by a meta-package with dynamic route discovery.
P0 Session Logouts from Premature Boot-Time API Calls — Unauthenticated tax code fetch calls during initial application boot triggered 401 errors, inadvertently logging users out of their host session.
Lazy Dialog Loading & Safe Host Boot Handlers — Engineered configureTaxApi boot abstractions and deferred API requests until dialog mount, guaranteeing 100% boot stability.
Heavy Server-Side PDF Rendering Infrastructure — Generating multi-page A4 balance sheets and monthly income statements previously required dedicated headless browser microservices.
Client-Side In-Browser A4 PDF Assembly — Engineered client-side rendering with hidden iframes, html2canvas rasterization, and jsPDF assembly for instant zero-server PDF exports.
Proof
Impact and product screens
My results
Product outcomes
Click any preview to open full size. Use arrow keys to browse.
Build
Stack and engineering choices
Technology
Frontend
- Quasar Framework (v2)
- Vue.js (v3) + TypeScript
- Pinia (+ PersistedState)
- Vue Router 4 (appPlugin Discovery)
- Vite 7 (Library Mode: ESM/CJS)
- html2canvas + jsPDF
Backend
- Laravel 11 API (itc/pennyperfect)
- Laravel Sanctum (auth:sanctum)
- Multi-Tenant Branch & User Scoping
Database
- PostgreSQL (Double-Entry Ledgers, Tax Codes & Statements)
DevOps & Infra
- pnpm Workspaces (workspace:*)
- Nested Git Submodules (.modules)
- Docker Compose Local Stack
- Vite HMR & Menu Auto-Discovery
Key decisions
Finance teams inside Supercards tenants needed in-app accounting—accounts, journal entries, tax-aware income/expense, and standard financial reports—without bolting on a separate ERP. Legacy PennyPerfect UIs assumed a monolithic loan-app API (e.g. /loanapp/branchs, cashbook import/export) and wrong default API hosts, causing broken branch filters, failed imports, and session logout when tax endpoints 401'd on page load.
Feature scope vs. maintainability in a monorepo with nested git repos
Decision: Split PennyPerfect into domain packages (@itc/pennyperfect-transactions, -chartofaccounts, -balancesheet, -incomestatement, -reports, -settings) with @itc/pennyperfect as a meta dependency installer; each package ships appPlugin.routes + appPlugin.menu with parent: pennyperfect.
Outcome: Teams can version, build, and publish modules independently; host integration is boot + spread routes + discover:ci instead of a growing frontend/src tree.
Inconsistent HTTP client patterns across packages (raw Axios vs @itc/coreservice callApi)
Decision: Standardized host boot files (pennyperfect-transactions, pennyperfect-settings, pennyperfect-balancesheet) calling configureTaxApi / configureSettingsApi / configureBalanceSheetApi with apiUrlBuilder + appId: pennyperfect; feature pages inject apiClient, authStore, tenantStore for Axios-interceptor packages.
Outcome: Single source of truth for API base URL from VITE_API_BASE_URL; Bearer + x-tenant-id headers applied consistently; tax codes load only when dialogs open.
Legacy branch API (/loanapp/branchs) missing in Supercards backend
Decision: Migrated income statement and reports branch loaders to GET /tenants/{tenantId}/branches (itc/core-auth-accounts); made branchId nullable across transaction and settings forms to match backend validation.
Outcome: Branch filters populate on Income Statement and Reports; transactions save without forced branch selection.
Reports had duplicate route definitions (src/routes.ts vs src/router/routes.ts)
Decision: Unified appPlugin.routes to ./src/router/routes.ts; host imports { routes } from package entry as single source of truth.
Outcome: One route set for /penny-perfect/reports plus /external/reports print URLs and voucher preview routes.
Show 1 more decisions
Print/PDF export without server-side rendering
Client-side PDF via hidden iframe loading /external/reports, html2canvas snapshot of .report-preview-a4, jsPDF multi-page assembly.
Monthly/daily summaries export to PDF without additional backend render pipeline.
Trust
Security and roadmap
Security & reliability
- All accounting APIs require auth:sanctum; tenant context via X-Tenant-Id from tenantStore interceptors on apiClient.
- Tax and settings modules support configure*Api with shared callApiClient from host boot—no hardcoded production tokens in package source.
- Pinia persisted state (reports, chart-of-accounts) retains filter preferences locally; failed fetches clear stale lists and rethrow or return empty payloads.
- System accounts in chart of accounts are guarded in UI (SystemAccountWarningDialog) to prevent destructive edits on protected rows.
Future roadmap
- Migrate cashbook import/export from legacy /loanapp/transaction/cashbook-* to itc/pennyperfect-backed endpoints.
- Consolidate remaining /loanapp/* settings APIs onto core-auth-accounts + pennyperfect tax-code routes.
- Add general ledger package (@itc/pennyperfect-general-ledger) to the meta-package dependency set for a seventh reporting surface.
- Unify all packages on @itc/coreservice callApi instead of mixed raw Axios service layers.
Executive Summary
PennyPerfect is an enterprise modular double-entry accounting suite engineered for multi-tenant Supercards organizations. Rather than a monolithic ERP, PennyPerfect is architected as seven composable frontend packages (@itc/pennyperfect-*) that deliver dedicated accounting modules—from chart of accounts and journal transactions to balance sheets, income statements, and PDF reporting.
All packages are orchestrated by a meta-dependency package (@itc/pennyperfect), auto-discovered through @itc/menu-system, and powered by a consolidated Laravel package (itc/pennyperfect) operating under /api/v1 with Sanctum authentication and strict tenant-scoping.
Architecture
Modular Package Composition & Host Ingestion Topology
flowchart TB
subgraph Host_App ["Supercards Host Application (Quasar / Vue 3)"]
BOOT["Host Boot Files<br/>(configureTaxApi, configureSettingsApi)"]
INJECT["Vue provide/inject<br/>(apiClient, authStore, tenantStore)"]
MENU_SYS["@itc/menu-system<br/>(discover:ci / appPlugin auto-discovery)"]
end
subgraph Meta_Package ["@itc/pennyperfect (Meta-Orchestrator)"]
DEPS["Exports aggregated routes & package bindings"]
end
subgraph Domain_Packages ["7 Composable Vue 3 / Vite Library Packages"]
PKG_COA["@itc/pennyperfect-chartofaccounts<br/>(Ledger Trees, System Account Guards)"]
PKG_TX["@itc/pennyperfect-transactions<br/>(Income, Expense, Journal, Tax Dialogs)"]
PKG_IS["@itc/pennyperfect-incomestatement<br/>(P&L Statements, Branch Breakdown)"]
PKG_BS["@itc/pennyperfect-balancesheet<br/>(Asset/Liability Ledgers, Equity Rollup)"]
PKG_REP["@itc/pennyperfect-reports<br/>(Daily/Monthly Summaries, A4 PDF Export)"]
PKG_SET["@itc/pennyperfect-settings<br/>(Tax Codes, Fiscal Years, Currency)"]
end
subgraph Backend_Services ["Laravel API Gateway (/api/v1)"]
SANCTUM["Laravel Sanctum (auth:sanctum)"]
TENANT_MW["Tenant Scoping Middleware (X-Tenant-Id)"]
PP_BE["itc/pennyperfect (Accounting Engine)"]
AUTH_BE["itc/core-auth-accounts (Branches & Users)"]
PG_DB[("PostgreSQL Database<br/>(Tenant-Scoped Accounts & Ledgers)")]
end
Host_App --> Meta_Package
Meta_Package --> Domain_Packages
BOOT & INJECT --> Domain_Packages
Domain_Packages -->|"HTTPS / Bearer Token + X-Tenant-Id"| SANCTUM
SANCTUM --> TENANT_MW
TENANT_MW --> PP_BE & AUTH_BE
PP_BE & AUTH_BE --> PG_DBPackage Architecture Standard
Each @itc/pennyperfect-* package is structured as an isolated, independently versioned Vite library package:
@itc/pennyperfect-<module>/
├── src/
│ ├── components/ # Quasar UI components, Dialogs, Trees
│ ├── pages/ # Root module pages mounted under /penny-perfect/*
│ ├── stores/ # Module Pinia stores (with persisted state if needed)
│ ├── services/ # HTTP API services (apiUrlBuilder + callApi / apiClient)
│ ├── types/ # TypeScript interfaces & DTO contracts
│ ├── router/ # routes.ts exporting RouteRecordRaw[]
│ └── index.ts # appPlugin manifest (routes, menu, boot helpers)
├── package.json # Scoped package manifest, peerDependencies
├── tsconfig.json # TypeScript configuration
└── vite.config.ts # Vite 7 library build (ESM + CJS)Data Schema & Accounting Ledger Flow
PennyPerfect enforces double-entry bookkeeping rules across all journal, income, and expense entries:
erDiagram
TENANT ||--o{ ACCOUNT : "defines chart of"
ACCOUNT ||--o{ ACCOUNT : "parent/child hierarchy"
TENANT ||--o{ TRANSACTION : "records"
TRANSACTION ||--o{ TRANSACTION_ENTRY : "contains debit/credit lines"
ACCOUNT ||--o{ TRANSACTION_ENTRY : "impacted by"
TAX_CODE ||--o{ TRANSACTION : "applied to"
BRANCH ||--o{ TRANSACTION : "attributed to"
ACCOUNT {
uuid id PK
string code
string name
string type "Asset | Liability | Equity | Revenue | Expense"
uuid parent_id FK
boolean is_system_account
decimal current_balance
}
TRANSACTION {
uuid id PK
string reference_no
date transaction_date
string type "Journal | Income | Expense"
uuid tax_code_id FK
uuid branch_id FK
decimal total_amount
string status "Draft | Posted"
}
TRANSACTION_ENTRY {
uuid id PK
uuid transaction_id FK
uuid account_id FK
string entry_type "DEBIT | CREDIT"
decimal amount
}
TAX_CODE {
uuid id PK
string code
decimal rate_percentage
boolean is_active
}Visual Workflows & Production Interfaces
1. Chart of Accounts Ledger Hierarchy

2. Multi-Tab Transactions & Tax Code Management

3. Financial Statements: Balance Sheet & Income Statement


4. Operational Financial Reports & Export

Client-Side Report Preview & Multi-Page A4 PDF Assembly
sequenceDiagram
autonumber
actor User as Finance Manager
participant Page as Reports Page (/penny-perfect/reports)
participant Store as useReportsStore (Pinia)
participant API as itc/pennyperfect (/api/v1/reports)
participant Iframe as Hidden Print Iframe (/external/reports)
participant Engine as html2canvas + jsPDF
User->>Page: Select Monthly Summary & Branch Filter
Page->>Store: fetchMonthlySummary({ branchId, month, year })
Store->>API: GET /api/v1/reports/monthly-summary
API-->>Store: JSON Summary Records
Store-->>Page: Render On-Screen Report
User->>Page: Click "Export to PDF"
Page->>Iframe: Mount styled report in hidden A4 print frame
Iframe->>Engine: html2canvas captures high-res DOM snapshot (.report-preview-a4)
Engine->>Engine: Paginate canvas slices into 297x210mm A4 pages (jsPDF)
Engine-->>User: Trigger browser PDF download (PennyPerfect_Report_2026.pdf)What I Built (Personal Contributions)
- Engineered Multi-Package Frontend Architecture: Decomposed the accounting system into 7 modular Vite/Vue 3 packages (
@itc/pennyperfect-*) with standalone routes, Pinia stores, and Quasar UI pages. - P0 Authentication & Tax API Resolution: Diagnosed and fixed boot-time tax endpoint failure that caused unexpected session logouts on page load by implementing
configureTaxApilazy configuration. - Standardized Host Provide/Inject Integration: Implemented host boot providers for
apiClient,authStore, andtenantStore, ensuring uniform Sanctum Bearer tokens andX-Tenant-Idheader propagation. - Branch API Alignment: Refactored branch loaders across statements and reports to consume
GET /tenants/{tenantId}/branchesfromitc/core-auth-accountsand made branch fields nullable for flexible transactions. - Route & Menu Discovery Pipeline: Streamlined
appPlugin.routesand@itc/menu-systemauto-discovery to expose 6 production accounting surfaces under the/penny-perfect/*hierarchy. - Client-Side PDF Generation Engine: Designed an in-browser PDF export pipeline using hidden iframe rendering,
html2canvas, andjsPDFfor pixel-perfect A4 accounting statements without server rendering load.
Case closed
More work.