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
- Indexed TransactionID: Fast lookups when retrieving images for a transaction
- Cascade Delete: When a transaction is deleted, all associated images are automatically deleted
- 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:
- Image Compression: Implement automatic image compression on upload
- Thumbnail Generation: Create and store thumbnail versions for faster loading
- Cloud Storage: Support for S3 or other cloud storage providers
- Image Metadata: Store EXIF data, dimensions, orientation
- Image Processing: Auto-rotation, format conversion
- Batch Upload: Support uploading multiple images at once
- Image Search: Full-text search on image metadata
Related Files
backend/internal/models/transaction_image.go- Model definitionbackend/internal/models/transaction_image_test.go- Unit testsbackend/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