Skip to content

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.