Code Standards¶
Coding conventions for the Consystence codebase.
.NET conventions¶
Target framework¶
All services target .NET 10. Use the latest C# language features (C# 13).
Data transfer¶
Use records for DTOs and grain state:
[GenerateSerializer]
public record DeviceStatus
{
[Id(0)] public string DeviceId { get; init; } = "";
[Id(1)] public bool IsOnline { get; init; }
[Id(2)] public DateTime LastSeen { get; init; }
}
Orleans serialization¶
All types that cross grain boundaries must have [GenerateSerializer] with [Id(n)] on each property. Do not use Newtonsoft.Json or System.Text.Json for grain communication.
Async rendering¶
Use ValueTask for rendering methods that often return synchronously (cached HTML fragments):
public ValueTask<string> RenderAsync(ComponentNode node, RenderContext context)
{
if (_cache.TryGetValue(node, out var html))
return ValueTask.FromResult(html);
return new ValueTask<string>(RenderSlowPathAsync(node, context));
}
HTML in C¶
Use raw string literals for HTML templates:
var html = $$"""
<div class="p-4 bg-slate-800 rounded-lg">
<h3 class="text-sm text-slate-400">{{label}}</h3>
<span class="text-2xl text-white">{{value}} {{unit}}</span>
</div>
""";
Naming conventions¶
IDs and keys¶
| Context | Convention | Example |
|---|---|---|
| Event/component IDs | kebab-case | alarm-list, pump-faceplate |
| Device type IDs | dot-notation | consystence.pump.centrifugal |
| Grain keys | GUID hex string | a3f1c9e0-7b2d-4e8a-b5f6-1d2e3f4a5b6c |
| Composite grain keys | GUID/slug | d4e5f6a7-.../pump-01 |
C# naming¶
Follow the standard .NET conventions:
| Element | Style | Example |
|---|---|---|
| Class / record | PascalCase | DeviceInstanceGrain |
| Interface | IPascalCase | IComponentServer |
| Method | PascalCase | RenderAsync |
| Private field | _camelCase | _deviceRepository |
| Property | PascalCase | DeviceId |
| Local variable | camelCase | currentSpeed |
Theming¶
Tailwind CSS palette¶
The dark theme uses these colour tokens:
| Token | Hex | Usage |
|---|---|---|
slate-900 | #0f172a | Page background |
slate-800 | #1e293b | Card / panel background |
slate-700 | #334155 | Borders, dividers |
slate-400 | #94a3b8 | Secondary text |
slate-200 | #e2e8f0 | Primary text |
white | #ffffff | Headings, emphasis |
cyan-400 | #22d3ee | Accent, links, active states |
red-500 | #ef4444 | Critical alarms, errors |
amber-500 | #f59e0b | Warning alarms |
emerald-500 | #10B981 | Running / healthy |
slate-500 | #64748B | Stopped / inactive |
Brand colours¶
| Name | Hex | Usage |
|---|---|---|
| Primary Navy | #002236 | Header, navigation |
| Navy Light | #001a29 | Footer, tab bar |
| Accent Cyan | #00C5FF | Primary accent |
| Accent Purple | #B900FF | Gradient accent (logo, highlights) |
YAML conventions¶
Device type definitions, alarm configs, and command configs use YAML:
- 2-space indentation
- No trailing whitespace
- Strings quoted only when necessary (e.g. containing
:or#) - Lists use
-with a space
Architectural boundaries¶
Orleans services¶
The site server (consystence-server) uses Orleans for all stateful operations: device instances, page sessions, alarm evaluation, and audit logging.
Plain ASP.NET Core services¶
Platform services that do not need distributed state use plain ASP.NET Core without Orleans:
| Service | Framework | Reason |
|---|---|---|
consystence-auth | ASP.NET Core | Stateless JWT issuance |
consystence-api | ASP.NET Core | Thin API gateway to cloud resources |
consystence-marketplace | ASP.NET Core | Package registry — stateless CRUD |
Tip
Do not add Orleans to platform services. The auth service, API gateway, and marketplace are deliberately kept simple and stateless.