backend lead & delägare · compys.se · alpha

Compys.se
Jag byggde baksidan.

Fem personer, fortfarande i alpha. Backend och drift gör jag på fritiden.

Headhunting för juniora, utan CV-högar

Compys hjälper startups att hitta juniora utvecklare, praktikanter och första-anställningar genom personlig matchning i stället för ansökningsflod. Ett fåtal relevanta kandidater per roll — inte hundratals CV:n att sålla i.

Mitt jobb är allt som händer bakom knapparna: API:et som driver matchningen, databasen där profiler och roller lever, och infrastrukturen som håller det igång på Azure.

Backend lead & delägare

Som backend lead sätter jag den tekniska riktningen: arkitektur, kodstandard och de riktlinjer teamet bygger efter. Som delägare bär jag också ansvaret för att det vi levererar faktiskt håller — skalbart, säkert och möjligt att förvalta.

ansvar.md

arkitektur
Design av backend-systemet med fokus på prestanda, säkerhet och att det går att bygga vidare på.
ledarskap
Teknisk riktning för teamet — best practices, kodstandard och beslut som håller över tid.
api
Robusta API:er och serverkomponenter i .NET 8 och C# v8.
databas
Datamodell och frågor i MongoDB, optimerade för snabb hämtning.
moln
Azure-baserad infrastruktur och drift, byggd för att skala.
betalningar
Stripe-integration för säkra betalningsflöden.
säkerhet
Säkerhetsstandarder och proaktivt skydd av data och system.

Tråkig kärna, medvetna val ovanpå

Ett litet team har inte råd med teknik som bara en person förstår, så kärnan är medvetet konventionell: .NET 8 och C#. Det intressanta ligger i valen ovanpå — rätt databas per domän, riktig molnplattform och en arkitektur som går att bygga vidare på utan att riva grunden.

Datan är polyglot: MongoDB där det är dokumenttungt och föränderligt, PostgreSQL via EF Core där relationer och transaktioner räknas. Auth via Firebase och JWT, realtidsnotiser via SignalR, betalningar via Stripe — allt hostat på Azure.

En slice per feature, CQRS rakt igenom

Backenden är ett trettiotal vertikala slices — en mapp per domän som äger hela vägen från request till svar, i stället för lager som skär tvärs igenom allt. Läsning och skrivning är åtskilda med CQRS via MediatR: queries hämtar, commands ändrar.

Det som annars upprepas i varje endpoint — validering, caching, loggning — ligger som pipeline-behaviors runt varje anrop. En query behöver bara säga att den får cachas; behaviorn sköter resten, en gång för alla.

CachingBehavior.cs

// En query är bara data — den vet inget om cache, validering eller loggning.
public record SearchProfilesQuery(string? SearchQuery, int PageSize /* … */)
    : ICacheableQuery<SearchProfilesResponse>
{
    public string CacheKey   => $"profiles:{SearchQuery}:{PageSize}";
    public TimeSpan? Expiration => TimeSpan.FromMinutes(5);
}

// En pipeline-behavior lägger cachen runt varje sådan query — en gång, för alla.
public class CachingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : ICacheableQuery<TResponse>
{
    public Task<TResponse> Handle(TRequest req, RequestHandlerDelegate<TResponse> next, CancellationToken ct)
        => _cache.TryGetValue(req.CacheKey, out TResponse? hit) && hit is not null
            ? Task.FromResult(hit)
            : CacheAndReturn(req, next);
}

Tungt jobb utanför request-tråden

Poäng, topplistor och aviseringar ska inte räknas medan användaren väntar på svar. De läggs på en kö och plockas av en BackgroundService-worker som kör själva jobbet som ett eget MediatR-command — samma mönster som allt annat, fast utanför request-tråden.

EmailDesigner — så marketing slipper be om kod

Vår marketing-person Mio ville kunna skicka snygga, stylade mejl till partners och intressenter utan att gå via mig varje gång. Så jag byggde EmailDesigner: ett litet fristående verktyg där hon loggar in (Firebase), bygger mejlet visuellt och skickar — rakt genom vår egen backend.

Inget externt mejl-SaaS. Backendens EmailDomain renderar mallar med Scriban, levererar via Azure Communication Services och loggar varje utskick med status. Samma command/handler-mönster som resten av API:et: ett SendCommunicationEmail-command in, ett spårbart EmailLog ut.

Drift på Azure — som kod, inte klick

Infrastrukturen är mitt bord, och den bor i Terraform — inte i portalens klickträd. Hela miljön går att läsa, granska och återskapa. Secrets ligger i Key Vault och aldrig i koden, filer i Blob Storage, loggarna i App Service.

Stripe-webhooks körs idempotent: samma event kan komma två gånger utan att något dubbelbokförs. Det som ska funka testas — både unit- och integrationstester. Samma princip som i homelabben: automatisera det tråkiga, dokumentera resten. Fortfarande en alpha byggd på fritiden, men byggd för att växa.

/* ett riktigt projekt, inte en demo — därför står det bara det jag kan visa publikt */