Skip to content

UsmanovMahmudkhan/ai-finance

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AI Service

Handles receipt processing, spending analysis, and goal generation via a Python FastAPI microservice. It integrates OCR, Google’s generative AI model, and a simple merchant-category learner.

ai-service/Dockerfile

Defines the Python container build.

FROM python:3.10-slim
WORKDIR /app

COPY requirements.txt .
RUN apt-get update \
    && apt-get install -y libgl1 libglib2.0-0 tesseract-ocr \
    && rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir -r requirements.txt
COPY . .

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
  • Base image: Python 3.10 slim
  • Installs: Tesseract OCR & OpenCV libs
  • Runs: uvicorn main:app

ai-service/requirements.txt

Lists Python dependencies:

  • fastapi
  • uvicorn
  • python-multipart
  • opencv-python
  • pytesseract
  • google-generativeai
  • numpy
  • pandas
  • scikit-learn
  • python-dotenv
  • requests

ai-service/ai_client.py

Wraps Google Gemini for:

  • analyze_receipt: Extracts JSON from image
  • analyze_spending: Generates advice
  • generate_goals: Proposes savings goals
from typing import Dict, Any
import google.generativeai as genai
import os, json

class AIClient:
    def __init__(self):
        api_key = os.getenv("GOOGLE_API_KEY")
        if api_key:
            genai.configure(api_key=api_key)
            self.model = genai.GenerativeModel('gemini-2.0-flash')

    def analyze_receipt(self, image_data: bytes, mime_type: str) -> Dict[str, Any]:
        prompt = """Analyze receipt and extract JSON..."""
        response = self.model.generate_content([prompt, {"mime_type": mime_type, "data": image_data}])
        return json.loads(response.text.strip().strip("```json").strip("```"))
    # analyze_spending and generate_goals similarly...
  • Initializes Gemini-2.0

ai-service/category_learner.py

Maintains and updates merchant→category mappings.

class CategoryLearner:
    def __init__(self):
        self.merchant_categories = {}
        self.load_mappings()

    def load_mappings(self):
        self.merchant_categories = {
            # Food
            "starbucks": "Food", "mcdonald's": "Food",
            # Transport
            "shell": "Transport",
            # Utilities
            "comcast": "Utilities",
            # Entertainment
            "netflix": "Entertainment",
            # Shopping
            "amazon": "Shopping",
            # Health
            "cvs": "Health"
        }

    def get_category(self, merchant_name: str) -> str:
        if not merchant_name: return "Other"
        name = merchant_name.lower().strip()
        if name in self.merchant_categories:
            return self.merchant_categories[name]
        for m, cat in self.merchant_categories.items():
            if m in name or name in m:
                return cat
        return "Other"
  • learn_mapping adds new pairs

ai-service/ocr_service.py

Performs OCR preprocessing and text extraction.

import cv2, pytesseract, numpy as np
from fastapi import UploadFile

class OCRService:
    async def extract_text(self, file: UploadFile) -> str:
        contents = await file.read()
        img = cv2.imdecode(np.frombuffer(contents, np.uint8), cv2.IMREAD_COLOR)
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        denoised = cv2.fastNlMeansDenoising(gray)
        _, thresh = cv2.threshold(denoised, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
        return pytesseract.image_to_string(thresh)
  • Converts image → grayscale → threshold → Tesseract

ai-service/main.py

Defines FastAPI endpoints:

  • GET /: Health check
  • POST /process_receipt: Runs OCR & AI, applies merchant-category overrides
  • POST /analyze_spending: Spending advice
  • POST /generate_goals: AI-driven goals
app = FastAPI()
ocr = OCRService()
ai_client = AIClient()
learner = CategoryLearner()

@app.post("/process_receipt")
async def process_receipt(file: UploadFile = File(...)):
    data = ai_client.analyze_receipt(await file.read(), file.content_type)
    cat = learner.get_category(data["merchant_name"])
    # override categories...
    return {"status": "success", "data": data}
  • Coordinates OCR, AIClient, CategoryLearner

Receipt Processing Sequence

sequenceDiagram
    participant FE as Frontend
    participant BE as Backend
    participant AI as AI Service
    participant OCR as OCRService
    FE->>BE: POST /api/receipts/upload
    BE->>AI: POST /process_receipt
    AI->>OCR: extract_text()
    AI->>AI: analyze_receipt()
    AI->>BE: JSON data
    BE->>DB: save Receipt/Transaction/Items
    BE-->>FE: Receipt object
Loading

Backend

Implements REST API, persistence, and AI service integration.

backend/Dockerfile

Two-stage build: Maven → Corretto

FROM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /app
COPY pom.xml . & src ./src
RUN mvn clean package -DskipTests

FROM amazoncorretto:17
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
ENTRYPOINT ["java","-jar","app.jar"]
  • Packages Spring Boot JAR

backend/pom.xml

Defines dependencies:

Artifact Purpose
spring-boot-starter-data-jpa JPA & Hibernate
spring-boot-starter-web REST controllers
spring-boot-starter-validation Request validation
postgresql JDBC driver (runtime)
lombok (optional) Boilerplate reduction
spring-boot-starter-test (test) Testing

BackendApplication.java

Spring Boot entrypoint.

@SpringBootApplication
public class BackendApplication {
    public static void main(String[] args) {
        SpringApplication.run(BackendApplication.class, args);
    }
}

WebConfig.java

Serves uploaded files under /uploads/**.

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry reg) {
        reg.addResourceHandler("/uploads/**")
           .addResourceLocations("file:uploads/");
    }
}

Controllers & Endpoints

AnalyticsController.java

Manages spending data and AI suggestions.

@RestController
@RequestMapping("/api/analytics")
@CrossOrigin(origins="*")
public class AnalyticsController {
    @Autowired private AnalyticsService analyticsService;
    @GetMapping("/spending") …
    @GetMapping("/categories") …
    @GetMapping("/suggestions") …
}
  • Delegates to AnalyticsService

GET /api/analytics/spending

{
  "title": "Get Spending Trends",
  "description": "Fetch daily, monthly, or yearly spending data for a user",
  "method": "GET",
  "baseUrl": "http://localhost:8080",
  "endpoint": "/api/analytics/spending",
  "queryParams": [
    {"key": "userId", "value": "User ID", "required": true},
    {"key": "period", "value": "day|month|year", "required": true}
  ],
  "responses": {
    "200": {
      "description": "Spending list",
      "body": "[{\"date\":\"2025-01-01\",\"total\":120.50}, …]"
    },
    "400": {"description": "Invalid period"}
  }
}

GET /api/analytics/categories

{
  "title": "Get Category Spending",
  "description": "Fetch spending breakdown by category",
  "method": "GET",
  "baseUrl": "http://localhost:8080",
  "endpoint": "/api/analytics/categories",
  "queryParams": [{"key":"userId","value":"User ID","required":true}],
  "responses": {
    "200": {"description":"Category totals","body":"[{\"category\":\"Food\",\"total\":300.00}, …]"}
  }
}

GET /api/analytics/suggestions

{
  "title": "Get AI Spending Advice",
  "description": "Retrieve AI-generated spending advice",
  "method": "GET",
  "baseUrl": "http://localhost:8080",
  "endpoint": "/api/analytics/suggestions",
  "queryParams": [{"key":"userId","value":"User ID","required":true}],
  "responses": {
    "200": {
      "description":"Advice and tips",
      "body":"{\"analysis\":\"You spent…\",\"tips\":[\"Reduce…\",\"Consider…\"]}"
    }
  }
}

GoalController.java

CRUD & AI-powered goal generation.

@RestController
@RequestMapping("/api/goals")
@CrossOrigin(origins="*")
public class GoalController { … }
``]
- Uses `GoalService`  

#### GET /api/goals

```api
{
  "title": "List User Goals",
  "description": "Get all goals for a user",
  "method": "GET",
  "baseUrl": "http://localhost:8080",
  "endpoint": "/api/goals",
  "queryParams":[{"key":"userId","value":"User ID","required":true}],
  "responses":{"200":{"body":"[{\"id\":1,\"title\":\"Save\",\"targetAmount\":500.0,…}]"}}
}

POST /api/goals

{
  "title": "Create Goal",
  "description": "Add a new savings goal",
  "method": "POST",
  "baseUrl": "http://localhost:8080",
  "endpoint": "/api/goals",
  "queryParams":[{"key":"userId","value":"User ID","required":true}],
  "bodyType":"json",
  "requestBody":"{\"title\":\"Vacation\",\"targetAmount\":1000.0,\"deadline\":\"2025-06-01\"}",
  "responses":{"200":{"body":"{\"id\":2,\"title\":\"Vacation\",…}" }}
}

PUT /api/goals/{id}

{
  "title": "Update Goal",
  "description": "Modify existing goal amounts or status",
  "method":"PUT",
  "baseUrl":"http://localhost:8080",
  "endpoint":"/api/goals/2",
  "pathParams":[{"key":"id","value":"Goal ID","required":true}],
  "bodyType":"json",
  "requestBody":"{\"currentAmount\":200.0}",
  "responses":{"200":{"body":"{\"id\":2,\"currentAmount\":200.0,…}" }}
}

POST /api/goals/generate

{
  "title":"AI Generate Goals",
  "description":"Generate personalized goals via AI",
  "method":"POST",
  "baseUrl":"http://localhost:8080",
  "endpoint":"/api/goals/generate",
  "queryParams":[{"key":"userId","value":"User ID","required":true}],
  "responses":{"200":{"body":"{\"category_breakdown\":[…],\"monthly_trend\":[…]}" }}
}

ReceiptController.java

Handles receipt upload & retrieval.

@RestController
@RequestMapping("/api/receipts")
@CrossOrigin(origins="*")
public class ReceiptController { … }
  • Relies on ReceiptServiceImpl

POST /api/receipts/upload

{
  "title":"Upload Receipt",
  "description":"Upload an image for AI processing",
  "method":"POST",
  "baseUrl":"http://localhost:8080",
  "endpoint":"/api/receipts/upload",
  "formData":[
    {"key":"userId","value":"User ID","required":true},
    {"key":"file","value":"Image file","required":true}
  ],
  "responses":{
    "200":{"body":"{\"id\":5,\"status\":\"PROCESSING\",\"imageUrl\":\"uploads/…\"}"}
  }
}

GET /api/receipts/user/{userId}

{
  "title":"List Receipts",
  "description":"Get all receipts for a user",
  "method":"GET",
  "baseUrl":"http://localhost:8080",
  "endpoint":"/api/receipts/user/1",
  "pathParams":[{"key":"userId","value":"User ID","required":true}],
  "responses":{"200":{"body":"[{\"id\":5,…}, …]"}}
}

GET /api/receipts/{id}

{
  "title":"Get Receipt",
  "description":"Retrieve one receipt and its transaction",
  "method":"GET",
  "baseUrl":"http://localhost:8080",
  "endpoint":"/api/receipts/5",
  "pathParams":[{"key":"id","value":"Receipt ID","required":true}],
  "responses":{"200":{"body":"{\"id\":5,\"transaction\":{…}}" }}
}

DTO & Models

AIAnalysisResponse.java

Holds AI output for receipts:

  • status: success|failed
  • raw_text: textual OCR fallback
  • data: merchant_name, date, total_amount, currency, items[]

Domain Models

Class Table Relationships
User users 1—* Receipts, 1—* Goals
Receipt receipts *—1 User, 1—1 Transaction
Transaction transactions 1—* Items, 1—1 Receipt
Item items *—1 Transaction
Goal goals *—1 User, tracks progress & status
ReceiptStatus Enum: PROCESSING, COMPLETED, FAILED
GoalStatus Enum: ACTIVE, COMPLETED, CANCELLED
erDiagram
    USERS ||--o{ RECEIPTS : has
    RECEIPTS ||--o{ TRANSACTIONS : links
    TRANSACTIONS ||--o{ ITEMS : contains
    USERS ||--o{ GOALS : sets
Loading

Repositories

Spring Data JPA repos for CRUD & custom queries:

  • UserRepository
  • ReceiptRepository (findByUser_Id)
  • TransactionRepository (daily/monthly/yearly/category queries)
  • ItemRepository
  • GoalRepository (findByUser_Id)

Services

Service Role
ReceiptServiceImpl Saves files, calls AI, builds entities
PythonAIServiceClient Bridges backend ↔ AI Service via REST
AnalyticsService Aggregates spending data, delegates AI suggestions
GoalService CRUD goals, triggers AI-generated goals

application.properties

Configures DB & AI service URL:

spring.datasource.url=jdbc:postgresql://localhost:5432/finance_db
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.hibernate.ddl-auto=update

# AI Service
ai.service.url=http://ai-service:8000/process_receipt

Frontend

Built with Vite + React + Tailwind; consumes the backend REST API.

frontend/Dockerfile

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5173
CMD ["npm","run","dev","--","--host"]

package.json

Defines scripts, React, Recharts, Framer Motion, Lucide icons, Vite:

{
  "scripts": {"dev":"vite","build":"tsc - b && vite build"},
  "dependencies": {
    "react": "^18.x","react-dom":"^18.x","react-router-dom":"^7.x",
    "recharts":"^3.x","framer-motion":"^11.x","lucide-react":"^0.x"
  }
}

index.html

Mounts React <div id="root"> and loads main.tsx.

postcss.config.js & tailwind.config.js

Enables Tailwind + autoprefixer; custom stripe color palette and animations.

vite.config.ts

Sets up React plugin:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({ plugins: [react()] });

src/api.ts

Centralizes API calls and TypeScript interfaces:

  • uploadReceipt(userId, file)
  • getUserReceipts(userId)
  • getSpending(userId, period)
  • getCategorySpending(userId)
  • getSuggestions(userId)
  • getGoals, createGoal, updateGoal, generateGoals
export interface Receipt { id:number; status:string; imageUrl:string; transaction?:Transaction; }
export const uploadReceipt = async (...) => { /* FormData POST */ }

src/main.tsx

Bootstraps React app:

import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode><App/></React.StrictMode>
);

src/App.tsx

Defines routing layout:

  • /: Upload & Dashboard
  • /analytics: AnalyticsPage
  • /insights: InsightsPage
  • /goals: GoalsPage

Nav uses react-router-dom with active styles.


Components

ReceiptUpload.tsx

Drag-and-drop / file-picker upload UI with status indicators. Calls uploadReceipt and triggers refresh on success.

Dashboard.tsx

Displays recent receipts in a responsive grid. Shows status badges, thumbnails, transaction summary.


Pages

AnalyticsPage.tsx

Renders spending trends via recharts Line/Bar charts. Switches between day/month/year.

InsightsPage.tsx

Shows category pie chart and AI suggestions. Fetches both in parallel.

GoalsPage.tsx

Lists user goals, lets users create manually or via AI. Includes progress bars and deadlines.


Architecture Overview

C4Container
    title Personal Finance AI System
    Person(user, "End User", "Uses the web UI")
    System(frontend, "Frontend (React + Vite)", "Renders UI, calls API")
    System(backend, "Backend (Spring Boot)", "Handles business logic, persistence")
    System(aiservice, "AI Service (FastAPI)", "OCR + Generative AI")
    SystemDb(db, "PostgreSQL", "Stores receipts, transactions, goals, users")

    Rel(user, frontend, "Interacts with")
    Rel(frontend, backend, "REST API", "JSON/HTTP")
    Rel(backend, aiservice, "AI calls", "JSON/HTTP")
    Rel(backend, db, "JPA", "SQL")
Loading

This documentation covers all listed files, their roles, and interdependencies across AI service, backend, and frontend layers.


UML Diagrams (PlantUML)

This section adds UML 2.5 compliant PlantUML diagrams for the whole system. It complements the previous Mermaid views with a different notation.

Use Case Diagram

This diagram shows how a user interacts with the system and its main features. It focuses on user goals rather than implementation details.

@startuml
left to right direction
actor User

rectangle "Personal Finance AI System" {
  usecase "Upload Receipt" as UC_Upload
  usecase "View Receipts Dashboard" as UC_Dashboard
  usecase "View Spending Analytics" as UC_Analytics
  usecase "View AI Insights" as UC_Insights
  usecase "Manage Savings Goals" as UC_Goals
  usecase "Generate AI Goals" as UC_AI_Goals
}

User --> UC_Upload
User --> UC_Dashboard
User --> UC_Analytics
User --> UC_Insights
User --> UC_Goals
User --> UC_AI_Goals
@enduml

Class Diagram

This diagram captures the main backend and AI service classes. It emphasizes domain entities, services, controllers, and repositories.

@startuml
skinparam packageStyle rectangle

package "backend.model" {
  class User {
    +Long id
    +String username
    +String passwordHash
    +String email
  }

  class Receipt {
    +Long id
    +String imageUrl
    +ReceiptStatus status
    +LocalDateTime createdAt
    +Transaction transaction
    +User user
  }

  enum ReceiptStatus {
    PROCESSING
    COMPLETED
    FAILED
  }

  class Transaction {
    +Long id
    +String merchantName
    +LocalDate transactionDate
    +BigDecimal totalAmount
    +String currency
    +List<Item> items
    +Receipt receipt
  }

  class Item {
    +Long id
    +String description
    +Integer quantity
    +BigDecimal unitPrice
    +String category
    +Transaction transaction
  }

  class Goal {
    +Long id
    +String title
    +Double targetAmount
    +Double currentAmount
    +String category
    +LocalDate deadline
    +GoalStatus status
    +User user
  }

  enum GoalStatus {
    ACTIVE
    COMPLETED
    CANCELLED
  }
}

package "backend.dto" {
  class AIAnalysisResponse {
    +String status
    +String raw_text
    +ExtractedData data
  }

  class ExtractedData {
    +String merchant_name
    +String date
    +BigDecimal total_amount
    +String currency
    +List<ExtractedItem> items
  }

  class ExtractedItem {
    +String description
    +Integer quantity
    +BigDecimal unit_price
    +String category
  }
}

package "backend.repository" {
  interface UserRepository
  interface ReceiptRepository
  interface TransactionRepository
  interface ItemRepository
  interface GoalRepository
}

package "backend.service" {
  class ReceiptServiceImpl
  interface ReceiptService
  class AnalyticsService
  class GoalService
  class PythonAIServiceClient
}

package "backend.controller" {
  class ReceiptController
  class AnalyticsController
  class GoalController
}

package "ai-service" {
  class AIClient
  class OCRService
  class CategoryLearner
}

User "1" -- "0..*" Receipt
User "1" -- "0..*" Goal
Receipt "1" -- "0..1" Transaction
Transaction "1" -- "0..*" Item

ReceiptRepository "1" ..> Receipt : manages
TransactionRepository "1" ..> Transaction : manages
ItemRepository "1" ..> Item : manages
GoalRepository "1" ..> Goal : manages
UserRepository "1" ..> User : manages

ReceiptServiceImpl ..|> ReceiptService
ReceiptServiceImpl --> ReceiptRepository
ReceiptServiceImpl --> UserRepository
ReceiptServiceImpl --> PythonAIServiceClient

AnalyticsService --> TransactionRepository
AnalyticsService --> PythonAIServiceClient

GoalService --> GoalRepository
GoalService --> UserRepository
GoalService --> AnalyticsService
GoalService --> PythonAIServiceClient

ReceiptController --> ReceiptService
AnalyticsController --> AnalyticsService
GoalController --> GoalService

PythonAIServiceClient ..> AIAnalysisResponse
PythonAIServiceClient ..> "ai-service" : HTTP

AIClient ..> CategoryLearner
AIClient ..> OCRService

@enduml

Sequence Diagram

This sequence diagram details the flow when a user uploads a receipt. It shows interactions across frontend, backend, AI service, and database.

@startuml
actor User
participant "React Frontend" as FE
participant "ReceiptController" as RC
participant "ReceiptServiceImpl" as RS
participant "PythonAIServiceClient" as PY
participant "AI Service\n(FastAPI)" as AIS
participant "AIClient" as AIC
database "PostgreSQL" as DB

User -> FE : Select receipt image
FE -> RC : POST /api/receipts/upload\nmultipart(userId, file)
RC -> RS : uploadReceipt(userId, file)

RS -> RS : Store file on disk\nuploads/<uuid>_file.jpg
RS -> RS : Create Receipt(status=PROCESSING)

RS -> PY : analyzeReceipt(imagePath)
PY -> AIS : POST /process_receipt\nmultipart(file)
AIS -> AIC : analyze_receipt(bytes, mime)
AIC -> AIC : Call Gemini model\nparse JSON
AIC --> AIS : Structured JSON
AIS --> PY : AIAnalysisResponse JSON
PY --> RS : AIAnalysisResponse

RS -> RS : Map AI data to\nTransaction and Items
RS -> RS : Update Receipt\nstatus COMPLETED or FAILED
RS -> DB : save(Receipt, Transaction, Items)

RS --> RC : Receipt DTO
RC --> FE : 200 OK + Receipt JSON
FE --> User : Show processing state\nand new card
@enduml

Activity Diagram

This activity diagram describes the receipt processing workflow. It focuses on decisions and actions from upload through AI enrichment.

@startuml
start

:User uploads receipt\nvia frontend;
:Backend receives\nmultipart request;

:Store file on disk;
:Create Receipt\nstatus=PROCESSING;

:Call PythonAIServiceClient\nanalyzeReceipt;

if (AI service call successful?) then (yes)
  if (AI status == success?) then (yes)
    :Create Transaction\nfrom AIAnalysisResponse;
    :Create Items for\neach AI item;
    :Attach Transaction\nto Receipt;
    :Set Receipt status\nCOMPLETED;
  else (no)
    :Set Receipt status\nFAILED;
  endif
else (no)
  :Set Receipt status\nFAILED;
endif

:Persist Receipt,\nTransaction, Items;

stop
@enduml

State Machine Diagram

This state machine models the lifecycle of a Receipt. It uses the ReceiptStatus enum and transitions based on processing outcomes.

@startuml
[*] --> PROCESSING : uploadReceipt()

state PROCESSING {
}

PROCESSING --> COMPLETED : AI analysis success
PROCESSING --> FAILED : AI analysis failure
PROCESSING --> FAILED : AI service error

COMPLETED --> COMPLETED : read-only usage
FAILED --> FAILED : read-only usage

COMPLETED --> [*]
FAILED --> [*]
@enduml

Component Diagram

This diagram shows the main deployable components and their interfaces. It abstracts away internal classes and focuses on services.

@startuml
rectangle "User Browser" as Browser

component "React Frontend\n(Vite SPA)" as Frontend
component "Spring Boot Backend\nREST API" as Backend
component "AI Service\nFastAPI + Gemini" as AISvc
database "PostgreSQL\nDatabase" as DB

Browser --> Frontend : HTTPS\nSPA assets
Frontend --> Backend : HTTP JSON\n/api/...
Backend --> AISvc : HTTP JSON\n/process_receipt\n/analyze_spending\n/generate_goals
Backend --> DB : JDBC\nJPA queries

@enduml

Deployment Diagram

This deployment diagram represents runtime nodes and their deployed artifacts. It reflects the docker-compose setup with separate containers.

@startuml
node "User Device" {
  artifact "Web Browser" as Browser
}

node "Docker Host" {
  node "frontend container\nnode:18-alpine" as FrontendNode {
    artifact "Vite Dev Server\nReact SPA" as FrontendApp
  }

  node "backend container\namazoncorretto:17" as BackendNode {
    artifact "Spring Boot JAR\nbackend-0.0.1.jar" as BackendJar
  }

  node "ai-service container\npython:3.10-slim" as AINode {
    artifact "FastAPI app\nmain.py" as AIApp
  }

  node "db container\npostgres:15-alpine" as DBNode {
    database "PostgreSQL\nfinance_db" as DB
  }
}

Browser --> FrontendApp : HTTPS 5173
FrontendApp --> BackendJar : HTTP 8080
BackendJar --> AIApp : HTTP 8000
BackendJar --> DB : JDBC 5432

@enduml

Formal Architecture Explanation

This section explains the architecture and codebase structure. It describes each layer, its classes, and their interactions.

High-Level Layers

The system follows a classic three-tier architecture with an additional AI microservice. The tiers are frontend, backend, and database, with AI as an external service.

  • The frontend is a React single-page application using Vite and Tailwind CSS.
  • The backend is a Spring Boot REST API exposing endpoints for receipts, analytics, and goals.
  • The AI service is a Python FastAPI app wrapping OCR and the Gemini model.
  • The database is PostgreSQL, accessed through Spring Data JPA repositories.

AI Service Layer

The AI service encapsulates all machine intelligence. It combines OCR, heuristic categorization, and generative AI.

  • main.py defines the FastAPI application and three endpoints.
  • /process_receipt receives an image, calls AIClient.analyze_receipt, and applies CategoryLearner.
  • /analyze_spending and /generate_goals accept JSON and delegate to AIClient methods.
  • AIClient configures the Gemini client, sends prompts, and parses structured JSON.
  • OCRService prepares images and extracts text using OpenCV and Tesseract, though current receipt processing is multimodal.
  • CategoryLearner maps merchant names to spending categories using simple string matching.

Backend Layer: Configuration and Bootstrap

The backend layer exposes REST APIs, persists data, and coordinates AI invocations. Configuration files define environment-specific behavior.

  • BackendApplication is the Spring Boot entry point and triggers component scanning.
  • WebConfig maps the /uploads/** URL path to the local uploads/ directory.
  • application.properties configures PostgreSQL connection and AI service URL.

Backend Layer: Domain Model

The domain model represents users, receipts, transactions, items, and goals. JPA annotations map each class to a table.

  • User represents application users with unique username and email.
  • Receipt stores metadata for uploaded receipt images, including file path and status.
  • Transaction represents a financial transaction derived from a receipt and holds merchant, date, amount, and currency.
  • Item models individual line items associated with a transaction, including quantity and per-unit price.
  • Goal captures a savings goal with target, current amount, category, deadline, and status.
  • ReceiptStatus and GoalStatus enumerate possible lifecycle states for receipts and goals.

JPA relationships wire these entities.

  • Each User has many Receipt and Goal instances.
  • Each Receipt has at most one Transaction.
  • Each Transaction can have many Item entities.
  • JSON back-reference annotations prevent infinite recursion during serialization.

Backend Layer: Repositories

The repository layer abstracts persistence details with Spring Data JPA. Each repository interface exposes CRUD and custom queries.

  • UserRepository provides basic user queries and a findByUsername method.
  • ReceiptRepository offers CRUD for receipts and findByUser_Id.
  • TransactionRepository contains JPQL queries for daily, monthly, yearly, and category spending aggregations.
  • ItemRepository handles item persistence with generic JPA methods.
  • GoalRepository enables CRUD and findByUser_Id for goals.

These repositories are injected into services. They allow services to remain persistence-agnostic.

Backend Layer: DTOs and AI Client

The backend uses a dedicated DTO to isolate AI response shape. A separate service handles HTTP calls to the Python AI service.

  • AIAnalysisResponse mirrors the JSON returned by /process_receipt.
  • It contains nested ExtractedData and ExtractedItem classes matching the AI schema.
  • PythonAIServiceClient uses RestTemplate to call AI endpoints.
  • analyzeReceipt sends a multipart request with a file and maps JSON to AIAnalysisResponse.
  • getSpendingAdvice and generateGoals post JSON to other AI endpoints and receive generic maps.

This design decouples the backend from direct HTTP handling. It centralizes AI communication.

Backend Layer: Services

Service classes implement business logic and orchestrate repositories and external calls. They hide complexity from controllers.

  • ReceiptServiceImpl implements ReceiptService.
  • It validates the user, stores the uploaded file, and creates a Receipt marked as PROCESSING.
  • It uses PythonAIServiceClient to analyze the image and receives AIAnalysisResponse.
  • On success, it builds a Transaction and associated Item entities from AI output.
  • It sets the Receipt status to COMPLETED or FAILED based on AI results.
  • Finally, it persists everything using ReceiptRepository.

AnalyticsService focuses on reporting and AI insights.

  • It calls TransactionRepository aggregate queries for different periods and categories.
  • It combines results into a data map with category_breakdown and monthly_trend.
  • It passes the map to PythonAIServiceClient.getSpendingAdvice for narrative tips.

GoalService manages user goals.

  • It uses GoalRepository and UserRepository for CRUD operations.
  • It updates only the mutable fields currentAmount and status.
  • It composes analytics data and calls PythonAIServiceClient.generateGoals.
  • The AI service returns suggestions, which the frontend can turn into actual goals.

Backend Layer: Controllers

Controllers expose API endpoints and delegate to services. They define request mappings, parameters, and response bodies.

  • ReceiptController maps under /api/receipts.
  • It exposes POST /upload, GET /user/{userId}, and GET /{id}.
  • It uses @RequestParam for userId and MultipartFile for images.

AnalyticsController exposes analytics related endpoints.

  • It handles GET /api/analytics/spending with userId and period query parameters.
  • It uses a switch statement to return daily, monthly, or yearly data.
  • It also defines GET /api/analytics/categories and GET /api/analytics/suggestions.

GoalController manages goals.

  • It defines GET /api/goals to list goals for a user.
  • It exposes POST /api/goals to create a goal and PUT /api/goals/{id} to update one.
  • POST /api/goals/generate triggers AI goal generation based on analytics data.

Frontend Layer: Structure

The frontend is a Vite-powered React application. It uses modern React, TypeScript, and Tailwind CSS.

  • main.tsx bootstraps the React application and mounts App.
  • App.tsx sets up routing using react-router-dom.
  • It defines navigation between dashboard, analytics, insights, and goals pages.
  • It also fetches receipts on mount and passes them to Dashboard.

api.ts centralizes HTTP calls and types.

  • It defines interfaces for Receipt, Transaction, Item, and Goal.
  • It provides helper functions for uploads, analytics, suggestions, and goals.
  • All calls use the same API_BASE_URL, which matches the backend port.

Frontend Layer: Components and Pages

UI components are presentational and rely on api.ts for data. Framer Motion and Recharts provide animations and charts.

  • ReceiptUpload presents a drag-and-drop upload panel with camera capture support.
  • It calls uploadReceipt and notifies the parent on success.
  • Dashboard renders receipt cards with thumbnails, statuses, and summary values.

Pages organize higher-level workflows.

  • AnalyticsPage visualizes spending trends using Recharts line and bar charts.
  • It switches period state and refetches data accordingly.
  • InsightsPage shows a category pie chart and AI advisor panel with textual tips.
  • GoalsPage retrieves goals, shows progress bars, and allows AI-driven goal generation.

Cross-Cutting Interactions and Data Flow

The system has a clear data flow from user actions to AI and back. Each step maps to code structures.

  • The user uploads a receipt, triggering frontend uploadReceipt.
  • The backend stores the file, calls AI, and saves structured data.
  • The frontend polls or reloads getUserReceipts to show updated receipts and transactions.
  • Analytics views call dedicated endpoints that reuse aggregated transaction data.
  • The AI service enriches analytics with narrative insights and recommended goals.
  • These interactions use JSON over HTTP and map to strongly typed DTOs and entities.

This completes the formal architecture description and aligns with the provided UML diagrams.

About

fastapi uvicorn python-multipart opencv-python pytesseract google-generativeai numpy pandas scikit-learn python-dotenv requests

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors