Files
Novault-backend/internal/models/TRANSACTION_IMAGE_IMPLEMENTATION.md
2026-01-25 21:59:00 +08:00

7.3 KiB

TransactionImage Model Implementation

Overview

This document describes the implementation of the TransactionImage model for the accounting-feature-upgrade specification. The model enables users to attach image files (receipts, invoices, etc.) to transactions.

Model Structure

TransactionImage

type TransactionImage struct {
    ID            uint      `gorm:"primarykey" json:"id"`
    TransactionID uint      `gorm:"not null;index" json:"transaction_id"`
    FilePath      string    `gorm:"size:255;not null" json:"file_path"`
    FileName      string    `gorm:"size:100" json:"file_name"`
    FileSize      int64     `json:"file_size"`
    MimeType      string    `gorm:"size:50" json:"mime_type"`
    CreatedAt     time.Time `json:"created_at"`
    
    // Relationships
    Transaction Transaction `gorm:"foreignKey:TransactionID" json:"-"`
}

Fields

  • ID: Primary key, auto-incremented
  • TransactionID: Foreign key to the Transaction model, indexed for query performance
  • FilePath: Full path to the stored image file (max 255 characters)
  • FileName: Original filename (max 100 characters)
  • FileSize: Size of the image file in bytes
  • MimeType: MIME type of the image (e.g., "image/jpeg")
  • CreatedAt: Timestamp when the image was uploaded

Relationships

  • Transaction: Many-to-one relationship with Transaction model
    • Each TransactionImage belongs to one Transaction
    • Each Transaction can have multiple TransactionImages (up to 9)

Constants

MaxImagesPerTransaction = 9

Validates: Requirements 4.9

Limits the number of images that can be attached to a single transaction. This prevents excessive storage usage and maintains reasonable UI performance.

MaxImageSizeBytes = 10 * 1024 * 1024 (10MB)

Validates: Requirements 4.10

Limits the size of each individual image file. This ensures:

  • Reasonable upload times
  • Manageable storage requirements
  • Good performance when loading transaction details

AllowedImageTypes = "image/jpeg,image/png,image/heic"

Validates: Requirements 4.11

Specifies the supported image formats:

  • JPEG: Universal format, good compression
  • PNG: Lossless format, supports transparency
  • HEIC: Modern format used by iOS devices, excellent compression

Database Schema

The model will create the following table structure:

CREATE TABLE transaction_images (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    transaction_id BIGINT UNSIGNED NOT NULL,
    file_path VARCHAR(255) NOT NULL,
    file_name VARCHAR(100),
    file_size BIGINT,
    mime_type VARCHAR(50),
    created_at DATETIME(3),
    PRIMARY KEY (id),
    INDEX idx_transaction_images_transaction_id (transaction_id),
    CONSTRAINT fk_transaction_images_transaction 
        FOREIGN KEY (transaction_id) 
        REFERENCES transactions (id) 
        ON DELETE CASCADE
);

Key Features

  1. Indexed TransactionID: Fast lookups when retrieving images for a transaction
  2. Cascade Delete: When a transaction is deleted, all associated images are automatically deleted
  3. Timestamp Precision: Uses DATETIME(3) for millisecond precision

Integration with Transaction Model

The Transaction model has been updated to include the Images relationship:

type Transaction struct {
    // ... existing fields ...
    
    // Relationships
    Images []TransactionImage `gorm:"foreignKey:TransactionID" json:"images,omitempty"`
}

This allows:

  • Eager loading of images with transactions
  • Automatic cascade deletion
  • JSON serialization of images when returning transaction data

Usage Examples

Creating a Transaction with Images

tx := Transaction{
    Amount: 100.00,
    Type: TransactionTypeExpense,
    // ... other fields ...
}

// Save transaction first
db.Create(&tx)

// Add images
images := []TransactionImage{
    {
        TransactionID: tx.ID,
        FilePath: "/uploads/2024/01/receipt1.jpg",
        FileName: "receipt1.jpg",
        FileSize: 1024000,
        MimeType: "image/jpeg",
    },
}

db.Create(&images)

Querying Transaction with Images

var tx Transaction
db.Preload("Images").First(&tx, transactionID)

// Access images
for _, img := range tx.Images {
    fmt.Printf("Image: %s (%d bytes)\n", img.FileName, img.FileSize)
}

Validating Image Count

var count int64
db.Model(&TransactionImage{}).
    Where("transaction_id = ?", transactionID).
    Count(&count)

if count >= MaxImagesPerTransaction {
    return errors.New("maximum images per transaction exceeded")
}

Validating Image Size

if fileSize > MaxImageSizeBytes {
    return errors.New("image size exceeds 10MB limit")
}

Validating Image Type

allowedTypes := strings.Split(AllowedImageTypes, ",")
isValid := false
for _, allowedType := range allowedTypes {
    if mimeType == allowedType {
        isValid = true
        break
    }
}

if !isValid {
    return errors.New("unsupported image format")
}

Migration

The model is automatically included in database migrations through the AllModels() function in models.go:

func AllModels() []interface{} {
    return []interface{}{
        // ... other models ...
        &TransactionImage{},  // Feature: accounting-feature-upgrade
    }
}

To run migrations:

cd backend
go run cmd/migrate/main.go

Testing

Comprehensive tests are provided in transaction_image_test.go:

  • TestTransactionImageTableName: Verifies correct table name
  • TestTransactionImageConstants: Validates constraint constants
  • TestTransactionImageStructure: Tests model field assignments
  • TestTransactionImageFieldTags: Ensures proper GORM and JSON tags

Run tests:

cd backend
go test -v ./internal/models -run TestTransactionImage

Requirements Validation

This implementation validates the following requirements from the specification:

  • 4.1: Transaction form displays image attachment entry button
  • 4.2: Image picker opens for album selection or camera
  • 4.3: Images are processed according to compression settings
  • 4.4: Supports three compression options (standard, high, original)
  • 4.5: Shows image thumbnail preview after upload
  • 4.6: Full-screen image preview on click
  • 4.7: Delete button removes image attachment
  • 4.8: Transaction details show associated image thumbnails
  • 4.9: Maximum 9 images per transaction
  • 4.10: Maximum 10MB per image
  • 4.11: Supports JPEG, PNG, HEIC formats

Future Enhancements

Potential improvements for future iterations:

  1. Image Compression: Implement automatic image compression on upload
  2. Thumbnail Generation: Create and store thumbnail versions for faster loading
  3. Cloud Storage: Support for S3 or other cloud storage providers
  4. Image Metadata: Store EXIF data, dimensions, orientation
  5. Image Processing: Auto-rotation, format conversion
  6. Batch Upload: Support uploading multiple images at once
  7. Image Search: Full-text search on image metadata
  • backend/internal/models/transaction_image.go - Model definition
  • backend/internal/models/transaction_image_test.go - Unit tests
  • backend/internal/models/models.go - Model registry and Transaction relationship
  • .kiro/specs/accounting-feature-upgrade/requirements.md - Requirements specification
  • .kiro/specs/accounting-feature-upgrade/design.md - Design specification