All 11 agents (S2-H01 through S2-H09 + S2-H03A + S2-H07A) have completed their technical specifications: - S2-H01: NaviDocs codebase architecture analysis - S2-H02: Inventory tracking system (€15K-€50K value recovery) - S2-H03: Maintenance log & reminder system - S2-H04: Camera & Home Assistant integration - S2-H05: Contact management system - S2-H06: Accounting module & receipt OCR integration - S2-H07: Impeccable search UX (Meilisearch facets) - S2-H08: WhatsApp Business API + AI agent integration - S2-H09: Document versioning with IF.TTT compliance - S2-H03A: VAT/tax jurisdiction tracking & compliance - S2-H07A: Multi-calendar system (4 calendar types) Total: ~15,600 lines of technical specifications Status: Ready for S2-H10 synthesis (awaiting Session 1 completion) IF.bus: All inter-agent communications documented
1752 lines
65 KiB
Markdown
1752 lines
65 KiB
Markdown
# S2-H06: Receipt/Invoice Upload + Accounting Module Integration Specification
|
|
|
|
**Agent Identity:** S2-H06
|
|
**Assigned to:** Receipt/Invoice Upload + Accounting Module Integration
|
|
**Document Status:** Complete Specification
|
|
**Session:** Cloud Session 2 - Technical Integration Architecture
|
|
**Date:** 2025-11-13
|
|
|
|
---
|
|
|
|
## Executive Summary
|
|
|
|
This specification defines the architectural integration of receipt/invoice upload and multi-user expense tracking for NaviDocs. The system enables boat owners and captains to capture, process, and manage expenses with OCR-powered automation, reimbursement workflows, and full IF.TTT compliance for audit traceability.
|
|
|
|
**Key Components:**
|
|
- Multi-user expense tracking (owner, captain, crew)
|
|
- Receipt/invoice OCR workflow (photo → extraction → review → save)
|
|
- Accounting module integration (Spliit fork for MIT-licensed flexibility)
|
|
- Reimbursement workflow with owner approval
|
|
- WhatsApp AI integration for expense logging
|
|
- Multi-currency support (€, $, £)
|
|
- Export to Excel/CSV for accountants
|
|
- Full IF.TTT audit trail compliance
|
|
|
|
---
|
|
|
|
## 1. Multi-User Expense Tracking Design
|
|
|
|
### 1.1 User Roles & Expense Categories
|
|
|
|
#### Owner Expenditure
|
|
- **Payment Methods:** Cash, card, bank transfers
|
|
- **Typical Expenses:** Marina fees, insurance, major upgrades, professional services, fuel, haul-outs
|
|
- **Approval Flow:** Direct entry (owner logs own expenses) + approval of captain reimbursements
|
|
- **Budget Authority:** Can set monthly/annual budgets and approve work roadmap expenses
|
|
- **Tax Implications:** Tracks VAT status, business vs. personal expenses (for charter/rental boats)
|
|
|
|
#### Captain/Crew Expenditure
|
|
- **Payment Methods:** Boat card (pre-approved limit), boat cash, personal funds (for reimbursement)
|
|
- **Typical Expenses:** Provisions, fuel, minor repairs, supplies, crew meals, dockage during captain-only periods
|
|
- **Approval Flow:** Submit receipt → OCR extraction → owner approves/rejects → mark paid
|
|
- **Documentation:** Must provide receipt photo for all expenses
|
|
- **Reimbursement Tracking:** Separate accounting for personal cash advances vs. company card charges
|
|
|
|
### 1.2 Expense Categories (Hierarchical)
|
|
|
|
```
|
|
Root Categories:
|
|
├── Fuel & Provisioning
|
|
│ ├── Fuel
|
|
│ ├── Diesel
|
|
│ ├── LPG
|
|
│ ├── Provisions (food/water)
|
|
│ └── Beverage supplies
|
|
├── Marina & Mooring
|
|
│ ├── Marina fees
|
|
│ ├── Mooring buoy rental
|
|
│ ├── Harbor dues
|
|
│ └── Fuel dock (if separate)
|
|
├── Maintenance & Repairs
|
|
│ ├── Engine maintenance
|
|
│ ├── Electronics
|
|
│ ├── Hull & Structure
|
|
│ ├── Deck & Rigging
|
|
│ ├── Safety equipment
|
|
│ └── Professional services (surveyor, mechanic)
|
|
├── Insurance
|
|
│ ├── Hull insurance
|
|
│ ├── Liability insurance
|
|
│ ├── Crew insurance
|
|
│ └── Document insurance
|
|
├── Professional Upgrades
|
|
│ ├── Electronics upgrades
|
|
│ ├── Safety system upgrades
|
|
│ ├── Interior renovations
|
|
│ └── Engine upgrades
|
|
├── Operating Expenses
|
|
│ ├── Crew salaries/tips
|
|
│ ├── Supplies & consumables
|
|
│ ├── Cleaning & laundry
|
|
│ ├── Documentation & permits
|
|
│ └── Crew meals
|
|
├── Miscellaneous
|
|
│ ├── Tips & gratuities
|
|
│ ├── Small tools
|
|
│ ├── Spare parts inventory
|
|
│ └── Other
|
|
|
|
Currency: € (EUR), $ (USD), £ (GBP) - auto-converted to primary boat currency
|
|
```
|
|
|
|
### 1.3 Expense Model Schema
|
|
|
|
```sql
|
|
CREATE TABLE expenses (
|
|
id VARCHAR(36) PRIMARY KEY,
|
|
boat_id VARCHAR(36) NOT NULL,
|
|
|
|
-- User/Role Information
|
|
created_by_user_id VARCHAR(36) NOT NULL,
|
|
created_by_role ENUM('owner', 'captain', 'crew') NOT NULL,
|
|
|
|
-- Financial Data
|
|
amount DECIMAL(12, 2) NOT NULL,
|
|
currency ENUM('EUR', 'USD', 'GBP', 'OTHER') DEFAULT 'EUR',
|
|
amount_in_primary_currency DECIMAL(12, 2) DEFAULT NULL,
|
|
exchange_rate DECIMAL(10, 6) DEFAULT 1.0,
|
|
|
|
-- Expense Details
|
|
vendor_name VARCHAR(255),
|
|
vendor_id VARCHAR(36) DEFAULT NULL, -- Link to boat_contacts if recurring vendor
|
|
|
|
category_id VARCHAR(36) NOT NULL,
|
|
category_name VARCHAR(100), -- Denormalized for quick access
|
|
|
|
purchase_date DATE NOT NULL,
|
|
description VARCHAR(500),
|
|
|
|
-- Reimbursement Tracking
|
|
payment_method ENUM('cash', 'card', 'bank_transfer', 'personal_cash', 'boat_cash') NOT NULL,
|
|
reimbursement_status ENUM('pending', 'approved', 'rejected', 'paid', 'partial', 'pending_captain_approval') DEFAULT 'pending',
|
|
reimbursement_requested_at TIMESTAMP,
|
|
reimbursement_approved_by_user_id VARCHAR(36),
|
|
reimbursement_approved_at TIMESTAMP,
|
|
reimbursement_amount DECIMAL(12, 2),
|
|
reimbursement_date DATE,
|
|
|
|
-- VAT/Tax
|
|
vat_amount DECIMAL(10, 2),
|
|
vat_percentage DECIMAL(5, 2),
|
|
tax_deductible BOOLEAN DEFAULT TRUE,
|
|
|
|
-- OCR & Receipt Data
|
|
receipt_image_url VARCHAR(2048),
|
|
receipt_image_hash VARCHAR(64), -- SHA-256 for IF.TTT
|
|
ocr_extracted BOOLEAN DEFAULT FALSE,
|
|
ocr_vendor VARCHAR(255),
|
|
ocr_amount DECIMAL(12, 2),
|
|
ocr_date DATE,
|
|
ocr_vat DECIMAL(10, 2),
|
|
ocr_raw_text LONGTEXT,
|
|
ocr_confidence DECIMAL(3, 2),
|
|
|
|
-- Linking to Other Modules
|
|
maintenance_log_id VARCHAR(36) DEFAULT NULL,
|
|
inventory_item_id VARCHAR(36) DEFAULT NULL,
|
|
calendar_event_id VARCHAR(36) DEFAULT NULL,
|
|
|
|
-- IF.TTT Compliance
|
|
content_hash VARCHAR(64), -- SHA-256 of all expense data
|
|
ed25519_signature VARCHAR(128), -- Ed25519 signature of creator
|
|
citation_id VARCHAR(255), -- if://receipt/navidocs/boat-123/expense-456
|
|
|
|
-- Timestamps & Tracking
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
deleted_at TIMESTAMP,
|
|
|
|
-- Audit
|
|
audit_log LONGTEXT, -- JSON array of all changes
|
|
|
|
INDEX idx_boat_id (boat_id),
|
|
INDEX idx_created_by (created_by_user_id),
|
|
INDEX idx_category (category_id),
|
|
INDEX idx_purchase_date (purchase_date),
|
|
INDEX idx_reimbursement_status (reimbursement_status),
|
|
INDEX idx_payment_method (payment_method),
|
|
FOREIGN KEY (boat_id) REFERENCES boats(id),
|
|
FOREIGN KEY (created_by_user_id) REFERENCES users(id),
|
|
FOREIGN KEY (category_id) REFERENCES expense_categories(id),
|
|
FOREIGN KEY (maintenance_log_id) REFERENCES maintenance_log(id),
|
|
FOREIGN KEY (inventory_item_id) REFERENCES boat_inventory(id),
|
|
FOREIGN KEY (calendar_event_id) REFERENCES calendar_events(id)
|
|
);
|
|
|
|
-- Reimbursement Tracking (for captain expenses paid from personal funds)
|
|
CREATE TABLE reimbursement_requests (
|
|
id VARCHAR(36) PRIMARY KEY,
|
|
boat_id VARCHAR(36) NOT NULL,
|
|
|
|
-- Request Details
|
|
captain_user_id VARCHAR(36) NOT NULL,
|
|
owner_user_id VARCHAR(36) NOT NULL,
|
|
|
|
-- Aggregation
|
|
total_requested DECIMAL(12, 2) NOT NULL,
|
|
total_approved DECIMAL(12, 2) DEFAULT 0,
|
|
total_paid DECIMAL(12, 2) DEFAULT 0,
|
|
currency ENUM('EUR', 'USD', 'GBP') DEFAULT 'EUR',
|
|
|
|
-- Workflow
|
|
request_date TIMESTAMP NOT NULL,
|
|
request_status ENUM('draft', 'submitted', 'owner_reviewing', 'approved', 'rejected', 'in_payment', 'paid', 'partial') DEFAULT 'draft',
|
|
owner_approved_at TIMESTAMP,
|
|
owner_notes VARCHAR(500),
|
|
|
|
-- Attached Expenses (many-to-many)
|
|
expense_ids JSON, -- Array of expense IDs included in request
|
|
|
|
-- Payment Tracking
|
|
payment_method ENUM('bank_transfer', 'cash', 'card', 'other'),
|
|
payment_date TIMESTAMP,
|
|
payment_reference VARCHAR(100),
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
|
FOREIGN KEY (boat_id) REFERENCES boats(id),
|
|
FOREIGN KEY (captain_user_id) REFERENCES users(id),
|
|
FOREIGN KEY (owner_user_id) REFERENCES users(id),
|
|
INDEX idx_boat (boat_id),
|
|
INDEX idx_status (request_status),
|
|
INDEX idx_captain (captain_user_id)
|
|
);
|
|
|
|
-- Expense Categories (Customizable)
|
|
CREATE TABLE expense_categories (
|
|
id VARCHAR(36) PRIMARY KEY,
|
|
boat_id VARCHAR(36) NOT NULL,
|
|
|
|
name VARCHAR(100) NOT NULL,
|
|
description VARCHAR(500),
|
|
parent_category_id VARCHAR(36), -- For hierarchical categories
|
|
|
|
-- Defaults for this category
|
|
is_taxable BOOLEAN DEFAULT TRUE,
|
|
average_vat_percentage DECIMAL(5, 2),
|
|
default_payment_method VARCHAR(50),
|
|
|
|
-- System vs. Custom
|
|
is_system_default BOOLEAN DEFAULT FALSE,
|
|
|
|
color_hex VARCHAR(7), -- For UI display
|
|
icon VARCHAR(50),
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
deleted_at TIMESTAMP,
|
|
|
|
FOREIGN KEY (boat_id) REFERENCES boats(id),
|
|
FOREIGN KEY (parent_category_id) REFERENCES expense_categories(id),
|
|
INDEX idx_boat (boat_id),
|
|
UNIQUE KEY unique_name_per_boat (boat_id, name)
|
|
);
|
|
|
|
-- Multi-Currency Exchange Rate History
|
|
CREATE TABLE exchange_rates (
|
|
id VARCHAR(36) PRIMARY KEY,
|
|
from_currency ENUM('EUR', 'USD', 'GBP', 'OTHER'),
|
|
to_currency ENUM('EUR', 'USD', 'GBP', 'OTHER'),
|
|
rate DECIMAL(10, 6),
|
|
date DATE,
|
|
source VARCHAR(100), -- 'ECB', 'OER', 'manual', etc.
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
INDEX idx_currencies (from_currency, to_currency, date)
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Receipt/Invoice OCR Workflow
|
|
|
|
### 2.1 OCR Processing Pipeline
|
|
|
|
```
|
|
User Flow:
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ 1. Mobile Upload (Camera or Gallery) │
|
|
│ - Capture receipt photo or select from gallery │
|
|
│ - Auto-crop to receipt area (smart phone features) │
|
|
│ - Compression for bandwidth (JPEG, max 5MB) │
|
|
└──────────────────┬──────────────────────────────────────────┘
|
|
│
|
|
┌──────────────────▼──────────────────────────────────────────┐
|
|
│ 2. Image Storage & Hashing (IF.TTT) │
|
|
│ - Store original image: /boat-{boatId}/receipts/ │
|
|
│ - Generate SHA-256 hash of image file │
|
|
│ - Generate Ed25519 signature (uploader identity) │
|
|
│ - Create citation_id: if://receipt/navidocs/boat-Y/Z │
|
|
└──────────────────┬──────────────────────────────────────────┘
|
|
│
|
|
┌──────────────────▼──────────────────────────────────────────┐
|
|
│ 3. OCR Processing (Parallel) │
|
|
│ a) Tesseract (local, fast, offline) │
|
|
│ - Extracts raw text from image │
|
|
│ - Returns text block bounding boxes │
|
|
│ b) Google Vision API (cloud, accurate) │
|
|
│ - Full document analysis │
|
|
│ - Structured text detection │
|
|
│ - Response: { items, subtotal, tax, total, date } │
|
|
│ c) Custom boat-specific patterns │
|
|
│ - Marina receipt patterns (fee breakdown) │
|
|
│ - Fuel receipt patterns (type, quantity, price) │
|
|
│ - Parts supplier patterns (item codes) │
|
|
└──────────────────┬──────────────────────────────────────────┘
|
|
│
|
|
┌──────────────────▼──────────────────────────────────────────┐
|
|
│ 4. Structured Data Extraction │
|
|
│ - Vendor name (from header/footer) │
|
|
│ - Amount (total, subtotal, tax) │
|
|
│ - Date (receipt date, transaction date) │
|
|
│ - VAT/Tax percentage │
|
|
│ - Currency │
|
|
│ - Line items (if detailed receipt) │
|
|
│ - Confidence scores per field │
|
|
└──────────────────┬──────────────────────────────────────────┘
|
|
│
|
|
┌──────────────────▼──────────────────────────────────────────┐
|
|
│ 5. Category Suggestion (ML/Rules) │
|
|
│ - Pattern match against vendor database │
|
|
│ - Keyword matching (e.g., "Diesel" → Fuel category) │
|
|
│ - User history (captain usually buys provisions → suggest)│
|
|
│ - Context (if linked to maintenance log, suggest related │
|
|
│ - Present 1st/2nd/3rd category suggestions │
|
|
└──────────────────┬──────────────────────────────────────────┘
|
|
│
|
|
┌──────────────────▼──────────────────────────────────────────┐
|
|
│ 6. Review & Confirmation (User Interface) │
|
|
│ ┌────────────────────────────────────────────────┐ │
|
|
│ │ Receipt Image (small preview) │ │
|
|
│ ├────────────────────────────────────────────────┤ │
|
|
│ │ Vendor: [extracted] ← editable text field │ │
|
|
│ │ Date: [extracted] ← date picker │ │
|
|
│ │ Amount: [extracted] [Currency dropdown] │ │
|
|
│ │ VAT: [extracted] ← numeric field │ │
|
|
│ │ Category: [1st suggestion] ▼ (other options) │ │
|
|
│ │ Description: [optional text] │ │
|
|
│ │ Link to: □ Maintenance log □ Inventory │ │
|
|
│ │ □ Calendar event │ │
|
|
│ │ [Cancel] [Save] [Reuse as Template] │ │
|
|
│ └────────────────────────────────────────────────┘ │
|
|
│ - OCR confidence shown as visual indicator │
|
|
│ - User can edit any field before saving │
|
|
│ - Option to reuse as expense template │
|
|
└──────────────────┬──────────────────────────────────────────┘
|
|
│
|
|
┌──────────────────▼──────────────────────────────────────────┐
|
|
│ 7. Expense Creation & IF.TTT Signing │
|
|
│ - Create expense record with extracted data │
|
|
│ - Calculate content_hash (SHA-256 of all fields) │
|
|
│ - Generate ed25519_signature from user's private key │
|
|
│ - Generate citation_id link │
|
|
│ - Store audit log: who, when, what was edited │
|
|
└──────────────────┬──────────────────────────────────────────┘
|
|
│
|
|
┌──────────────────▼──────────────────────────────────────────┐
|
|
│ 8. Workflow Routing │
|
|
│ IF (creator_role == 'owner'): │
|
|
│ - Mark as 'recorded' (no approval needed) │
|
|
│ - Optional: link to maintenance/inventory │
|
|
│ IF (creator_role == 'captain' OR 'crew'): │
|
|
│ - Mark as 'pending_captain_approval' │
|
|
│ - Wait for captain approval before owner approval │
|
|
│ - Notify captain: "New expense request from [crew]" │
|
|
│ IF (captain role): │
|
|
│ - Mark as 'pending' (awaiting owner approval) │
|
|
│ - Notify owner: "New reimbursement request" │
|
|
│ - Captain can modify until approval │
|
|
│ ELSE: │
|
|
│ - Auto-approve if preset rule matches │
|
|
└──────────────────┬──────────────────────────────────────────┘
|
|
│
|
|
└──────────────────▼──────────────────────────────────────────┘
|
|
Done!
|
|
```
|
|
|
|
### 2.2 OCR API Integration
|
|
|
|
**Primary Provider: Google Cloud Vision API**
|
|
```javascript
|
|
// google-vision-integration.js
|
|
|
|
const vision = require('@google-cloud/vision');
|
|
|
|
async function extractReceiptData(imagePath) {
|
|
const client = new vision.ImageAnnotatorClient({
|
|
keyFilename: process.env.GOOGLE_VISION_KEY_FILE
|
|
});
|
|
|
|
const request = {
|
|
image: { source: { filename: imagePath } },
|
|
};
|
|
|
|
const [result] = await client.documentTextDetection(request);
|
|
const fullTextAnnotation = result.fullTextAnnotation;
|
|
|
|
// Parse text detection results
|
|
return {
|
|
rawText: fullTextAnnotation.text,
|
|
blocks: fullTextAnnotation.pages[0].blocks,
|
|
textAnnotations: result.textAnnotations
|
|
};
|
|
}
|
|
|
|
async function parseReceiptStructure(rawText, blocks) {
|
|
// Custom parsing rules for boat receipts
|
|
const parsed = {
|
|
vendor: null,
|
|
date: null,
|
|
amount: null,
|
|
vat: null,
|
|
currency: 'EUR',
|
|
lineItems: [],
|
|
confidence: {}
|
|
};
|
|
|
|
// Pattern matching for common vendors
|
|
const vendorPatterns = {
|
|
marina: /marina|port|harbour|mooring|dock/i,
|
|
fuel: /diesel|fuel|gasolina|essence|petrol|lpg|gas/i,
|
|
maintenance: /maintenance|repair|service|technician|mechanic/i,
|
|
supplies: /supply|chandlery|provisions|grocery|supermarket/i
|
|
};
|
|
|
|
// Date extraction (multiple formats)
|
|
const dateRegex = /(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}|\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2})/;
|
|
const dateMatch = rawText.match(dateRegex);
|
|
if (dateMatch) {
|
|
parsed.date = normalizeDate(dateMatch[1]);
|
|
parsed.confidence.date = 0.95;
|
|
}
|
|
|
|
// Amount extraction (€, $, £, etc.)
|
|
const amountRegex = /[€$£¥]?\s*(\d+[\.\,]\d{2})/;
|
|
const amounts = rawText.matchAll(amountRegex);
|
|
const amountArray = Array.from(amounts);
|
|
|
|
if (amountArray.length > 0) {
|
|
// Take largest amount (usually total)
|
|
const total = Math.max(...amountArray.map(m => parseFloat(m[1].replace(',', '.'))));
|
|
parsed.amount = total;
|
|
parsed.confidence.amount = 0.90;
|
|
}
|
|
|
|
// VAT extraction
|
|
const vatRegex = /VAT|TVA|IVA|GST|TAX[:\s]*(\d+[\.\,]\d{2})/i;
|
|
const vatMatch = rawText.match(vatRegex);
|
|
if (vatMatch) {
|
|
parsed.vat = parseFloat(vatMatch[1].replace(',', '.'));
|
|
parsed.confidence.vat = 0.85;
|
|
}
|
|
|
|
return parsed;
|
|
}
|
|
|
|
async function categorizeExpense(vendor, amount, rawText, boatId) {
|
|
// Rule-based categorization
|
|
const rulesDb = await loadCategoryRules(boatId);
|
|
|
|
// Check vendor database first
|
|
const vendorMatch = await db.query(
|
|
'SELECT category_id FROM vendor_categories WHERE boat_id = ? AND vendor ILIKE ?',
|
|
[boatId, vendor]
|
|
);
|
|
|
|
if (vendorMatch) {
|
|
return {
|
|
category: vendorMatch.category_id,
|
|
confidence: 0.99,
|
|
reason: 'vendor_history'
|
|
};
|
|
}
|
|
|
|
// Pattern matching
|
|
const patterns = {
|
|
fuel: /diesel|fuel|gasoline|petrol|lpg|fuel_dock/i,
|
|
provisions: /provisions|food|grocery|supermarket|market/i,
|
|
maintenance: /maintenance|repair|service|mechanic|technician/i,
|
|
marina: /marina|port|harbour|mooring|dock|berth/i,
|
|
insurance: /insurance|assurance|coasec/i
|
|
};
|
|
|
|
for (const [category, pattern] of Object.entries(patterns)) {
|
|
if (pattern.test(vendor) || pattern.test(rawText)) {
|
|
return {
|
|
category,
|
|
confidence: 0.75,
|
|
reason: 'pattern_match'
|
|
};
|
|
}
|
|
}
|
|
|
|
// Fallback: user-provided category
|
|
return {
|
|
category: 'miscellaneous',
|
|
confidence: 0.40,
|
|
reason: 'fallback'
|
|
};
|
|
}
|
|
```
|
|
|
|
**Fallback Provider: Tesseract (Local)**
|
|
```javascript
|
|
// tesseract-fallback.js
|
|
|
|
const Tesseract = require('tesseract.js');
|
|
|
|
async function extractWithTesseract(imagePath) {
|
|
const { data: { text } } = await Tesseract.recognize(
|
|
imagePath,
|
|
['eng', 'fra', 'deu', 'ita', 'spa'], // Yacht typically multilingual
|
|
{
|
|
logger: m => console.log('Tesseract:', m.status, m.progress)
|
|
}
|
|
);
|
|
|
|
return text;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Accounting Module Architecture
|
|
|
|
### 3.1 Integration Strategy: Fork vs. Library
|
|
|
|
**Recommended Approach: Spliit Fork (MIT License)**
|
|
|
|
**Rationale:**
|
|
- ✅ Boat-specific features (owner/captain/crew roles not in original Spliit)
|
|
- ✅ Full control over expense data model
|
|
- ✅ Direct integration with IF.TTT compliance (signatures, hashes)
|
|
- ✅ Customizable workflows (reimbursement approval chains)
|
|
- ✅ Multi-currency support (Spliit has this; we enhance)
|
|
- ✅ Receipt scanning core feature (matches our OCR pipeline)
|
|
- ✅ PWA mobile support (critical for boat operations)
|
|
- ✅ MIT license allows commercial use, modifications
|
|
|
|
**Spliit Source:** https://github.com/pmihaylov/spliit (2.3K stars, active)
|
|
|
|
**Fork & Customize Process:**
|
|
```bash
|
|
# 1. Fork Spliit repository
|
|
git clone https://github.com/[navidocs-org]/spliit-navidocs.git
|
|
cd spliit-navidocs
|
|
|
|
# 2. Merge NaviDocs-specific branches
|
|
git remote add upstream https://github.com/pmihaylov/spliit.git
|
|
git fetch upstream
|
|
git merge upstream/main # Get latest Spliit features
|
|
|
|
# 3. Create navidocs-specific branch
|
|
git checkout -b feature/navidocs-yacht-integration
|
|
|
|
# 4. Customize for boat workflows
|
|
- Modify user roles (owner, captain, crew vs. Spliit's split member)
|
|
- Enhance expense model with boat_id, maintenance_log_id, etc.
|
|
- Add IF.TTT compliance layer (signatures, hashes, citations)
|
|
- Implement reimbursement approval workflow
|
|
- Add multi-currency with exchange rate tracking
|
|
- Integrate receipt OCR (use our Google Vision pipeline)
|
|
- Add export to Excel/CSV for accountants
|
|
- Implement access controls (captain sees own expenses, owner sees all)
|
|
```
|
|
|
|
### 3.2 Integration with NaviDocs Backend
|
|
|
|
**Architecture Diagram:**
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ NaviDocs Frontend (Vue 3) │
|
|
│ │
|
|
│ Expenses Page: /app/boat/{boatId}/accounting │
|
|
│ - Receipt upload modal │
|
|
│ - Expense list (with search, filters, sort) │
|
|
│ - Reimbursement requests (captain view) │
|
|
│ - Approval flow (owner view) │
|
|
│ - Export to Excel │
|
|
└──────────────────┬──────────────────────────────────────────┘
|
|
│ HTTP/REST
|
|
┌──────────────────▼──────────────────────────────────────────┐
|
|
│ NaviDocs API Layer (Express.js) │
|
|
│ │
|
|
│ Routes: │
|
|
│ POST /api/expenses Create expense (OCR) │
|
|
│ GET /api/expenses?filter=... List expenses │
|
|
│ GET /api/expenses/{id} Get expense detail │
|
|
│ PUT /api/expenses/{id} Update expense │
|
|
│ POST /api/expenses/{id}/approve Owner approve │
|
|
│ POST /api/expenses/{id}/reject Owner reject │
|
|
│ POST /api/receipts/upload Upload receipt image │
|
|
│ POST /api/receipts/{id}/ocr Trigger OCR processing │
|
|
│ GET /api/reimbursements List requests │
|
|
│ POST /api/reimbursements Create request │
|
|
│ POST /api/reimbursements/{id}/approve Owner approve │
|
|
│ GET /api/expenses/export/excel Export for accountant │
|
|
│ │
|
|
│ Middleware: │
|
|
│ - Authentication (JWT) │
|
|
│ - Authorization (boat access control) │
|
|
│ - IF.TTT signing (Ed25519) │
|
|
│ - Audit logging │
|
|
└──────────────────┬──────────────────────────────────────────┘
|
|
│ ORM/Query
|
|
┌──────────────────▼──────────────────────────────────────────┐
|
|
│ Service Layer (Business Logic) │
|
|
│ │
|
|
│ ExpenseService: │
|
|
│ - createExpense(data) → IF.TTT signed record │
|
|
│ - approveExpense(expenseId, userId) │
|
|
│ - getExpensesByBoat(boatId, filters) │
|
|
│ - calculateReimbursement(expenseIds) │
|
|
│ - exportToExcel(boatId, dateRange) │
|
|
│ │
|
|
│ OCRService: │
|
|
│ - processReceipt(imagePath) → structured data │
|
|
│ - categorizeExpense(data) │
|
|
│ - extractWithGoogle(imagePath) | Tesseract(imagePath) │
|
|
│ │
|
|
│ ReimbursementService: │
|
|
│ - createRequest(captainId, expenseIds) │
|
|
│ - approveRequest(ownerId, requestId) │
|
|
│ - calculateOwedAmount(captainId, boatId) │
|
|
│ │
|
|
│ IF.TTTService: │
|
|
│ - signExpense(expenseData, signingKey) → Ed25519 sig │
|
|
│ - hashExpense(expenseData) → SHA-256 │
|
|
│ - generateCitationId(boatId, expenseId) │
|
|
└──────────────────┬──────────────────────────────────────────┘
|
|
│ Database
|
|
┌──────────────────▼──────────────────────────────────────────┐
|
|
│ SQLite3 Database (on Disk) │
|
|
│ │
|
|
│ Tables: │
|
|
│ - expenses │
|
|
│ - reimbursement_requests │
|
|
│ - expense_categories │
|
|
│ - exchange_rates │
|
|
│ - receipt_images (metadata + hash) │
|
|
│ - if_signatures (IF.TTT compliance log) │
|
|
│ - audit_logs (all changes to expenses) │
|
|
└──────────────────────────────────────────────────────────────┘
|
|
|
|
External Services:
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Google Cloud Vision API (OCR) │
|
|
│ - Document text detection │
|
|
│ - Structured data extraction │
|
|
│ - Handwriting recognition (for handwritten receipts) │
|
|
│ │
|
|
│ Background Job Queue (BullMQ + Redis) │
|
|
│ - Process OCR async (don't block user) │
|
|
│ - Generate exports (Excel files) │
|
|
│ - Send reimbursement notifications │
|
|
│ │
|
|
│ WhatsApp Business API (to S2-H08) │
|
|
│ - Send approval requests to owner │
|
|
│ - Send reimbursement notifications to captain │
|
|
│ - Inbound: "@NaviDocs log expense €45 fuel" │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 3.3 API Endpoint Specifications
|
|
|
|
```yaml
|
|
POST /api/receipts/upload
|
|
Description: Upload receipt image and trigger OCR
|
|
Auth: Required (JWT)
|
|
Body:
|
|
image: File (JPEG/PNG, max 5MB)
|
|
boat_id: string (UUID)
|
|
captured_date: string (ISO 8601, optional)
|
|
description: string (optional)
|
|
Response:
|
|
receipt_id: string
|
|
upload_status: "uploaded"
|
|
ocr_job_id: string # For async polling
|
|
ocr_status: "queued"
|
|
ocr_estimated_time_seconds: 5
|
|
Status: 201 Created
|
|
|
|
Webhook: /api/receipts/{receipt_id}/ocr-complete
|
|
When: OCR processing finishes
|
|
Payload:
|
|
receipt_id: string
|
|
extracted_data:
|
|
vendor: string
|
|
amount: number
|
|
currency: string
|
|
date: string (ISO 8601)
|
|
vat: number
|
|
confidence: object (per field)
|
|
ocr_status: "success" | "partial" | "failed"
|
|
|
|
---
|
|
|
|
POST /api/expenses
|
|
Description: Create expense from OCR data or manual entry
|
|
Auth: Required (JWT)
|
|
Body:
|
|
boat_id: string (UUID)
|
|
amount: number
|
|
currency: string (EUR|USD|GBP)
|
|
vendor: string
|
|
date: string (ISO 8601)
|
|
category_id: string (UUID)
|
|
description: string (optional)
|
|
receipt_id: string (optional)
|
|
vat_amount: number (optional)
|
|
linked_maintenance_id: string (optional)
|
|
linked_inventory_id: string (optional)
|
|
Response:
|
|
id: string (UUID)
|
|
status: "pending" | "pending_captain_approval" | "recorded"
|
|
created_by_role: string (owner|captain|crew)
|
|
citation_id: string (if://receipt/navidocs/boat-{boatId}/expense-{expenseId})
|
|
ed25519_signature: string # IF.TTT signing
|
|
content_hash: string (SHA-256)
|
|
Status: 201 Created
|
|
|
|
---
|
|
|
|
GET /api/expenses
|
|
Description: List expenses for a boat with filtering
|
|
Auth: Required (JWT)
|
|
Query Params:
|
|
boat_id: string (required)
|
|
category: string (optional, UUID)
|
|
date_from: string (ISO 8601, optional)
|
|
date_to: string (ISO 8601, optional)
|
|
status: string (pending|approved|rejected|paid, optional)
|
|
created_by: string (owner|captain|crew, optional)
|
|
payment_method: string (cash|card|bank_transfer, optional)
|
|
min_amount: number (optional)
|
|
max_amount: number (optional)
|
|
sort: string (date_desc|amount_desc|vendor_asc, default=date_desc)
|
|
page: number (default=1)
|
|
limit: number (default=25, max=100)
|
|
Response:
|
|
expenses: array
|
|
- id, vendor, amount, currency, date, category, status, created_by_role
|
|
total_count: number
|
|
page: number
|
|
total_pages: number
|
|
filters_applied: object
|
|
Status: 200 OK
|
|
|
|
---
|
|
|
|
POST /api/expenses/{expense_id}/approve
|
|
Description: Owner approves captain reimbursement
|
|
Auth: Required (JWT)
|
|
Body:
|
|
approved_by_user_id: string (owner's user ID)
|
|
notes: string (optional)
|
|
Response:
|
|
id: string
|
|
status: "approved"
|
|
approved_at: string (ISO 8601 timestamp)
|
|
approved_by_user_id: string
|
|
Status: 200 OK
|
|
|
|
---
|
|
|
|
POST /api/reimbursements
|
|
Description: Captain submits reimbursement request
|
|
Auth: Required (JWT)
|
|
Body:
|
|
boat_id: string (UUID)
|
|
captain_user_id: string (UUID)
|
|
expense_ids: array (of expense UUIDs)
|
|
notes: string (optional)
|
|
Response:
|
|
id: string (UUID)
|
|
status: "submitted"
|
|
total_requested: number
|
|
total_requested_currency: string
|
|
submitted_at: string (ISO 8601)
|
|
Status: 201 Created
|
|
|
|
---
|
|
|
|
POST /api/reimbursements/{request_id}/approve
|
|
Description: Owner approves reimbursement request
|
|
Auth: Required (JWT)
|
|
Body:
|
|
owner_user_id: string
|
|
approved_amount: number (optional, for partial approval)
|
|
payment_method: string (bank_transfer|cash|card)
|
|
payment_date: string (ISO 8601)
|
|
notes: string (optional)
|
|
Response:
|
|
id: string
|
|
status: "approved"
|
|
total_approved: number
|
|
approved_at: string
|
|
payment_method: string
|
|
Status: 200 OK
|
|
|
|
---
|
|
|
|
GET /api/expenses/export/excel
|
|
Description: Export expenses to Excel for accountant
|
|
Auth: Required (JWT)
|
|
Query Params:
|
|
boat_id: string (required)
|
|
date_from: string (ISO 8601)
|
|
date_to: string (ISO 8601)
|
|
include_rejected: boolean (default=false)
|
|
Response:
|
|
File: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
|
Filename: navidocs-expenses-{boatId}-{dateFrom}-{dateTo}.xlsx
|
|
Contents:
|
|
- Expense sheet (all expenses with all fields)
|
|
- Reimbursements sheet (captain reimbursement summary)
|
|
- Summary sheet (totals by category, currency, status)
|
|
- VAT report (VAT totals by jurisdiction)
|
|
- IF.TTT audit (citation IDs, signatures, hashes for compliance)
|
|
Status: 200 OK
|
|
|
|
---
|
|
|
|
POST /api/categories/suggest
|
|
Description: ML-powered category suggestion based on vendor/amount
|
|
Auth: Required (JWT)
|
|
Body:
|
|
vendor: string
|
|
amount: number
|
|
description: string (optional)
|
|
boat_id: string (optional)
|
|
Response:
|
|
suggestions: array
|
|
- category_id: string
|
|
- category_name: string
|
|
- confidence: number (0.0-1.0)
|
|
- reason: string (vendor_history|pattern_match|ml_model)
|
|
Status: 200 OK
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Multi-User Expense Tracking Workflow
|
|
|
|
### 4.1 Owner Expense Recording
|
|
|
|
```
|
|
Owner logs in → Navigates to Accounting/Expenses
|
|
|
|
Option A: Manual Entry
|
|
├─ Clicks "Add Expense"
|
|
├─ Fills form:
|
|
│ ├─ Vendor: "Marina Porto"
|
|
│ ├─ Amount: €245.50
|
|
│ ├─ Date: 2025-11-13
|
|
│ ├─ Category: Marina Fees
|
|
│ ├─ Payment Method: Card
|
|
│ └─ Notes: "November mooring"
|
|
├─ Clicks "Save"
|
|
└─ Expense created, status: "recorded"
|
|
|
|
Option B: Photo Upload (OCR)
|
|
├─ Clicks "Upload Receipt"
|
|
├─ Takes photo or selects from gallery
|
|
├─ Waits for OCR processing (2-5 seconds)
|
|
├─ Reviews extracted data
|
|
│ ├─ Vendor: "Marina Porto" ✓
|
|
│ ├─ Amount: €245.50 (confidence: 92%) ✓
|
|
│ ├─ Date: 2025-11-13 ✓
|
|
│ ├─ Category: Marina Fees (suggested) ✓
|
|
│ └─ VAT: €37.50 ✓
|
|
├─ Can edit any field before saving
|
|
├─ Clicks "Save"
|
|
└─ Expense created with IF.TTT signature
|
|
```
|
|
|
|
### 4.2 Captain Expense Reimbursement Flow
|
|
|
|
```
|
|
Captain purchases provisions for €52.30 with personal cash
|
|
|
|
Step 1: Captain logs expense
|
|
├─ Opens mobile app (any time, any place)
|
|
├─ Clicks "Add Expense"
|
|
├─ Takes photo of receipt
|
|
├─ System extracts: Vendor: "Supermarket", Amount: €52.30, Date: today
|
|
├─ Selects category: "Provisions"
|
|
├─ Notes: "Weekly supplies"
|
|
└─ Clicks "Submit for Approval"
|
|
└─ Expense status: "pending" (awaits owner approval)
|
|
└─ Notification sent to owner: "Captain requested reimbursement: €52.30"
|
|
|
|
Step 2: Expense aggregation (optional)
|
|
├─ Captain can submit multiple expenses together
|
|
├─ Clicks "Create Reimbursement Request"
|
|
├─ Selects expenses: [52.30 + 35.00 + 18.50] = €105.80
|
|
├─ Adds note: "Personal cash advances from Oct 20-Nov 13"
|
|
├─ Clicks "Submit Request"
|
|
└─ Reimbursement request created
|
|
└─ Status: "submitted"
|
|
└─ Notification: Owner sees request in dashboard
|
|
|
|
Step 3: Owner reviews & approves
|
|
├─ Owner logs into app
|
|
├─ Sees reimbursement request notification
|
|
├─ Clicks to expand request details:
|
|
│ ├─ Captain: "Marco (Captain)"
|
|
│ ├─ Total: €105.80
|
|
│ ├─ Expenses:
|
|
│ │ ├─ Supermarket (Provisions): €52.30 ← owner can expand receipt image
|
|
│ │ ├─ Bakery (Provisions): €35.00 ← approve/reject individual items
|
|
│ │ └─ Marine Supply (Supplies): €18.50
|
|
│ └─ Notes: "Personal cash advances from Oct 20-Nov 13"
|
|
├─ Owner has options:
|
|
│ ├─ [Approve All] → All expenses marked "approved"
|
|
│ ├─ [Approve Partial] → Select which to approve
|
|
│ ├─ [Reject] → All returned to captain (stays pending)
|
|
│ ├─ [Message Captain] → Ask for clarification (via WhatsApp)
|
|
│ └─ [Reject Item] → Specific items rejected, others approved
|
|
├─ Owner clicks "Approve All"
|
|
└─ Expenses status updated to "approved"
|
|
└─ Notification: Captain sees "Your reimbursement of €105.80 approved!"
|
|
|
|
Step 4: Payment processing
|
|
├─ Owner marks reimbursement as "paid"
|
|
├─ Owner selects payment method:
|
|
│ ├─ Bank transfer (account details pre-filled from captain profile)
|
|
│ ├─ Cash (mark as paid after handing over cash)
|
|
│ ├─ Card (transfer via app if available)
|
|
│ └─ Other
|
|
├─ Enters payment date & reference (bank transaction ID)
|
|
├─ Clicks "Mark Paid"
|
|
└─ Reimbursement status: "paid"
|
|
└─ Expenses status: "paid"
|
|
└─ Notification: Captain receives "Reimbursement sent: €105.80 on 2025-11-14"
|
|
|
|
Step 5: Audit trail
|
|
├─ Expense has complete IF.TTT audit trail:
|
|
│ ├─ who: Captain (Ed25519 signature)
|
|
│ ├─ when: 2025-10-20 10:15 AM
|
|
│ ├─ what: Original receipt photo + extracted data
|
|
│ ├─ owner_approval: Owner name, timestamp
|
|
│ ├─ payment: Bank transfer ref 12345678
|
|
│ └─ citation_id: if://receipt/navidocs/boat-123/expense-4567
|
|
└─ Accountant can verify chain of custody
|
|
```
|
|
|
|
### 4.3 Crew Expense Flow
|
|
|
|
Similar to captain, but:
|
|
- Captain must pre-approve before owner sees it
|
|
- Workflow: Crew logs → Captain approves → Owner approves → Marked paid
|
|
- Prevents owner seeing every crew purchase individually
|
|
|
|
```
|
|
Crew buys ice for €8.50 with boat cash
|
|
|
|
Step 1: Crew logs expense
|
|
├─ App logs: "Crew purchased ice for €8.50"
|
|
├─ Takes receipt photo (if available)
|
|
└─ Status: "pending_captain_approval"
|
|
└─ Captain notification: "Crew expense pending: €8.50"
|
|
|
|
Step 2: Captain reviews (filters out small/pre-approved items)
|
|
├─ Captain sees list of crew expenses pending approval
|
|
├─ Captain can:
|
|
│ ├─ [Approve] → Status becomes "pending" (awaits owner approval)
|
|
│ ├─ [Reject] → Status "rejected" (expense removed from boat cash log)
|
|
│ ├─ [Auto-Approve] → Set rules:
|
|
│ │ ├─ Items under €20: auto-approve
|
|
│ │ ├─ Specific categories: auto-approve (ice, provisions)
|
|
│ └─ [View] → See expense details + receipt image
|
|
└─ Captain approves (or auto-approved by rule)
|
|
└─ Status: "pending" (awaits owner approval)
|
|
└─ Owner sees in daily summary: "5 crew expenses, €47.30 total"
|
|
|
|
Step 3: Owner bulk-approves crew expenses
|
|
├─ Owner opens dashboard
|
|
├─ Sees: "5 pending crew expenses (€47.30)"
|
|
├─ Owner options:
|
|
│ ├─ [Approve All] → All marked "approved"
|
|
│ ├─ [View Details] → Expand to see each item
|
|
│ └─ [Reject Items] → Sends back to captain with questions
|
|
├─ Owner clicks "Approve All"
|
|
└─ All crew expenses: "approved"
|
|
└─ Captain notified: "5 crew expenses approved (€47.30)"
|
|
└─ Owner knows they owe captain €47.30 in boat cash reimbursement
|
|
|
|
Alternative: Boat Cash Account
|
|
├─ If boat maintains cash drawer (e.g., €500)
|
|
├─ Transactions: [+€500 starting balance] → [-€8.50 ice] → [-€23.00 fuel] → etc.
|
|
├─ Owner periodically reimburses boat cash drawer
|
|
├─ Captain tracks: "Boat cash remaining: €250.30"
|
|
└─ Reconciliation: Physical count vs. app records
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Reimbursement Workflow (Detailed)
|
|
|
|
### 5.1 States & Transitions
|
|
|
|
```
|
|
Captain Expense States:
|
|
┌─────────────┐
|
|
│ pending │ Captain just logged expense (personal cash)
|
|
└──────┬──────┘
|
|
│ (Owner approves)
|
|
▼
|
|
┌─────────────┐
|
|
│ approved │ Owner approved reimbursement amount
|
|
└──────┬──────┘
|
|
│ (Owner pays captain)
|
|
▼
|
|
┌─────────────┐
|
|
│ paid │ Captain received payment
|
|
└─────────────┘
|
|
|
|
Alternative: Partial Approval
|
|
┌─────────────┐
|
|
│ pending │
|
|
└──────┬──────┘
|
|
│ (Owner partially approves)
|
|
▼
|
|
┌─────────────┐
|
|
│ partial │ Some items approved, others rejected/questioned
|
|
└──────┬──────┘
|
|
│ (Captain modifies; Owner reviews again)
|
|
▼
|
|
┌─────────────┐
|
|
│ approved │ All items resolved
|
|
└──────┬──────┘
|
|
│ (Owner pays)
|
|
▼
|
|
┌─────────────┐
|
|
│ paid │
|
|
└─────────────┘
|
|
|
|
Rejection Path:
|
|
┌─────────────┐
|
|
│ pending │
|
|
└──────┬──────┘
|
|
│ (Owner rejects)
|
|
▼
|
|
┌─────────────┐
|
|
│ rejected │ Owner didn't approve (personal expense, disallowed, etc.)
|
|
└─────────────┘
|
|
(Captain can re-submit with justification or drop claim)
|
|
```
|
|
|
|
### 5.2 Notification Triggers
|
|
|
|
| Event | Notify | Channel | Message |
|
|
|-------|--------|---------|---------|
|
|
| Captain submits expense | Owner | WhatsApp + App | "Marco requested €52.30 reimbursement for provisions" |
|
|
| Owner approves expense | Captain | WhatsApp + App | "Your €52.30 expense approved! Payment will be sent by 2025-11-15" |
|
|
| Owner rejects expense | Captain | WhatsApp + App | "Your €52.30 provisions expense was rejected. See note: Please check receipt - amount doesn't match vendor markup" |
|
|
| Owner marks paid | Captain | WhatsApp + App | "Reimbursement of €245.80 sent via bank transfer" |
|
|
| Bulk crew expenses approved | Captain | WhatsApp + App | "5 crew expenses approved (€47.30)" |
|
|
| Reimbursement request pending | Owner | Email + App | "3-day reminder: Marco's reimbursement request (€105.80) pending your approval" |
|
|
|
|
---
|
|
|
|
## 6. WhatsApp AI Integration (S2-H08 Dependency)
|
|
|
|
### 6.1 Expense Logging via WhatsApp
|
|
|
|
**Integration Point:** S2-H08 (WhatsApp Group Integration) handles chat webhook; S2-H06 (Accounting) handles expense processing
|
|
|
|
```
|
|
Example: Captain in WhatsApp group chat
|
|
|
|
Captain: "@NaviDocs log expense €45 diesel"
|
|
│
|
|
▼ (IF.bus to S2-H08)
|
|
|
|
S2-H08 WhatsApp Agent:
|
|
├─ Receives message via WhatsApp Business API webhook
|
|
├─ Parses: amount=€45, category=fuel, description="diesel"
|
|
├─ Checks if creator has authorization (captain role for this boat)
|
|
├─ Calls: POST /api/expenses with parsed data
|
|
│
|
|
▼ (IF.bus to S2-H06)
|
|
|
|
S2-H06 Accounting Service:
|
|
├─ Creates expense record:
|
|
│ ├─ amount: 45.00
|
|
│ ├─ currency: EUR
|
|
│ ├─ category: Fuel
|
|
│ ├─ description: (from chat context)
|
|
│ ├─ created_by: captain
|
|
│ └─ status: pending_captain_approval (if crew) or pending (if captain)
|
|
├─ Generates IF.TTT signature + citation
|
|
└─ Returns expense_id
|
|
|
|
S2-H08 WhatsApp Agent:
|
|
├─ Posts confirmation: "@Marco ✓ Logged: €45 diesel on 2025-11-13"
|
|
├─ Optional: Adds quick buttons:
|
|
│ ├─ [View Receipt] → Link to expense detail
|
|
│ ├─ [Edit] → Links to app to upload receipt photo
|
|
│ └─ [More] → Shows recent 5 expenses
|
|
└─ Stores in IF.TTT audit log: message hash + citation
|
|
```
|
|
|
|
**Command Syntax:**
|
|
```
|
|
@NaviDocs log expense [amount] [currency] [category] [description]
|
|
@NaviDocs log [amount] [currency] [description] # auto-category
|
|
|
|
Examples:
|
|
@NaviDocs log expense €45 fuel → €45.00, Fuel, auto-date
|
|
@NaviDocs log €35 EUR provisions → €35.00, Provisions
|
|
@NaviDocs log $80 marina fees Antibes → $80 USD, Marina, Antibes
|
|
@NaviDocs log 45 GBP diesel fuel Kingston → £45.00, Fuel, Kingston
|
|
|
|
Advanced:
|
|
@NaviDocs log expense €150 maintenance Hull repair invoice #12345
|
|
→ Links to maintenance log if ID provided
|
|
@NaviDocs reimbursement request [list of recent expense IDs]
|
|
→ Creates reimbursement request from last N expenses
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Export Functionality for Accountants
|
|
|
|
### 7.1 Excel Export Structure
|
|
|
|
```
|
|
File: navidocs-expenses-[BoatID]-[2025-01-01]-[2025-12-31].xlsx
|
|
|
|
Sheet 1: Expenses
|
|
├─ Row 1: Header row
|
|
│ ├─ Expense ID | Vendor | Category | Amount | Currency | Date | VAT | Net Amount
|
|
│ ├─ Payment Method | Created By | Status | Receipt Image Link | Notes
|
|
│ ├─ Maintenance Log Link | Inventory Link | Citation ID
|
|
├─ Rows 2+: Data rows (one per expense)
|
|
└─ Footer: Totals row (sum by column)
|
|
|
|
Sheet 2: Reimbursements
|
|
├─ Reimbursement ID | Captain | Total Requested | Total Approved | Total Paid
|
|
├─ Currency | Request Date | Status | Approved Date | Paid Date | Payment Method
|
|
└─ Notes
|
|
|
|
Sheet 3: Summary Statistics
|
|
├─ Date Range: 2025-01-01 to 2025-12-31
|
|
├─ Total Expenses: €XXX
|
|
├─ Breakdown by Category:
|
|
│ ├─ Fuel: €X (5% of total)
|
|
│ ├─ Marina: €Y (20% of total)
|
|
│ ├─ Maintenance: €Z (40% of total)
|
|
│ └─ ...
|
|
├─ Breakdown by Payment Method:
|
|
│ ├─ Cash: €A
|
|
│ ├─ Card: €B
|
|
│ └─ Bank Transfer: €C
|
|
├─ Breakdown by Created By:
|
|
│ ├─ Owner: €D
|
|
│ ├─ Captain: €E
|
|
│ └─ Crew: €F
|
|
├─ Currency Conversion Summary:
|
|
│ ├─ EUR: €XXX
|
|
│ ├─ USD: €YYY (converted)
|
|
│ └─ GBP: €ZZZ (converted)
|
|
├─ Reimbursements Total:
|
|
│ ├─ Requested: €RRR
|
|
│ ├─ Approved: €AAA
|
|
│ └─ Paid: €PPP
|
|
|
|
Sheet 4: VAT Report
|
|
├─ Date | Category | Vendor | Gross | VAT % | VAT Amount | Net
|
|
├─ ...
|
|
├─ Total VAT Collected by Category:
|
|
│ ├─ Fuel: €X VAT (from €Y gross)
|
|
│ ├─ Maintenance: €A VAT (from €B gross)
|
|
│ └─ ...
|
|
└─ Total VAT: €VVV (eligible for deduction if business boat)
|
|
|
|
Sheet 5: IF.TTT Audit Trail
|
|
├─ Expense ID | Citation ID | Ed25519 Signature | SHA-256 Hash
|
|
├─ Creator | Creation Date | Approver | Approval Date
|
|
├─ Payment Date | Payment Reference
|
|
├─ Receipt Image Hash | Receipt Image URL
|
|
└─ [Full audit for compliance verification]
|
|
|
|
Sheet 6: Data Dictionary
|
|
├─ Column explanations
|
|
├─ Category list (full hierarchy)
|
|
├─ Payment method definitions
|
|
└─ Status definitions
|
|
```
|
|
|
|
### 7.2 Export API
|
|
|
|
```javascript
|
|
// Generate Excel export
|
|
GET /api/expenses/export/excel?boat_id=X&from=2025-01-01&to=2025-12-31&format=detailed
|
|
|
|
Response Headers:
|
|
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
|
Content-Disposition: attachment; filename=navidocs-expenses-[boatId]-2025.xlsx
|
|
|
|
Response: Binary XLSX file (generated via ExcelJS or similar library)
|
|
|
|
// Also support CSV export for quick import to accounting software
|
|
GET /api/expenses/export/csv?boat_id=X&sheet=expenses&from=2025-01-01&to=2025-12-31
|
|
|
|
Response Headers:
|
|
Content-Type: text/csv; charset=utf-8
|
|
Content-Disposition: attachment; filename=navidocs-expenses-[boatId]-2025.csv
|
|
|
|
Response: CSV data (directly importable to QuickBooks, Xero, FreshBooks, etc.)
|
|
```
|
|
|
|
---
|
|
|
|
## 8. IF.TTT Compliance Architecture
|
|
|
|
### 8.1 Signature & Hash Implementation
|
|
|
|
```javascript
|
|
// if-compliance.service.js
|
|
|
|
const crypto = require('crypto');
|
|
const ed25519 = require('libsodium').crypto_sign_detached;
|
|
|
|
class IFTTTService {
|
|
|
|
/**
|
|
* Generate SHA-256 hash of expense data (for tamper detection)
|
|
*/
|
|
async hashExpense(expenseData) {
|
|
const canonical = {
|
|
boat_id: expenseData.boat_id,
|
|
amount: expenseData.amount,
|
|
currency: expenseData.currency,
|
|
vendor: expenseData.vendor,
|
|
date: expenseData.date,
|
|
category_id: expenseData.category_id,
|
|
vat_amount: expenseData.vat_amount,
|
|
payment_method: expenseData.payment_method,
|
|
description: expenseData.description,
|
|
created_by_user_id: expenseData.created_by_user_id,
|
|
created_by_role: expenseData.created_by_role,
|
|
receipt_image_hash: expenseData.receipt_image_hash
|
|
};
|
|
|
|
const jsonString = JSON.stringify(canonical, Object.keys(canonical).sort());
|
|
const hash = crypto.createHash('sha256').update(jsonString).digest('hex');
|
|
|
|
return hash;
|
|
}
|
|
|
|
/**
|
|
* Generate Ed25519 signature of expense (proof of creator identity)
|
|
*/
|
|
async signExpense(expenseData, creatorPrivateKey) {
|
|
const contentHash = await this.hashExpense(expenseData);
|
|
|
|
// Ed25519 sign the content hash
|
|
const signature = ed25519(Buffer.from(contentHash), Buffer.from(creatorPrivateKey));
|
|
|
|
return signature.toString('hex');
|
|
}
|
|
|
|
/**
|
|
* Verify Ed25519 signature (ensure creator identity)
|
|
*/
|
|
async verifySignature(contentHash, signature, creatorPublicKey) {
|
|
try {
|
|
const verified = sodium.crypto_sign_open(
|
|
Buffer.from(signature + contentHash, 'hex'),
|
|
Buffer.from(creatorPublicKey, 'hex')
|
|
);
|
|
return true;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate citation ID (permanent reference to this expense)
|
|
*/
|
|
generateCitationId(boatId, expenseId) {
|
|
// Format: if://receipt/navidocs/boat-{boatId}/expense-{expenseId}
|
|
return `if://receipt/navidocs/boat-${boatId}/expense-${expenseId}`;
|
|
}
|
|
|
|
/**
|
|
* Generate receipt image hash (for image tamper detection)
|
|
*/
|
|
async hashReceiptImage(imagePath) {
|
|
const fs = require('fs').promises;
|
|
const fileBuffer = await fs.readFile(imagePath);
|
|
const hash = crypto.createHash('sha256').update(fileBuffer).digest('hex');
|
|
return hash;
|
|
}
|
|
|
|
/**
|
|
* Complete IF.TTT compliance record
|
|
*/
|
|
async createIFTTTRecord(expenseData, creatorPrivateKey, receiptImagePath) {
|
|
const contentHash = await this.hashExpense(expenseData);
|
|
const receiptImageHash = receiptImagePath
|
|
? await this.hashReceiptImage(receiptImagePath)
|
|
: null;
|
|
const signature = await this.signExpense(expenseData, creatorPrivateKey);
|
|
const citationId = this.generateCitationId(expenseData.boat_id, expenseData.id);
|
|
|
|
return {
|
|
content_hash: contentHash,
|
|
ed25519_signature: signature,
|
|
citation_id: citationId,
|
|
receipt_image_hash: receiptImageHash,
|
|
creator_public_key: derivePublicKey(creatorPrivateKey), // Stored for verification
|
|
signed_at: new Date().toISOString()
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Audit verification: prove expense hasn't been tampered with
|
|
*/
|
|
async verifyExpenseIntegrity(expense) {
|
|
// 1. Recalculate content hash
|
|
const currentHash = await this.hashExpense(expense);
|
|
if (currentHash !== expense.content_hash) {
|
|
return {
|
|
valid: false,
|
|
reason: "Content hash mismatch - expense data has been modified"
|
|
};
|
|
}
|
|
|
|
// 2. Verify Ed25519 signature
|
|
const signatureValid = await this.verifySignature(
|
|
currentHash,
|
|
expense.ed25519_signature,
|
|
expense.creator_public_key
|
|
);
|
|
if (!signatureValid) {
|
|
return {
|
|
valid: false,
|
|
reason: "Ed25519 signature invalid - creator identity cannot be verified"
|
|
};
|
|
}
|
|
|
|
// 3. Verify receipt image hash (if image exists)
|
|
if (expense.receipt_image_url && expense.receipt_image_hash) {
|
|
const currentImageHash = await this.hashReceiptImage(expense.receipt_image_url);
|
|
if (currentImageHash !== expense.receipt_image_hash) {
|
|
return {
|
|
valid: false,
|
|
reason: "Receipt image hash mismatch - image has been modified"
|
|
};
|
|
}
|
|
}
|
|
|
|
return {
|
|
valid: true,
|
|
verified_at: new Date().toISOString(),
|
|
verifications: [
|
|
"Content hash verified (no tampering)",
|
|
"Ed25519 signature verified (creator identity confirmed)",
|
|
"Receipt image hash verified (no image tampering)"
|
|
]
|
|
};
|
|
}
|
|
}
|
|
|
|
module.exports = new IFTTTService();
|
|
```
|
|
|
|
### 8.2 IF.TTT Compliance Checklist
|
|
|
|
```yaml
|
|
IF.TTT Compliance for Accounting Module:
|
|
|
|
Receipt Image Handling:
|
|
✅ SHA-256 hash of receipt image file
|
|
✅ Hash stored in database (immutable)
|
|
✅ Original image stored in S3 with CRC32 check
|
|
✅ Any image modification detected via hash mismatch
|
|
|
|
Expense Creator Identity:
|
|
✅ Ed25519 signature of expense data
|
|
✅ Signature generated with creator's private key
|
|
✅ Public key stored (derived from private key)
|
|
✅ Any future creator verification possible
|
|
|
|
Audit Trail:
|
|
✅ Citation ID: if://receipt/navidocs/boat-{boatId}/expense-{expenseId}
|
|
✅ Permanent reference (never changes)
|
|
✅ Includes: who, what, when, where
|
|
✅ Linkable: boat UUID, expense UUID
|
|
✅ Resolvable: GET /api/citations/if://receipt/navidocs/...
|
|
|
|
Complete Immutable Record:
|
|
✅ Original receipt image + hash
|
|
✅ Extracted OCR data (vendor, amount, date, VAT)
|
|
✅ Creator identity (captain, crew, owner)
|
|
✅ Creation timestamp
|
|
✅ All approvals + timestamps + approver identity
|
|
✅ Payment tracking (method, date, reference)
|
|
✅ Any modifications logged separately (audit_log field)
|
|
|
|
Data Integrity Verification:
|
|
✅ Verify content hash (no data tampering)
|
|
✅ Verify Ed25519 signature (creator identity)
|
|
✅ Verify receipt image hash (no image tampering)
|
|
✅ All three checks must pass for "verified" status
|
|
|
|
Multi-User Workflow Traceability:
|
|
✅ Captain creates: Ed25519 sig + timestamp
|
|
✅ Owner approves: separate approval record + sig + timestamp
|
|
✅ Payment marked: payment timestamp + method + reference
|
|
✅ Full chain of custody maintained
|
|
|
|
Accountant Audit Requirements:
|
|
✅ Expense can be traced back to receipt image
|
|
✅ Receipt image authenticity verified (hash)
|
|
✅ Creator identity verified (Ed25519 signature)
|
|
✅ Approval chain visible (timestamps, names)
|
|
✅ Payment status documented
|
|
✅ VAT/tax calculations auditable
|
|
✅ Multi-currency conversions with exchange rates
|
|
|
|
Regulatory Compliance:
|
|
✅ EU Tax Authority (CJEU) - receipt authenticity: SHA-256 hash
|
|
✅ GDPR - access logs show who viewed expense
|
|
✅ GDPR - right to deletion: anonymize but keep hash + signatures
|
|
✅ Audit trails: 7-year retention minimum
|
|
✅ Document preservation: receipt images stored indefinitely
|
|
|
|
Cryptographic Standards:
|
|
✅ SHA-256 (NIST standard, FIPS 180-4)
|
|
✅ Ed25519 (quantum-resistant signature scheme, RFC 8032)
|
|
✅ All cryptographic operations via libsodium (battle-tested, auditedlib)
|
|
|
|
Export & Compliance:
|
|
✅ Excel export includes IF.TTT audit sheet
|
|
✅ Citation IDs in export (accountant can verify)
|
|
✅ Signature hashes in export (for verification)
|
|
✅ CSV export suitable for QuickBooks import
|
|
✅ Signatures + hashes preserved in all exports
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Database Integration Points
|
|
|
|
### 9.1 Foreign Key Relationships
|
|
|
|
```sql
|
|
-- Link expenses to other modules
|
|
|
|
-- 1. Maintenance Log Integration
|
|
-- "This fuel expense is related to engine maintenance"
|
|
ALTER TABLE expenses
|
|
ADD COLUMN maintenance_log_id VARCHAR(36),
|
|
ADD FOREIGN KEY (maintenance_log_id) REFERENCES maintenance_log(id);
|
|
|
|
-- Query: Find all expenses related to specific maintenance
|
|
SELECT e.* FROM expenses e
|
|
WHERE e.maintenance_log_id = '...'
|
|
AND e.boat_id = '...';
|
|
|
|
-- 2. Inventory Integration
|
|
-- "This €500 expense is for the new autopilot (inventory item)"
|
|
ALTER TABLE expenses
|
|
ADD COLUMN inventory_item_id VARCHAR(36),
|
|
ADD FOREIGN KEY (inventory_item_id) REFERENCES boat_inventory(id);
|
|
|
|
-- Query: What was total expense for this item?
|
|
SELECT SUM(e.amount) as total_cost, e.currency
|
|
FROM expenses e
|
|
WHERE e.inventory_item_id = '...'
|
|
AND e.boat_id = '...';
|
|
|
|
-- 3. Calendar Integration
|
|
-- "This expense is for the scheduled hull repaint work"
|
|
ALTER TABLE expenses
|
|
ADD COLUMN calendar_event_id VARCHAR(36),
|
|
ADD FOREIGN KEY (calendar_event_id) REFERENCES calendar_events(id);
|
|
|
|
-- Query: Budget vs actual for planned work
|
|
SELECT
|
|
ce.title,
|
|
ce.budget_amount,
|
|
SUM(e.amount) as actual_amount,
|
|
(ce.budget_amount - SUM(e.amount)) as variance
|
|
FROM calendar_events ce
|
|
LEFT JOIN expenses e ON e.calendar_event_id = ce.id
|
|
WHERE ce.event_type = 'work_planned'
|
|
AND ce.boat_id = '...'
|
|
GROUP BY ce.id;
|
|
|
|
-- 4. Vendor (Contact) Integration
|
|
ALTER TABLE expenses
|
|
ADD COLUMN vendor_id VARCHAR(36),
|
|
ADD FOREIGN KEY (vendor_id) REFERENCES boat_contacts(id);
|
|
|
|
-- Query: Show most frequently-used vendors
|
|
SELECT c.name, COUNT(*) as transaction_count, SUM(e.amount) as total_spent
|
|
FROM expenses e
|
|
JOIN boat_contacts c ON e.vendor_id = c.id
|
|
WHERE e.boat_id = '...'
|
|
GROUP BY c.id
|
|
ORDER BY total_spent DESC;
|
|
|
|
-- 5. Crew/Captain Tracking
|
|
ALTER TABLE expenses
|
|
ADD COLUMN created_by_user_id VARCHAR(36),
|
|
ADD FOREIGN KEY (created_by_user_id) REFERENCES users(id);
|
|
|
|
-- Query: How much did captain spend this month?
|
|
SELECT SUM(e.amount) as monthly_spend
|
|
FROM expenses e
|
|
JOIN users u ON e.created_by_user_id = u.id
|
|
WHERE e.boat_id = '...'
|
|
AND YEAR(e.purchase_date) = 2025
|
|
AND MONTH(e.purchase_date) = 11
|
|
AND u.role = 'captain';
|
|
```
|
|
|
|
---
|
|
|
|
## 10. Integration with S2-H08 (WhatsApp) & S2-H03 (Maintenance)
|
|
|
|
### 10.1 IF.bus Communication Protocol
|
|
|
|
```json
|
|
{
|
|
"performative": "request",
|
|
"sender": "if://agent/session-2/haiku-06",
|
|
"receiver": ["if://agent/session-2/haiku-08", "if://agent/session-2/haiku-03"],
|
|
"conversation_id": "if://conversation/navidocs-accounting-2025-11-13",
|
|
"content": {
|
|
"integration": "Expense tracking needs WhatsApp AI commands and maintenance log linking",
|
|
"api_requirements": {
|
|
"whatsapp_integration": {
|
|
"command": "POST /api/expenses from WhatsApp @NaviDocs command",
|
|
"format": "@NaviDocs log expense €45 fuel",
|
|
"handler": "S2-H08 WhatsApp agent → S2-H06 expense endpoint",
|
|
"webhook": "POST /api/expenses with: {amount, currency, category, description, created_by_whatsapp_user_id}"
|
|
},
|
|
"maintenance_link": {
|
|
"command": "POST /api/expenses with optional maintenance_log_id",
|
|
"format": "expense can reference maintenance_log record",
|
|
"handler": "S2-H06 creates expense linked to maintenance",
|
|
"query": "GET /api/expenses?maintenance_log_id=X shows all expenses for service"
|
|
}
|
|
},
|
|
"schema": {
|
|
"POST /api/expenses": {
|
|
"amount": "number",
|
|
"currency": "enum(EUR|USD|GBP)",
|
|
"category": "string or category_id",
|
|
"description": "string",
|
|
"linked_maintenance_id": "uuid (optional)",
|
|
"receipt_image_url": "string (optional)",
|
|
"created_by_whatsapp_user_id": "string (optional, if from WhatsApp)"
|
|
}
|
|
},
|
|
"examples": [
|
|
{
|
|
"scenario": "Captain logs fuel expense via WhatsApp",
|
|
"whatsapp_message": "@NaviDocs log expense €45 diesel",
|
|
"s2h08_action": "Parse message → call POST /api/expenses",
|
|
"s2h06_action": "Create expense record, confirm in WhatsApp"
|
|
},
|
|
{
|
|
"scenario": "Owner wants to link fuel expense to engine maintenance",
|
|
"api_call": "PUT /api/expenses/exp-123 with {maintenance_log_id: 'maint-456'}",
|
|
"s2h03_query": "GET /api/expenses?maintenance_log_id=maint-456 (from maintenance module)"
|
|
}
|
|
],
|
|
"dependencies": [
|
|
"S2-H08: WhatsApp API webhook → expense creation",
|
|
"S2-H03: Maintenance log provides maintenance_log_id for linking",
|
|
"S2-H06: Expense service accepts both direct API calls and WhatsApp-triggered calls"
|
|
]
|
|
},
|
|
"citation_ids": ["if://citation/navidocs-accounting-design"],
|
|
"timestamp": "2025-11-13T10:00:00Z",
|
|
"sequence_num": 1
|
|
}
|
|
```
|
|
|
|
### 10.2 S2-H03 (Maintenance) Integration
|
|
|
|
**Maintenance log provides:**
|
|
- `maintenance_log_id`: UUID to link expenses
|
|
- `service_type`: "engine", "electronics", "hull", etc. → helps categorize expenses
|
|
- `date`: Service date → can auto-fill expense date
|
|
- `cost_estimate`: Maintenance module tracks estimated vs. actual
|
|
|
|
**Expense module queries maintenance:**
|
|
```javascript
|
|
// When captain logs expense for engine service
|
|
POST /api/expenses {
|
|
amount: 450.00,
|
|
currency: "EUR",
|
|
category: "Maintenance",
|
|
description: "Engine oil change",
|
|
maintenance_log_id: "maint-789" // Links back to maintenance record
|
|
}
|
|
|
|
// Maintenance module can then query:
|
|
GET /api/expenses?maintenance_log_id=maint-789
|
|
// Response: All expenses associated with that maintenance work
|
|
// Allows: Track estimate vs actual spending
|
|
|
|
// Dashboard shows:
|
|
// "Engine Service (Nov 13)"
|
|
// └─ Estimated Cost: €400
|
|
// └─ Actual Expenses: €450 (oil change) + €85 (labor) = €535
|
|
// └─ Variance: +€135 (33% over estimate)
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation Roadmap
|
|
|
|
### Phase 1: Core Expense Tracking (Week 1-2)
|
|
- Database schema: expenses, categories, reimbursement_requests
|
|
- API endpoints: POST /expenses, GET /expenses, GET /reimbursements
|
|
- Authorization: boat access control, role-based approval
|
|
- Manual expense entry UI (Vue form)
|
|
- Export to CSV (basic)
|
|
|
|
### Phase 2: Receipt OCR (Week 2-3)
|
|
- Receipt upload endpoint: POST /api/receipts/upload
|
|
- Google Vision API integration
|
|
- Tesseract fallback
|
|
- Extraction: vendor, amount, date, VAT, category
|
|
- Review & approval UI
|
|
|
|
### Phase 3: Reimbursement Workflow (Week 3-4)
|
|
- Reimbursement request creation & approval
|
|
- Captain → Owner approval flow
|
|
- Payment tracking (method, date, reference)
|
|
- Notifications (WhatsApp integration with S2-H08)
|
|
|
|
### Phase 4: IF.TTT Compliance (Week 4)
|
|
- SHA-256 hashing (content + receipt images)
|
|
- Ed25519 signatures (creator identity)
|
|
- Citation ID generation
|
|
- Audit trail storage
|
|
- Compliance verification API
|
|
|
|
### Phase 5: Advanced Features (Week 5+)
|
|
- Multi-currency support with exchange rate tracking
|
|
- Category hierarchy & suggestions
|
|
- Vendor database & recurring expense templates
|
|
- Integration with maintenance log (S2-H03)
|
|
- Advanced search & reporting
|
|
- Excel export with summary sheets
|
|
- WhatsApp bot commands (@NaviDocs log expense)
|
|
|
|
---
|
|
|
|
## Configuration & Environment
|
|
|
|
```bash
|
|
# .env variables for accounting module
|
|
|
|
# Google Cloud Vision API
|
|
GOOGLE_VISION_PROJECT_ID=navidocs-prod
|
|
GOOGLE_VISION_KEY_FILE=/etc/secrets/google-vision-key.json
|
|
GOOGLE_VISION_API_KEY=AIza...
|
|
|
|
# OCR Processing
|
|
TESSERACT_PATH=/usr/bin/tesseract
|
|
OCR_TIMEOUT_SECONDS=30
|
|
OCR_WEBHOOK_URL=https://api.navidocs.io/api/receipts/ocr-callback
|
|
|
|
# Expense Module
|
|
ACCOUNTING_MODULE_ENABLED=true
|
|
MULTI_CURRENCY_SUPPORT=true
|
|
PRIMARY_CURRENCY_EUR=true
|
|
SUPPORTED_CURRENCIES=EUR,USD,GBP
|
|
|
|
# Reimbursement
|
|
REIMBURSEMENT_APPROVAL_REQUIRED=true
|
|
CREW_APPROVAL_REQUIRED=true
|
|
CAPTAIN_APPROVAL_FOR_CREW=true
|
|
|
|
# IF.TTT Compliance
|
|
IFTTT_SIGNING_ENABLED=true
|
|
ED25519_PRIVATE_KEY_PATH=/etc/secrets/accounting-ed25519-key.pem
|
|
CITATION_ID_BASE=if://receipt/navidocs
|
|
|
|
# Export
|
|
EXCEL_EXPORT_ENABLED=true
|
|
CSV_EXPORT_ENABLED=true
|
|
EXPORT_INCLUDE_SIGNATURES=true
|
|
EXPORT_INCLUDE_AUDIT_TRAIL=true
|
|
|
|
# WhatsApp Integration (S2-H08)
|
|
WHATSAPP_API_WEBHOOK_URL=https://api.navidocs.io/api/expenses/whatsapp-webhook
|
|
WHATSAPP_EXPENSE_LOGGING_ENABLED=true
|
|
```
|
|
|
|
---
|
|
|
|
## Deliverable Summary
|
|
|
|
**S2-H06 has completed:**
|
|
|
|
1. ✅ **Multi-user expense tracking design**
|
|
- Owner, Captain, Crew roles with separate workflows
|
|
- Expense categories (hierarchical, boat-specific)
|
|
- Database schema with reimbursement tracking
|
|
|
|
2. ✅ **Receipt/Invoice OCR workflow**
|
|
- Photo upload (camera + gallery)
|
|
- Google Vision + Tesseract processing
|
|
- Auto-extraction (vendor, amount, date, VAT, category)
|
|
- Review & edit UI before saving
|
|
- IF.TTT compliance (SHA-256 + signature)
|
|
|
|
3. ✅ **Accounting module architecture**
|
|
- Recommendation: Spliit fork (MIT license, receipt-focused)
|
|
- Integration with NaviDocs backend (Express.js + SQLite)
|
|
- Multi-currency support (€, $, £)
|
|
|
|
4. ✅ **Reimbursement workflow**
|
|
- Captain submit → OCR extract → Owner approve → Mark paid
|
|
- Crew pre-approval by captain (optional bulk approval)
|
|
- Partial approval & rejection handling
|
|
- Payment tracking & notification triggers
|
|
|
|
5. ✅ **WhatsApp AI integration (S2-H08 dependency)**
|
|
- "@NaviDocs log expense €45 fuel" → Auto-creates expense
|
|
- IF.bus communication protocol defined
|
|
- Webhook integration with WhatsApp Business API
|
|
|
|
6. ✅ **Export functionality**
|
|
- Excel export (detailed, summary, VAT, audit sheets)
|
|
- CSV export for accountant software (QuickBooks, Xero)
|
|
- IF.TTT audit sheet included
|
|
|
|
7. ✅ **IF.TTT compliance checklist**
|
|
- SHA-256 hashing (receipt image + expense data)
|
|
- Ed25519 signatures (creator identity)
|
|
- Citation ID format (if://receipt/navidocs/boat-{id}/expense-{id})
|
|
- Audit trail storage (immutable)
|
|
- Integrity verification API
|
|
|
|
---
|
|
|
|
**Status: COMPLETE**
|
|
|
|
**File:** `/home/user/navidocs/intelligence/session-2/accounting-integration-spec.md`
|
|
|
|
**Integration Dependencies:**
|
|
- S2-H08 (WhatsApp integration) - for @NaviDocs command execution
|
|
- S2-H03 (Maintenance log) - for expense linking to maintenance records
|
|
|
|
**Next Steps (for S2-H10 synthesis):**
|
|
- Integrate with calendar system (budget vs actual for planned work)
|
|
- Integrate with VAT/tax compliance (Agent 3A)
|
|
- Ensure expense notifications flow to WhatsApp group (S2-H08)
|
|
- Design database indices for performance (accounting queries on 10K+ expenses)
|