-
-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture.md
This document describes the high-level architecture, design philosophy, and structural decisions of OpenCashFlow.
OpenCashFlow follows Clean Architecture principles with these goals:
- Separation of Concerns - Each layer has a single responsibility
- Dependency Inversion - High-level modules don't depend on low-level modules
- Testability - Business logic is isolated from infrastructure
- Maintainability - Changes in one layer don't cascade to others
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Presentation Layer β
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ β
β β OpenCashFlow β β OpenCashFlow β β OpenCashFlow β β
β β .App β β .API β β .Admin β β
β β (MVC + UI) β β (REST API) β β (Admin Panel) β β
β ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ β
βββββββββββββΌβββββββββββββββββββββΌβββββββββββββββββββββΌββββββββββββ
β β β
ββββββββββββββββββββββΌβββββββββββββββββββββ
β
ββββββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββ
β Shared Layer β
β βββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββ β
β β OpenCashFlow.Shared β β
β β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββββββ β β
β β β Models β β DTOs β β Services β β Repositories β β β
β β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββββββ β β
β β ββββββββββββ ββββββββββββ ββββββββββββ β β
β β β Enums β β Mappings β β DbContextβ β β
β β ββββββββββββ ββββββββββββ ββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββ
β Data Layer β
β ββββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββ β
β β PostgreSQL 16 β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The presentation layer contains three separate applications:
| Project | Responsibility |
|---|---|
| OpenCashFlow.App | User-facing MVC application with Razor views, handles UI rendering and user authentication flows |
| OpenCashFlow.API | RESTful API for data operations, consumed by the App via AJAX and by external integrations |
| OpenCashFlow.Admin | Administrative dashboard for system management and monitoring |
The shared library (OpenCashFlow.Shared) contains:
- Models (Entities) - Database entity definitions with EF Core mappings
- DTOs - Data Transfer Objects for API contracts
- Services - Business logic implementations
- Repositories - Data access abstractions
- Enums - Shared enumerations (permissions, statuses, types)
- Mappings - AutoMapper profiles for entity-DTO conversion
- DbContext - Entity Framework Core database context
PostgreSQL database with:
- Multi-tenant data isolation via
TenantID - Audit trail fields on all entities
- Soft delete support
- Optimistic concurrency where needed
Every business entity includes a TenantID field that represents the owning company:
public class Payment
{
public Guid PaymentID { get; set; }
public Guid TenantID { get; set; } // Company identifier
public decimal Amount { get; set; }
// ... other fields
}All queries filter by TenantID to ensure data isolation between companies.
Data access is abstracted through repository interfaces:
// Interface definition
public interface IPaymentRepository
{
Task<IEnumerable<Payment>> GetAllAsync(Guid tenantId);
Task<Payment?> GetByIdAsync(Guid paymentId);
Task<Payment> CreateAsync(Payment payment);
Task UpdateAsync(Payment payment);
Task DeleteAsync(Guid paymentId);
}
// Controller usage
public class PaymentController : ControllerBase
{
private readonly IPaymentRepository _paymentRepository;
public PaymentController(IPaymentRepository paymentRepository)
{
_paymentRepository = paymentRepository;
}
}DTOs separate API contracts from internal entities:
// Entity (internal)
public class Payment
{
public Guid PaymentID { get; set; }
public Guid TenantID { get; set; }
public decimal Amount { get; set; }
public string CreatedBy { get; set; }
public DateTime DateIns { get; set; }
// ... audit fields
}
// DTO (external contract)
public class Payment_List_DTO
{
public Guid PaymentID { get; set; }
public decimal Amount { get; set; }
public string EntryType { get; set; }
public DateTime PaymentDate { get; set; }
}Controllers and repositories are split using partial classes for maintainability:
Controllers/
PaymentController.cs # Main controller definition
PaymentController.Create.cs # Create payment logic
PaymentController.Update.cs # Update payment logic
PaymentController.Delete.cs # Delete payment logic
Startup configuration is organized into chainable extension methods:
// Program.cs
builder.AppStartConfigureLogging();
builder.AppStartConfigureServices();
builder.AppStartConfigureAuthentication();
// Extension method files
// AppStart/00_Logging.cs
// AppStart/01_Configuration.cs
// AppStart/02_Authentication.csHTTP Request
β
βΌ
βββββββββββββββββββββββ
β Middleware β
β - Authentication β
β - Authorization β
β - Subscription β
β - Error Handling β
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β Controller β
β - Route handling β
β - Input validation β
β - Response mapping β
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β Service β
β - Business logic β
β - Validation rules β
β - Orchestration β
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β Repository β
β - Data access β
β - Query building β
β - CRUD operations β
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β DbContext β
β - EF Core β
β - Change tracking β
β - Migrations β
ββββββββββββ¬βββββββββββ
β
βΌ
PostgreSQL
HTTP Request
β
βΌ
βββββββββββββββββββββββ
β MVC Controller β
β - Authentication β
β - View selection β
ββββββββββββ¬βββββββββββ
β
βββββββββββββββββββ
β β
βΌ βΌ
βββββββββββββββ βββββββββββββββ
β Razor View β β AJAX Call β
β (server) β β to API β
βββββββββββββββ ββββββββ¬βββββββ
β
βΌ
βββββββββββββββ
β OpenCash β
β Flow.API β
βββββββββββββββ
All entities inherit audit fields for compliance and debugging:
| Field | Purpose |
|---|---|
CreatedBy |
User who created the record |
DateIns |
Creation timestamp |
EditedBy |
User who last modified the record |
DateEdit |
Last modification timestamp |
IsDeleted |
Soft delete flag |
IsDeletedBy |
User who deleted the record |
IsDeletedWhy |
Reason for deletion |
DateDeleted |
Deletion timestamp |
All API responses use a consistent wrapper:
public class ApiResponse<T>
{
public bool Success { get; set; }
public string Message { get; set; }
public T Data { get; set; }
public List<string> Errors { get; set; }
}Example responses:
// Success
{
"success": true,
"message": "Payment created successfully",
"data": { "paymentId": "..." },
"errors": []
}
// Error
{
"success": false,
"message": "Validation failed",
"data": null,
"errors": ["Amount must be greater than zero"]
}Services are registered in Program.cs with appropriate lifetimes:
// Scoped (per-request)
builder.Services.AddScoped<IPaymentRepository, PaymentRepository>();
builder.Services.AddScoped<IPaymentService, PaymentService>();
// Singleton (application lifetime)
builder.Services.AddSingleton<IEmailService, EmailService>();
// Transient (new instance each time)
builder.Services.AddTransient<IValidator<PaymentDto>, PaymentValidator>();| Service | Purpose |
|---|---|
| Stripe | Subscription billing, payment processing, webhooks |
| Sentry | Error tracking and monitoring |
| Slack | Log notifications (via Serilog) |
| SMTP | Email delivery |
Project status
OpenCashFlow is under active development.
APIs, database schema, and UI may change until the first stable release.
Built with
.NET Β· ASP.NET Core Β· Entity Framework Core Β· PostgreSQL Β· Tabler
Β© 2026 OpenCashFlow
- Developer Preview
- Not production-ready
- First-run setup included