Files
accounting-system/ARCHITECTURE.md
Invoice Master 05ea67144f feat: initial project setup
- Add .NET 8 backend with Clean Architecture
- Add React + Vite + TypeScript frontend
- Implement authentication with JWT
- Implement Azure Blob Storage client
- Implement OCR integration
- Implement supplier matching service
- Implement voucher generation
- Implement Fortnox provider
- Add unit and integration tests
- Add Docker Compose configuration
2026-02-04 20:14:34 +01:00

32 KiB
Raw Permalink Blame History

Invoice Master - 系统架构文档

版本: v3.0
日期: 2026-02-03
状态: 设计中


1. 项目概述

1.1 目标

构建一个多会计系统集成的发票处理平台,允许企业通过 Invoice Master OCR 技术自动识别发票并导入到各种会计软件。首个支持 Fortnox架构设计支持未来无缝集成其他会计系统如 Visma, Hogia 等)。

1.2 核心功能

  1. 多会计系统支持 - 统一的抽象层,支持连接不同的会计软件
  2. OAuth2 认证 - 安全连接用户会计系统账户
  3. 发票 OCR 识别 - 调用现有 invoice-master API 进行发票字段提取
  4. 供应商自动匹配 - 智能匹配或创建会计系统供应商
  5. 会计凭证生成 - 自动生成会计凭证
  6. 文件存档 - 上传发票 PDF 到会计系统
  7. 审计追踪 - 完整的操作日志和事件溯源

1.3 集成模式

采用 外部独立应用 (External App) 模式,支持多提供商:

┌─────────────────┐     ┌─────────────────────────┐     ┌─────────────────┐
│   Fortnox       │────▶│                         │────▶│   Fortnox       │
│   (点击集成)     │     │                         │     │   (数据已导入)   │
└─────────────────┘     │   Invoice Master        │     └─────────────────┘
                        │   (多会计系统集成平台)    │
┌─────────────────┐     │                         │     ┌─────────────────┐
│   Visma         │────▶│  - Fortnox Provider     │────▶│   Visma         │
│   (点击集成)     │     │  - Visma Provider       │     │   (数据已导入)   │
└─────────────────┘     │  - Hogia Provider       │     └─────────────────┘
                        │  - ...                  │
┌─────────────────┐     │                         │     ┌─────────────────┐
│   Hogia         │────▶│                         │────▶│   Hogia         │
│   (点击集成)     │     │                         │     │   (数据已导入)   │
└─────────────────┘     └─────────────────────────┘     └─────────────────┘

2. 系统架构

2.1 整体架构(.NET + 轻量级 DDD

┌─────────────────────────────────────────────────────────────────────────────┐
│                              用户层 (User Layer)                             │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │                         React Frontend                               │  │
│  │  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │  │
│  │  │  登录/授权    │ │  发票上传     │ │  结果确认     │ │  历史记录    │ │  │
│  │  │    页面      │ │    页面      │ │    页面      │ │    页面     │ │  │
│  │  └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘
                                        │
                                        │ HTTPS / REST API
                                        ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                            应用层 (Application Layer)                        │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │                      ASP.NET Core Web API                            │  │
│  │                                                                      │  │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐ │  │
│  │  │  Controllers│  │   Minimal   │  │   Filters   │  │   Middleware│ │  │
│  │  │             │  │    APIs     │  │             │  │             │ │  │
│  │  └──────┬──────┘  └──────┬──────┘  └─────────────┘  └─────────────┘ │  │
│  │         │                │                                          │  │
│  │         └────────────────┼──────────────────────────────────────────┘  │
│  │                          │                                             │
│  │  ┌───────────────────────┴──────────────────────────────────────────┐ │  │
│  │  │                    Application Layer (CQRS Lite)                 │ │  │
│  │  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐               │ │  │
│  │  │  │  Commands   │  │   Queries   │  │   DTOs      │               │ │  │
│  │  │  │  Handlers   │  │   Handlers  │  │   Mappers   │               │ │  │
│  │  │  └─────────────┘  └─────────────┘  └─────────────┘               │ │  │
│  │  └──────────────────────────────────────────────────────────────────┘ │  │
│  │                                                                        │  │
│  │  ┌──────────────────────────────────────────────────────────────────┐ │  │
│  │  │                    Domain Layer (DDD Lite)                       │ │  │
│  │  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐              │ │  │
│  │  │  │ Aggregates  │  │   Domain    │  │   Domain    │              │ │  │
│  │  │  │  (Invoice)  │  │   Events    │  │   Services  │              │ │  │
│  │  │  │ (Connection)│  │             │  │             │              │ │  │
│  │  │  └─────────────┘  └─────────────┘  └─────────────┘              │ │  │
│  │  │                                                                  │ │  │
│  │  │  ┌─────────────────────────────────────────────────────────────┐│ │  │
│  │  │  │              Accounting System Integration Layer            ││ │  │
│  │  │  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         ││ │  │
│  │  │  │  │  Abstract   │  │  Fortnox    │  │   Visma     │  ...    ││ │  │
│  │  │  │  │  Interface  │──│  Provider   │  │  Provider   │         ││ │  │
│  │  │  │  │             │  │             │  │             │         ││ │  │
│  │  │  │  │ - Supplier  │  │ - OAuth2    │  │ - OAuth2    │         ││ │  │
│  │  │  │  │ - Voucher   │  │ - REST API  │  │ - REST API  │         ││ │  │
│  │  │  │  │ - Account   │  │ - Webhooks  │  │ - Webhooks  │         ││ │  │
│  │  │  │  └─────────────┘  └─────────────┘  └─────────────┘         ││ │  │
│  │  │  │                                                             ││ │  │
│  │  │  │  Factory: IAccountingSystemFactory.Create("fortnox")       ││ │  │
│  │  │  └─────────────────────────────────────────────────────────────┘│ │  │
│  │  └──────────────────────────────────────────────────────────────────┘ │  │
│  │                                                                        │  │
│  │  ┌──────────────────────────────────────────────────────────────────┐ │  │
│  │  │                    Infrastructure Layer                          │ │  │
│  │  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐              │ │  │
│  │  │  │   EF Core   │  │    Redis    │  │    Blob     │              │ │  │
│  │  │  │  Repository │  │    Cache    │  │   Storage   │              │ │  │
│  │  │  │   EventStore│  │             │  │             │              │ │  │
│  │  │  └─────────────┘  └─────────────┘  └─────────────┘              │ │  │
│  │  └──────────────────────────────────────────────────────────────────┘ │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘
                                        │
                                        │ HTTP API
                                        ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                           外部服务层 (External Services)                      │
│  ┌─────────────────────┐  ┌─────────────────────┐  ┌─────────────────────┐  │
│  │   Invoice Master    │  │       Fortnox       │  │       Visma         │  │
│  │   OCR API           │  │     Platform        │  │     Platform        │  │
│  │                     │  │                     │  │                     │  │
│  │  - /api/v1/infer    │  │  - OAuth2 Server    │  │  - OAuth2 Server    │  │
│  │  - YOLO + PaddleOCR │  │  - REST API         │  │  - REST API         │  │
│  │  - 94.8% accuracy   │  │  - Supplier/Voucher │  │  - Supplier/Voucher │  │
│  └─────────────────────┘  └─────────────────────┘  └─────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘
                                        │
                                        │ SQL / Redis
                                        ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                           数据层 (Data Layer)                                │
│  ┌──────────────────┐  ┌──────────────────┐  ┌──────────────────────────┐  │
│  │   PostgreSQL     │  │      Redis       │  │    Azure Blob Storage    │  │
│  │                  │  │                  │  │                          │  │
│  │  - Users         │  │  - Token Cache   │  │  - Invoice PDFs          │  │
│  │  - Connections   │  │  - Rate Limiting │  │  - Temporary Files       │  │
│  │  - Invoices      │  │  - Session Store │  │                          │  │
│  │  - DomainEvents  │  │                  │  │                          │  │
│  └──────────────────┘  └──────────────────┘  └──────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘

2.2 分层架构详解

┌─────────────────────────────────────────────────────────────────────┐
│                         Presentation Layer                          │
│                    (Controllers / Minimal APIs)                     │
│                                                                     │
│  - Input validation (FluentValidation)                              │
│  - Authentication / Authorization                                   │
│  - Response mapping                                                 │
└─────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      Application Layer (CQRS Lite)                  │
│                                                                     │
│  Commands (Write):                    Queries (Read):               │
│  - ImportInvoiceCommand               - GetInvoiceQuery             │
│  - CreateConnectionCommand            - ListInvoicesQuery           │
│  - UpdateSupplierCommand              - GetConnectionQuery          │
│                                                                     │
│  - MediatR for dispatching                                          │
│  - AutoMapper for DTO mapping                                       │
└─────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────┐
│                        Domain Layer (DDD Lite)                      │
│                                                                     │
│  Aggregates:                                                        │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐     │
│  │    Invoice      │  │ AccountingConnection│   SupplierCache │     │
│  │                 │  │                 │  │                 │     │
│  │ - Submit()      │  │ - Connect()     │  │ - Update()      │     │
│  │ - Import()      │  │ - Disconnect()  │  │ - Expire()      │     │
│  │ - Reject()      │  │ - RefreshToken()│  │                 │     │
│  │                 │  │                 │  │                 │     │
│  │ Domain Events:  │  │ Domain Events:  │  │                 │     │
│  │ - InvoiceSubmitted│ - Connected     │  │                 │     │
│  │ - InvoiceImported │ - TokenRefreshed│  │                 │     │
│  └─────────────────┘  └─────────────────┘  └─────────────────┘     │
│                                                                     │
│  Domain Services:                                                   │
│  - InvoiceProcessingService                                         │
│  - SupplierMatchingService                                          │
│  - VoucherGenerationService                                         │
└─────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      Infrastructure Layer                           │
│                                                                     │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐     │
│  │   EF Core       │  │  Event Store    │  │  External APIs  │     │
│  │   Repositories  │  │  (Audit Table)  │  │                 │     │
│  │                 │  │                 │  │ - FortnoxClient │     │
│  │ - IRepository   │  │ - Append events │  │ - VismaClient   │     │
│  │ - Unit of Work  │  │ - Replay events │  │ - OCRClient     │     │
│  └─────────────────┘  └─────────────────┘  └─────────────────┘     │
└─────────────────────────────────────────────────────────────────────┘

2.3 会计系统集成层详解

┌─────────────────────────────────────────────────────────────────────┐
│                    Accounting System Integration                    │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                    Abstract Interface                        │   │
│  │  (InvoiceMaster.Integrations/Accounting/IAccountingSystem.cs)│   │
│  │                                                              │   │
│  │  public interface IAccountingSystem                          │   │
│  │  {                                                           │   │
│  │    string ProviderName { get; }                              │   │
│  │    Task<AuthResult> AuthenticateAsync(string code);          │   │
│  │    Task<List<Supplier>> GetSuppliersAsync();                │   │
│  │    Task<Voucher> CreateVoucherAsync(Voucher voucher);       │   │
│  │    // ...                                                    │   │
│  │  }                                                           │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                              ▲                                      │
│                              │ implements                            │
│          ┌───────────────────┼───────────────────┐                  │
│          │                   │                   │                  │
│  ┌───────▼──────┐  ┌────────▼────────┐  ┌──────▼───────┐          │
│  │   Fortnox    │  │     Visma       │  │     Hogia    │  ...     │
│  │   Provider   │  │    Provider     │  │   Provider   │          │
│  │              │  │                 │  │              │          │
│  │ - OAuth2     │  │ - OAuth2        │  │ - OAuth2     │          │
│  │ - Swedish    │  │ - Nordic APIs   │  │ - Swedish    │          │
│  │ - BAS 2024   │  │ - Localized     │  │ - Custom     │          │
│  └──────────────┘  └─────────────────┘  └──────────────┘          │
│                                                                     │
│  Factory: IAccountingSystemFactory.Create(providerName: string)     │
│  Registry: services.AddAccountingSystem<FortnoxProvider>("fortnox") │
└─────────────────────────────────────────────────────────────────────┘

2.4 领域事件与审计

┌─────────────────────────────────────────────────────────────────────┐
│                     Domain Event Flow                               │
│                                                                     │
│  1. Domain Action                                                   │
│     Invoice.Import() called                                         │
│              │                                                      │
│              ▼                                                      │
│  2. Event Raised                                                    │
│     _domainEvents.Add(new InvoiceImportedEvent { ... })             │
│              │                                                      │
│              ▼                                                      │
│  3. Transaction Commit                                              │
│     EF Core SaveChangesAsync()                                      │
│              │                                                      │
│              ▼                                                      │
│  4. Event Dispatcher                                                │
│     DispatchDomainEventsInterceptor                                 │
│              │                                                      │
│              ├──────────────────┬──────────────────┐               │
│              ▼                  ▼                  ▼               │
│  5. Handlers:         Save to DB          Send Notification        │
│     - AuditLogHandler DomainEvents table  - SignalR               │
│     - NotificationHandler                  - Webhook              │
│     - IntegrationHandler                                         │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

3. 技术栈选型

3.1 后端技术栈 (.NET 8)

技术 版本 用途
.NET 8.0 运行时和框架
ASP.NET Core 8.0 Web API
Entity Framework Core 8.0 ORM
MediatR 12.x CQRS / 中介者模式
AutoMapper 12.x 对象映射
FluentValidation 11.x 输入验证
FluentAssertions 6.x 测试断言
xUnit 2.x 测试框架
Moq 4.x Mocking
Serilog 3.x 结构化日志
Polly 8.x 重试和熔断
JWT Bearer 8.x 认证
Swagger/OpenAPI 6.x API 文档

3.2 审计与事件存储

// 领域事件基类
public abstract class DomainEvent
{
    public Guid EventId { get; } = Guid.NewGuid();
    public DateTime OccurredAt { get; } = DateTime.UtcNow;
    public string EventType { get; protected set; }
    public string AggregateType { get; set; }
    public Guid AggregateId { get; set; }
    public string UserId { get; set; }
    public string CorrelationId { get; set; }
}

// 具体事件
public class InvoiceImportedEvent : DomainEvent
{
    public string Provider { get; set; }
    public string VoucherNumber { get; set; }
    public decimal Amount { get; set; }
    
    public InvoiceImportedEvent()
    {
        EventType = nameof(InvoiceImportedEvent);
    }
}

3.3 会计系统集成使用示例

// 使用示例
public class ImportInvoiceCommandHandler : IRequestHandler<ImportInvoiceCommand, Result<InvoiceDto>>
{
    private readonly IAccountingSystemFactory _factory;
    private readonly IInvoiceRepository _invoiceRepository;
    
    public async Task<Result<InvoiceDto>> Handle(
        ImportInvoiceCommand request, 
        CancellationToken cancellationToken)
    {
        // 创建 Fortnox 连接
        var accounting = _factory.Create("fortnox", connection.AccessToken);
        
        // 创建 Visma 连接(未来)
        // var accounting = _factory.Create("visma", connection.AccessToken);
        
        // 统一接口,无需关心底层实现
        var invoice = await _invoiceRepository.GetByIdAsync(request.InvoiceId);
        
        // 执行业务逻辑
        invoice.Import(request.Provider, request.UserId);
        
        await _invoiceRepository.SaveChangesAsync();
        
        // 领域事件自动保存到审计表
        return Result.Success(_mapper.Map<InvoiceDto>(invoice));
    }
}

4. 数据模型变更

4.1 数据库表结构

核心表:

  • Users - 用户表
  • AccountingConnections - 通用会计系统连接表
  • Invoices - 通用发票表
  • SupplierCaches - 通用供应商缓存表
  • DomainEvents - 领域事件表(审计)
-- 领域事件表(审计)
CREATE TABLE DomainEvents (
    Id UUID PRIMARY KEY,
    EventType VARCHAR(255) NOT NULL,
    AggregateType VARCHAR(255) NOT NULL,
    AggregateId UUID NOT NULL,
    OccurredAt TIMESTAMP WITH TIME ZONE NOT NULL,
    UserId VARCHAR(255),
    CorrelationId VARCHAR(255),
    Payload JSONB NOT NULL,
    Processed BOOLEAN DEFAULT FALSE
);

CREATE INDEX IX_DomainEvents_Aggregate ON DomainEvents(AggregateType, AggregateId);
CREATE INDEX IX_DomainEvents_OccurredAt ON DomainEvents(OccurredAt DESC);

5. 扩展性设计

5.1 添加新会计系统的步骤

  1. 创建 Provider 类
// InvoiceMaster.Integrations/Accounting/Providers/VismaProvider.cs
public class VismaProvider : IAccountingSystem
{
    public string ProviderName => "visma";
    
    public async Task<AuthResult> AuthenticateAsync(string code)
    {
        // Visma OAuth2 实现
    }
    
    public async Task<List<Supplier>> GetSuppliersAsync()
    {
        // Visma API 实现
    }
    
    // ... 其他方法实现
}
  1. 注册到 DI 容器
// Program.cs
builder.Services.AddAccountingSystem<VismaProvider>("visma");
  1. 添加配置
{
  "Visma": {
    "ClientId": "xxx",
    "ClientSecret": "xxx",
    "RedirectUri": "..."
  }
}
  1. 完成 - 无需修改业务逻辑代码

5.2 未来支持的会计系统

会计系统 市场 优先级 预计工作量
Fortnox 瑞典 P0 已完成
Visma eAccounting 北欧 P1 2-3 周
Hogia Smart 瑞典 P2 2-3 周
BjornLunden 瑞典 P2 2-3 周
Sage 欧洲 P3 3-4 周
QuickBooks 全球 P3 3-4 周

6. API 设计变更

6.1 会计系统连接 API

# 获取支持的会计系统列表
GET /api/v1/accounting/providers

# 获取特定会计系统的授权 URL
GET /api/v1/accounting/{provider}/auth/url

# OAuth 回调(通用)
GET /api/v1/accounting/{provider}/auth/callback?code=xxx&state=xxx

# 获取用户的所有连接
GET /api/v1/accounting/connections

# 断开特定会计系统连接
DELETE /api/v1/accounting/connections/{provider}

6.2 审计 API

# 获取发票的审计日志
GET /api/v1/invoices/{id}/audit-log

# 获取用户的操作历史
GET /api/v1/users/me/audit-log

# 导出审计报告(管理员)
GET /api/v1/admin/audit-export?from=2026-01-01&to=2026-02-01

7. 相关文档


文档历史:

版本 日期 作者 变更
3.0 2026-02-03 Claude Code 重构为 .NET + 轻量级 DDD
2.0 2026-02-03 Claude Code 重构为多会计系统架构
1.0 2026-02-03 Claude Code 初始版本(仅 Fortnox