The project's README from github.com/AhmadHassan-BTed/Ledgerify. As one markdown file: README.md.
A resilient, browser-native analytics platform engineered for complex Shopify Excel exports. Built with an Obsidian dark interface, zero-backend architecture, dynamic schema normalization, and multi-departmental intelligence.
Modern e-commerce ledgers generated by Shopify exports often contain irregular schemas, composite product bundles, inconsistent date serials, and fragmented departmental requirements. Ledgerify was created to solve this problem entirely on the client side.
By combining browser-native SheetJS parsing, resilient schema normalization, and an Inversion-of-Control (IoC) dependency injection container, Ledgerify transforms raw, multi-megabyte Excel spreadsheets into structured domain intelligence across eight specialized organizational roles without sending data to an external server.
The platform provides human-centric visibility: leaders and operators receive clear, synthesized conclusions rather than being overwhelmed by raw tabular data.
Ledgerify is built upon three core engineering pillars:
For the comprehensive technical specification, class diagrams, normalization rules, and state management flow, see ARCHITECTURE.md.
flowchart TD
subgraph ClientLayer["Client Layer (Browser Runtime)"]
A["User Upload (.xlsx / .csv)"] --> B["IFileParser (SheetJS Engine)"]
B --> C["Resilient Normalizer & Header Mapper"]
C --> D["Domain Entities (NormalizedOrder[])"]
D --> E["IStorageService (IndexedDB Cache)"]
end
subgraph ServiceLayer["Domain & Service Layer (IoC Container)"]
E --> F["Dependency Injection Container"]
F --> G1["ExecutiveService"]
F --> G2["FinanceService"]
F --> G3["InventoryService"]
F --> G4["OperationsService"]
F --> G5["MarketingService"]
F --> G6["CreativeService"]
F --> G7["AdminDataQualityService"]
F --> G8["CompareService"]
end
subgraph PresentationLayer["Presentation Layer (Obsidian UI)"]
G1 & G2 & G3 & G4 & G5 & G6 & G7 & G8 --> H["React Context Providers"]
H --> I["Departmental View Controllers"]
I --> J["Interactive Visualizations & Drill-Downs"]
end
Raw Shopify exports exhibit variations across stores, countries, and export configurations. The normalization pipeline dynamically detects headers, reconciles currency formats, and structures composite line items.
flowchart LR
A["Raw Workbook Buffer"] --> B["Workbook Sheet Discovery"]
B --> C["Header Fuzzy Normalization"]
C --> D["Value Sanitization & Type Coercion"]
D --> E["Compound Bundle Splitting"]
E --> F["Flag & Anomaly Tagging"]
F --> G["NormalizedOrder Schema"]
subgraph NormalizationLogic["Transformation Rules"]
C -.- C1["Case & whitespace agnostic regex matching"]
D -.- D1["Excel serial date to ISO UTC conversion"]
E -.- E1["Extracts individual bottles from Discovery/Trio sets"]
F -.- F1["Identifies $0 test orders, missing emails, spike quantities"]
end
When an operator uploads a workbook or toggles between datasets, the execution flow follows a deterministic, non-blocking lifecycle:
sequenceDiagram
autonumber
actor User as Operator
participant UI as Dashboard UI
participant Parser as File Parser (SheetJS)
participant Normalizer as Schema Normalizer
participant Storage as IndexedDB Storage
participant DI as IoC Container
participant Services as Domain Services
User->>UI: Selects .xlsx / .csv file
UI->>Parser: Passes ArrayBuffer
Parser->>Normalizer: Streams raw sheet records
Normalizer->>Normalizer: Resolves dynamic column mappings
Normalizer->>Normalizer: Extracts category yields & anomalies
Normalizer-->>Storage: Persists NormalizedDataset
Normalizer-->>DI: Injects Active Dataset State
DI->>Services: Trigger reactive metric calculation
Services-->>UI: Dispatches aggregated view models
UI-->>User: Renders Obsidian dashboards with 0ms server latency
The application decouples interface components from domain calculation algorithms through the Service Context and IoC Container.
classDiagram
class IFileParser {
<<interface>>
+parse(file: File): Promise~NormalizedOrder[]~
}
class IStorageService {
<<interface>>
+saveDataset(dataset: Dataset): Promise~void~
+getDatasets(): Promise~Dataset[]~
+deleteDataset(id: string): Promise~void~
}
class ServiceContainer {
+financeService: FinanceService
+executiveService: ExecutiveService
+inventoryService: InventoryService
+operationsService: OperationsService
+marketingService: MarketingService
+creativeService: CreativeService
+adminService: AdminDataQualityService
+compareService: CompareService
}
class DataProvider {
+activeDataset: Dataset
+filteredOrders: NormalizedOrder[]
+setFilter(filter: FilterState): void
}
ServiceContainer --> FinanceService
ServiceContainer --> ExecutiveService
ServiceContainer --> InventoryService
ServiceContainer --> OperationsService
ServiceContainer --> MarketingService
DataProvider ..> ServiceContainer : Consumes via Context
IFileParser <|.. XlsxParser
IStorageService <|.. IndexedDbStorage
Ledgerify utilizes automated continuous integration via GitHub Actions, compiling TypeScript bundles and deploying static assets to GitHub Pages.
flowchart TD
subgraph GitRepository["Git Repository"]
A["Push to main branch"] --> B["GitHub Actions Triggered"]
end
subgraph CIWorkflow["CI / CD Pipeline"]
B --> C["Setup Node.js Runtime"]
C --> D["npm ci (Deterministic Dependency Tree)"]
D --> E["tsc --noEmit (Type Integrity Validation)"]
E --> F["vite build (Production Minification)"]
F --> G["Upload Artifact (dist/)"]
end
subgraph HostingInfrastructure["Edge Hosting"]
G --> H["Deploy to GitHub Pages Environment"]
H --> I["Public Release (HTTPS / Global CDN)"]
end
Ledgerify structures analytical output into eight dedicated dashboards, each aligned with specific business functions:
| View Perspective | Target Role | Key Metrics & Visualizations | Status |
|---|---|---|---|
| Executive | CEO / Founders | Month-over-Month trajectory, buyer retention rates, revenue pacing gauge, customer acquisition split. | ✓ |
| Finance | CFO / Controller | Gross ledger totals, net revenue, category yields (50ml, 100ml, Discovery, Trio), refund liabilities. | ✓ |
| Inventory | Supply Chain / Ops | Fragrance velocity meters, reorder urgency triage, composite set extraction, physical bottle share. | ✓ |
| Operations | Warehouse / Fulfillment | Day-of-week dispatch heatmap, shipping province hotspots, multi-box packing complexity ratios. | ✓ |
| Marketing | Growth / Performance | High-value customer tiers, geographic ad allocation, cart co-purchase affinity matrix, repeat cohorts. | ✓ |
| Creative | Design & Studio | Visual brief generators, hero product identification, packaging style trends, scent keyword demand. | ✓ |
| Admin Quality | Data Engineers | Automated health scores, missing field audits, test order isolation, quantity spike detection. | ✓ |
| Comparison | Strategy & Finance | Side-by-side multi-file benchmarking, variance delta calculations, dual-series curves. | ✓ |
The normalizer handles varied naming conventions across Shopify CSV and Excel exports:
Name, Order ID, Order Number, #, Invoice IDCreated at, Order Date, Date, Processed at, Sale DateEmail, Customer Email, Contact EmailFinancial Status, Payment Status, StatusTotal, Total Amount, Gross Sales, Net Sales, SubtotalLineitem name, Item Name, Items, Products, DescriptionLineitem quantity, Total Quantity, Quantity, QtyShipping City, City, Shipping Province, State, RegionLedgerifyDB) operating within origin sandboxing.Ledgerify/
├── .github/
│ └── workflows/
│ └── deploy.yml # GitHub Actions Pages deployment pipeline
├── scripts/
│ ├── inspect.js # CLI utility for workbook inspection
│ └── inspect_sheets.js # Multi-sheet diagnostic analyzer
├── src/
│ ├── components/
│ │ ├── charts/ # Recharts components (Area, Bar, Donut, Multi-Series)
│ │ ├── layout/ # Top navigation, dataset switcher, theme controls
│ │ ├── ui/ # Atomic UI cards, heatmaps, gauges, tables
│ │ └── views/ # 8 departmental dashboard implementations
│ ├── context/
│ │ ├── DataContext.tsx # Dataset state and upload orchestrator
│ │ ├── FilterContext.tsx # Date, search, and category filter provider
│ │ ├── ServiceContext.tsx # Dependency injection context provider
│ │ └── ThemeContext.tsx # Obsidian dark / light mode manager
│ ├── core/
│ │ ├── di/
│ │ │ └── container.ts # IoC Service Container
│ │ ├── parser/
│ │ │ ├── IFileParser.ts # Parser contract
│ │ │ ├── normalizer.ts # Resilient header & entity normalizer
│ │ │ └── xlsxParser.ts # SheetJS workbook parser
│ │ ├── services/ # Pure departmental calculation services
│ │ └── storage/ # IndexedDB persistence adapter
│ ├── styles/
│ │ └── themes/ # CSS theme definitions and role accents
│ ├── types/ # Domain interfaces and analytics models
│ ├── App.tsx # Root application container
│ ├── index.css # Obsidian design tokens and base styles
│ └── main.tsx # Application entry point
├── package.json # Project manifests and scripts
├── tsconfig.json # TypeScript compiler configuration
└── vite.config.ts # Vite build bundler configuration
# Clone the repository
git clone https://github.com/AhmadHassan-BTed/.github.git Ledgerify
cd Ledgerify
# Install dependencies deterministically
npm ci
# Start the local development server
npm run dev
The application will be accessible at http://localhost:5173. A sample ledger is pre-bundled for instant local evaluation.
# Execute TypeScript type validation and Vite production bundling
npm run build
# Preview production build locally
npm run preview
Contributions adhering to strict engineering standards are welcomed. When submitting changes:
core/services/, not inside presentation components.any overrides where domain models exist.$0 test orders, and missing columns without runtime exceptions.npm run build passes with zero errors before opening pull requests.Engineered and designed by Ahmad Hassan (B-Ted).
This project is open-source software licensed under the MIT License.