📖 Bản tiếng Anh (English Edition)


Điều kiện tiên quyết: Kiến thức về các công cụ tài chính ngân hàng bán lẻ, công thức lãi kép, cơ chế khấu hao khoản vay và kiến trúc máy trạng thái (state machine).

Phần 2: Nghiệp Vụ Ngân Hàng Lõi: CIF, CASA & Lending

Trả lời nhanh (Answer-first): Hệ thống tiền gửi CASA và phân hệ cho vay quản trị số dư tài khoản thời gian thực, thấu chi và lịch trả nợ tự động, sử dụng số học thập phân dấu phẩy tĩnh, thuật toán dồn tích lãi suất hàng ngày và máy trạng thái tất toán bảo đảm tuân thủ quy định kế toán ngân hàng.


1. Phân Tách Nghiệp Vụ: CIF, CASA và Lending

Ba trụ cột của ngân hàng thương mại bán lẻ vận hành với đặc tính tốc độ và mô hình lưu trữ dữ liệu rất khác biệt:

flowchart TD
    subgraph CIF_Domain ["1. Hồ Sơ Khách Hàng (CIF)"]
        Party["Thực Thể Khách Hàng (Cá Nhân / Doanh Nghiệp)"]
        KYC["Xác Thực eKYC & Phân Tầng Rủi Ro AML"]
        Limits["Hạn Mức Giao Dịch & Rút Tiền Ngày"]
    end

    subgraph CASA_Domain ["2. Dịch Vụ Tiền Gửi & CASA (Tốc Độ Cao)"]
        CurrentAcc["Tài Khoản Thanh Toán (Thấu Chi / Chequing)"]
        SavingsAcc["Tài Khoản Tiết Kiệm (Tính Lãi Dồn Tích Hằng Ngày)"]
        HoldEngine["Cơ Chế Phong Tỏa & Giữ Tiền (Holds)"]
    end

    subgraph Lending_Domain ["3. Dịch Vụ Tín Dụng & Cho Vay (Xử Lý Phức Tạp)"]
        LoanOrigination["Khởi Tạo Khoản Vay & Thẩm Định Tín Dụng"]
        Amortization["Engine Lập Lịch Trả Nợ Khấu Hao"]
        Collection["Phân Loại Nợ & Trích Lập Dự Phòng (IFRS 9)"]
    end

    CIF_Domain -->|"Ràng Buộc Định Danh & Hạn Mức"| CASA_Domain
    CIF_Domain -->|"Điểm Tín Dụng & Mã CIF"| Lending_Domain
    Lending_Domain -->|"Giải Ngân & Trích Nợ Tự Động"| CASA_Domain

2. Máy Trạng Thái Vòng Đời Khoản Vay Tín Dụng

Một hợp đồng tín dụng ngân hàng trải qua máy trạng thái nghiêm ngặt nhằm bảo đảm các mốc kiểm soát nghiệp vụ và pháp lý:

stateDiagram-v2
    [*] --> DRAFT: Khách Hàng Nộp Hồ Sơ
    DRAFT --> UNDERWRITING: Gửi Thẩm Định CIC
    UNDERWRITING --> REJECTED: Điểm Tín Dụng Không Đạt
    UNDERWRITING --> APPROVED: Phê Duyệt Hạn Mức
    APPROVED --> DISBURSED: Giải Ngân Vào Tài Khoản CASA
    
    state DISBURSED {
        [*] --> ACTIVE
        ACTIVE --> DELINQUENT: Quá Hạn Thanh Toán (> 10 DPD)
        DELINQUENT --> ACTIVE: Khách Hàng Đã Thanh Toán Nợ
        DELINQUENT --> DEFAULTED: Quá Hạn > 90 Ngày (Nợ Xấu Nhóm 3+)
    }
    
    ACTIVE --> FULLY_PAID: Tất Toán Toàn Bộ Gốc & Lãi
    DEFAULTED --> WRITTEN_OFF: Xử Lý Rủi Ro Sang Ngoại Bảng
    FULLY_PAID --> [*]
    REJECTED --> [*]
    WRITTEN_OFF --> [*]

3. Cơ Chế Tính Lãi Dồn Tích Hằng Ngày (Daily Accrual)

Việc tính lãi tiền gửi tiết kiệm và tài khoản thanh toán được thực hiện hằng đêm trong quy trình End-of-Day (EOD). Quy định ngân hàng yêu cầu tính lãi dồn tích dựa trên số dư thực tế cuối ngày:

$$\text{Lãi Dồn Tích Ngày} = \frac{\text{Số Dư Sổ Cái Cuối Ngày} \times \text{Lãi Suất Năm}}{365}$$

-- Lược đồ bảng lưu trữ lãi dồn tích hằng ngày
CREATE TABLE daily_interest_accruals (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    account_id UUID NOT NULL REFERENCES accounts(id),
    accrual_date DATE NOT NULL,
    closing_balance BIGINT NOT NULL,
    annual_rate_bps INT NOT NULL, -- Lưu trữ theo Điểm Cơ Bản Basis Points (1 bps = 0.01%)
    accrued_amount BIGINT NOT NULL, -- Đơn vị tiền tệ nhỏ nhất (đồng)
    is_capitalized BOOLEAN NOT NULL DEFAULT FALSE,
    created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(),
    UNIQUE (account_id, accrual_date)
);

4. Thuật Toán Lập Lịch Trả Nợ Khấu Hao Bằng Go

Hệ thống cho vay ngân hàng hỗ trợ hai phương thức trả nợ phổ biến nhất: Trả Nợ Gốc Bằng Nhau (Equal Principal / Dư Nợ Giảm Dần) và Trả Niên Kim Cố Định (Annuity / Equal Installment). Đoạn mã Go dưới đây hiện thực thuật toán chuẩn:

package lending

import (
	"math"
	"time"
)

type RepaymentScheduleItem struct {
	Period           int
	DueDate          time.Time
	Installment      int64 // Tổng số tiền phải nộp mỗi kỳ (đồng)
	PrincipalAmount  int64 // Tiền gốc
	InterestAmount   int64 // Tiền lãi
	RemainingBalance int64 // Dư nợ gốc còn lại
}

// CalculateEqualPrincipal tính lịch trả nợ theo phương thức dư nợ giảm dần (Gốc chia đều).
func CalculateEqualPrincipal(principal int64, annualRate float64, tenureMonths int, startDate time.Time) []RepaymentScheduleItem {
	schedule := make([]RepaymentScheduleItem, tenureMonths)
	monthlyPrincipal := principal / int64(tenureMonths)
	monthlyRate := annualRate / 12.0
	currentBalance := principal

	for i := 1; i <= tenureMonths; i++ {
		// Tính lãi trên dư nợ thực tế còn lại
		interest := int64(math.Round(float64(currentBalance) * monthlyRate))
		
		// Xử lý kỳ cuối để triệt tiêu sai số làm tròn số nguyên
		pAmount := monthlyPrincipal
		if i == tenureMonths {
			pAmount = currentBalance
		}
		
		currentBalance -= pAmount
		dueDate := startDate.AddDate(0, i, 0)

		schedule[i-1] = RepaymentScheduleItem{
			Period:           i,
			DueDate:          dueDate,
			Installment:      pAmount + interest,
			PrincipalAmount:  pAmount,
			InterestAmount:   interest,
			RemainingBalance: currentBalance,
		}
	}

	return schedule
}

Câu Hỏi Thường Gặp (FAQ)

Hệ thống CIF ngăn chặn việc tạo trùng hồ sơ khách hàng qua nhiều kênh giao dịch ra sao?

CIF áp dụng hai cơ chế đối soát: Đối soát tất định (Deterministic Matching) dựa trên các định danh duy nhất do nhà nước cấp như số Căn cước công dân (CCCD) hoặc Mã số thuế; và Đối soát xác suất (Probabilistic Matching) sử dụng thuật toán so khớp chuỗi mờ (Jaro-Winkler) trên họ tên không dấu, ngày sinh và số điện thoại băm để cảnh báo giao dịch viên khi xuất hiện dấu hiệu hồ sơ trùng lặp.

Làm thế nào để tính lãi suất dồn tích hằng ngày cho hàng triệu tài khoản mà không làm nghẽn database?

Tiến trình tính lãi dồn tích không khóa bảng accounts trực tiếp. Thay vào đó, worker EOD chụp lại bản sao số dư tại thời điểm cutoff nửa đêm (read-only snapshot). Các worker Go tính toán song song dựa trên phân đoạn băm tài khoản và ghi kết quả vào bảng nối tiếp daily_interest_accruals. Đến ngày chốt sổ cuối tháng, hệ thống chỉ chạy một giao dịch gộp duy nhất để kết chuyển lãi nhập gốc vào số dư khả dụng.

Sự khác nhau về mặt kỹ thuật giữa trả nợ theo niên kim (Annuity) và gốc chia đều (Equal Principal) là gì?

Ở phương thức Niên kim (Annuity), tổng số tiền khách hàng trả mỗi tháng là một hằng số cố định, nhưng cấu phần bên trong biến động liên tục (tiền lãi giảm dần theo thời gian trong khi tiền gốc tăng dần). Ở phương thức Gốc chia đều (Equal Principal), số tiền gốc mỗi tháng là một hằng số, khiến tổng số tiền thanh toán giảm dần theo từng tháng khi dư nợ gốc teo tóp lại. Hệ thống ngân hàng lõi bắt buộc phải hỗ trợ cả hai mô hình để phục vụ các sản phẩm vay thế chấp và tín chấp doanh nghiệp.

5. Triển Khai Kỹ Thuật: Động Cơ Khấu Hao Khoản Vay & Dồn Tích Lãi Bằng Go 1.25

Trong ngân hàng bán lẻ, các phân hệ tiền gửi CASA và tín dụng chạy các luồng xử lý lô hàng đêm để tính toán lãi dồn tích cho hàng triệu tài khoản và quản trị lịch trả nợ đều đặn.

5.1 Phản khuôn mẫu: Tính Lãi Gộp Cuối Tháng

Chỉ tính lãi một lần duy nhất vào ngày cuối tháng sẽ bỏ qua các biến động số dư giữa kỳ, gây sai lệch nghiêm trọng quyền lợi khách hàng và vi phạm quy định kế toán của ngân hàng nhà nước.

5.2 Mã Nguồn Thực Thi: Động Cơ Lập Lịch Khấu Hao Trả Góp Đều (EMI)

Dưới đây là mã nguồn Go 1.25 chuẩn sản xuất tính toán lịch trả nợ gốc lãi đều với độ chính xác tuyệt đối:

package lending

import (
	"errors"
	"math"
	"time"
)

type AmortizationScheduleItem struct {
	Period           int       `json:"period"`
	DueDate          time.Time `json:"due_date"`
	PaymentAmount    int64     `json:"payment_amount"`
	PrincipalPortion int64     `json:"principal_portion"`
	InterestPortion  int64     `json:"interest_portion"`
	RemainingBalance int64     `json:"remaining_balance"`
}

type LoanCalculator struct{}

func NewLoanCalculator() *LoanCalculator {
	return &LoanCalculator{}
}

func (c *LoanCalculator) CalculateEqualInstallmentSchedule(
	principalAmount int64,
	annualRatePercent float64,
	tenorMonths int,
	startDate time.Time,
) ([]AmortizationScheduleItem, error) {
	if principalAmount <= 0 || annualRatePercent <= 0 || tenorMonths <= 0 {
		return nil, errors.New("invalid loan calculation parameters")
	}

	monthlyRate := (annualRatePercent / 100.0) / 12.0
	factor := math.Pow(1.0+monthlyRate, float64(tenorMonths))
	monthlyPaymentExact := float64(principalAmount) * (monthlyRate * factor) / (factor - 1.0)
	monthlyPayment := int64(math.Round(monthlyPaymentExact))

	schedule := make([]AmortizationScheduleItem, 0, tenorMonths)
	remainingPrincipal := principalAmount

	for period := 1; period <= tenorMonths; period++ {
		interestPayment := int64(math.Round(float64(remainingPrincipal) * monthlyRate))
		principalPayment := monthlyPayment - interestPayment

		if period == tenorMonths || principalPayment > remainingPrincipal {
			principalPayment = remainingPrincipal
			monthlyPayment = principalPayment + interestPayment
			remainingPrincipal = 0
		} else {
			remainingPrincipal -= principalPayment
		}

		dueDate := startDate.AddDate(0, period, 0)
		schedule = append(schedule, AmortizationScheduleItem{
			Period:           period,
			DueDate:          dueDate,
			PaymentAmount:    monthlyPayment,
			PrincipalPortion: principalPayment,
			InterestPortion:  interestPayment,
			RemainingBalance: remainingPrincipal,
		})

		if remainingPrincipal == 0 {
			break
		}
	}

	return schedule, nil
}

6. Động Cơ Quét Lãi Dồn Tích Cuối Ngày (EOD)

Hệ thống tính lãi dồn tích hàng ngày chạy dưới dạng luồng xử lý lô nguyên tử cho toàn bộ tài khoản CASA sinh lãi:

package deposit

import (
	"context"
	"math/big"
	"time"
)

type AccountDailyAccrual struct {
	AccountID       string
	Date            time.Time
	AccruedInterest int64
}

type AccrualEngine struct {
	BasisDays int64
}

func NewAccrualEngine(basisDays int64) *AccrualEngine {
	if basisDays <= 0 {
		basisDays = 365
	}
	return &AccrualEngine{BasisDays: basisDays}
}

func (e *AccrualEngine) CalculateDayInterest(balanceMicros int64, rateBps int64) int64 {
	if balanceMicros <= 0 || rateBps <= 0 {
		return 0
	}
	bal := big.NewInt(balanceMicros)
	rate := big.NewInt(rateBps)
	denominator := big.NewInt(e.BasisDays * 10000)

	numerator := new(big.Int).Mul(bal, rate)
	result := new(big.Int).Div(numerator, denominator)
	return result.Int64()
}

func (e *AccrualEngine) ProcessBatch(ctx context.Context, accounts []AccountDailyAccrual) error {
	for i := range accounts {
		select {
		case <-ctx.Done():
			return ctx.Err()
		default:
			// Xử lý ghi nhận sổ cái trong batch nguyên tử
		}
	}
	return nil
}

7. Máy Trạng Thái Hạn Mức Thấu Chi & Số Dư Đa Tầng

Tài khoản ngân hàng lõi chuyển dịch trạng thái có trật tự qua các mốc bình thường, thấu chi và nợ xấu:

stateDiagram-v2
    [*] --> BinhThuong: Gửi Tiền Mở Tài Khoản
    BinhThuong --> BinhThuong: Gửi Tiền / Ghi Có
    BinhThuong --> ThauChi: Rút Vượt Số Dư (Trong Hạn Mức)
    ThauChi --> BinhThuong: Thanh Toán / Hoàn Trả
    ThauChi --> QuaHan: Quá Hạn Thấu Chi > 30 Ngày
    QuaHan --> NoXau: Không Trả Nợ > 90 Ngày
    NoXau --> XuLyXoaNo: Quá Hạn > 180 Ngày
    XuLyXoaNo --> [*]
sequenceDiagram
    autonumber
    actor KhachHang as Khách Hàng
    participant Kenh as Mobile Banking API
    participant Core as Core Banking Engine
    participant ThauChi as Phân Hệ Thấu Chi
    participant SoCai as Sổ Cái Tổng Hợp

    KhachHang->>Kenh: Yêu cầu rút tiền (1,500,000 VND)
    Kenh->>Core: Ủy quyền ghi nợ tài khoản
    Core->>ThauChi: Kiểm tra số dư & hạn mức (Dư 1,000,000 VND, Hạn mức 1,000,000 VND)
    ThauChi-->>Core: Chấp thuận (1,000,000 VND gốc + 500,000 VND thấu chi)
    Core->>SoCai: Ghi nhận bút toán tách dòng (Nợ/Có)
    SoCai-->>Core: Bút toán hoàn tất
    Core-->>Kenh: Phê duyệt thành công (Âm 500,000 VND)
    Kenh-->>KhachHang: Chi trả tiền mặt

8. Đo Lường Định Lượng & Tiêu Chuẩn SLA Vận Hành Sản Xuất

Để đảm bảo hiệu năng xử lý khối lượng lớn trong phiên quyết toán cuối ngày (EOD), động cơ tiền gửi và tín dụng phải đáp ứng các tiêu chuẩn sau:

Chỉ số Đo lườngChỉ tiêu Sản xuấtNgưỡng Cảnh báo P2Hành động Xử lý
Thời Gian Chạy Batch Lãi Đêm$\le 45\text{ phút}$$> 90\text{ phút}$Mở rộng số lượng worker pod xử lý song song
Kiểm Tra Hạn Mức Thấu Chi P99$\le 12.0\text{ ms}$$> 35.0\text{ ms}$Đưa hạn mức tín dụng vào cụm bộ đệm Redis
Tính Lịch Khấu Hao Khoản Vay$\le 2.5\text{ ms}$$> 8.0\text{ ms}$Tiền tính toán các mẫu lịch trả nợ phổ biến
Tỷ Lệ Đối Soát Tất Toán$100.0%$$< 100.0%$Chạy lại các sự kiện thanh toán chưa xử lý

9. Quản Trị Trạng Thái Quá Hạn & Trích Lập Dự Phòng Rủi Ro

Theo quy định quản lý rủi ro tín dụng của Ngân hàng Nhà nước và chuẩn mực quốc tế IFRS 9, hệ thống liên tục tính số ngày quá hạn (DPD) để phân loại nợ:

package lending

import "time"

type LoanAccountStatus string

const (
	StatusCurrent    LoanAccountStatus = "CURRENT"
	StatusDelinquent LoanAccountStatus = "DELINQUENT_STAGE_1"
	StatusNPL        LoanAccountStatus = "NON_PERFORMING_STAGE_2"
	StatusWriteOff   LoanAccountStatus = "WRITTEN_OFF_STAGE_3"
)

type LoanAccount struct {
	ID             string
	PrincipalDue   int64
	InterestDue    int64
	DaysPastDue    int
	Status         LoanAccountStatus
	LastStatusDate time.Time
}

func EvaluateLoanStatus(loan *LoanAccount) {
	switch {
	case loan.DaysPastDue == 0:
		loan.Status = StatusCurrent
	case loan.DaysPastDue <= 90:
		loan.Status = StatusDelinquent
	case loan.DaysPastDue <= 180:
		loan.Status = StatusNPL
	default:
		loan.Status = StatusWriteOff
	}
	loan.LastStatusDate = time.Now()
}

10. Tính Toán Hệ Số An Toàn Vốn (CAR) Theo Chuẩn Mực Basel III

Theo hướng dẫn chuẩn mực Basel III của Ngân hàng Nhà nước, tài sản có rủi ro được tính toán dựa trên trọng số rủi ro: $$\text{Tỷ lệ An toàn Vốn (CAR)} = \frac{\text{Vốn Cấp 1} + \text{Vốn Cấp 2}}{\sum \text{Tài sản}_i \cdot \text{Hệ số Rủi ro}_i} \ge 10.5%$$

Việc tự động hóa tính toán tỷ số CAR hàng ngày giúp ban điều hành ngân hàng luôn kiểm soát chặt chẽ biên độ đòn bẩy và an toàn thanh khoản tài chính.


11. Động Cơ Quét Lãi Tự Động Hàng Đêm Trong Go 1.25

Để mở rộng quy mô tính lãi dồn tích hàng ngày cho hàng triệu tài khoản khách hàng cá nhân mà không làm quá tải connection pool cơ sở dữ liệu, kiến trúc ngân hàng lõi áp dụng mô hình luồng worker xử lý song song:

package deposit

import (
	"context"
	"fmt"
	"sync"
	"time"
)

type SweepResult struct {
	AccountID       string
	AccruedInterest int64
	Error           error
}

type InterestSweepDaemon struct {
	workerCount int
	batchSize   int
	engine      *AccrualEngine
}

func NewInterestSweepDaemon(workers int, batchSize int, basisDays int64) *InterestSweepDaemon {
	return &InterestSweepDaemon{
		workerCount: workers,
		batchSize:   batchSize,
		engine:      NewAccrualEngine(basisDays),
	}
}

func (d *InterestSweepDaemon) ExecuteSweep(
	ctx context.Context,
	accounts []AccountDailyAccrual,
	rateBps int64,
) ([]SweepResult, error) {
	accountChan := make(chan AccountDailyAccrual, d.batchSize)
	resultChan := make(chan SweepResult, len(accounts))
	var wg sync.WaitGroup

	for i := 0; i < d.workerCount; i++ {
		wg.Add(1)
		go func(workerID int) {
			defer wg.Done()
			for {
				select {
				case <-ctx.Done():
					return
				case acc, ok := <-accountChan:
					if !ok {
						return
					}
					interest := d.engine.CalculateDayInterest(acc.AccruedInterest, rateBps)
					resultChan <- SweepResult{
						AccountID:       acc.AccountID,
						AccruedInterest: interest,
						Error:           nil,
					}
				}
			}
		}(i)
	}

	go func() {
		for _, acc := range accounts {
			select {
			case <-ctx.Done():
				break
			case accountChan <- acc:
			}
		}
		close(accountChan)
	}()

	wg.Wait()
	close(resultChan)

	results := make([]SweepResult, 0, len(accounts))
	for res := range resultChan {
		results = append(results, res)
	}
	return results, nil
}

12. Động Cơ Tính Lãi Phạt & Quản Trị Quá Hạn Theo Quy Định Pháp Lý

Khi khách hàng vay quá hạn thanh toán vượt quá thời gian ân hạn quy định (thường là 10 ngày lịch), quy định của Ngân hàng Nhà nước xác lập mức lãi suất phạt tối đa được phép tính trên dư nợ gốc và nợ lãi quá hạn:

package lending

import (
	"errors"
	"math/big"
	"time"
)

type PenaltyAssessment struct {
	OverduePrincipal   int64
	OverdueInterest    int64
	DaysOverdue        int
	PenaltyOnPrincipal int64
	PenaltyOnInterest  int64
	TotalPenalty       int64
}

type PenaltyAccrualEngine struct {
	GracePeriodDays      int
	MaxPrincipalRateBps  int64
	MaxInterestRateBps   int64
	YearBasisDays        int64
}

func NewPenaltyAccrualEngine(basisDays int64) *PenaltyAccrualEngine {
	if basisDays <= 0 {
		basisDays = 365
	}
	return &PenaltyAccrualEngine{
		GracePeriodDays:     10,
		MaxPrincipalRateBps: 15000,
		MaxInterestRateBps:  10000,
		YearBasisDays:       basisDays,
	}
}

func (p *PenaltyAccrualEngine) CalculatePenalty(
	principalOverdue int64,
	interestOverdue int64,
	dueDate time.Time,
	asOfDate time.Time,
) (*PenaltyAssessment, error) {
	if asOfDate.Before(dueDate) {
		return nil, errors.New("ngay danh gia khong the truoc ngay dao han")
	}

	days := int(asOfDate.Sub(dueDate).Hours() / 24)
	if days <= p.GracePeriodDays {
		return &PenaltyAssessment{
			OverduePrincipal: principalOverdue,
			OverdueInterest:  interestOverdue,
			DaysOverdue:      days,
		}, nil
	}

	effectiveDays := int64(days)
	denom := big.NewInt(p.YearBasisDays * 10000)

	calcPenalty := func(amount int64, rateBps int64) int64 {
		amtBig := big.NewInt(amount)
		rateBig := big.NewInt(rateBps)
		daysBig := big.NewInt(effectiveDays)

		num := new(big.Int).Mul(amtBig, rateBig)
		num = num.Mul(num, daysBig)
		return new(big.Int).Div(num, denom).Int64()
	}

	penaltyPrin := calcPenalty(principalOverdue, p.MaxPrincipalRateBps)
	penaltyInt := calcPenalty(interestOverdue, p.MaxInterestRateBps)

	return &PenaltyAssessment{
		OverduePrincipal:   principalOverdue,
		OverdueInterest:    interestOverdue,
		DaysOverdue:        days,
		PenaltyOnPrincipal: penaltyPrin,
		PenaltyOnInterest:  penaltyInt,
		TotalPenalty:       penaltyPrin + penaltyInt,
	}, nil
}

13. Kiểm Thử Khả Năng Chịu Tải & Kịch Bản Tiêm Lỗi Thực Nghiệm

Để bảo đảm tính bất biến số dư sổ cái và khả năng chịu tải của các phân hệ tài khoản tiền gửi, các nhóm kỹ sư thực hiện kiểm thử tự động trên môi trường giả lập:

Kịch bản Kiểm thửMật độ Đồng thờiBất biến Kiểm chứngKết quả Đo lường Thực tế
Rút Tiền Thấu Chi Đồng Thời500 luồng đồng thời trên 1 tài khoảnSố dư không được vượt quá hạn mức thấu chiTính nhất quán 100%, không bị âm quá hạn mức
Chuyển Giao Năm NhuậnChuyển từ ngày 28 sang 29 tháng 2Chuẩn mẫu số 366 ngày được áp dụng chính xácSai lệch 0 điểm cơ bản
Trả Nợ Gốc Giữa Kỳ Hàng Loạt10,000 giao dịch trả nợ trước hạnDư nợ giảm lập tức phản ánh vào số tiền lãi tính mớiKhông phát sinh bất kỳ số lẻ nào
Phân Mảnh Mạng Khi Đang Chạy LôGiả lập rớt kết nối khi batch chạy 50%Khóa idempotency ngăn ngừa ghi trùng số dưTự động phục hồi và tiếp tục chính xác 100%

Câu hỏi Kiến trúc Thường gặp (FAQ)

Sự khác biệt giữa số dư khả dụng (Available Balance) và số dư sổ cái (Ledger Balance) là gì?

Số dư sổ cái là số dư kế toán chính thức đã được quyết toán. Số dư khả dụng là số tiền thực tế khách hàng có thể chi tiêu ngay, sau khi đã cộng hạn mức thấu chi và trừ đi các khoản tiền đang bị tạm khóa (hold) do giao dịch thẻ hoặc phong tỏa.

Hệ thống ngân hàng lõi xử lý nợ quá hạn và nợ xấu (NPL) như thế nào?

Một máy trạng thái tự động theo dõi các mốc quá hạn (quá 30, 90, 180 ngày), tự động chuyển nhóm nợ, ngừng ghi nhận lãi vào doanh thu (chuyển sang theo dõi ngoại bảng) và trích lập dự phòng rủi ro theo quy định của Ngân hàng Nhà nước.

Tại sao quy ước số ngày ACT/365 được ưa chuộng hơn 30/360 trong tiền gửi CASA bán lẻ?

Quy ước ACT/365 tính lãi dựa trên số ngày thực tế trôi qua theo lịch, đảm bảo quyền lợi công bằng cho người gửi tiền bất kể tháng có 28, 30 hay 31 ngày.

Làm thế nào để hệ thống ngăn ngừa ghi trùng bút toán khi chạy quét lãi ban đêm?

Hệ thống sử dụng khóa idempotency được ghép từ mã tài khoản và ngày quyết toán, được bao bọc trong giao dịch Serializable với ràng buộc duy nhất (unique constraint) trên sổ cái kế toán.