260 lines
7.3 KiB
Markdown
260 lines
7.3 KiB
Markdown
# 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
|
|
|
|
```go
|
|
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:
|
|
|
|
```sql
|
|
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:
|
|
|
|
```go
|
|
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
|
|
|
|
```go
|
|
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
|
|
|
|
```go
|
|
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
|
|
|
|
```go
|
|
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
|
|
|
|
```go
|
|
if fileSize > MaxImageSizeBytes {
|
|
return errors.New("image size exceeds 10MB limit")
|
|
}
|
|
```
|
|
|
|
### Validating Image Type
|
|
|
|
```go
|
|
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`:
|
|
|
|
```go
|
|
func AllModels() []interface{} {
|
|
return []interface{}{
|
|
// ... other models ...
|
|
&TransactionImage{}, // Feature: accounting-feature-upgrade
|
|
}
|
|
}
|
|
```
|
|
|
|
To run migrations:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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
|
|
|
|
## Related Files
|
|
|
|
- `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
|