Kiến trúc & quy tắc kỹ thuật

SwiftUI + SwiftData, máy chủ Node.js, quy tắc đồng bộ, kiểm tra dữ liệu, kiểm thử.

MoneyFlowCập nhật 23/10/2026
kiến trúcswift

MoneyFlow gồm một ứng dụng iOS/iPadOS viết bằng SwiftUI và SwiftData (Swift 5, nhắm tới iOS và iPadOS 26.1 trở lên) và một máy chủ đồng bộ Node.js + Express + PostgreSQL. Trọng tâm kiến trúc là làm cho sổ chung của nhiều người luôn nhất quán, kể cả khi có thiết bị ngoại tuyến hay lệch giờ.

Cấu trúc mã nguồn

MoneyFlow (ứng dụng iOS / iPadOS)
├── Views       Giao diện SwiftUI: Tổng quan, Giao dịch, Tiết kiệm, Danh mục, Tài khoản...
├── Managers    DataManager, SavingsManager, UserManager, AppLockManager, NotificationManager (@Observable)
├── Models      Model SwiftData: Transaction, Category, Budget, Gold, Savings, SavingsGoal, DebtRecord...
├── Services    SyncManager (đồng bộ push/pull), GoldPriceService (giá vàng)
├── Helpers     CategorySuggester, DataExporter (CSV), ImageStorageHelper, DemoData
└── Theme.swift Hệ thống thiết kế: màu, kiểu chữ, thẻ gradient, Liquid Glass

Backend (Node.js + Express + PostgreSQL)
├── routes      auth, sync, gold
├── middleware  xác thực JWT
└── db          khởi tạo lược đồ và kết nối
Phần Vai trò
Views Năm tab: Tổng quan, Giao dịch, Thêm (mở màn nhập), Tiết kiệm, Danh mục. Ngân sách, Báo cáo, Định kỳ, Hoá đơn, Nợ, Chia tiền nằm trong Tài khoản.
Managers Lớp quản lý dữ liệu dùng macro @Observable: DataManager (giao dịch, danh mục, ngân sách, định kỳ, hoá đơn, nợ, chia tiền), SavingsManager (vàng, tiết kiệm, mục tiêu), UserManager, AppLockManager, NotificationManager.
Models Mười model SwiftData: Transaction, Category, Budget, User, Gold, Savings, RecurringTransaction, BillReminder, DebtRecord, SavingsGoal.
Services SyncManager đồng bộ với máy chủ; GoldPriceService lấy giá vàng.
Helpers CategorySuggester (gợi ý danh mục), DataExporter (CSV), ImageStorageHelper (ảnh hoá đơn), DemoData (chỉ bản Debug).
Theme.swift Màu thích ứng sáng/tối, kiểu chữ theo Dynamic Type, chữ số dạng bảng cho số tiền, bốn kiểu thẻ gradient (xanh ngọc, hồng cam, vàng, tím), Liquid Glass cho thanh điều hướng có phương án dự phòng.

Máy chủ có các đường dẫn chính: POST /api/auth/login, GET /api/sync/pull, POST /api/sync/push, POST /api/sync/reset và GET /api/gold/price.

Quy tắc đồng bộ

  • Danh mục mặc định có mã định danh tất định theo tên và loại, để mọi thiết bị khớp nhau mà không cần hỏi máy chủ. Đổi tên một danh mục mặc định phải giữ mã cũ qua idSeed (ví dụ "Xe cộ" đổi thành "Độ xe" mà vẫn giữ mã cũ).
  • Xoá là xoá mềm (isDeleted) để thay đổi được đồng bộ sang thiết bị khác.
  • Con trỏ đồng bộ dùng thời gian của máy chủ. Mỗi dòng trên máy chủ có hai mốc: updated_at do thiết bị gửi, chỉ dùng để phân xử "bản sửa sau cùng thắng", và server_updated_at do cơ sở dữ liệu gán, là con trỏ kéo. Nhờ đó chỉnh sửa gửi muộn từ máy lệch giờ vẫn đến được các máy khác.
  • Kéo không bỏ sót. Đẩy dữ liệu giữ một khoá tư vấn dùng chung trong giao dịch của nó, còn kéo dữ liệu lấy khoá độc quyền vừa đủ để mở ảnh chụp và đọc đồng hồ máy chủ. Vì vậy khi con trỏ được chốt, mọi lần đẩy đang chạy đã hoàn tất.
  • Kiểm tra dữ liệu gửi lên bằng bộ kiểm tra riêng (validatePushBody) với giới hạn độ dài cột, số bản ghi mỗi bảng (5.000), số nhãn, năm hợp lệ, và updated_at không được vượt thời gian hiện tại quá 5 phút.
  • Đẩy theo lô 500 bản ghi. Nếu một lô thất bại thì chưa ghi nhận tiến triển nào, lần đồng bộ sau gửi lại.

Quy tắc về dữ liệu và bảo mật

  • Không đưa mật khẩu, khoá API hay dữ liệu tài chính thật vào mã nguồn; cấu hình nhạy cảm nằm trong .env, đã được loại khỏi git.
  • Số tiền tính theo đồng (VND), hiển thị theo chuẩn Việt Nam: 1.234.567 đ, dạng rút gọn 51,9tr. Một giao dịch nhập tay tối đa 100 tỷ đồng.
  • Dữ liệu demo nằm trong kho riêng, đồng bộ bị tắt trong chế độ demo.
  • Khi lược đồ không mở được, kho cũ được đổi tên rồi giữ lại thay vì xoá.
  • Thông báo hoá đơn được lên lịch lại từ đầu mỗi lần mở ứng dụng, và dọn các thông báo của hoá đơn không còn tồn tại.

Kiểm thử

  • 63 test ứng dụng (MoneyFlowTests) chạy trên kho SwiftData trong bộ nhớ với lược đồ đầy đủ. Phạm vi gồm hoá đơn (chu kỳ, quá hạn), giao dịch định kỳ (ngày gốc, tạm dừng), ngân sách cuốn chiếu, phân tích giá vàng và trạng thái giá cũ, định dạng tiền, xuất CSV, màn nhập giao dịch và bộ gợi ý danh mục.
  • Kiểm thử máy chủ cho phần kiểm tra dữ liệu đồng bộ: npm test chạy node test/validate.test.js.
  • Chạy test ứng dụng bằng Xcode chính thức; bản beta có thể làm trình chạy kiểm thử không phản hồi.
xcodebuild test -project MoneyFlow.xcodeproj -scheme MoneyFlow \
  -destination 'platform=iOS Simulator,name=iPhone 17 Pro' \
  -only-testing:MoneyFlowTests

Người đóng góp

  • Steven Lam: tác giả. Lên kế hoạch và định hướng sản phẩm, thiết kế kiến trúc, định hướng thiết kế, vận hành máy chủ, kiểm thử thực tế và phát hành.
  • Claude (Anthropic): viết code theo kế hoạch và kiến trúc của tác giả, qua Claude Code. Các commit viết cùng Claude có dòng Co-Authored-By: Claude.
  • Gemini (Google): chỉnh giao diện, qua Antigravity.
  • Codex (OpenAI): review code, góp ý về lỗi.

Mọi thay đổi được kiểm chứng bằng cách chạy kiểm thử thật, không chỉ dựa vào mô tả.