Uge 39: Backend Skeleton
- Kenneth H Sørensen
- Sep 24
- 4 min read
Updated: Sep 26

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.

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.

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

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.



Arkitektur og struktur (indre)
Ingestion Service eksempel
Skelet med Hexagonal Arkitektur

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

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

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.



