189 lines
5.2 KiB
Markdown
189 lines
5.2 KiB
Markdown
# Ledger Model Implementation
|
|
|
|
## Overview
|
|
|
|
This document describes the implementation of the Ledger model for the multi-ledger accounting system feature.
|
|
|
|
## Feature
|
|
|
|
**Feature:** accounting-feature-upgrade
|
|
**Task:** 1.1 创建Ledger账本模型和数据库迁移
|
|
**Requirements:** 3.1
|
|
|
|
## Model Definition
|
|
|
|
### Ledger Struct
|
|
|
|
```go
|
|
type Ledger struct {
|
|
BaseModel
|
|
Name string `gorm:"size:100;not null" json:"name"`
|
|
Theme string `gorm:"size:50" json:"theme"` // pink, beige, brown
|
|
CoverImage string `gorm:"size:255" json:"cover_image"`
|
|
IsDefault bool `gorm:"default:false" json:"is_default"`
|
|
SortOrder int `gorm:"default:0" json:"sort_order"`
|
|
|
|
// Relationships
|
|
Transactions []Transaction `gorm:"foreignKey:LedgerID" json:"-"`
|
|
}
|
|
```
|
|
|
|
### Fields
|
|
|
|
- **ID** (inherited from BaseModel): Primary key, auto-increment
|
|
- **CreatedAt** (inherited from BaseModel): Timestamp when ledger was created
|
|
- **UpdatedAt** (inherited from BaseModel): Timestamp when ledger was last updated
|
|
- **DeletedAt** (inherited from BaseModel): Soft delete timestamp (NULL if not deleted)
|
|
- **Name**: Ledger name (max 100 characters, required)
|
|
- **Theme**: Theme color identifier (max 50 characters, optional)
|
|
- Supported values: "pink", "beige", "brown"
|
|
- **CoverImage**: Path to cover image (max 255 characters, optional)
|
|
- **IsDefault**: Whether this is the default ledger (boolean, default: false)
|
|
- **SortOrder**: Display order for ledgers (integer, default: 0)
|
|
|
|
### Relationships
|
|
|
|
- **Transactions**: One-to-many relationship with Transaction model
|
|
- A ledger can have multiple transactions
|
|
- Foreign key: `LedgerID` in Transaction model
|
|
|
|
### Constants
|
|
|
|
```go
|
|
const MaxLedgersPerUser = 10
|
|
```
|
|
|
|
Maximum number of ledgers a user can create (Requirement 3.12)
|
|
|
|
## Database Schema
|
|
|
|
### Table: ledgers
|
|
|
|
```sql
|
|
CREATE TABLE IF NOT EXISTS ledgers (
|
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
created_at DATETIME(3) DEFAULT NULL,
|
|
updated_at DATETIME(3) DEFAULT NULL,
|
|
deleted_at DATETIME(3) DEFAULT NULL,
|
|
name VARCHAR(100) NOT NULL,
|
|
theme VARCHAR(50) DEFAULT NULL,
|
|
cover_image VARCHAR(255) DEFAULT NULL,
|
|
is_default TINYINT(1) DEFAULT 0,
|
|
sort_order INT DEFAULT 0,
|
|
PRIMARY KEY (id),
|
|
INDEX idx_ledgers_deleted_at (deleted_at)
|
|
);
|
|
```
|
|
|
|
### Transaction Model Extension
|
|
|
|
The Transaction model has been extended with a `LedgerID` field:
|
|
|
|
```go
|
|
LedgerID *uint `gorm:"index" json:"ledger_id,omitempty"`
|
|
```
|
|
|
|
This creates a foreign key relationship between transactions and ledgers.
|
|
|
|
## Migration
|
|
|
|
### Using Go Migration Tool
|
|
|
|
```bash
|
|
cd backend
|
|
go run cmd/migrate/main.go
|
|
```
|
|
|
|
This will automatically create the `ledgers` table and add the `ledger_id` column to the `transactions` table.
|
|
|
|
### Manual SQL Migration
|
|
|
|
```bash
|
|
mysql -u username -p database_name < backend/migrations/001_add_ledger_support.sql
|
|
```
|
|
|
|
## Testing
|
|
|
|
Unit tests are provided in `ledger_test.go`:
|
|
|
|
```bash
|
|
cd backend
|
|
go test ./internal/models/... -v
|
|
```
|
|
|
|
Tests verify:
|
|
- Table name is correct ("ledgers")
|
|
- All model fields work correctly
|
|
- MaxLedgersPerUser constant has the correct value
|
|
|
|
## Usage Example
|
|
|
|
```go
|
|
// Create a new ledger
|
|
ledger := models.Ledger{
|
|
Name: "Wedding Expenses",
|
|
Theme: "pink",
|
|
CoverImage: "/images/wedding-cover.jpg",
|
|
IsDefault: false,
|
|
SortOrder: 1,
|
|
}
|
|
|
|
// Save to database
|
|
db.Create(&ledger)
|
|
|
|
// Query ledgers
|
|
var ledgers []models.Ledger
|
|
db.Where("deleted_at IS NULL").Order("sort_order ASC").Find(&ledgers)
|
|
|
|
// Soft delete a ledger
|
|
db.Delete(&ledger)
|
|
|
|
// Restore a soft-deleted ledger
|
|
db.Model(&ledger).Update("deleted_at", nil)
|
|
```
|
|
|
|
## Next Steps
|
|
|
|
The following tasks will build upon this model:
|
|
|
|
1. **Task 3.1**: Implement Ledger CRUD API endpoints
|
|
2. **Task 3.2**: Implement soft delete and restore functionality
|
|
3. **Task 10.1-10.3**: Implement frontend components for ledger management
|
|
|
|
## Validation Rules
|
|
|
|
When implementing the API layer, ensure:
|
|
|
|
1. **Name validation**: Required, max 100 characters
|
|
2. **Theme validation**: Optional, must be one of: "pink", "beige", "brown"
|
|
3. **Ledger count limit**: User cannot create more than 10 ledgers (MaxLedgersPerUser)
|
|
4. **Default ledger**: At least one ledger must exist and be marked as default
|
|
5. **Soft delete**: Use GORM's soft delete feature (DeletedAt field)
|
|
|
|
## Design Considerations
|
|
|
|
### Soft Delete
|
|
|
|
The model uses GORM's soft delete feature (DeletedAt field from BaseModel). This means:
|
|
- Deleted ledgers are not physically removed from the database
|
|
- Deleted ledgers are automatically excluded from queries
|
|
- Historical transaction data is preserved even after ledger deletion
|
|
- Ledgers can be restored if needed
|
|
|
|
### Sort Order
|
|
|
|
The `SortOrder` field allows users to customize the display order of their ledgers. Lower values appear first.
|
|
|
|
### Default Ledger
|
|
|
|
The `IsDefault` field ensures there's always a default ledger for new transactions. Business logic should ensure:
|
|
- At least one ledger is always marked as default
|
|
- When the default ledger is deleted, another ledger is automatically promoted to default
|
|
|
|
## Compliance
|
|
|
|
This implementation satisfies:
|
|
- **Requirement 3.1**: Ledger data model with all specified fields
|
|
- **Requirement 3.12**: Maximum 10 ledgers per user (constant defined)
|
|
- **Design Document**: Ledger model structure matches the design specification
|