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.                                                                                |
 |