Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .doc/adr/0001-supabase-database.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# ADR 0001: Use Supabase for Database

## Status
Accepted

## Context
Smart GL needs a database for storing transactions, categorisations, journal entries, and chart of accounts. Need multi-tenant isolation and vector search for AI categorisation.

## Decision
Use Supabase (PostgreSQL + pgvector + RLS) as the database layer.

## Consequences
- **Positive**: Built-in RLS for tenant isolation, pgvector for embeddings, managed PostgreSQL
- **Negative**: Requires Supabase account, Pro plan for pg_cron

## Alternatives Considered
- **Neon**: No RLS support (would need manual tenant filtering)
- **Plain PostgreSQL**: Missing pgvector, no built-in auth
22 changes: 22 additions & 0 deletions .doc/adr/TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# ADR Template

## Title
Brief description of the decision

## Status
Proposed | Accepted | Deprecated | Superseded

## Context
What motivated this decision?

## Decision
What was decided?

## Consequences
Positive and negative outcomes

## Alternatives Considered
Other options and why they were rejected

---
*Use format: adr/NNNN-title.md*
194 changes: 194 additions & 0 deletions .doc/api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
# Smart GL API Reference

## Base URL
```
http://localhost:8000
```

## Authentication
Currently: None (development mode)
Future: Bearer token via Supabase Auth

## Endpoints

### Health Check

**GET** `/health`

Response:
```json
{
"status": "ok",
"version": "1.0.0"
}
```

### Transactions

**GET** `/transactions`

Query parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| limit | int | Max results (default: 50) |
| offset | int | Pagination offset |
| category_id | uuid | Filter by category |
| start_date | date | Filter from date |
| end_date | date | Filter to date |

Response:
```json
{
"items": [
{
"id": "uuid",
"date": "2024-01-15",
"description": "Coffee shop",
"amount": 550,
"currency": "AUD",
"category_id": "uuid",
"category_name": "Meals & Entertainment",
"account_id": "uuid",
"account_name": "Business Account"
}
],
"total": 100
}
```

**POST** `/transactions/{id}/categorise`

Body:
```json
{
"category_id": "uuid"
}
```

### Journal

**GET** `/journal`

Query parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| transaction_id | uuid | Filter by transaction |
| start_date | date | Filter from date |
| end_date | date | Filter to date |

Response:
```json
{
"items": [
{
"id": "uuid",
"transaction_id": "uuid",
"account_id": "uuid",
"account_code": "200",
"account_name": "Accounts Receivable",
"debit": 0,
"credit": 10000,
"date": "2024-01-15"
}
]
}
```

### Reports

**GET** `/reports/balance-sheet`

Query parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| date | date | As of date |

**GET** `/reports/profit-loss`

Query parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| start_date | date | Period start |
| end_date | date | Period end |

### Accounts

**GET** `/accounts`

Response:
```json
{
"items": [
{
"id": "uuid",
"code": "100",
"name": "Cash at Bank",
"type": "asset",
"normal_balance": "debit",
"parent_id": null
}
]
}
```

**POST** `/accounts`

Body:
```json
{
"code": "200",
"name": "Accounts Receivable",
"type": "asset",
"parent_id": "uuid"
}
```

### Bank Feeds (Basiq)

**POST** `/basiq/connect`

Body:
```json
{
"institution_id": "AU00001",
"access_token": "string"
}
```

**GET** `/basiq/accounts`

**GET** `/basiq/transactions`

### AI Categorisation

**GET** `/categorise/stats`

Returns categorisation accuracy metrics.

## Error Responses

### 400 Bad Request
```json
{
"detail": "Validation error message"
}
```

### 404 Not Found
```json
{
"detail": "Resource not found"
}
```

### 500 Internal Server Error
```json
{
"detail": "Internal server error"
}
```

## Rate Limits

Development: None
Production: 100 requests/minute
120 changes: 120 additions & 0 deletions .doc/architecture/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Smart GL Architecture

## High-Level Diagram

```mermaid
graph TB
subgraph "Client"
Web[Next.js Frontend]
end

subgraph "API Layer"
FastAPI[FastAPI Backend]
end

subgraph "Data Layer"
Supabase[(Supabase PostgreSQL)]
Formance[Formance Ledger]
end

subgraph "External Services"
Basiq[Basiq Bank API]
Anthropic[Anthropic Claude]
OpenAI[OpenAI Embeddings]
end

Web -->|HTTP| FastAPI
FastAPI -->|SQL| Supabase
FastAPI -->|Ledger API| Formance
FastAPI -->|Bank Data| Basiq
FastAPI -->|AI Categorisation| Anthropic
FastAPI -->|Embeddings| OpenAI
```

## Component Overview

### Frontend (apps/web)
- **Framework**: Next.js 15 with App Router
- **UI**: React 18, Tailwind CSS, shadcn/ui
- **Charts**: Recharts
- **Port**: 3000

### Backend (apps/api)
- **Framework**: FastAPI (Python 3.12)
- **Database**: Supabase (PostgreSQL + pgvector + RLS)
- **Ledger**: Formance Ledger v2
- **Port**: 8000

### Routers

| Router | Path | Description |
|--------|-----|-------------|
| transactions | /transactions | Transaction CRUD |
| journal | /journal | Journal entries |
| reports | /reports | Financial reports |
| accounts | /accounts | Chart of accounts |
| basiq | /basiq | Bank feed integration |

### Services

| Service | Purpose |
|---------|---------|
| categorise.py | AI transaction categorization |
| basiq.py | Basiq API integration |
| formance.py | Formance Ledger interface |

## Database Schema

### Core Tables

- `tenants` - Multi-tenant isolation
- `accounts` - Chart of accounts
- `transactions` - Bank transactions
- `categorisations` - AI categorisation results
- `journal_entries` - Double-entry records

### Key Conventions

- **Monetary values**: Stored as cents (integers)
- **Time zone**: UTC in DB, Australia/Sydney for display
- **Soft deletes**: `deleted_at` field
- **Tenant isolation**: RLS + `app.current_tenant_id`

## Data Flow

### Transaction Categorisation

```mermaid
sequenceDiagram
participant User
participant API
participant Basiq
participant OpenAI
participant Anthropic
participant Supabase

User->>API: Fetch transactions
API->>Basiq: Get bank data
Basiq->>API: Transaction list
API->>OpenAI: Generate embeddings
OpenAI->>API: Embeddings
API->>Anthropic: Categorise with Claude
Anthropic->>API: Category suggestions
API->>Supabase: Save categorisations
API->>User: Display results
```

## Security

- **Tenant isolation**: Row-level security (RLS)
- **API keys**: Environment variables only
- **Authentication**: Bearer tokens (future: Supabase Auth)

## Deployment

| Component | Platform |
|-----------|-----------|
| Frontend | Vercel |
| Backend | Fly.io |
| Database | Supabase |
| Ledger | Docker (self-hosted) |
Loading
Loading