75 lines
8.9 KiB
Markdown
75 lines
8.9 KiB
Markdown
# 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`, raw `JObject`/`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 the `FinlyticCore` project.
|
|
- **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**: `FinlyticBackend` is 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 `FinlyticBackend` **must** 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 the `Authorization` header (`Bearer <token>`). This must be handled centrally via HTTP Interceptors (e.g., `Dio` interceptor or custom `HttpClient`).
|
|
- **Automated Authentication Invalidation (Auto-Logout)**:
|
|
- If any API request returns an unauthenticated response (`401 Unauthorized` or `403 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.
|
|
|
|
## 9. Asynchronous Programming Guidelines
|
|
- **Async All the Way**: Avoid blocking asynchronous code using `.Result`, `.Wait()`, or `.GetAwaiter().GetResult()`. Use `async`/`await` consistently 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 `CancellationToken` as their last parameter and pass it down to underlying async calls.
|
|
- **ValueTask Usage**: Prefer `ValueTask<T>` over `Task<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 `FinlyticBackend` Admin Panel.
|
|
- **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**: `FinlyticBackend` must 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>` or `IOptionsMonitor<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.json` excluded 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. |