8.9 KiB
8.9 KiB
Development Rules & Guidelines
To ensure scalability, readability, and consistency across all microservices and frontend clients, the following architectural and coding rules must be adhered to:
1. Service Interfaces and Implementations
- Single File Co-location: Every service interface (e.g.,
IAssetsDbService) and its corresponding implementation class (e.g.,AssetsDbService) must reside in the same file. - Naming Convention: The file must be named after the implementation class (e.g.,
AssetsDbService.cs).
2. Mandatory Method Documentation
- English Language: All documentation must be written in English.
- XML Documentation: Every method (public, private, internal, or protected) must have proper XML documentation.
- Required Fields:
<summary>: Clarifying the purpose and behavior of the method.<param>: Explaining each parameter (if applicable).<returns>: Specifying what the method returns (if applicable).
- Implementation Inheritdoc: For class methods implementing interfaces or overriding base methods, use
/// <inheritdoc />to inherit documentation unless customization is needed. Note that any custom helper or private methods in the implementation must still have their own explicit XML comments.
3. Data Class & Model Architecture
- Strict Data Class Usage: ALL data processing, state passing, API payloads, MQTT message schemas, and internal data transfers must strictly use strongly-typed Data Classes (e.g., C#
record,class, or immutable DTOs / Dart Data Classes). - Prohibition of Loose Types: The use of untyped data containers such as
Dictionary<string, object>,dynamic, rawJObject/JsonDocument, or unstructured string-based JSON passing within internal logic is strictly forbidden. - Core Placement: All data classes, DTOs, and shared enums (e.g.,
AssetType) that are or could be used by multiple services must be defined in theFinlyticCoreproject. - Service-Specific Exception: Data classes and models may only reside in a specific service project (e.g.,
FinlyticAssets) if they strictly concern the internal operations of that service (e.g., raw API request/response structures for an integration that only that service manages).
4. Absolute Prohibition of Demo Data & Mandatory Empty-State Transparency
- No Mocks or Fallbacks: Mock data, demo fallbacks, hardcoded fake arrays, placeholder graphs, or dummy fallback responses are strictly forbidden across all backend microservices and frontend clients.
- Strict Data Reality: Either real results are available from database queries/API responses or the system must return empty result sets / raise explicit exceptions. Silent mock fallbacks are prohibited.
- Explicit UI Zero-Data Handling: In the frontend (Flutter/Dart), if an API call returns no data, never show placeholder content or fake metrics. The UI must explicitly inform the user via an unambiguous Empty State view (e.g., "No active recommendations available" or "No trades found for this period"). The user must always clearly know when data is missing versus when real data is present.
5. Inter-Service Communication via MQTT Only
- Exclusive Protocol: All internal communication between backend microservices must run exclusively over MQTT (Pub/Sub & RPC).
- Single Web Gateway:
FinlyticBackendis the only microservice allowed to host Kestrel HTTP/WebSocket endpoints for external client access (FinlyticApp). Background microservices must never expose HTTP webservers or REST controllers.
6. EF Core Migrations Management
- Command-Only Creation: Database migrations (EF Core Migrations) must strictly be created via CLI commands (e.g.,
dotnet ef migrations add <MigrationName>). Manual hand-crafted creation of migration files is strictly prohibited.
7. Security & API Authorization (Backend Gateway)
- Mandatory Route Authorization: Every single HTTP controller endpoint or WebSocket route in
FinlyticBackendmust be protected with[Authorize]attributes (or explicitly scoped authorization policies). - Explicit Whitelisting Only: Endpoints without authentication (e.g.,
/api/v1/auth/login) are the only allowed exception and must be explicitly marked with[AllowAnonymous]. Unprotected endpoints without explicit anonymous authorization are forbidden.
8. Dart / Flutter Frontend Architecture & JWT Handling
- Mandatory JWT Injection: Every outgoing HTTP/WebSocket request from the Flutter app (
FinlyticApp) must include the JWT Bearer Token in theAuthorizationheader (Bearer <token>). This must be handled centrally via HTTP Interceptors (e.g.,Diointerceptor or customHttpClient). - Automated Authentication Invalidation (Auto-Logout):
- If any API request returns an unauthenticated response (
401 Unauthorizedor403 Forbidden), the frontend interceptor must immediately invalidate the stored local JWT. - The application state must instantly trigger an automated logout, clear user tokens/cache, and redirect the user back to the Login screen.
- Under no circumstances should the client remain in an authenticated state after receiving an invalid or expired JWT error from the gateway.
- If any API request returns an unauthenticated response (
9. Asynchronous Programming Guidelines
- Async All the Way: Avoid blocking asynchronous code using
.Result,.Wait(), or.GetAwaiter().GetResult(). Useasync/awaitconsistently throughout the call stack to prevent thread pool starvation. - Cancellation Tokens: All asynchronous methods interacting with DBs, network/MQTT calls, or external APIs must accept a
CancellationTokenas their last parameter and pass it down to underlying async calls. - ValueTask Usage: Prefer
ValueTask<T>overTask<T>for hot-path methods that frequently complete synchronously (e.g., cached database lookups).
10. Logging and Diagnostics
- Channel-Based Logging: Logging must be organized into logical, domain-specific channels (e.g.,
MqttChannel,DatabaseChannel,AnalyzerChannel,StrategyChannel,RiskEngineChannel).- Dynamic Toggle Control: Every log channel must be configurable at runtime. Microservices must react to channel configuration changes without requiring a service restart (e.g., via
IOptionsMonitor<T>or MQTT configuration broadcast events). - Admin Panel Integration: The state of each logging channel (Enabled / Disabled / LogLevel) must be exposed to and manageable from the
FinlyticBackendAdmin Panel.
- Dynamic Toggle Control: Every log channel must be configurable at runtime. Microservices must react to channel configuration changes without requiring a service restart (e.g., via
- Structured Logging: Always use structured logging with named placeholders (e.g.,
_logger.LogInformation("[{Channel}] Processing recommendation for asset {Symbol}", "AnalyzerChannel", symbol)instead of string interpolation$"{symbol}"). - Log Levels Rules:
Trace/Debug: Fine-grained internal flow, payload dumps, and low-level MQTT events.Information: Business-relevant milestones (e.g., recommendation generated, manual trade validated).Warning: Recoverable issues or expected unexpected behavior (e.g., transient network retries, rate limits hit).Error: Unhandled exceptions, failed DB queries, or lost service connections requiring attention.
- No Sensitive Data: Never log raw authorization tokens, passwords, or personal credentials.
11. Error Handling and Resilience
- Explicit Exception Handling: Catch specific exceptions rather than
System.Exception. Always log the caught exception with full stack trace using_logger.LogError(ex, "Message"). - Global Error Handling in Gateway:
FinlyticBackendmust handle failures gracefully using standardized error responses (e.g., Problem Details). Background services must fail fast or retry safely using resilience pipelines (e.g., Polly for MQTT reconnection/API retries). - Result Pattern: For domain operations where failure is an expected outcome (e.g., trade validation failed due to missing inputs), prefer returning a typed Result object (
Result<T>) instead of throwing control-flow exceptions.
12. Configuration & Environment Management
- Strongly-Typed Settings: All service configurations (e.g., MQTT broker settings, API keys, database connection strings) must be bound to strongly-typed options classes using
IOptions<T>orIOptionsMonitor<T>. - No Hardcoded Secrets: Secrets, connection strings, and private keys must never be hardcoded or checked into source control. Use environment variables or local user secrets (
appsettings.Local.jsonexcluded via.gitignore).
13. Testing and Verification Standards
- No Production Code Mocks: Unit tests and integration tests must be located in dedicated test projects (e.g.,
FinlyticCore.Tests). Do not include test-only mock classes inside production assemblies. - Deterministic Testing: Integration tests connecting to real databases or MQTT brokers must run against isolated local containers (e.g., Testcontainers or isolated local DB instances) to ensure non-destructive and predictable test execution.