This commit is contained in:
2026-01-25 21:59:00 +08:00
parent 7fd537bef3
commit 4cad3f0250
118 changed files with 30473 additions and 0 deletions

View File

@@ -0,0 +1,259 @@
# 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