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

5.2 KiB

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

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

const MaxLedgersPerUser = 10

Maximum number of ledgers a user can create (Requirement 3.12)

Database Schema

Table: ledgers

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:

LedgerID *uint `gorm:"index" json:"ledger_id,omitempty"`

This creates a foreign key relationship between transactions and ledgers.

Migration

Using Go Migration Tool

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

mysql -u username -p database_name < backend/migrations/001_add_ledger_support.sql

Testing

Unit tests are provided in ledger_test.go:

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

// 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