top of page

Uge 39: Backend Skeleton

  • Writer: Kenneth H Sørensen
    Kenneth H Sørensen
  • Sep 24
  • 4 min read

Updated: Sep 26

ree

Laying the groundwork

"From clean repo to professional backend baseline"


Jeg vil samle nogle af de tanker jeg har haft, og skrive dem ned, og tegne lidt, for at få overblik over hvordan jeg gerne vil løse min opgave på den bedste måde for mig og min læring.


Et par af de spørgsmål jeg har haft

  • Skal ansvaret for adgang/adgangskontrol (ingestion) deles op i flere services?

  • Skal vi bruge GraphQL - har systemet reelt behov for det?


Og så vil jeg sætte min backend op, så jeg kan komme i gang med at kode.



Fra indledende tanker til plan


Jeg startede med at lave en indledende overordnet plan over hvordan jeg troede en løsning kunne se ud. Med mit ansvarsområde markeret.

ree


Hvis jeg zoomer ind på min del, så overvejer jeg at dele dens ansvar op i 3 services.


Ift. læring giver det mig et helt lille system for sig selv, hvor jeg får mulighed for at arbejde i dybden med backend design, intern kommunikation og IT-sikkerhed.


ree

De får hver deres ansvar

  • Ingestion Service - data ind i systemet

  • Media Access Service - data ud af systemet

  • Storage Service - IAM: Full bucket (storage) access


Vigtig note:

  • I virkeligheden burde AI service nok have sin egen scoped adgang til storage.

    AI service kunne reagere på ImageUploaded event, samt det info der bliver published og direkte hente billedet fra storage.


  • Men igen: designet her giver mulighed for læring og eksperimentering ift. intern kommunikation og IT-sikkerhed.



Kommunikation:

  • Efter at have læst om GraphQL tænker jeg ikke vores system har direkte behov for det.

  • Uge 39: Overvejer derfor stærkt REST / gRPC (stadig kafka asynkront)

    • Uge 38: GraphQL (link) - efter mere dyb læsning om GraphQL

    • Uge 37: Arkitekturvalg (link) - tidligere valg om at jeg ville benytte GraphQL

  • og HVIS Trusted Source (mobilapp via gateway eller andet) ender med at kalde Ingestion Service med GraphQL, så kunne vi lave en intern GraphQL BFF der tager GraphQL og omdanner til REST / gRPC


Vigtig note:

  • Mange hops mellem services giver øget latency og flere potentielle fejlpunkter

  • Vigtigt at balancere "flere services = mere læring" mod "simpelt og robust flow"




Plan nu og frem (for MVP)

  • Opsæt repositories for hver service

  • Begynd at kode / designe LLD

  • Endpoints REST / gRPC (for nu)



Ingestion Service

  • POST /v1/uploads/start - call Storage for PUT URL - (Create upload session, return URL)

  • POST /v1/uploads/confirm  - validate, persist data, publish ImageUploaded (kafka)

  • GET /v1/uploads/{id}/status - evt. for upload status


Storage Service

  • POST /internal/v1/storage/presign-put

  • POST /internal/v1/storage/presign-get


  • TTL ≤ 60s, consistent key scheme, (audit log each issuance)


Media Access

  • POST /internal/v1/media/get-url  - authZ  - call Storage for presign-get

  • POST /internal/v1/media/get-url-batch - evt. for flere på en gang


AI Service

  • Consume ImageUploaded

  • Call Media Access




Shared repos i vores organisation på GitHub


For at gøre klar til CI i alle 3 services, har jeg oprettet et .github repo, som alle andre repos kan kalde for workflows.


ree

Måske ikke strengt nødvendig for os, men man undgår at skulle gentage arbejde med at lave workflow filer til hver eneste service, hvilket specielt er nyttigt hvis de er ens.


Don't Repeat Yourself (DRY)


Lige nu er der bare et simpelt workflow i det shared .github repo, men her kan der lægges forskellige workflows, så de kan bruges på tværs af vores services.


I Ingestion Service er der gjort klar til at benytte shared .github repo workflows.


ree

ree

nice
nice


Arkitektur og struktur (indre)


Ingestion Service eksempel

Skelet med Hexagonal Arkitektur


ree

Ingestion

.Api - Indbound adapter

  • Controller

    • Modtager HTTP requests

    • Pakker dem i DTO

    • Kalder use case

.Application - Inbound ports / Outbound ports

  • Indhold

    • Interfaces (ports), f.eks IUseCase

    • Use case handlers, f.eks UseCaseHandler - use case logik

  • Flow

    • Orkestrerer proces

    • Kalder Domain - for regler og entiteter (ændre state, validere, forretningslogik)

    • Kalder Outbound ports, som Infrastruktur implementerer

.Domain - Core

  • Indhold

    • Entiteter (f.eks Upload session, UploadStatus)

    • Regler / metoder til at ændre state

  • Kender ikke til HTTP, DB, Storage eller frameworks

  • Bruges af Application (direkte)

.Infrastructure - Outbound adapter

  • Ansvar

    • Implementerer Application's Outbound ports

    • Kommunikerer med omverdenen (DB, Storage, Messaging)

  • Eksempler

    • UploadRepo (EF core) imp. IUploadRepo

    • MinioPresignService imp. IStoragePresignService

    • KafkaEventPublisher imp. IEventPublisher


ree


Konkret Hexagonal mappestruktur


.Api Indgang. Eksponerer endpoints, håndterer requests og mapper dem ind i use cases.

  • Controllers/ - Web API controllers

  • Contracts/  - HTTP request/response DTOs (eksterne kontrakter)

  • Filters/  - Exception filters, middleware

  • Program.cs  - Composition root, DI registration, hosting-konfiguration


.Application Definerer servicens use cases og porte (interfaces). Koordinerer ml. Api og Domain.

  • Interfaces/ - Porte (f.eks IStorageClient, IEventBus, IUploadSessionRepository)

  • Services/  - Application services der implementerer use cases

  • Dtos/  - Interne datakontrakter (commands, queries, results)

  • Mapping/  - Konvertering mellem Api-Contracts ↔ Application-DTOs ↔ Domain


.Domain Kerne/forretningslogik. Ren, framework-uafhængig kode.

  • Entities/  - Aggregates, entities

  • ValueObjects/  - Stærke typer (ObjectKey, UploadId, Checksum)

  • Services/  - Domæneservices (forretningsregler)

  • Events/  - Domæneevents


.Infrastructure Implementerer porte defineret i Application. Håndterer eksterne systemer.

  • Persistence/  - EF Core DbContext, repositories, migrations

  • Messaging/  - Kafka producer/consumer

  • ExternalServices/  - Adapters til HTTP-klienter (f.eks MinIO)

  • Config/  - Konfiguration og DI registration


.Contracts Integrationskontrakter der deles med andre services (f.eks events / SDK)

  • Events/  - Versionerede event payloads (f.eks ImageUploadedV1)

  • Dtos/  - Delte datastrukturer, hvis man udgiver SDK’er

  • Laves som et stabilt, versioneret interface


Hvorfor

  • Separation of concerns  - Hver lag har ét ansvar

  • Testbarhed  - Domain og Application kan unit-testes uden infrastruktur

  • Fleksibilitet  - EF, Kafka, MinIO kan skiftes uden at ændre kerne­logikken

  • Klarhed  - Andre kan se hvor ting hører til



Refleksion


Ved at splitte mit ansvarsområde op i tre services har jeg skabt et lille system, hvor jeg kan arbejde i dybden med backend- og API-design, intern kommunikation og IT-sikkerhed.


Det fungerer som en sandkasse, hvor jeg kan eksperimentere med den teori, jeg arbejder med i mine valgfag, f.eks.

  • Design- og arkitekturpatterns

  • Sikkerhedsprincipper som CIA-triaden og 'OWASP Top 10'-sårbarheder

  • API-designs og message brokers

  • ... og andre relevante emner undervejs i semesterprojektet


Med de rammer kan jeg både afprøve ting frit og samtidig lære, hvordan man bygger noget, der fungerer sammen med resten af teamets løsning.


Det bliver udfordrende, men jeg ser frem til at bygge videre på fundamentet og se, hvordan min del kan integreres i det samlede system.



Videre plan


Jeg har sat op

  • .github (shared repo med ci workflows)

  • Skelet med Hexagonal arkitektur samt test projekter for unit og integrationstest

    • Ingestion Service

    • Media Access Service

    • Storage Service

  • README filer

ree


Næste skridt

  • Kode og udarbejde LLD

  • Forbinde mine tre services via porte og adaptere (intern kommunikation)

  • Indarbejde IT-sikkerhed med inspiration fra CIA-triaden og OWASP Top 10 (Web og API)

Jeg planlægger at arbejde i vertical slices, og starter med UC1 ud fra Storage Service.


ree



bottom of page