Some checks failed
		
		
	
	Build Test Deploy / authority-container (push) Has been cancelled
				
			Build Test Deploy / docs (push) Has been cancelled
				
			Build Test Deploy / deploy (push) Has been cancelled
				
			Build Test Deploy / build-test (push) Has been cancelled
				
			Docs CI / lint-and-preview (push) Has been cancelled
				
			
		
			
				
	
	
		
			170 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Markdown
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			170 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Markdown
		
	
	
		
			Executable File
		
	
	
	
	
| #  18 · Coding Standards & Contributor Guide — **Stella Ops**  
 | ||
| *(v2.0 — 12 Jul 2025 · supersedes v1.0)*  
 | ||
| 
 | ||
| > **Audience** — Anyone sending a pull‑request to the open‑source Core.  
 | ||
| > **Goal** — Keep the code‑base small‑filed, plug‑in‑friendly, DI‑consistent, and instantly readable.
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ##  0 Why read this?
 | ||
| 
 | ||
| * Cuts review time → quicker merges.  
 | ||
| * Guarantees code is **hot‑load‑safe** for run‑time plug‑ins.  
 | ||
| * Prevents style churn and merge conflicts.  
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ##  1 High‑level principles
 | ||
| 
 | ||
| 1. **SOLID first** – especially Interface & Dependency Inversion.  
 | ||
| 2. **100‑line rule** – any file > 100 physical lines must be split or refactored.  
 | ||
| 3. **Contract‑level ownership** – public abstractions live in lightweight *Contracts* libraries; impl classes live in runtime projects.  
 | ||
| 4. **Single Composition Root** – all DI wiring happens in **`StellaOps.Web/Program.cs`** and in each plug‑in’s `IoCConfigurator`; nothing else calls `IServiceCollection.BuildServiceProvider`.  
 | ||
| 5. **No Service Locator** – constructor injection only; static `ServiceProvider` is banned.  
 | ||
| 6. **Fail‑fast startup** – configuration validated before the web‑host listens.  
 | ||
| 7. **Hot‑load compatible** – no static singletons that survive plug‑in unload; avoid `Assembly.LoadFrom` outside the built‑in plug‑in loader.  
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ##  2 Repository layout (flat, July‑2025)**
 | ||
| 
 | ||
| ```text
 | ||
| src/
 | ||
| ├─ backend/
 | ||
| │   ├─ StellaOps.Web/                # ASP.NET host + composition root
 | ||
| │   ├─ StellaOps.Common/             # Serilog, Result<T>, helpers
 | ||
| │   ├─ StellaOps.Contracts/          # DTO + interface contracts (no impl)
 | ||
| │   ├─ StellaOps.Configuration/      # Options + validation
 | ||
| │   ├─ StellaOps.Localization/
 | ||
| │   ├─ StellaOps.PluginLoader/       # Cosign verify, hot‑load
 | ||
| │   ├─ StellaOps.Scanners.Trivy/     # First‑party scanner
 | ||
| │   ├─ StellaOps.TlsProviders.OpenSsl/
 | ||
| │   └─ … (additional runtime projects)
 | ||
| ├─ plugins-sdk/                      # Templated contracts & abstractions
 | ||
| └─ frontend/                         # Angular workspace
 | ||
| tests/                               # Mirrors src structure 1‑to‑1
 | ||
| ```
 | ||
| 
 | ||
| There are no folders named “Module” and no nested solutions.
 | ||
| 
 | ||
| ##  3 Naming & style conventions
 | ||
| 
 | ||
| | Element                                                                         | Rule                                    | Example                         |
 | ||
| | ------------------------------------------------------------------------------- | --------------------------------------- | ------------------------------- |
 | ||
| | Namespaces                                                                      | File‑scoped, StellaOps.<Area>           | namespace StellaOps.Scanners;   |
 | ||
| | Interfaces                                                                      | I prefix, PascalCase                    | IScannerRunner                  |
 | ||
| | Classes / records                                                               | PascalCase                              | ScanRequest, TrivyRunner        |
 | ||
| | Private fields                                                                  | camelCase (no leading underscore)       | redisCache, httpClient          |
 | ||
| | Constants                                                                       | SCREAMING_SNAKE_CASE                    | const int MAX_RETRIES = 3;      |
 | ||
| | Async methods                                                                   | End with Async                          | Task<ScanResult> ScanAsync()    |
 | ||
| | File length                                                                     | ≤ 100 lines incl. using & braces        | enforced by dotnet format check |
 | ||
| | Using directives                                                                | Outside namespace, sorted, no wildcards | —                               |
 | ||
| 
 | ||
| Static analyzers (.editorconfig, StyleCop.Analyzers package) enforce the above. 
 | ||
| 
 | ||
| ##  4 Dependency‑injection policy
 | ||
| 
 | ||
| Composition root – exactly one per process:
 | ||
| 
 | ||
| ```csharp
 | ||
| builder.Services
 | ||
|        .AddStellaCore()          // extension methods from each runtime project
 | ||
|        .AddPluginLoader("/Plugins", cfg);   // hot‑load signed DLLs
 | ||
| ```
 | ||
| 
 | ||
| Plug‑ins register additional services via the IoCConfigurator convention described in the Plug‑in SDK Guide, §5.
 | ||
| Never resolve services manually (provider.GetService<T>()) outside the composition root; tests may use WebApplicationFactory or ServiceProvider.New() helpers.
 | ||
| Scoped lifetime is default; singletons only for stateless, thread‑safe helpers.
 | ||
| 
 | ||
| ##  5 Project organisation rules
 | ||
| 
 | ||
| Contracts vs. Runtime – public DTO & interfaces live in <Area>.Contracts; implementation lives in sibling project.
 | ||
| Feature folders – inside each runtime project group classes by use‑case, e.g.
 | ||
| 
 | ||
| ```text
 | ||
| ├─ Scan/
 | ||
| │   ├─ ScanService.cs
 | ||
| │   └─ ScanController.cs
 | ||
| ├─ Feed/
 | ||
| └─ Tls/
 | ||
| ```
 | ||
| 
 | ||
| Tests – mirror the structure under tests/ one‑to‑one; no test code inside production projects.
 | ||
| 
 | ||
| ##  6 C# language features
 | ||
| 
 | ||
| Nullable reference types enabled.
 | ||
| record for immutable DTOs.
 | ||
| Pattern matching encouraged; avoid long switch‑cascades.
 | ||
| Span<T> & Memory<T> OK when perf‑critical, but measure first.
 | ||
| Use await foreach over manual paginator loops.
 | ||
| 
 | ||
| ##  7 Error‑handling template
 | ||
| 
 | ||
| ```csharp
 | ||
| public async Task<IActionResult> PostScan([FromBody] ScanRequest req)
 | ||
| {
 | ||
|     if (!ModelState.IsValid) return BadRequest(ModelState);
 | ||
| 
 | ||
|     try
 | ||
|     {
 | ||
|         ScanResult result = await scanService.ScanAsync(req);
 | ||
|         if (result.Quota != null) 
 | ||
|         {
 | ||
|             Response.Headers.TryAdd("X-Stella-Quota-Remaining", result.Quota.Remaining.ToString());
 | ||
|             Response.Headers.TryAdd("X-Stella-Reset", result.Quota.ResetUtc.ToString("o"));
 | ||
|         }
 | ||
|         return Ok(result);
 | ||
|     }
 | ||
| }
 | ||
| ```
 | ||
| 
 | ||
| RFC 7807 ProblemDetails for all non‑200s.
 | ||
| Capture structured logs with Serilog’s message‑template syntax.
 | ||
| 
 | ||
| ##  8 Async & threading
 | ||
| 
 | ||
| * All I/O is async; no .Result / .Wait().
 | ||
| * Library code: ConfigureAwait(false).
 | ||
| * Limit concurrency via Channel<T> or Parallel.ForEachAsync, never raw Task.Run loops.
 | ||
| 
 | ||
| ##  9 Testing rules
 | ||
| 
 | ||
| | Layer                    | Framework                | Coverage gate              |
 | ||
| | ------------------------ | ------------------------ | -------------------------- |
 | ||
| | Unit                     | xUnit + FluentAssertions | ≥ 80 % line, ≥ 60 % branch |
 | ||
| | Integration              | Testcontainers           | Real Redis & Trivy         |
 | ||
| | Mutation (critical libs) | Stryker.NET              | ≥ 60 % score               |
 | ||
| 
 | ||
| One test project per runtime/contract project; naming <Project>.Tests.
 | ||
| 
 | ||
| ##  10 Static analysis & formatting
 | ||
| 
 | ||
| * dotnet format must exit clean (CI gate).
 | ||
| * StyleCop.Analyzers + Roslyn‑Security‑Guard run on every PR.
 | ||
| * CodeQL workflow runs nightly on main.
 | ||
| 
 | ||
| ##  11 Commit & PR checklist
 | ||
| 
 | ||
| * Conventional Commit prefix (feat:, fix:, etc.).
 | ||
| * dotnet format & dotnet test both green.
 | ||
| * Added or updated XML‑doc comments for public APIs.
 | ||
| * File count & length comply with 100‑line rule.
 | ||
| * If new public contract → update relevant markdown doc & JSON‑Schema.
 | ||
| 
 | ||
| ##  12 Common pitfalls
 | ||
| 
 | ||
| |Symptom|  Root cause | Fix
 | ||
| |-------|-------------|-------------------
 | ||
| |InvalidOperationException: Cannot consume scoped service...| Mis‑matched DI lifetimes| Use scoped everywhere unless truly stateless
 | ||
| |Hot‑reload plug‑in crash| Static singleton caching plugin types| Store nothing static; rely on DI scopes
 | ||
| 
 | ||
| > 100‑line style violation |Large handlers or utils |Split into private helpers or new class
 | ||
| 
 | ||
| ##  13 Change log
 | ||
| 
 | ||
| | Version | Date       | Notes                                                                                              |
 | ||
| | ------- | ---------- | -------------------------------------------------------------------------------------------------- |
 | ||
| | v2.0    | 2025‑07‑12 | Updated DI policy, 100‑line rule, new repo layout, camelCase fields, removed “Module” terminology. |
 | ||
| | 1.0     | 2025‑07‑09 | Original standards.                                                                                |
 |