<?xml version="1.0" encoding="utf-8" standalone="yes"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="da">
  <title>Engineer — Software — Portefølje og noter</title>
  <subtitle>Engineer ApS — softwareudvikling &amp; IT-rådgivning i København, Danmark. En portefølje af dokumenterede ingeniørresultater inden for software, data, cloud og IT.</subtitle>
  <id>https://software.engineer.company/da/</id>
  <updated>2026-09-13T01:45:50+02:00</updated>
  <author>
    <name>Engineer ApS</name>
    <uri>https://software.engineer.company/da/</uri>
    <email>welcome@engineer.company</email>
  </author>
  <rights>Copyright © 2025 – nu · Engineer ApS</rights>
  <generator uri="https://gohugo.io/">Hugo 0.166.0</generator>
  <icon>https://software.engineer.company/assets/icons/apple/apple-touch-icon.png</icon>
  <logo>https://software.engineer.company/assets/images/brand/card.webp</logo>
  <link href="https://software.engineer.company/da/" rel="alternate" type="text/html" />
  <link href="https://software.engineer.company/da/atom.xml" rel="self" type="application/atom+xml" />
  <entry>
    <title>Har designet en omfattende infrastrukturramme for DTU, der berører 14 afdelinger, med fleksible moduler, samlede datapipelines og strukturerede supportstrategier med henblik på langsigtet udbredelse.</title>
    <id>https://software.engineer.company/da/portfolio/designed-a-comprehensive-infrastructure-framework-for-dtu-impacting-3/</id>
    <link href="https://software.engineer.company/da/portfolio/designed-a-comprehensive-infrastructure-framework-for-dtu-impacting-3/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance" scheme="https://software.engineer.company/da/categories/" />
    <category term="Datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Infrastruktur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Løsningsarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Stakeholder &amp; rapportering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Teknisk ledelse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance &amp; datakvalitet" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk dokumentation" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk ledelse &amp; rådgivning" scheme="https://software.engineer.company/da/services/" />
    <category term="Udvikling af datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/services/" />
    <summary>Designede en omfattende infrastrukturramme for DTU på tværs af 14 afdelinger — modulær, med samlede datapipelines og supportstrategier.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; På et forskningsinstitut bestående af 14 forskellige forskningsgrupper arbejdede hver gruppe med forskellige datakilder, formater, skalaer og softwareværktøjer. Den tekniske ekspertise og de tilgængelige IT‑ressourcer varierede meget på tværs af grupperne. Mens nogle få havde formået at skabe og udrulle skræddersyede IT‑løsninger, kæmpede mange med kompleksiteten af deres datainfrastrukturbehov, hvilket tog værdifuld tid og fokus fra deres kerneforskning.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Opgaven var at udtænke en løsning, der ville give forskerne mulighed for at fokusere på deres videnskabelige arbejde frem for IT‑udfordringer. Målet var at designe og implementere en skalerbar, institutdækkende datainfrastruktur, der kunne rumme de brede og forskelligartede behov hos størstedelen af forskningsgrupperne.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; En robust og fremtidssikret infrastrukturplan blev udviklet, der balancerede fleksibilitet og standardisering. Planen skitserede nøglekomponenter såsom modulær arkitektur, integrationsveje for forskellige datakilder, brugervenlige grænseflader tilpasset varierende tekniske niveauer samt skalerbare lagrings- og behandlingsløsninger. Den omfattede også strategier for onboarding, support og governance for at sikre udbredelse og bæredygtighed.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Den resulterende infrastrukturplan var både teknisk solid og strategisk afstemt med instituttets forskningsmål. Den forenede visionen for datahåndtering på tværs af organisationen, gav en klar vej til at reducere IT‑byrden på forskerne og lagde fundamentet for et fælles, effektivt og fremtidsklart forskningsdatamiljø. Planen blev vel modtaget for sin inklusivitet, klarhed og tilpasningsevne og satte en stærk retning for instituttets transformation af datainfrastrukturen.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har øget ydeevnen af geografiske datapipelines med 50 gange ved at forbedre SQL‑programmering og datamodellering på tværs af PostgreSQL, MS SQL og Google Cloud BigQuery.</title>
    <id>https://software.engineer.company/da/portfolio/accelerated-geographical-data-pipeline-performance-by-50x-by-5/</id>
    <link href="https://software.engineer.company/da/portfolio/accelerated-geographical-data-pipeline-performance-by-50x-by-5/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data warehousing" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="SQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaseoptimering" scheme="https://software.engineer.company/da/services/" />
    <category term="Design af data warehouse" scheme="https://software.engineer.company/da/services/" />
    <category term="GIS &amp; geospatiale løsninger" scheme="https://software.engineer.company/da/services/" />
    <category term="Udvikling af datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/services/" />
    <summary>Accelererede en geografisk datapipeline 50× via SQL- og datamodeloptimering på tværs af PostgreSQL, MS SQL og Google BigQuery.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Organisationen oplevede betydelige forsinkelser i behandlingen af store mængder geografiske data, hvilket påvirkede effektiviteten af datadrevne beslutningsprocesser og analytisk rapportering.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Målet var at optimere den geografiske datapipeline for at forbedre ydeevnen og reducere behandlingstiden, så dataanalyse kunne udføres mere effektivt og i realtid.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; De eksisterende SQL‑programmerings- og datamodelleringsstrukturer på tværs af PostgreSQL, MS SQL og Google Cloud BigQuery blev analyseret grundigt, hvilket afslørede flaskehalse relateret til ineffektive indekseringsstrategier, suboptimale forespørgsler og manglende constraints. For at afhjælpe dette blev datamodellerne redesignet og partitioneringsstrategier indført, avancerede indekseringsteknikker (B‑tree og GiST i PostgreSQL, filtrerede indeks i MS SQL og clustering i BigQuery) anvendt, komplekse SQL‑forespørgsler optimeret ved at refaktorere subqueries og reducere joins, samt data integrity‑constraints som foreign keys og check‑constraints indført for at sikre konsistens uden at gå på kompromis med ydeevnen.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Disse omfattende optimeringer accelererede den geografiske datapipelines ydeevne 50 gange og reducerede databehandlingstiden markant. Forbedringen muliggjorde realtidsanalyse, styrkede rapporteringskapaciteten og gav interessenterne rettidige, datadrevne indsigter, hvilket i sidste ende bidrog til mere velfunderede strategiske beslutninger.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har forbedret geografiske kortapplikationers ydeevne med 10 gange gennem en strategisk databaseovergang fra MSSQL til PostgreSQL, hvilket har optimeret behandlingen og datasikkerheden.</title>
    <id>https://software.engineer.company/da/portfolio/improved-geographical-map-application-performance-by-10x-through-6/</id>
    <link href="https://software.engineer.company/da/portfolio/improved-geographical-map-application-performance-by-10x-through-6/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="Migrering &amp; modernisering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Sikkerhed" scheme="https://software.engineer.company/da/categories/" />
    <category term="SQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databasemigrering &amp; modernisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Databaseoptimering" scheme="https://software.engineer.company/da/services/" />
    <category term="GIS &amp; geospatiale løsninger" scheme="https://software.engineer.company/da/services/" />
    <summary>Forbedrede en GIS-kortapplikation 10× ved migrering fra MSSQL til PostgreSQL — spatiale forespørgsler fra 2,5 s til under 250 ms.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Organisationens geografiske kortapplikation, der understøttede realtids‑spatialforespørgsler for mange brugere, oplevede alvorlige flaskehalse i ydeevnen. Latens ved rendering af kortlag og forespørgsler på lokationsbaserede data påvirkede både brugeroplevelsen og backend‑tjenesternes pålidelighed. Systemet byggede på en ældre Microsoft SQL Server‑database (MSSQL) uden native geospatial indeksering.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At forbedre kortapplikationens ydeevne, skalerbarhed og sikkerhed med det specifikke mål at reducere forespørgselslatensen og øge gennemløbet for spatiale operationer.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; En strategisk databasemigrering fra MSSQL til PostgreSQL med PostGIS‑udvidelsen blev ledet for at muliggøre native geospatial understøttelse. Et nyt skema optimeret til spatiale data blev designet med GiST- og SP‑GiST‑indeks på geometri- og geografikolonner, strikse foreign key- og check‑constraints defineret, over 50 millioner spatiale records migreret via ETL‑pipelines med transformation til nye SRID‑standarder (EPSG:4326), PostgreSQL‑konfigurationsparametre (work_mem, effective_cache_size) tunet og role‑based access control (RBAC) og row‑level security implementeret.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; En 10‑dobbelt forbedring i spatial forespørgselsydeevne blev opnået, og den gennemsnitlige svartid reduceret fra 2,5 sekunder til under 250 millisekunder. Backend‑CPU‑belastningen faldt med 65 %, og systemtilgængeligheden blev bedre i spidsbelastningsperioder. Sikkerheden blev også styrket med granulære adgangspolitikker og valideringsconstraints, hvilket reducerede risikoen for korruption af spatiale data.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har løst 1.000 problemer i geografiske data og tidsseriedata ved hjælp af GDAL, ArcGIS, PostGIS, Mapbox, QGIS, SQL (PL/pgSQL, Transact‑SQL) og Bash, hvilket har sikret behandling af big data i høj kvalitet.</title>
    <id>https://software.engineer.company/da/portfolio/resolved-1-000-issues-in-geographical-data-and-7/</id>
    <link href="https://software.engineer.company/da/portfolio/resolved-1-000-issues-in-geographical-data-and-7/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="SQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance &amp; datakvalitet" scheme="https://software.engineer.company/da/services/" />
    <category term="GIS &amp; geospatiale løsninger" scheme="https://software.engineer.company/da/services/" />
    <category term="Udvikling af datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/services/" />
    <summary>Løste 1.000+ problemer i geografiske og tidsseriedata med GDAL, PostGIS, ArcGIS, Mapbox, QGIS og SQL — 35 % hurtigere forespørgsler.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Under arbejdet på et storstilet geospatialt analyseprojekt stødte teamet på talrige uoverensstemmelser og anomalier i de geografiske datasæt og tidsseriedatasæt. Disse problemer påvirkede nøjagtigheden af spatiale analyser og beslutningsværktøjer på tværs af flere afdelinger.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Ansvaret var at identificere, løse og optimere over 1.000 datakvalitetsproblemer i disse komplekse datasæt for at sikre integriteten og ydeevnen af downstream‑applikationer og visualiseringer.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Spatiale fejl blev systematisk diagnosticeret og rettet med en kombination af værktøjer, herunder GDAL, QGIS og ArcGIS, og automatiserede workflows implementeret med Bash‑scripting til tilbagevendende datarensning. PostGIS blev brugt til avancerede spatiale forespørgsler og spatial indeksering, og robuste procedurer skrevet i PL/pgSQL og Transact‑SQL til at håndtere og transformere både geografiske og tidsmæssige data i PostgreSQL- og SQL Server‑databaserne. Derudover blev de rensede data integreret i interaktive visualiseringer med Mapbox.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Gennem denne indsats blev over 1.000 kritiske problemer løst, hvilket markant forbedrede datanøjagtigheden og behandlingshastigheden. Det bidrog direkte til en 35 % reduktion i køretider for spatiale forespørgsler og muliggjorde mere pålidelige spatiale analyser. Arbejdet sikrede, at data af høj kvalitet konsekvent var tilgængelige til analyse og rapportering til støtte for strategiske beslutninger på tværs af organisationen.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har designet, implementeret og administreret 6 ETL/ELT‑pipelines med Google BigQuery, MSSQL, PostgreSQL, shell‑scripting, PL/pgSQL og Transact‑SQL og integreret data til effektiv behandling via Python API.</title>
    <id>https://software.engineer.company/da/portfolio/designed-implemented-and-administered-6-etl-elt-pipelines-8/</id>
    <link href="https://software.engineer.company/da/portfolio/designed-implemented-and-administered-6-etl-elt-pipelines-8/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Cloud" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data warehousing" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/categories/" />
    <category term="Netværk &amp; VPN" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="SQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Databasedesign &amp; datamodellering" scheme="https://software.engineer.company/da/services/" />
    <category term="Design af data warehouse" scheme="https://software.engineer.company/da/services/" />
    <category term="Udvikling af datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/services/" />
    <summary>Designede og driftede 6 ETL/ELT-pipelines (BigQuery, MSSQL, PostgreSQL) — fra 3 timers manuelt arbejde til under 20 minutter, dagligt.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Organisationen havde behov for at konsolidere og behandle store mængder strukturerede data fra et fjernt data warehouse bag en IPSec VPN. Disse data var afgørende for interne analyse‑dashboards og eksterne Python API&amp;rsquo;er brugt af kunder og partnere.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Målet var at designe, implementere og vedligeholde et sæt robuste og automatiserede ETL/ELT‑pipelines til sikkert at hente, transformere og indlæse data i Google BigQuery med sikring af datanøjagtighed, ydeevne og skalerbarhed.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; 6 end‑to‑end ETL/ELT‑pipelines blev designet, implementeret og administreret på tværs af Google BigQuery, MSSQL, PostgreSQL, shell‑scripting, PL/pgSQL og Transact‑SQL. Sikre forbindelser til en fjernserver bag en IPSec VPN blev etableret, download af komprimerede dataarkiver (Parquet, CSV og .bak) planlagt, Bash- og Python‑scripts udviklet til at udtrække og klassificere filer, .bak‑filer gendannet i en lokal MSSQL Server‑instans, strukturerede data indlæst i staging‑skemaer med bcp, psql og SSIS, modulære PL/pgSQL- og T‑SQL‑procedurer skrevet til rensning og berigelse og upload og skema‑mapping til Google BigQuery automatiseret via bq CLI og Python‑baseret dataindtagelse.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Disse automatiserede pipelines reducerede den manuelle indsats og behandlingstid markant — fra over 3 timers manuelt arbejde til under 20 minutter end‑to‑end — og forbedrede dataaktualiteten fra ugentlig til daglig synkronisering. Python‑API&amp;rsquo;erne, der forbrugte dataene, opnåede en 30 % ydeevneforbedring, og den øgede synlighed hjalp forretningsanalytikere med at levere hurtigere indsigter. Løsningen forbliver skalerbar og udvidelig til nye datakilder, efterhånden som forretningen vokser.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har leveret 8 Power BI‑projekter med omfattende manualer, hvor Microsoft Power BI‑værktøjer er integreret med NodeJS API og Python FastAPI for effektiv dataanalyse og visualisering.</title>
    <id>https://software.engineer.company/da/portfolio/delivered-8-power-bi-projects-with-comprehensive-manuals-10/</id>
    <link href="https://software.engineer.company/da/portfolio/delivered-8-power-bi-projects-with-comprehensive-manuals-10/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dataanalyse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produkt &amp; krav" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Dataanalyse &amp; BI‑dashboards" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk dokumentation" scheme="https://software.engineer.company/da/services/" />
    <summary>Leverede 8 Power BI-analyseprojekter (Node.js API, Python FastAPI) med manualer — 60 % mere effektiv rapportgenerering.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Organisationen havde behov for dynamiske, visuelle indsigter i komplekse datasæt om elnettets ydeevne og geografisk fordeling for at understøtte beslutninger på tværs af tekniske og strategiske teams.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At udvikle interaktive dashboards og rapporteringsløsninger, der effektivt kunne præsentere både realtids- og historiske geografiske og elektriske data, så interessenter hurtigt kunne identificere tendenser, anomalier og nøgletal.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Microsoft Power BI blev integreret med en skræddersyet backend baseret på NodeJS API og Python FastAPI for at strømline dataindtagelse, transformation og visualisering. Dashboards blev designet og implementeret med kortvisualiseringer, målinger af energiforbrug, sporing af nedbrud og indikatorer for neteffektivitet, og genanvendelige skabeloner og detaljeret dokumentation udviklet for at understøtte skalerbarhed og brugervenlighed.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; 8 dataanalyseprojekter blev leveret, hvilket forbedrede effektiviteten af rapportgenerering med 60 % og gjorde det muligt for tværfaglige teams at træffe hurtigere, datadrevne beslutninger. Interessenterne rapporterede en markant øget forståelse af den regionale elektriske ydeevne og nøjagtigheden af ressourceplanlægningen.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har udgivet 500 rapporter om analyse af el- og GIS‑data, hvor jeg har anvendt dybdegående forskning og fejlfinding for at sikre nøjagtige geografiske og tidsmæssige big data‑indsigter.</title>
    <id>https://software.engineer.company/da/portfolio/released-500-electricity-and-gis-data-analysis-reports-11/</id>
    <link href="https://software.engineer.company/da/portfolio/released-500-electricity-and-gis-data-analysis-reports-11/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Data governance" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data warehousing" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dataanalyse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="SQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Stakeholder &amp; rapportering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance &amp; datakvalitet" scheme="https://software.engineer.company/da/services/" />
    <category term="Dataanalyse &amp; BI‑dashboards" scheme="https://software.engineer.company/da/services/" />
    <category term="GIS &amp; geospatiale løsninger" scheme="https://software.engineer.company/da/services/" />
    <summary>Udgav 500 rapporter om el- og GIS-dataanalyse — en tværgående reference for load balancing, energieffektivitet og anomalidetektion.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Teamet håndterede enorme datasæt genereret af smart‑metre installeret på tværs af flere geografiske regioner. Disse smart‑metre producerede granulære tidsserie‑data om elforbrug, som blev brugt af energianalytikere, ingeniører og regionale planlæggere til drifts- og strategiske beslutninger.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Ansvaret var at producere analytiske rapporter af høj kvalitet, gennemsigtige og reproducerbare, som kunne afdække mønstre i energiforbruget, opdage anomalier og identificere regionale forbrugstendenser, samtidig med at ikke‑tekniske interessenter let kunne fortolke og genbruge resultaterne.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Over 500 dybdegående dataanalyserapporter blev oprettet og leveret, med ren SQL til al dataudtræk, transformation og analyse direkte i cloud‑baserede miljøer som PostgreSQL og BigQuery. Dataene omfattede geolokationskoordinater, meter‑ID&amp;rsquo;er, tidsstemplet energiforbrug og miljømetadata. SQL‑scripts benyttede CTE&amp;rsquo;er, window functions, subqueries og geospatiale joins for skalerbar og effektiv behandling. Hver rapport indeholdt annoteret SQL‑kode, så kolleger fuldt ud kunne reproducere og revidere forskningen, og fejlfindingsnoter blev tilføjet og almindelige datakvalitetsproblemer dokumenteret med anbefalede håndteringsprocedurer.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Rapporterne blev en standardreference på tværs af afdelinger og hjalp med regional load balancing, planlægning af energieffektivitet og anomalidetektion. Ved at sikre fuld gennemsigtighed og reproducerbarhed hjalp det med at styrke interessenternes tillid til dataene, og arbejdet bidrog til mere præcise prognosemodeller og en 10–15 % forbedring af driftsplanlægningens effektivitet.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har arkitekteret, oprettet og administreret 100 data warehouse‑databaser i PostgreSQL, MS SQL og Google BigQuery med primært GIS- og tidsseriedata og optimeret ydeevne og skalerbarhed.</title>
    <id>https://software.engineer.company/da/portfolio/architected-created-and-managed-100-postgresql-ms-sql-12/</id>
    <link href="https://software.engineer.company/da/portfolio/architected-created-and-managed-100-postgresql-ms-sql-12/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data warehousing" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="SQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaseadministration (DBA)" scheme="https://software.engineer.company/da/services/" />
    <category term="Databasedesign &amp; datamodellering" scheme="https://software.engineer.company/da/services/" />
    <category term="Databaseoptimering" scheme="https://software.engineer.company/da/services/" />
    <category term="Design af data warehouse" scheme="https://software.engineer.company/da/services/" />
    <category term="GIS &amp; geospatiale løsninger" scheme="https://software.engineer.company/da/services/" />
    <summary>Arkitekterede og driftede 100 data warehouse-databaser (PostgreSQL, MS SQL, BigQuery) for GIS- og tidsseriedata — 40–60 % hurtigere.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; I en hurtigt voksende teknologivirksomhed var der et kritisk behov for at oprette, administrere og optimere en bred portefølje af over 100 databaser på tværs af PostgreSQL, Microsoft SQL Server og Google BigQuery. Disse databaser håndterede primært komplekse datasæt, herunder GIS‑data (spatiale koordinater og lokationsbaseret analyse) og tidsseriedata (sensoraflæsninger, logs og realtidsmetrikker). Den eksisterende infrastruktur havde udfordringer med skalerbarhed, forespørgselsydeevne og datakonsistens, efterhånden som datamængden voksede eksponentielt.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Det primære mål var at designe, implementere og administrere et skalerbart data warehouse‑økosystem med høj ydeevne skræddersyet til GIS- og tidsseriedata. Det indebar at håndtere flaskehalse i komplekse spatiale og tidsbaserede forespørgsler, sikre skalerbarhed og omkostningseffektivitet og samarbejde med tværfaglige teams om at afstemme databasedesign med forretningsbehov.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Skalerbare arkitekturer blev designet med normaliserede og denormaliserede skemaer til PostgreSQL og SQL Server, spatial indeksering (PostGIS) og tidsseriepartitionering udnyttet samt BigQuerys tidspartitionerede og clustrede tabeller. Optimeringsstrategier som indeksering, materialized views og caching blev indført, datakomprimering og kolonnelagring anvendt i BigQuery og best practices for GIS- og tidsseriedatamodellering dokumenteret til fremtidige projekter.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Initiativerne førte til betydelige forbedringer: svartider for GIS- og tidsseriedata faldt med 40–60 %, automatiseret overvågning reducerede nedetid med 50 %, og standardiserede processer øgede produktiviteten. Den optimerede infrastruktur gjorde det muligt for virksomheden at lancere nye datadrevne produkter og opfylde krav om data governance og regulatorisk compliance — hvilket styrkede organisationens evne til at håndtere komplekse datamæssige udfordringer.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har automatiseret udrulning af GIS SaaS‑applikationer, databehandling og rapporteringssystem ved hjælp af GitHub Actions CI/CD, Python, Bash og SQL.</title>
    <id>https://software.engineer.company/da/portfolio/automated-gis-saas-application-deployment-data-processing-and-16/</id>
    <link href="https://software.engineer.company/da/portfolio/automated-gis-saas-application-deployment-data-processing-and-16/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Cloud" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="SQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="GIS &amp; geospatiale løsninger" scheme="https://software.engineer.company/da/services/" />
    <category term="Udvikling af datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/services/" />
    <summary>Automatiserede GIS SaaS-udrulning, databehandling og rapportering med GitHub Actions CI/CD, Python, Bash og SQL — pålidelige releases.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Hos Utiligize var det at få GIS SaaS‑appen udrullet, behandle dens data og producere rapporterne alt sammen manuelle trin — og manuelle trin er både langsomme og stille farlige. Hver release åd engineering‑tid og bar chancen for en fejl, og det tilbagevendende data- og rapporteringsarbejde sad der og åd kapacitet uge efter uge.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At automatisere hele vejen fra kode til produktion, plus det tilbagevendende databehandlings- og rapporteringsarbejde, var opgaven — målet var releases, der var hurtige, sikre og reproducerbare frem for et omhyggeligt manuelt ritual hver gang.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Hele vejen blev automatiseret. GitHub Actions‑pipelines overtog test‑build‑deploy‑cyklussen, så en release holdt op med at afhænge af, at nogen huskede trinene. Den tilbagevendende databehandling og rapporterne flyttede over i planlagte Python-, Bash- og SQL‑jobs, så de bare kørte i stedet for at være nogens pligt. Og konfigurationen og secrets blev standardiseret, så hvert miljø opførte sig ens — hvilket er det, der dræber &amp;ldquo;det virker på min maskine&amp;rdquo;-overraskelserne, for der holder op med at være en &amp;ldquo;min maskine&amp;rdquo;, der er anderledes end produktion.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Udrulning, databehandling og rapportering blev alle automatiserede og pålidelige, det manuelle slid kom af teamets bord, og releasecyklussen blev kortere. Teamet kunne rette sin opmærksomhed mod produktet i stedet for driften, der var pakket omkring det.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har automatiseret levering af 20 GIS‑datapipelines og ETL‑processer for appdata og strømlinet infrastrukturautomatisering og rapportering.</title>
    <id>https://software.engineer.company/da/portfolio/automated-delivery-of-20-gis-data-pipelines-and-17/</id>
    <link href="https://software.engineer.company/da/portfolio/automated-delivery-of-20-gis-data-pipelines-and-17/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="Monitorering &amp; observability" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="GIS &amp; geospatiale løsninger" scheme="https://software.engineer.company/da/services/" />
    <category term="Udvikling af datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/services/" />
    <summary>Automatiserede 20 GIS-datapipelines og ETL-processer for appdata — strømlinet infrastrukturautomatisering og pålidelige, aktuelle data.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Platformen kørte på en masse GIS‑datapipelines og ETL‑processer for appdata, og de blev leveret og overvåget i hånden. Håndkørte pipelines skaber flaskehalse, de driver ud af konsistens, og værst af alt bærer de en konstant lav risiko for, at en stille fejler, og ingen bemærker det, før dataene allerede er forkerte længere nede.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At automatisere leveringen af de pipelines og ETL‑processer — så dataene flød pålideligt og forudsigeligt uden nogen til at føre dem igennem — var opgaven.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Tyve GIS‑datapipelines og ETL‑processerne for appdata kom under automatiseret levering, fra ende til anden. Planlægningen, loggingen og fejlhåndteringen blev standardiseret, så hver pipeline opførte sig ens og, afgørende, man kunne se, når en ikke gjorde — en stille fejl er kun stille, hvis intet holder øje. Og de blev foldet ind i den eksisterende infrastrukturautomatisering og rapportering, så de var en del af ét sammenhængende system frem for en skuffe fuld af scripts, nogen skulle huske at køre.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Alle tyve pipelines og deres ETL kørte automatisk og forudsigeligt, og hele billedet af infrastrukturautomatisering og rapportering blev pænere for det. Forretningen fik pålidelige, aktuelle data, uden at nogen skulle gå dem igennem i hånden — og uden den stille‑fejl‑risiko hængende over sig.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har ledet softwareudviklingen af en GIS‑kortapplikation, øget omsætningen 10 gange og positioneret produktet som et primært dataaktiv.</title>
    <id>https://software.engineer.company/da/portfolio/led-the-software-development-of-a-gis-map-24/</id>
    <link href="https://software.engineer.company/da/portfolio/led-the-software-development-of-a-gis-map-24/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="DevOps" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="Løsningsarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Mentoring &amp; coaching" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produkt &amp; krav" scheme="https://software.engineer.company/da/categories/" />
    <category term="Teamledelse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Teknisk ledelse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="GIS &amp; geospatiale løsninger" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <category term="Produktstrategi &amp; kravspecifikation" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk ledelse &amp; rådgivning" scheme="https://software.engineer.company/da/services/" />
    <summary>Ledede udviklingen af en GIS-kortapplikation, der blev en platformshjørnesten og drev en 10× omsætningsstigning via mersalg og datalicensering.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Kerneudfordringen var at bygge en platform, der kunne spore, overvåge og optimere vedvarende energiaktiver som solpaneler og vindmøller. Den oprindelige løsning manglede dog robuste geospatiale funktioner, hvilket gjorde det svært for kunder at visualisere aktivlokationer, analysere spatiale data eller udlede handlingsorienterede indsigter. Ledelsen prioriterede derfor udviklingen af en GIS‑kortapplikation for at øge platformens værdi.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Opgaven var at lede udviklingen af GIS‑applikationen, en kritisk komponent til at differentiere produktet på det konkurrenceprægede marked for grøn energi. Rollen strakte sig ud over softwareudvikling — som teknisk leder, DevOps‑ingeniør, dataingeniør og SRE. Målet var at skabe et skalerbart, intuitivt GIS‑værktøj, der integrerede problemfrit med SaaS‑platformen, og som kunne udvikle sig i takt med virksomheden.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Det begyndte med at samarbejde med interessenter om at definere applikationens kernefunktioner med fokus på integration med den eksisterende SaaS‑platform og realtidsvisualisering. På grund af det lille team blev en modulær arkitektur designet med open source‑GIS‑biblioteker for at holde systemet let og skalerbart. CI/CD‑pipelines, automatiseret infrastrukturprovisionering og overvågning blev også implementeret. Efterhånden som teamet voksede, blev nye ingeniører mentoreret, tværfagligt samarbejde faciliteret og brugerfeedback prioriteret for at forfine applikationen iterativt.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; GIS‑applikationen blev en hjørnesten i SaaS‑platformen og drev en 10‑dobbelt stigning i omsætningen gennem mersalg, datalicensering og nye kunder. Dens evne til at visualisere grønne energiaktiver i realtid forbedrede kundernes driftseffektivitet, og den løbende forfining positionerede den som et primært dataaktiv. Projektets succes styrkede virksomhedens omdømme i sektoren for vedvarende energi og demonstrerede værdien af en tværfaglig tilgang i et hurtigt voksende startup‑miljø.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har styret full‑stack‑udvikling af GIS‑kort med ansvar for PostgreSQL, Mapbox, ReactJS og NodeJS for at levere en integreret løsning.</title>
    <id>https://software.engineer.company/da/portfolio/directed-full-stack-gis-map-development-overseeing-postgresql-25/</id>
    <link href="https://software.engineer.company/da/portfolio/directed-full-stack-gis-map-development-overseeing-postgresql-25/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Teknisk ledelse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="GIS &amp; geospatiale løsninger" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk ledelse &amp; rådgivning" scheme="https://software.engineer.company/da/services/" />
    <summary>Styrede full-stack GIS-kortudvikling (PostgreSQL, Mapbox, React, Node.js) — én integreret, udvidbar kerne i platformen.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; På det her tidspunkt var GIS‑kortet holdt op med at være en funktion og var blevet grunden til, at kunderne overhovedet loggede ind. Problemet var, at det var vokset op i stumper. De spatiale data lå i PostgreSQL, selve kortet blev tegnet med Mapbox, og applikationen omkring det var ReactJS i frontenden med NodeJS bagved. Hver del virkede for sig. De var bare ikke bygget til at passe sammen, og sømmene begyndte at vise sig.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Rollen dækkede full‑stack‑udviklingen af kortet og den tekniske retning, der fulgte med: datamodellen, renderingen, API&amp;rsquo;et og React‑frontenden. Målet var at gøre fire ting, der tilfældigvis delte et repository, til ét produkt, der var værd at stå inde for.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Arkitekturen blev fastlagt først, og så blev arbejdet tæt på koden i stedet for at styre på afstand. På datasiden blev den spatiale model i PostgreSQL holdt ryddelig, så forespørgslerne ikke sneglede sig af sted, efterhånden som datasættene voksede. Mapbox stod for tegningen; opgaven var at fodre den med de rigtige data på de rigtige zoomniveauer i stedet for det hele på én gang. På applikationssiden blev ReactJS- og NodeJS‑arbejdet reviewet, teamet skubbet mod fælles konventioner, og ansvar flyttet tilbage til det lag, det hørte til i, når ét begyndte at lække ind i det næste. En god del af det var uglamourøst arbejde: at fange de små inkonsistenser, før de størknede til arkitektur.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Det, der kom ud, var én integreret kortapplikation, hvor data, rendering og grænseflade endelig trak samme vej. Den blev en central del af platformen og noget, teamet kunne blive ved med at bygge videre på, uden at den knækkede sammen, hver gang et lag blev tilføjet.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har optimeret prognose- og investeringsstrategier for 11 eldistributionsoperatører og øget driftseffektiviteten gennem datadrevne GIS‑løsninger.</title>
    <id>https://software.engineer.company/da/portfolio/optimized-forecasting-and-investment-strategies-for-11-electricity-27/</id>
    <link href="https://software.engineer.company/da/portfolio/optimized-forecasting-and-investment-strategies-for-11-electricity-27/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dataanalyse" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produkt &amp; krav" scheme="https://software.engineer.company/da/categories/" />
    <category term="Stakeholder &amp; rapportering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dataanalyse &amp; BI‑dashboards" scheme="https://software.engineer.company/da/services/" />
    <category term="GIS &amp; geospatiale løsninger" scheme="https://software.engineer.company/da/services/" />
    <category term="Produktstrategi &amp; kravspecifikation" scheme="https://software.engineer.company/da/services/" />
    <summary>Optimerede prognoser og investeringsstrategi for 11 eldistributionsoperatører med datadrevet GIS — troværdig, målrettet planlægning.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Eldistributionsoperatører står og falder på beslutninger om, hvor de skal forstærke nettet, og hvor de skal placere deres penge, og elleve af dem traf de beslutninger uden meget geospatial analyse under sig. De havde driftsdataene. Det, de ikke havde, var en måde at se dem på kortet, dér hvor mønstrene faktisk lever.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Opgaven var at skærpe deres prognoser og investeringsstrategier med GIS — at gøre tabeller af aflæsninger til noget, der viste dem, hvor kapaciteten blev knap, hvor risikoen byggede sig op, og hvor den næste krone var bedst givet ud.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Deres driftsdata blev bragt sammen med geospatial modellering, så de to forstærkede hinanden. I stedet for at lave prognoser i det abstrakte kunne nettet ses rumligt og stilles konkrete spørgsmål: hvilke strækninger var på vej mod deres grænser, hvilke områder retfærdiggjorde investering først. For elleve operatører betød det at tilpasse analysen til, hvordan hver af dem faktisk drev deres net, ikke at række alle den samme skabelon og håbe, den passede.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Operatørerne gik derfra med prognoser, de kunne stole på, og investeringsbeslutninger, der var målrettede frem for håbefulde. At forankre planlægningen i det, kortet viste, gjorde det hele mere effektivt — penge og opmærksomhed gik derhen, hvor dataene pegede, i stedet for derhen, hvor vanen gjorde.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har præsenteret 200 UI/UX‑forbedringer til GIS‑kortapplikationen og øget omsætningen 10 gange gennem forbedrede softwarefunktioner.</title>
    <id>https://software.engineer.company/da/portfolio/presented-200-ui-ux-improvements-for-the-gis-28/</id>
    <link href="https://software.engineer.company/da/portfolio/presented-200-ui-ux-improvements-for-the-gis-28/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Dataanalyse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produkt &amp; krav" scheme="https://software.engineer.company/da/categories/" />
    <category term="Stakeholder &amp; rapportering" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Produktstrategi &amp; kravspecifikation" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <summary>Leverede 200 UI/UX-forbedringer til en GIS-kortapplikation og bidrog til en 10× omsætningsstigning — omhyggelig UX som kommerciel driver.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Kortgrænsefladen var blevet kraftfuld og undervejs kompliceret. Der var steder, hvor man kunne mærke kunderne ikke få den værdi, der sad lige foran dem — god funktionalitet fanget bag klodsede interaktioner. Det gab mellem, hvad produktet kunne, og hvad folk fandt let at gøre, kostede os stille og roligt.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Opgaven var at finde de gab og skubbe rettelserne igennem: det brugervenlighedsarbejde, der ville gøre produktet lettere at få værdi ud af og — ikke tilfældigt — mere værd kommercielt.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; I stedet for at gætte på, hvad der var galt, gik arbejdet i feedbacken og brugsdataene, og ud af det kom en backlog på 200 konkrete UI/UX‑forbedringer. De blev ikke behandlet som ens — rangeret efter effekt, med dem, der betød noget, argumenteret for og ført gennem teamet for at blive sendt ud som rigtige funktioner i stedet for en ønskeliste, der lå og blev forældet i et dokument.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Grænsefladen blev mærkbart bedre at bruge, og produktets værdi fulgte efter: arbejdet bidrog til en tidobling af omsætningen. Det er et eksempel, der er værd at vende tilbage til, fordi det gør pointen rent — omhyggeligt UX‑arbejde er ikke kosmetik, det dukker op på fakturaen.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har styret gennemførelsen af 30 succesfulde GIS‑projekter og udvist lederskab i leveringen af innovative løsninger på tværs af feltet.</title>
    <id>https://software.engineer.company/da/portfolio/managed-the-execution-of-30-successful-gis-projects-32/</id>
    <link href="https://software.engineer.company/da/portfolio/managed-the-execution-of-30-successful-gis-projects-32/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Agile &amp; Scrum" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="Projektledelse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Stakeholder &amp; rapportering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Teamledelse" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS &amp; geospatiale løsninger" scheme="https://software.engineer.company/da/services/" />
    <category term="Projektledelse (Agile)" scheme="https://software.engineer.company/da/services/" />
    <category term="Teamopbygning &amp; mentoring" scheme="https://software.engineer.company/da/services/" />
    <summary>Leverede 30 succesfulde GIS-projekter — en historik af konsistent, innovativ levering, der skabte varig kundetillid.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Mappitall tjente sine penge på at levere GIS‑projekter, og der kørte mange af dem på én gang. Virksomhedens vækst red på at få dem ud ad døren pålideligt — ikke ét flagskibsprojekt gjort strålende, men en stabil strøm af dem, der landede til tiden og hang sammen, hvilket kun sker, når koordineringen på tværs af teamet faktisk fungerer.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Ansvaret var at få den portefølje leveret — at holde scope, folk og tidsplaner på linje på tværs af det hele og give teamet den retning, der skulle til for at levere.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Gennem de år kørte leveringen af tredive GIS‑projekter gennem den her rolle. I praksis betød det at holde scope i ro, når det ville krybe, at pege de rigtige folk mod det rigtige arbejde og at være tæt nok på hvert projekt til at fange problemer, mens de stadig var små. Når noget var ved at skride, bedre at vide det tidligt og rokere om end finde ud af det ved deadline. En stor del af jobbet var bare at holde tallerknerne i luften og kundens forventninger ærlige om, hvad der kom hvornår.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Alle tredive kom i mål. Den konsistens betød mere, end noget enkelt projekt ville have gjort — en kunde, der har set dig levere tredive gange, bekymrer sig ikke om den enogtredivte, og det omdømme er en god del af, hvorfor virksomheden blev ved med at vokse.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har ledet udvikling, idriftsættelse og support af over 30 GIS‑projekter og udvist ekspertise i PostgreSQL, Bash, Python, JavaScript, GDAL, ArcGIS, PostGIS og Mapbox.</title>
    <id>https://software.engineer.company/da/portfolio/led-the-development-deployment-and-support-of-over-35/</id>
    <link href="https://software.engineer.company/da/portfolio/led-the-development-deployment-and-support-of-over-35/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="SQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Teamledelse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Teknisk ledelse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="GIS &amp; geospatiale løsninger" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk ledelse &amp; rådgivning" scheme="https://software.engineer.company/da/services/" />
    <category term="Udvikling af datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/services/" />
    <summary>Ledede udvikling, drift og support af 30+ GIS-projekter med PostgreSQL, Python, GDAL, ArcGIS, PostGIS og Mapbox — hele livscyklussen.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Virksomhedens hele output var made‑to‑measure GIS — skræddersyet kortlægning og geodata‑systemer bygget til en kundes konkrete problem og så holdt kørende, når de var live. At bygge tingen er kun halvdelen; et geospatialt projekt, der ryger ud og så vælter i produktion, er ikke rigtig blevet leveret.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; De projekter kørte fra ende til anden gennem den her rolle — udviklingen, udrulningen og supporten, når de først var live — med den tekniske retning på tværs af en ret bred stak.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Leveringen kørte på mere end tredive GIS‑projekter, hands‑on på tværs af stakken hele vejen. PostgreSQL med PostGIS under til geodataene, GDAL/OGR til at flytte dem mellem formater — shapefiles, GeoJSON, GeoTIFF, KML, vector tiles — og QGIS og JOSM til selve dataarbejdet. Foran på det webkort bygget på Mapbox GL og Leaflet, nogle gange mod ArcGIS- eller HERE‑API&amp;rsquo;erne, med app‑laget i JavaScript, Python, PHP og SQL. Arbejdet spændte fra 2D- og 3D‑digital kortlægning over LiDAR‑behandling, georektifikation og vektorisering til indendørs kortlægning og navigation. Og ansvaret rakte forbi det punkt, tingen var sendt af sted — udrulningen og den løbende support i produktion var også en del af det, så problemer blev ikke givet videre; beslutningerne skulle leves med.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Tredive‑plus projekter bygget, udrullet og supporteret på tværs af hele det spænd. At stå på krogen for hele livscyklussen frem for bare bygget er det, der holdt kvaliteten ærlig — man designer anderledes, når man ved, det er en selv, der får opkaldet, hvis det går i stykker.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bidraget til designprocesser for brugergrænseflader og sikret intuitive, visuelt tiltalende og brugervenlige projektgrænseflader.</title>
    <id>https://software.engineer.company/da/portfolio/contributed-to-user-interface-design-processes-ensuring-intuitive-36/</id>
    <link href="https://software.engineer.company/da/portfolio/contributed-to-user-interface-design-processes-ensuring-intuitive-36/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <summary>Bidrog til UI-design med intuitive, forfinede og brugervenlige grænseflader — brugervenlighed stillet under design, ikke efter.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Grænsefladerne på tværs af projekterne var ujævne. Nogle var fine, nogle var tydeligvis bygget af ingeniører, der tænkte på datamodellen frem for den person, der skulle bruge dem, og designbeslutningerne blev ikke altid truffet med slutbrugeren i rummet. På et webkort‑produkt især er kortet den nemme del — det er kontrollerne, filtreringen og flowet rundt om det, hvor folk farer vild.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At blande sig i UI‑designprocessen var en del af rollen — for at hjælpe med at gøre grænsefladerne til noget, folk faktisk fandt intuitivt og behageligt at bruge, ikke bare funktionelt.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Rollen var ikke designerens, men den sad med i designprocessen og bragte et engineering‑perspektiv ind — pressede på layout, på flowet gennem en opgave, på om en skærm faktisk var klar eller bare var velkendt for dem, der havde bygget den. Det her var React-, Angular- og Vue‑frontends oven på Mapbox- og Leaflet‑kort, og en stor del af brugervenligheden lå i detaljerne: hvordan man filtrerede et datasæt, hvordan man skiftede mellem etager på et indendørskort, om tingen fortalte dig, hvad den lavede. Mest af alt betød det at stille de dumme brugerspørgsmål tidligt, mens de stadig var billige at rette, i stedet for efter release, når forvirringen kom tilbage som supportsager.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Grænsefladerne blev mere intuitive og mere forfinede, hvilket slutbrugerne mærkede direkte, og det løftede den samlede kvalitet af det, der blev sendt ud. At få brugervenlighedsspørgsmålene stillet under design frem for efter release er det meste af, hvad der gjorde forskellen.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har gennemgribende fornyet interne processer og sparet 8.000 timer ved at forbedre softwarearkitektur, systemer og planlægningseffektivitet.</title>
    <id>https://software.engineer.company/da/portfolio/overhauled-internal-processes-saving-8-000-hours-by-38/</id>
    <link href="https://software.engineer.company/da/portfolio/overhauled-internal-processes-saving-8-000-hours-by-38/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Infrastruktur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Løsningsarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Projektledelse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Teknisk ledelse" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <category term="Projektledelse (Agile)" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk ledelse &amp; rådgivning" scheme="https://software.engineer.company/da/services/" />
    <summary>Fornyede interne processer og sparede ~8.000 timer ved at forbedre softwarearkitektur, systemer og planlægningseffektivitet.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Måden, tingene blev gjort internt på, havde samlet den sædvanlige rust — softwarearkitektur, der var vokset ved aflejring frem for design, systemer, der virkede, men ikke effektivt, planlægning, der lod folk enten vente eller være pressede. Intet af det brændte, hvilket er præcis derfor, det var blevet ladt i fred, men det kostede stille og roligt en masse tid.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Målet var at forny de processer gennemgribende — at gå ud og finde spildet og tage det ud frem for at blive ved med at betale for det.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; De interne processer blev omarbejdet på tre fronter: softwarearkitekturen, så den var noget, man kunne ræsonnere om og bygge på i stedet for at arbejde uden om; systemerne, strømlinet, så det rutineprægede arbejde holdt op med at tage længere tid, end det burde; og planlægningen, så kapaciteten faktisk blev matchet med arbejdet. Og ændringerne blev gjort til at sidde fast — forankret i, hvordan teamet opererede, frem for efterladt som et notat, alle nikkede til og glemte — for procesforbedringer, der ikke gøres permanente, forfalder bare tilbage til den gamle måde.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Fornyelsen sparede omkring 8.000 timer ved at gøre arkitekturen, systemerne og planlægningen mærkbart mere effektive. Det er kapacitet, der gik direkte tilbage i arbejde med højere værdi i stedet for i overhead, ingen havde tænkt på at stille spørgsmål ved.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har udviklet et rapporteringssystem til dataanalyse og øget den kvartalsvise softwareomsætning med 400 % gennem Python‑baserede PDF‑rapporter.</title>
    <id>https://software.engineer.company/da/portfolio/developed-a-data-analytics-reporting-system-increasing-quarterly-44/</id>
    <link href="https://software.engineer.company/da/portfolio/developed-a-data-analytics-reporting-system-increasing-quarterly-44/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dataanalyse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produkt &amp; krav" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="Stakeholder &amp; rapportering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Dataanalyse &amp; BI‑dashboards" scheme="https://software.engineer.company/da/services/" />
    <category term="Produktstrategi &amp; kravspecifikation" scheme="https://software.engineer.company/da/services/" />
    <summary>Byggede et Python-rapporteringssystem til dataanalyse, der øgede den kvartalsvise softwareomsætning 400 % med klare, rettidige rapporter.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Interessenterne fik ikke analyse i nogen rettidig, læsbar form. Dataene fandtes, men at omsætte dem til noget, man faktisk kunne træffe en beslutning ud fra, var langsomt og manuelt, så indblikket i, hvordan tingene præsterede, haltede, og de kommercielle beslutninger haltede med.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At bygge et rapporteringssystem til dataanalyse — et, der omsatte rådata til klar, regelmæssig indsigt uden at nogen håndsamlede det hver gang — var jobbet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Et rapporteringssystem genererede PDF‑rapporter i Python og automatiserede hele kæden: at trække dataene, køre analysen og præsentere det i et rent, konsistent format, interessenterne faktisk kunne læse. Pointen var regelmæssighed og klarhed — den samme professionelle rapport landede forudsigeligt, så tallene blev noget, folk kiggede på som en selvfølge frem for noget, de skulle gå ud og grave frem.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Den rapportering er det, der drev den kvartalsvise softwareomsætning op med 400 %. At gøre analysen bedre og hurtigere var ikke en back‑office‑finesse — sæt klare, rettidige tal foran de folk, der træffer kommercielle beslutninger, og beslutningerne bliver bedre, og her viste det sig direkte på omsætningen.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har udviklet 100 webapplikationer med HTML/HTML5, CSS/SCSS, Django, WordPress og Joomla og sikret en alsidig online tilstedeværelse.</title>
    <id>https://software.engineer.company/da/portfolio/developed-100-web-applications-using-html-html5-css-51/</id>
    <link href="https://software.engineer.company/da/portfolio/developed-100-web-applications-using-html-html5-css-51/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Udviklede 100 webapplikationer med HTML5, CSS/SCSS, Django, WordPress og Joomla — hver løsning matchet til kundens reelle behov.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Kunder ville have webapplikationer, og de ville have vidt forskellige ting — forskellige størrelser, forskellige budgetter, forskellige niveauer af &amp;ldquo;få mig bare online&amp;rdquo; over for &amp;ldquo;byg mig noget skræddersyet.&amp;rdquo; At møde det betød at være alsidig frem for at tvinge hver kunde ned ad den samme teknologi.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At bygge webapplikationer, der gav hver kunde en alsidig, effektiv online tilstedeværelse, var jobbet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Hundrede webapplikationer blev bygget, og pointen var at matche værktøjet til opgaven frem for at have en favorit. Hvor en kunde havde brug for noget skræddersyet, var det HTML/HTML5, CSS/SCSS og Django; hvor de havde brug for noget mere standard, som de også selv kunne håndtere, var WordPress eller Joomla det hurtigere, mere fornuftige svar. En del af færdigheden var at vide, hvad der var hvad — at tale en kunde fra et skræddersyet build, de ikke havde brug for, eller til et, de havde.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; De hundrede applikationer gav kunderne en varieret, kompetent online tilstedeværelse, hver leveret på den teknologi, der faktisk passede til den. At matche tilgangen til kunden frem for omvendt er det, der gjorde dem effektive frem for bare leveret.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har designet 30 websites og leveret unikke og fleksible løsninger ved at konvertere Photoshop‑designs til HTML.</title>
    <id>https://software.engineer.company/da/portfolio/designed-30-websites-delivering-unique-and-flexible-solutions-52/</id>
    <link href="https://software.engineer.company/da/portfolio/designed-30-websites-delivering-unique-and-flexible-solutions-52/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Designede 30 websites og konverterede Photoshop-designs til HTML — distinktive, forfinede og vedligeholdelige webtilstedeværelser.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Kunder kom ind med et udseende, de ville have — ofte et færdigt visuelt design — og havde brug for et website bygget trofast ud fra det. Afstanden mellem en designfil og et fungerende site er der, hvor en masse kvalitet vindes eller tabes: det er nemt at sende noget ud, der er nogenlunde rigtigt og subtilt forkert.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At designe siderne og konvertere designene til nøjagtige, fleksible implementeringer var jobbet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Tredive websites blev designet og Photoshop‑designene konverteret til HTML i hånden. Trofast var standarden — mellemrummene, typografien, de detaljer, designeren faktisk mente, ikke en tilnærmelse af dem — men det var fleksibel også, for et site, der matcher mockuppen pixel for pixel og så falder fra hinanden i det øjeblik, indholdet ændrer sig, er ikke rigtig bygget godt. Så målet var markup, der forblev tro mod designet og forblev vedligeholdelig bagefter.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; De tredive sites matchede deres designs og forblev brugbare — distinktive, forfinede webtilstedeværelser, der ikke gik i stykker første gang, nogen redigerede dem. Trofast mod designet og stadig vedligeholdelig er den balance, der betød noget, og det er der, disse landede.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har administreret 40 websites på Ubuntu Linux‑hostingservere med Apache og Nginx og sikret høj tilgængelighed og ydeevne.</title>
    <id>https://software.engineer.company/da/portfolio/administered-40-websites-on-ubuntu-linux-hosting-servers-53/</id>
    <link href="https://software.engineer.company/da/portfolio/administered-40-websites-on-ubuntu-linux-hosting-servers-53/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Infrastruktur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Linux &amp; servere" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Systemadministration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Site reliability &amp; monitorering" scheme="https://software.engineer.company/da/services/" />
    <category term="Systemadministration" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Administrerede 40 websites på Ubuntu Linux med Apache og Nginx — høj tilgængelighed og ydeevne, hosting man ikke behøvede tænke over.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Der var en portefølje af live websites, der skulle blive oppe og blive hurtige — og hosting er endnu et af de jobs, der er usynlige, indtil et site går ned, hvorefter det er det eneste, nogen bekymrer sig om.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At administrere de sites og holde dem højt tilgængelige og hurtige var jobbet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Fyrre websites kørte på Ubuntu Linux‑hostingservere, på en blanding af Apache og Nginx — konfigurationen, ydeevnetuningen, den løbende vedligeholdelse for at holde dem pålidelige under reel trafik. Reel trafik er det afgørende: et site, der er fint, når ingen bruger det, og vælter, når de gør, er ikke blevet administreret, det er bare blevet ladt i fred. Så arbejdet var at holde dem sunde under faktisk belastning.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Alle fyrre kørte med høj tilgængelighed og god ydeevne, hvilket gav kunderne hosting, de ikke behøvede at tænke over. Stabil og pålidelig under reel brug er hele pointen med hosting, og det er det, disse leverede.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Arkitekt, udviklet, implementeret, understøttet infrastruktur, databehandling og kortapplikationen i 2 år uden pause, uden weekender, helligdage eller ferie, 10–14 timer om dagen.</title>
    <id>https://software.engineer.company/da/portfolio/architected-developed-implemented-supported-infrastructure-data-processing-and-55/</id>
    <link href="https://software.engineer.company/da/portfolio/architected-developed-implemented-supported-infrastructure-data-processing-and-55/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="GIS / Geospatial" scheme="https://software.engineer.company/da/categories/" />
    <category term="Infrastruktur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="GIS &amp; geospatiale løsninger" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <category term="Site reliability &amp; monitorering" scheme="https://software.engineer.company/da/services/" />
    <category term="Udvikling af datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/services/" />
    <summary>Arkitekterede, byggede og driftede infrastruktur, databehandling og kortapp i to år uden pause — produktets pålidelige rygrad.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; En green energy‑startup i en tidlig fase var afhængig af én platform til at spore, overvåge og optimere vedvarende energiaktiver, men havde hverken et dedikeret infrastrukturteam eller en etableret ingeniørorganisation til at bygge og drive den. Hele det tekniske fundament — cloud‑infrastruktur, datapipelines og den kundevendte GIS‑kortapplikation — skulle skabes og holdes kørende uafbrudt, på et marked hvor enhver nedetid eller datamangel direkte svækkede kundernes tillid og omsætningen.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Opgaven var egenhændigt at arkitektere, bygge og drive hele systemet fra ende til anden — på tværs af platform- og dataingeniørarbejde, DevOps og site reliability. Ud over at skrive softwaren betød det at eje produktionsmiljøet: at provisionere og hærde infrastruktur, designe databehandlingslaget der fodrede kortet, og garantere at applikationen forblev tilgængelig døgnet rundt for en voksende kundebase — alt sammen inden for en hurtig startups rammer og ubønhørlige tempo.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; I to år blev infrastrukturen, datapipelines og kortapplikationen designet, implementeret og understøttet uden afbrydelse — uden weekender, helligdage eller ferie, ofte ti til fjorten timer om dagen. En pragmatisk, modulær arkitektur blev valgt for at holde en enmandsdrift vedligeholdelsesvenlig, med automatiseret provisionering, monitorering og alarmering, så problemer kunne opdages og løses hurtigt. Databehandlingen blev løbende optimeret for pålidelighed og ydeevne, releases blev udrullet trinvist, og hvert lag — fra servere til det brugervendte kort — blev personligt vedligeholdt og forbedret ud fra reel kundeanvendelse.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Platformen forblev konstant tilgængelig og udviklede sig fra en skrøbelig tidlig prototype til produktets pålidelige rygrad og bar virksomheden gennem dens kritiske vækstfase alene på styrken af én ingeniørs ejerskab. Denne praktiske forvaltning holdt infrastruktur, data og kortapplikation pålidelig nok til at understøtte mersalg, datalicensering og tiltrækning af nye kunder og demonstrerede en sjælden grad af engagement, bredde og ansvar fra ende til anden på tværs af hele stakken.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har optimeret budgetomkostningerne 10 gange uden tab af produktivitet for den saudiarabiske virksomhed ved at nytænke den samlede infrastruktur, fjerne unødvendige tjenester og flytte væk fra AWS‑skyen.</title>
    <id>https://software.engineer.company/da/portfolio/optimized-budget-costs-10-times-with-zero-loss-56/</id>
    <link href="https://software.engineer.company/da/portfolio/optimized-budget-costs-10-times-with-zero-loss-56/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Cloud" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps" scheme="https://software.engineer.company/da/categories/" />
    <category term="Infrastruktur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Løsningsarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Migrering &amp; modernisering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Cloud‑infrastruktur &amp; migrering" scheme="https://software.engineer.company/da/services/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <summary>Reducerede infrastrukturbudgettet 10× uden produktivitetstab for en saudiarabisk virksomhed ved at nytænke stacken og forlade AWS.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; En virksomhed med base i Saudi‑Arabien slæbte rundt på slemt oppustede infrastrukturomkostninger. Deres AWS‑setup var blevet overdimensioneret og havde samlet tjenester, de ikke længere brugte, så cloud‑regningen var drevet fuldstændig ud af proportion med, hvad forretningen faktisk havde brug for. Det er en almindelig historie — ingen sætter sig for at overforbruge, det aflejrer sig bare, når ingen holder øje med måleren.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Opgaven var at skære omkostningerne betydeligt ned uden at miste produktivitet, hvilket betød at gentænke infrastrukturen ordentligt frem for at beskære i kanterne — kantbeskæring flytter sjældent en regning, der er strukturelt for stor.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Så arbejdet gik fra ende til anden. Først kom en audit af, hvad der faktisk blev brugt — hvilket er der, de duplikerede og unødvendige tjenester viser sig — og de blev skåret væk. Så blev det, der var tilbage, right‑sizet til at matche reel efterspørgsel i stedet for de worst‑case‑gæt, det oprindelige setup var bygget på. Og det store træk var at flytte workloads helt væk fra AWS, over på et mere omkostningseffektivt hosting‑arrangement — gjort omhyggeligt, i etaper, så den kørende forretning aldrig mærkede migreringen ske under sig.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Budgetomkostningerne faldt omkring ti gange, uden tab af produktivitet — den samme kapabilitet til en brøkdel af, hvad de havde betalt. Det frigjorde et reelt beløb, der stille og roligt var sivet ud i en overdimensioneret cloud‑regning måned efter måned, hvilket for forretningen var penge direkte tilbage på bundlinjen.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har arkitekteret en lagdelt maritim platform, der adskiller en Next.js PWA‑frontend, et Go (Huma/Fiber) API og et PostgreSQL‑funktionslag og holder al forretningslogik i databasen.</title>
    <id>https://software.engineer.company/da/portfolio/architected-a-layered-maritime-platform-separating-a-next-57/</id>
    <link href="https://software.engineer.company/da/portfolio/architected-a-layered-maritime-platform-separating-a-next-57/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Løsningsarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Teknisk ledelse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Databasedesign &amp; datamodellering" scheme="https://software.engineer.company/da/services/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <summary>Arkitekterede en lagdelt maritim platform — Next.js PWA, et Go (Huma/Fiber) API og et PostgreSQL-funktionslag med al forretningslogik.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; NextMariner skulle være en maritim platform — professionelt netværk, virksomhedsanmeldelser, sponsoreret uddannelse — og det var et ungt produkt, hvilket er en pæn måde at sige, at kravene ville flytte sig en hel del. Det, der skulle undgås, var en arkitektur, hvor en ændret forretningsregel betød, at man skulle røre frontenden, API&amp;rsquo;et og databasen på én gang. På en lille kodebase, der vokser hurtigt, er det den slags kobling, der gør en to‑linjers ændring til en hel eftermiddag.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Som arkitekt var beslutningen på forhånd, hvor hver slags logik boede, med grænser tydelige nok til at holde under pres, i stedet for at blive udvisket første gang nogen havde travlt.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Det landede på tre lag, ét job hver. Next.js‑frontenden står for præsentation og interaktivitet og intet andet. Go‑API&amp;rsquo;et — Huma oven på Fiber — er bevidst tyndt: det router, validerer requesten, laver sikkerhedsfiltreringen og orkestrerer, men det rummer slet ingen forretningslogik. Forretningslogikken bor i PostgreSQL‑funktioner, som samler det fulde resultat og giver det tilbage, som API&amp;rsquo;et videresender. Så når en regel ændrer sig, ændrer den sig i ét lag, i SQL, og de to andre behøver ikke vide det. Grænserne blev skrevet ned og håndhævet i review, for en konvention, ingen holder øje med, holder op med at være en.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Tingen forblev nem at holde i hovedet. Forretningslogikken sidder ét sted, man faktisk kan revidere, API&amp;rsquo;et er en kedelig adapter på den gode måde, og frontenden er ligeglad, når skemaet flytter sig under den. Den adskillelse er det, der lod produktet blive ved med at skrue funktioner på, uden at arkitekturen stille og roligt rådnede.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har designet en JSON passthrough‑arkitektur, hvor PostgreSQL‑funktioner returnerer komplet JSON, som Go‑API&#39;et videresender uændret, hvilket eliminerer mellemliggende unmarshalling og afkobler frontenden fra skemaændringer.</title>
    <id>https://software.engineer.company/da/portfolio/designed-a-json-passthrough-architecture-where-postgresql-functions-58/</id>
    <link href="https://software.engineer.company/da/portfolio/designed-a-json-passthrough-architecture-where-postgresql-functions-58/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="SQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Databasedesign &amp; datamodellering" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <summary>Designede en JSON passthrough, hvor PostgreSQL-funktioner returnerer komplet JSON videresendt uændret af Go-API&#39;et — frontend afkoblet fra skema.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Den sædvanlige måde, data kommer fra en database til en browser, er et stafetløb af transformationer. Databasen giver API&amp;rsquo;et rækker, API&amp;rsquo;et unmarshaller dem til structs, omformer dem, serialiserer dem tilbage til JSON, og først da ryger de ud. Hvert af de spring er kode, man skriver, kode, man tester, og endnu et sted, hvor API&amp;rsquo;ets idé om dataene og databasens idé om dem kan glide fra hinanden.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Idéen var at springe stafetløbet over. Hvis databasen kunne returnere det færdige svar, kunne API&amp;rsquo;et bare sende det videre, og frontenden kunne afhænge direkte af databasens form i stedet for af en håndholdt kopi af den, der lå i Go.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Så det blev bygget som en ren passthrough. PostgreSQL‑funktionerne samler hele svaret som JSON — formningen er en SQL‑opgave, gjort der, hvor dataene i forvejen er. Go‑handleren tager det tilbage som json.RawMessage og videresender det uændret; den dekomponerer det aldrig, re‑encoder det aldrig. En lille QueryJSON‑helper gjorde det mønster til vejen med mindst modstand frem for noget, man skulle huske at gøre. Det, der faldt fra, var alt det mellemliggende maskineri, et konventionelt lagdelt API samler op — DTO&amp;rsquo;erne, mapperne, svar‑structene.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Handler‑koden blev dramatisk kortere, og vigtigere endnu holdt frontenden op med at være koblet til Go. Skift, hvad en funktion returnerer, og den nye form flyder direkte igennem til klienten, uden at nogen redigerer en linje handler‑kode. Færre bevægelige dele, og en hel kategori af drift mellem lag findes simpelthen ikke her.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har designet et system til at skifte organisationskontekst med client‑localStorage og server‑side cookie‑spejling, så brugere kan agere som administrerede organisationer under håndhævelse af least‑privilege‑autorisation.</title>
    <id>https://software.engineer.company/da/portfolio/designed-an-organization-context-switching-system-with-client-59/</id>
    <link href="https://software.engineer.company/da/portfolio/designed-an-organization-context-switching-system-with-client-59/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Sikkerhed" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <category term="Sikkerhed &amp; adgangsstyring" scheme="https://software.engineer.company/da/services/" />
    <summary>Byggede organisationskontekst-skift med localStorage og server-cookie-spejling — brugere agerer som administrerede orgs under least-privilege.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; På NextMariner kan en maritim professionel administrere organisationer — virksomheder, akademier — der ikke har deres egne logins. Personen er kontoen; organisationen er noget, de agerer på vegne af. Så en bruger skal kunne bevæge sig gennem hele appen som enhver organisation, de administrerer, og skifte mellem dem frit, og den bekvemmelighed må ikke blive til et hul i autorisationen.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Kontekstskift skulle være hurtigt og upåfaldende for brugeren og samtidig sikre, at den aktive kontekst aldrig af sig selv kunne give nogen adgang, de ikke var berettiget til.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; En OrganizationContext håndterer det, med lagring på begge sider. På klienten er localStorage kilde til sandhed for, hvilken organisation man aktuelt agerer som, så skiftet er øjeblikkeligt — ingen rundtur. En server‑side cookie spejler det, så server‑renderede sider løser den samme kontekst under SSR; der er en getServerViewMode på serveren, der læser den. Det vigtige er, at intet af det bliver stolet på til adgangsbeslutninger. Autorisation genkontrolleres på serveren ved hver request. Frontend‑konteksten er der for oplevelsen — at vise dig det rigtige — og serveren er den eneste autoritet på, hvad du må.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; En bruger kan agere som enhver organisation, de administrerer, uden friktion, og grænsefladen holder sig i sync på både klient og server. Men fordi rettigheder verificeres server‑side hver gang, svækker intet af den bekvemmelighed sikkerheden. En, der pillede ved det, der ligger i localStorage, ændrer, hvad deres eget UI viser dem, og intet mere — serveren siger stadig nej.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har migreret HTTP‑API&#39;et fra Fiber til Huma v2 — 649 paths og 760 operationer — og opnået og fastholdt 100 % paritet mellem de ruter, serveren registrerer, og den OpenAPI‑beskrivelse, den udgiver.</title>
    <id>https://software.engineer.company/da/portfolio/migrated-the-http-api-from-fiber-to-huma-60/</id>
    <link href="https://software.engineer.company/da/portfolio/migrated-the-http-api-from-fiber-to-huma-60/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Migrering &amp; modernisering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk dokumentation" scheme="https://software.engineer.company/da/services/" />
    <summary>Migrerede HTTP-API&#39;et fra Fiber til Huma v2 — 649 paths, 760 operationer — 100 % paritet mellem registrerede ruter og den udgivne OpenAPI-beskrivelse.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; API&amp;rsquo;et startede sit liv på Fiber, med request‑validering skrevet ud i hånden, endpoint for endpoint. Det er fint, når der er en håndfuld endpoints. Det holder op med at være fint, efterhånden som fladen vokser: den håndskrevne validering bliver til en vedligeholdelsesskat, og små inkonsistenser sniger sig ind, fordi hvert endpoints tjek er dets eget lille særtilfælde. Og der var ingen enkelt beskrivelse af API&amp;rsquo;ets form nogen steder.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Målet var validering, der kom fra typerne i stedet for fra håndskrevne tjek, og en egentlig kontrakt, der beskrev API&amp;rsquo;et — uden at stoppe op for at lave en big‑bang‑omskrivning.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; HTTP‑laget flyttede over på Huma v2, oven på Fiber, så den eksisterende runtime blev bevaret. Hvert endpoint får input- og output‑structs, og Huma genererer request‑valideringen og respons‑modelleringen ud fra de typer. En OpenAPI‑beskrivelse falder ud af det gratis, hvilket betyder, at dokumentationen følger koden i stedet for at rådne i en wiki. Alt nyt blev skrevet mod Huma og de eksisterende ruter migreret over, med præcis to endpoints efterladt på rå Fiber — WebSocket‑dem, hvor man reelt vil have socket&amp;rsquo;en, og Humas request/response‑model ikke passer. Det, det er vokset til, er 649 paths, der bærer 760 operationer, og et tjek i CI, som sammenligner de ruter, serveren faktisk registrerer, med dem, OpenAPI‑beskrivelsen annoncerer. Pariteten er 100 %, og den bliver der, fordi en rute, der ikke er beskrevet, får buildet til at fejle.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Nye endpoints får validering og opdateret dokumentation, uden at nogen laver ekstra arbejde for det, og en hel klasse af request‑fejl — &amp;ldquo;nå ja, vi glemte at tjekke det felt her&amp;rdquo;-slagsen — forsvandt. Ved 760 operationer er beskrivelsen den eneste praktiske måde, nogen læser API&amp;rsquo;et på, så garantien for, at den er komplet, betyder mere, end den gjorde ved halvtreds. Den typede kontrakt gjorde API&amp;rsquo;et både sikrere at ændre og lettere at give videre til en anden, for typerne fortæller dig, hvad et endpoint forventer.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har genereret API‑kontrakten udad fra databasen — OpenAPI, en typet TypeScript‑klient på 44.076 linjer, 61 mock handlers og de grænser, UI&#39;et håndhæver — med en guard i hvert led, der fejler ved drift.</title>
    <id>https://software.engineer.company/da/portfolio/built-a-request-schema-validation-contract-with-automated-61/</id>
    <link href="https://software.engineer.company/da/portfolio/built-a-request-schema-validation-contract-with-automated-61/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <summary>Genererede API-kontrakten ud fra databasen — OpenAPI, en typet TypeScript-klient, mock handlers og UI-grænser — med en guard i hvert eneste led.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Frontend og backend bevæger sig i deres eget tempo, og deres antagelser om en request‑payload kan glide fra hinanden, uden at nogen bemærker det. Måden, man som regel opdager det på, er et 422 i browseren — efter uoverensstemmelsen allerede er udgivet, hvilket er det dyreste tidspunkt at få det at vide på. At skrive de to sider i hånden ud fra det samme dokument løser det ikke; det flytter bare driften over på den, der glemte at læse dokumentet igen.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; De to sider skulle genereres fra én kilde frem for aftales mellem to, med hvert trin i genereringen tjekket i stedet for taget for givet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Kæden starter ved databasen og løber udad. Skemaet og dets funktioner definerer formerne; Go‑typerne definerer API&amp;rsquo;et; Huma udsender OpenAPI‑beskrivelsen ud fra dem; en typet TypeScript‑klient — 44.076 linjer af den — genereres ud fra den beskrivelse; 61 mock‑handlere genereres ved siden af den, så frontendens egne tests kører mod den rigtige kontrakt frem for en håndskrevet fixture; og de grænser, UI&amp;rsquo;et håndhæver på en formular, kommer fra det samme sted i stedet for at blive tastet ind i en validator igen. Hvert hop har et værn. Et kontrakt‑tjek i CI sammenligner det, frontenden sender, med det, API&amp;rsquo;et forventer, og får buildet til at fejle ved afvigelse, med en schema‑probe under det, som tjekker de rigtige former frem for en beskrivelse af dem. Det dækker bevidst, hvor drift kan lide at gemme sig: valgfrie body‑felter, hvor &amp;ldquo;mangler&amp;rdquo; og &amp;ldquo;null&amp;rdquo; bliver forvekslet, og query‑parameter‑enums, hvor de to sider stille og roligt kan være uenige om de tilladte værdier.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Et felt kan ikke ændre sig på kun den ene side — det fejler ved det første hop, der bemærker det, i et build, minutter efter ændringen. Det tog en tilbagevendende og oprigtigt irriterende klasse af fejl af bordet — den slags, der er usynlig i code review og først dukker op i runtime. Prisen er et genereringstrin midt i det hele: at regenerere er en sur pligt, og kæden er kun så troværdig som sit dårligst bevogtede led, hvilket er grunden til, at hvert hop fik et.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget e‑mail som en kapabilitet i platformen — tre udbydere med failover, delivery‑webhooks, logning af afsendelse og levering, templating og kampagner — bag et opstartstjek, der ikke booter uden en af dem.</title>
    <id>https://software.engineer.company/da/portfolio/built-email-as-a-platform-capability-with-failover-62/</id>
    <link href="https://software.engineer.company/da/portfolio/built-email-as-a-platform-capability-with-failover-62/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Cloud" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Sikkerhed" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Sikkerhed &amp; adgangsstyring" scheme="https://software.engineer.company/da/services/" />
    <category term="Site reliability &amp; monitorering" scheme="https://software.engineer.company/da/services/" />
    <summary>Byggede e-mail som en kapabilitet i platformen: tre udbydere med failover, delivery-webhooks, logning af afsendelse og levering, templating og kampagner.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; E‑mail vejer tungt på NextMariner — verificering, notifikationer, digests, kampagner, de ting en bruger faktisk venter på. Og en mailudbyder er præcis den slags afhængighed, der fejler lydløst: konfigurationen ser fin ud, appen booter, og du opdager først, at noget er galt, når et rigtigt menneske aldrig får den besked, det blev lovet. Det er den værste måde at få det at vide på. Én udbyder gør det værre, fordi fejlen er total og en andens at rette.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; E‑mail skulle behandles som en evne, platformen ejer, frem for et klientbibliotek, den kalder — i stand til at overleve et udbyder‑nedbrud, i stand til at sige, hvad der skete med en given besked, og højlydt ved opstart i de miljøer, hvor stilhed er farlig.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Tre udbydere sidder bag én grænseflade — SendGrid som primær, med SMTP2GO og Azure Communication Services bagved — og failover mellem dem er automatisk frem for en konfigurationsændring foretaget under pres. Levering tages ikke for givet: indgående webhooks rapporterer, hvad hver udbyder gjorde med en besked, og begge sider registreres, i en send‑log og en delivery event‑tabel, så &amp;ldquo;fik det her menneske sin verificeringsmail&amp;rdquo; er en forespørgsel frem for et gæt. Templating holder beskedteksterne ude af koden, og et separat broadcast‑skema — 5 tabeller og 24 funktioner — bærer kampagner ud til segmenter af brugere, hvilket er et andet problem end transaktionsmail og blev bygget som et. Foran det hele sender et opstartstjek en rigtig besked gennem stakken, bag et flag: i udvikling logger det en advarsel og fortsætter, for ingen vil have deres laptop til at nægte at starte, fordi en sandkasse‑nøgle er udløbet, og i staging og produktion er en fejl fatal, og processen afslutter frem for at deploye et build, der ikke kan sende mail. Selve afsendelsesstien går gennem en SSRF‑beskyttet klient med et 30‑sekunders timeout, og den asynkrone leveringssti har retries og backoff, så et øjebliks udfald ikke taber en besked.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; En hel kategori af lydløs fejl flyttede fra &amp;ldquo;en bruger opdager det dage senere&amp;rdquo; til &amp;ldquo;deployet stopper&amp;rdquo;, og en udbyder, der har en dårlig eftermiddag, blev til en forringet sti frem for et udfald. Prisen er tre integrationer at holde kørende i stedet for én, og leveringslogs, der vokser og skal beskæres — begge accepteret, fordi e‑mail er den kanal, platformen ikke kan rute uden om.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har designet et function‑first datalag i PostgreSQL — 1.275 stored functions på tværs af 34 skemaer — så hver læsning og skrivning går gennem en funktion, databasen kan tildele rettigheder til, frem for gennem en tabel.</title>
    <id>https://software.engineer.company/da/portfolio/designed-a-postgresql-function-first-data-layer-across-63/</id>
    <link href="https://software.engineer.company/da/portfolio/designed-a-postgresql-function-first-data-layer-across-63/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Sikkerhed" scheme="https://software.engineer.company/da/categories/" />
    <category term="SQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Data governance &amp; datakvalitet" scheme="https://software.engineer.company/da/services/" />
    <category term="Databasedesign &amp; datamodellering" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <summary>Designede et function-first datalag i PostgreSQL — 1.275 stored functions på tværs af 34 skemaer — med adgangsgrænsen håndhævet af databasen selv.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Forretningslogik har det med at lække. Lidt ender i API&amp;rsquo;et, lidt i noget SQL, en handler kører inline, og før længe er den samme regel skrevet på to‑tre lidt forskellige måder, og der er ingen steder, man kan pege hen og sige &amp;ldquo;det her er, hvad systemet gør med sine data.&amp;rdquo; Det er sådan, fejl og sikkerhedshuller kommer ind.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Målet var ét hjem til det hele: hver læsning og skrivning gennem databasen, API&amp;rsquo;et en tynd adapter, der ikke kender forretningsreglerne, og det hele muligt at låse ned til.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Datalaget er function‑first. Skemaet er delt op efter domæne — identity, organization, review, message, notification og 29 mere, 34 i alt — og hver operation, appen kan udføre, er én af 1.275 PostgreSQL‑funktioner, den kalder; der er slet ingen direkte tabeladgang fra Go. Så håndhæver databasen det. Den rolle, API&amp;rsquo;et logger ind som, mariner, har EXECUTE på app‑funktionerne og USAGE på skemaerne og intet andet — ingen SELECT, ingen INSERT, ingen måde at røre en tabel direkte — hvilket løber op i cirka 4.000 eksplicitte grants frem for én generel. Funktionerne kører SECURITY DEFINER, ejet af en separat non‑login function_owner‑rolle med en pinned search_path, og superuser‑kontoen holdes reserveret til migrationer og cron, langt væk fra den kørende app.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Logikken bor ét sted, man faktisk kan revidere, API&amp;rsquo;et forbliver tyndt og kedeligt på den gode måde, og adgangsgrænsen håndhæves af Postgres selv frem for af, at alle husker reglerne. Hvis API&amp;rsquo;et på en eller anden måde blev kompromitteret, kunne det stadig ikke gøre noget, funktionerne ikke tillader. Ved 1.275 funktioner koster disciplinen noget reelt — et nyt felt er en migration og en funktionsændring, ikke en linje i en forespørgsel — og den friktion er prisen for, at grænsen holder.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har implementeret en katalogdrevet deep‑merge for lagrede JSON‑præferencer, hvilket forhindrer nedbrud på grund af manglende nøgler, når skemaet udvikler sig.</title>
    <id>https://software.engineer.company/da/portfolio/implemented-a-catalogue-driven-deep-merge-for-stored-65/</id>
    <link href="https://software.engineer.company/da/portfolio/implemented-a-catalogue-driven-deep-merge-for-stored-65/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Migrering &amp; modernisering" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Data governance &amp; datakvalitet" scheme="https://software.engineer.company/da/services/" />
    <category term="Databasedesign &amp; datamodellering" scheme="https://software.engineer.company/da/services/" />
    <summary>Implementerede en katalogdrevet deep-merge for lagrede JSON-præferencer — forhindrer nedbrud ved manglende nøgler, når skemaet vokser.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Platformen lagrer JSON‑præferencer — notifikationsindstillinger og den slags — som en brugers gemte værdier lagt over et sæt defaults. Den oprindelige merge gjorde det på ét niveau. Problemet dukker op senere: tilføj en ny nøgle til defaults, og rækker gemt før den nøgle eksisterede, har den simpelthen ikke. Så læser noget klientkode det felt, får undefined og vælter — for præcis de brugere, der har været der længst.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Det skulle være sikkert at udvikle præference‑skemaet, så det at tilføje en indstilling aldrig kunne bryde de folk, der meldte sig til, før den fandtes.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Enkelt‑niveau‑mergen blev erstattet med en deep‑merge drevet af defaults som et katalog. Defaults behandles som den autoritative liste over hver nøgle, der bør findes; brugerens gemte værdier merges rekursivt ovenpå, så alt i kataloget garanteret kommer ud til stede, uanset om det var i den gemte blob. Tilføj en nøgle til defaults, og den optræder i hver eksisterende rækkes effektive præferencer automatisk, nestede nøgler inkluderet. Det blev rullet ind gennem en migrering, så eksisterende data fik gavnen med det samme frem for at vente på at blive skrevet om.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Præferencer kan vokse uden frygt. At tilføje en indstilling risikerer ikke længere et undefined‑felt‑crash i klienten, og frontenden holdt op med at have brug for defensive tjek spredt rundt om hvert sted, den læser en præference. Det gav også resten af platformen en pålidelig måde at udvide en hvilken som helst lagret JSON‑blob — mønsteret, ikke bare den ene rettelse.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget Python‑scraperne til skibsdata (MarineTraffic, Maritime‑Database) og et gentageligt import‑trin, der seeder platformens referencedata — 184.197 rækker, heraf 698 virksomheder og 56.149 skibe.</title>
    <id>https://software.engineer.company/da/portfolio/built-a-python-vessel-data-scraper-marinetraffic-maritime-66/</id>
    <link href="https://software.engineer.company/da/portfolio/built-a-python-vessel-data-scraper-marinetraffic-maritime-66/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Udvikling af datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/services/" />
    <summary>Byggede Python-scrapere til skibsdata og seedede 184.197 rækker maritime referencedata — 698 virksomheder og 56.149 skibe — via en gentagelig pipeline.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Et maritimt netværks- og anmeldelsessite er dødt ved ankomst, hvis det er tomt. Ingen melder sig ind i et katalog uden virksomheder i. Så før nogen af de sociale funktioner betød noget, havde platformen brug for et rigtigt korpus af maritime virksomheder og skibe, der allerede sad der, klar til at blive fundet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Gå ud og hent de data — rigtige virksomheder og skibe, i nok skala til at føles befolket — og få dem ind i databasen på en måde, der kunne køres igen, ikke en engangs‑scrape, ingen ville kunne reproducere.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Scraperne er skrevet i Python. Én driver MarineTraffic med Playwright; en anden henter fra Maritime‑Database over async httpx; der er også en ClassNK‑fetcher. De skriver CSV&amp;rsquo;er ud, og et import‑trin renser og normaliserer dem og indlæser dem i Postgres‑skemaet gennem en enkelt task, så at seede databasen er én kommando frem for en eftermiddags manuelt arbejde. Det, der gik ind, endte på 184.197 rækker: 698 virksomheder, 56.149 fartøjer og 33.074 byer, med en senere opdatering, der erstattede 74.794 fartøjsrækker.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Platformen blev lanceret med et befolket katalog i stedet for tomme tabeller og et grundlag af referencedata, som netværks-, job- og anmeldelsesfunktionerne alle kunne bygge oven på. Fordi pipelinen er reproducerbar, er det bare at køre den igen at opdatere eller udvide den senere — hvilket er sådan, fartøjsopdateringen skete, uden at nogen byggede værktøjet om. Scrapede data ældes, og at holde dem aktuelle er en løbende omkostning frem for et løst problem.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har modelleret det maritime domæne i 348 normaliserede tabeller på tværs af 34 PostgreSQL‑skemaer — professionelle, virksomheder, skibe, jobs, anmeldelser og resten — med SMALLINT‑opslagstabeller og UUID v7‑nøgler.</title>
    <id>https://software.engineer.company/da/portfolio/modeled-the-maritime-domain-professionals-companies-ships-jobs-67/</id>
    <link href="https://software.engineer.company/da/portfolio/modeled-the-maritime-domain-professionals-companies-ships-jobs-67/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Data engineering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="SQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance &amp; datakvalitet" scheme="https://software.engineer.company/da/services/" />
    <category term="Databasedesign &amp; datamodellering" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <summary>Modellerede det maritime domæne i 348 normaliserede tabeller på tværs af 34 PostgreSQL-skemaer — SMALLINT-opslag, UUID v7-nøgler og én navnekonvention.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Hjertet i NextMariner er et tæt maritimt domæne — professionelle, virksomheder, skibe, jobs, anmeldelser — og de her ting refererer konstant til hinanden. En professionel sejler på skibe, arbejder for virksomheder, efterlader anmeldelser; en virksomhed ejer skibe og slår jobs op. Næsten hver funktion er en forespørgsel på tværs af det net, så hvor godt dataene er modelleret, afgør, hvor godt det meste af appen performer, og hvor fornuftigt det er at udvide den.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Det domæne skulle modelleres, så det holdt sig hurtigt og bevarede sin integritet, og så det at tilføje den næste entitetstype ikke betød at slås med skemaet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Det er lagt ud som normaliserede PostgreSQL‑skemaer organiseret efter domæne — 348 tabeller på tværs af 34 af dem efterhånden. De mange små, stabile enumerationer — statusser, typer, kategorier — blev SMALLINT‑opslagstabeller, hvilket holder rækkerne kompakte og joins billige i stedet for at gemme tekstkoder overalt. Entiteter får UUID v7‑primærnøgler, så de er globalt unikke, men stadig tidsordnet i indekset. Én navngivningskonvention løber hele vejen igennem — flertalstabeller inde i entalsnavngivne skemaer — anvendt uden undtagelse, hvilket som en bonus undgår en masse kollisioner med reserverede ord. Og relationerne holdes oppe af rigtige foreign keys og constraints, så integritet er databasens job, ikke noget applikationen skal huske at gøre.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Det, der kom ud, er en datamodel, der er konsistent og hurtig, og forudsigelig at arbejde i, fordi de samme regler holder overalt — der er ingen særtilfælde at huske. At tilføje en funktion betyder som regel at udvide skemaet med den eksisterende retning frem for imod den, hvilket er den eneste grund til, at 34 skemaer er en struktur frem for et vildnis. Det er gulvet, resten af platformen står på.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget Next.js 16‑frontenden med bevidste SSR-, SSG- og CSR‑strategier og en genbrugelig prefetched‑server‑page‑factory, der fjerner N&#43;1‑kaskaden fra hver autentificeret side, der flyttes over på den.</title>
    <id>https://software.engineer.company/da/portfolio/built-the-next-js-16-frontend-with-deliberate-73/</id>
    <link href="https://software.engineer.company/da/portfolio/built-the-next-js-16-frontend-with-deliberate-73/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Byggede Next.js 16-frontenden med SSR/SSG/CSR og et server-shell prefetch-and-hydrate-mønster, der eliminerede N+1-fetches.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Det autentificerede dashboard skulle føles hurtigt og forblive oprigtigt interaktivt, og de to mål trækker mod hinanden, hvis man er naiv omkring det. Hent alt på klienten, og førsteindlæsningen sløver, og værre endnu får man N+1‑mønsteret, hvor hver komponent vågner og fyrer sin egen request af, så en enkelt side bliver til en kaskade af rundture.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Hver del af appen skulle renderes på den måde, der faktisk passede til den, uden at opgive client‑side‑interaktiviteten, hvor den betød noget.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Next.js 16‑frontenden bruger den rette tilstand pr. flade i stedet for ét fladt valg. Marketing- og offentlige sider genereres statisk — de ændrer sig ikke pr. bruger, så der er ingen grund til at rendere dem ved hver request. De oprigtigt interaktive dele forbliver client‑renderede. Og dér, hvor N+1‑kaskaden faktisk bider — det autentificerede dashboard og de store oversigtslister — blev løsningen lagt i en factory frem for håndlavet: createPrefetchedServerPage henter sidens data på serveren og overlader dem til klienten allerede udfyldt, så komponenterne kommer op med deres data i stedet for hver at gå af sted for at spørge efter dem. En cache‑invalideringsstrategi er dokumenteret pr. forespørgsel, så data forbliver friske, uden at appen re‑fetcher ting, den allerede har.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; De sider, der er flyttet over på denne factory, kommer op på én rundtur i stedet for en storm af dem, og fordi det er en factory frem for et mønster, folk kopierer i hånden, arver den næste side, der flyttes over, opførslen gratis. Resten af den autentificerede app er stadig client‑renderet og står stadig i kø bagved — en migrering med en fungerende mekanisme og en indlysende næste side frem for et afsluttet sweep.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har leveret fuld Progressive Web App‑understøttelse — installerbar og offline‑dygtig — med Workbox runtime‑caching via next‑pwa.</title>
    <id>https://software.engineer.company/da/portfolio/delivered-full-progressive-web-app-support-installable-and-74/</id>
    <link href="https://software.engineer.company/da/portfolio/delivered-full-progressive-web-app-support-installable-and-74/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Leverede fuld Progressive Web App-understøttelse — installerbar og offline-dygtig — med Workbox runtime-caching via next-pwa.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; En stor del af NextMariners brugere er til søs. Søfarende og feltpersonale, på telefoner, ofte offline eller hængende på en dårlig forbindelse — ikke folk, der sidder ved et skrivebord på pålidelig kontor‑wifi. At bygge, som om alle havde et hurtigt, konstant netværk, ville stille og roligt have udelukket en stor del af det faktiske publikum.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Appen skulle være installerbar som en native app og stadig brugbar, når netværket falder ud.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Den er leveret som en fuld Progressive Web App. Den installeres på hjemmeskærmen med ordentlige ikoner i de forskellige størrelser, en splash‑skærm og temafarver, så den ser ud og starter som en app frem for et bogmærke. Service workeren er sat op gennem next‑pwa‑pluginet, og Workbox runtime‑caching bruger CacheFirst til de ting, der ikke ændrer sig pr. request — skrifttyper, billeder, lyd, video, CDN‑aktiver — sammen med fornuftige HTTP cache‑control‑headere. Fordi service workers kun rigtig opfører sig over HTTPS, validerede HTTPS‑baseret test offline- og installationsadfærden på rigtige enheder i stedet for at håbe, det virkede.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Brugere kan installere appen og blive ved med at bruge den offline, og genindlæsninger kommer hurtigt tilbage fra cache i stedet for over ledningen. Platformen opfører sig som en native app på det hardware, dens brugere faktisk bærer, hvilket for det her publikum ikke er en luksus — det er forskellen på, om appen er brugbar til søs eller ej.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har designet et iOS 26 &#39;Liquid Glass&#39;-designsystem og et kanonisk komponentbibliotek håndhævet af lint‑regler for at forhindre UI‑divergens.</title>
    <id>https://software.engineer.company/da/portfolio/designed-an-ios-26-liquid-glass-design-system-75/</id>
    <link href="https://software.engineer.company/da/portfolio/designed-an-ios-26-liquid-glass-design-system-75/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <summary>Designede et iOS 26 &#39;Liquid Glass&#39;-designsystem og et kanonisk komponentbibliotek håndhævet af lint-regler mod UI-divergens.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Et UI uden et fælles visuelt sprog og et fast sæt komponenter driver, og det driver hurtigt. Hver ny skærm genopfinder sine egne knapper og badges og kort, hver en lille smule anderledes, og de små inkonsistenser hober sig op, indtil produktet ser usammenhængende ud, og hver ændring betyder at røre fem specialbyggede versioner af den samme ting.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Designsystemet skulle være sammenhængende nok til at se bevidst ud, og håndhævbart nok til, at det ikke eroderede i det øjeblik, teamet havde travlt.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Det visuelle sprog og komponentsystemet blev designet som én ting. Sproget er et iOS 26 &amp;ldquo;Liquid Glass&amp;rdquo;-look — gennemsigtige paneler med backdrop‑blur, lagdelte skygger, en smule refraktion, spring‑animationer — bygget af Tailwind‑utilities. Ovenpå det sidder et kanonisk sæt komponenter, hver skærm er ment til at sammensætte af: Card, Label, Button, GlassIconButton, DirectoryGrid og resten. Det, der får det til at sidde fast, er lintingen: regler, der afviser et hjemmelavet badge eller chip og peger dig på den kanoniske komponent i stedet, så systemet holdes oppe af værktøjer frem for af, at den, der reviewer den dag, husker at bekymre sig. Og dokumentationen er parret med konkrete fejl‑til‑løsning‑noter, så vejledningen er &amp;ldquo;her er den forkerte måde og den rigtige&amp;rdquo;, ikke et abstrakt princip.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; UI&amp;rsquo;et forbliver konsistent og on‑brand, og de engangskomponenter, der ellers ville sprede sig, fanges, før de gør. Visuel konsistens holdt op med at være et spørgsmål om alles disciplin og blev til noget, værktøjerne holder linjen på, hvilket er den eneste version af det, der overlever en deadline.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har designet produktets UI og UX fra ende til anden — directory‑grids, dobbelte kort/tabel‑visninger, live‑kravvalidatorer og breadcrumb‑navigation.</title>
    <id>https://software.engineer.company/da/portfolio/designed-the-product-s-ui-and-ux-end-76/</id>
    <link href="https://software.engineer.company/da/portfolio/designed-the-product-s-ui-and-ux-end-76/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produkt &amp; krav" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Produktstrategi &amp; kravspecifikation" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <summary>Designede produktets UI/UX fra ende til anden — directory-grids, kort/tabel-visninger, live-validatorer og breadcrumbs — til maritime data.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; NextMariner stiller en masse forskellige entiteter foran folk — professionelle, virksomheder, skibe, jobs, anmeldelser — og grænsefladen skulle være to ting, der slås med hinanden: flot og oprigtigt brugbar. Tæt nok til at vise rigtige maritime data, men ikke så tæt, at den bliver til en mur, man preller af på.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Produktets UI og UX blev ejet fra ende til anden — layoutene, interaktionsmønstrene og det mindre, som hvordan nogen bliver ført gennem en formular uden at føle sig hakket på.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Et par beslutninger gjorde det meste af arbejdet. Directory‑grids har en kort/tabel‑toggle, så man kan browse visuelt eller scanne en tæt tabel, og appen husker, hvilken man valgte. Formularer bruger live‑kravvalidatorer, der sidder over inputtet og viser hver regel i grønt, når den er opfyldt, og ravgult, når den ikke er, så man bliver vejledt, mens man skriver, i stedet for hakket på, efter man har sendt. Navigationen er konsistente breadcrumbs og to‑kolonne‑entitetslayouts, så sider føles som det samme produkt frem for et sæt urelaterede skærme. Og fejlfilosofien er vejledning frem for fejl — ingen røde mure, redirects i stedet for blindgyder, appen prøver at holde dig i bevægelse frem for at stoppe dig.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Det, der kom ud, er en poleret, konsistent oplevelse, der gør tætte maritime data overskuelige og styrer folk gennem de komplicerede dele. Den fremstår gennemtænkt og troværdig, hvilket ikke er kosmetisk på en platform, folk bruger til deres faktiske karriere — hvis den så sjusket ud, ville de stole mindre på dataene, og de ville have ret i det.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har hærdet applikationen med nonce‑baseret CSP, HSTS, SameSite‑cookies, least‑privilege‑databaseroller og server‑side‑genkontrol af rettigheder.</title>
    <id>https://software.engineer.company/da/portfolio/hardened-the-application-with-nonce-based-csp-hsts-77/</id>
    <link href="https://software.engineer.company/da/portfolio/hardened-the-application-with-nonce-based-csp-hsts-77/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Sikkerhed" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Sikkerhed &amp; adgangsstyring" scheme="https://software.engineer.company/da/services/" />
    <summary>Hærdede appen med nonce-baseret CSP, HSTS, SameSite-cookies, least-privilege-databaseroller og server-side-genkontrol af rettigheder.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; NextMariner rummer professionelle og organisatoriske data, den slags folk forventer bliver håndteret ordentligt, så en enkelt forsvarslinje var aldrig nok. Arbejdsantagelsen må være, at klienten er fjendtlig — at alt, hvad browseren håndhæver, kan slås fra af den, der holder browseren — og sikkerheden må holde alligevel.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Platformen skulle hærdes på hvert lag — frontend, API, database — så sikkerhed blev håndhævet af serveren uafhængigt af, hvad grænsefladen nu tilfældigvis tillod.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; I frontenden sætter Next.js&amp;rsquo; proxy‑middleware — proxy.ts — en Content‑Security‑Policy med en per‑request‑nonce og strict‑dynamic, plus HSTS og SameSite‑cookies, så browseren er låst ned om, hvad den vil køre og sende. På API&amp;rsquo;et er der rate limiting, CORS, request‑størrelsesgrænser, input‑validering, før noget rører databasen, og logning af de sikkerhedsrelevante hændelser. I databasen logger API&amp;rsquo;et ind som en least‑privilege‑rolle, der kun kan EXECUTE app‑funktionerne, funktionerne kører SECURITY DEFINER, og alt er parametriseret. Og rettighederne — tier, rolle, organisation, skibs‑scoping — genkontrolleres på serveren ved hver request, hvor frontend‑gates kun behandles som UX. Gates afgør, hvad du ser; serveren afgør, hvad du må.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Sikkerhed afhænger ikke af, at UI&amp;rsquo;et opfører sig. Beskyttelserne er lagdelte, så det at komme forbi én ikke får dig forbi resten, og det hele er bygget på antagelsen om, at klienten ikke kan stoles på — hvilket er den rigtige antagelse for data, folk overlader i fortrolighed.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har etableret et engelsk/dansk internationaliseringssystem med 12.027 beskeder pr. locale på tværs af 458 namespace‑filer, med linter‑håndhævet ordforråd og et budget på 400 linjer pr. fil.</title>
    <id>https://software.engineer.company/da/portfolio/established-an-english-danish-internationalization-system-with-linter-78/</id>
    <link href="https://software.engineer.company/da/portfolio/established-an-english-danish-internationalization-system-with-linter-78/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Internationalisering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Internationalisering &amp; lokalisering" scheme="https://software.engineer.company/da/services/" />
    <summary>Etablerede et engelsk/dansk i18n-system med 12.027 beskeder pr. locale i 458 filer — linter-håndhævet ordforråd og et budget for filstørrelse.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; NextMariner kører på engelsk og dansk, og oversættelsessystemer har det med at vokse ud i et rod. Filerne vokser uden grænse, nøgler lækker — til stede i ét sprog, manglende i det andet — og de sprogspecifikke konventioner anvendes ujævnt, så ét sprog ender med at læse, som om det var oversat af et udvalg, der ikke talte sammen. For et professionelt produkt er det ikke en lille skønhedsfejl; det læses som sjusk.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Internationaliseringssystemet skulle skalere — holde begge sprog konsistente og korrekte og filerne til noget, et menneske stadig kunne vedligeholde et år inde.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Det er bygget på next‑intl med regler, som værktøjerne faktisk håndhæver. Den danske side har et låst ordforråd og en låst stil — literal æøå, det uformelle &amp;ldquo;du&amp;rdquo;, de rigtige imperative accenter, og semantiske mappinger for sammensatte ord, så de oversættes efter betydning frem for ord‑for‑ord — og en linter holder den til det. Der er et hårdt budget på 400 linjer pr. namespace‑fil, med en split‑and‑merge‑tilgang, så et stort område deles i nestede filer, der merges rent tilbage, i stedet for at én fil vokser i det uendelige; det budget er grunden til, at 12.027 beskeder pr. sprog bor i 458 filer frem for en håndfuld enorme. Et linter‑tjek sammenligner nøgler på tværs af sprog, så intet lækker eller mangler. Og lagrede overrides merges katalogdrevet frem for med skrøbelige top‑niveau‑fallbacks — den samme deep‑merge‑idé, der blev brugt til præferencer.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Begge sprog forbliver korrekte og konsistente ved 24.054 beskeder mellem dem, og filerne forbliver vedligeholdelige, efterhånden som antallet af strenge klatrer. Sprogkvalitet blev til noget, værktøjerne garanterer ved hver commit, frem for noget, der stille og roligt forringes, hver gang nogen tilføjer en streng i en fart. Budgettet er den bærende del: uden en grænse pr. fil ville 458 filer have været tolv, og ingen ville åbne dem.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har fastlagt platformens grundlæggende beslutninger i ugerne efter, at kodebasen blev åbnet i november 2025 — lagdelingen, database‑first‑dataadgang og zero‑warnings‑standarden — og de holder stadig ni måneder senere.</title>
    <id>https://software.engineer.company/da/portfolio/set-the-platform-s-founding-decisions-in-november-2025-80/</id>
    <link href="https://software.engineer.company/da/portfolio/set-the-platform-s-founding-decisions-in-november-2025-80/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Løsningsarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Sikkerhed" scheme="https://software.engineer.company/da/categories/" />
    <category term="Teamledelse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Teknisk ledelse" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk ledelse &amp; rådgivning" scheme="https://software.engineer.company/da/services/" />
    <summary>Fastlagde platformens grundlæggende beslutninger i november 2025 — lagdelingen, database-first-dataadgang og zero-warnings-standarden — og de holder stadig.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Repositoriet blev åbnet den 25. november 2025 uden noget i sig. Det, der bliver besluttet i de første par uger af et projekt som det, vejer uforholdsmæssigt tungt: lagdelingen, hvor forretningslogikken må bo, hvad kvalitetsstandarden er. De valg er billige at træffe på dag tre og tæt på umulige at vende om på i måned seks, hvor alt skrevet siden da forudsætter dem.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; De grundlæggende beslutninger skulle træffes bevidst og tidligt og træffes i en form, der kunne overleve at blive givet videre til andre mennesker og til en langt større kodebase, end der fandtes dengang.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Tre beslutninger gjorde det meste af arbejdet. Stakken blev lagdelt, så hver del har ét job — en Next.js‑frontend, et Go‑API, der validerer og videresender, et PostgreSQL‑funktionslag, der ejer forretningsreglerne — frem for at logik blev placeret, hvor det nu var bekvemt den eftermiddag. Dataadgang blev lagt bag stored functions fra starten, hvilket er det valg, alt andet i databasearbejdet følger af; at eftermontere det senere ville have betydet at skrive hver handler om. Og en zero‑warnings‑standard kom ind, før der var meget kode at holde til den, for en standard indført ved commit 5.000 er et oprydningsprojekt, hvorimod den samme standard ved commit 50 bare er, hvordan repositoriet fungerer. Ingen af de tre var den nemme mulighed dengang, og alle tre kostede momentum i den første måned.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Ni måneder og flere tusinde commits senere holder alle tre stadig: lagene er ikke blevet slørede, ingen handler taler direkte med en tabel, og buildet har stadig ingen warnings i sig. Det er den prøve, det er værd at lægge på en grundlæggende beslutning — ikke om den lød rigtig, men om den overlevede kontakten med den mængde arbejde, der kom efter, hvilket er det punkt, hvor bekvemme valg som regel stille og roligt bliver opgivet.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har udviklet og vedligeholdt Django‑webapplikationer til IPTV‑platformen med nye funktioner og forbedret performance og stabilitet.</title>
    <id>https://software.engineer.company/da/portfolio/developed-and-maintained-django-web-applications-for-the-84/</id>
    <link href="https://software.engineer.company/da/portfolio/developed-and-maintained-django-web-applications-for-the-84/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Udviklede og vedligeholdt Django-webapplikationer til en IPTV-platform — nye funktioner samt bedre performance og stabilitet.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; IPTV‑platformen havde webapplikationer bygget på Django omkring sig — de dele, folk faktisk klikkede på — og de skulle blive ved med at bevæge sig fremad: nye funktioner, og den performance og stabilitet, en platform, der kører døgnet rundt, kræver.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At holde de applikationer funktionsrige, hurtige og stabile var opgaven.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Django‑webapplikationerne blev udviklet og vedligeholdt — byggede nye funktioner, rettede fejlene og pressede på performance og stabilitet, arbejdet på tværs af teamet frem for i et hjørne. På noget, der betjener kunder kontinuerligt, er stabilitetssiden ikke en luksus ved siden af funktionerne; det er den begrænsning, funktionerne må respektere. En prangende funktion, der får tingen til at vakle, er ikke meget værd, når tingen ikke har råd til at vakle.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Applikationerne blev ved med at få flere funktioner og forblev samtidig pålidelige for både de interne teams og kunderne. At tilføje til noget uden at destabilisere det er den balance, der betød noget her, og det er det, arbejdet holdt sig til.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har planlagt og implementeret ny infrastrukturfunktionalitet til interne og eksterne systemer og bygget løsninger, der stadig kører år efter med minimale ændringer.</title>
    <id>https://software.engineer.company/da/portfolio/planned-and-implemented-new-infrastructure-functionality-for-internal-85/</id>
    <link href="https://software.engineer.company/da/portfolio/planned-and-implemented-new-infrastructure-functionality-for-internal-85/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Infrastruktur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Løsningsarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Systemadministration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <category term="Site reliability &amp; monitorering" scheme="https://software.engineer.company/da/services/" />
    <category term="Systemadministration" scheme="https://software.engineer.company/da/services/" />
    <summary>Planlagde og byggede infrastruktur til interne og eksterne systemer — robust nok til stadig at køre år efter med minimale ændringer.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Efterhånden som organisationen voksede, blev dens interne og eksterne systemer ved med at have brug for nye funktioner skruet på. Den nemme måde at gøre det på er, hvad end der er hurtigst i dag; problemet med den nemme måde er, at man er tilbage og retter det om et halvt år.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At planlægge og bygge infrastrukturfunktionalitet, der faktisk ville holde, var opgaven — ikke bare virke nu, men blive ved med at virke.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Ny infrastrukturfunktionalitet blev planlagt og implementeret på tværs af de interne og eksterne systemer, designet til at være holdbar — den slags, man bygger én gang, ordentligt, så den bliver ved med at køre i årevis med minimal berøring frem for at kræve konstant opmærksomhed. Det er et bevidst valg hver gang: at bruge en smule mere tanke i starten, så man ikke skriver sig op til at passe på den for evigt.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Systemerne forblev funktionelle og effektive længe efter, de blev bygget, og kørte i årevis med næsten ingen ændringer. Den lang levetid er det egentlige mål for infrastrukturarbejde — enhver kan lave noget, der virker i dag; at lave noget, der stadig stille og roligt virker år senere, er det sværere og mere nyttige.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har som en af de første medarbejdere designet og bygget hele kerneinfrastrukturen og de understøttende processer fra bunden for en grøn‑energi‑SaaS‑startup og lagt fundamentet for hurtig vækst.</title>
    <id>https://software.engineer.company/da/portfolio/as-one-of-the-first-hires-designed-and-86/</id>
    <link href="https://software.engineer.company/da/portfolio/as-one-of-the-first-hires-designed-and-86/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Cloud" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps" scheme="https://software.engineer.company/da/categories/" />
    <category term="Infrastruktur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Løsningsarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Sikkerhed" scheme="https://software.engineer.company/da/categories/" />
    <category term="Systemadministration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Cloud‑infrastruktur &amp; migrering" scheme="https://software.engineer.company/da/services/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <category term="Systemadministration" scheme="https://software.engineer.company/da/services/" />
    <summary>Designede og byggede som en af de første medarbejdere hele kerneinfrastrukturen fra bunden for en grøn-energi-SaaS-startup — grundlag for vækst.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Det her var en grøn‑energi‑SaaS‑startup med en lovende idé og reelt ingen teknisk fundament under sig endnu. At komme ind som en af de første medarbejdere betød det stadie, hvor der ikke er noget at vedligeholde, fordi der ikke findes noget — man bygger den grund, alle andre skal stå på.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At bygge kerneinfrastrukturen og processerne omkring den, fra bunden, var jobbet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Hele kerneinfrastrukturen og dens understøttende processer blev designet og bygget — serverne, netværkene, dataflowet, sikkerheden, driftssiden. At gøre det i en startup betyder at træffe beslutninger, der er svære at omgøre senere, så målet var ikke bare &amp;ldquo;få noget til at køre&amp;rdquo;, det var at lægge et fundament, der kunne bære vægten af hurtig vækst uden at skulle rives ud i det øjeblik, virksomheden blev større. Tidlige infrastrukturvalg bliver enten det, der lader dig skalere, eller det, du bruger et år på at gøre om; sigtet var klart den første slags.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Startuppen kom ud med et solidt teknisk fundament, og det er det, der lod forretningen vokse hurtigt bagefter. At være den, der bygger den base fra ingenting, er en særlig slags ansvar — gør du det rigtigt, bemærker ingen det, gør du det forkert, bemærker alle det — og denne holdt.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har vedligeholdt og forbedret det ældre Hugo‑baserede statiske website og bidraget med UI/UX‑forbedringer til det primære asset management‑produkt.</title>
    <id>https://software.engineer.company/da/portfolio/maintained-and-enhanced-the-legacy-hugo-static-site-87/</id>
    <link href="https://software.engineer.company/da/portfolio/maintained-and-enhanced-the-legacy-hugo-static-site-87/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Vedligeholdt og forbedrede et ældre Hugo-baseret website og bidrog med UI/UX-forbedringer til det centrale asset management-produkt.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Der var et ældre website bygget på Hugo — en statisk site‑generator — der kørte ved siden af virksomhedens hovedprodukt, et asset management‑system. Websitet var den gamle, etablerede ting; produktet var, hvor den reelle værdi sad.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At holde websitet sundt og samtidig forbedre produktets oplevelse var opgaven.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Det statiske Hugo‑site blev vedligeholdt og forbedret — holdt opdateret og fungerende — mens UI/UX‑forbedringer og feedback samtidig fodredes ind i det primære asset management‑produkt. At dele opmærksomheden mellem et ældre site og flagskibsproduktet handler mest om ikke at lade den gamle ting rådne, mens man er fokuseret på den nye; begge repræsenterer virksomheden over for nogen, så begge skulle holdes anstændige.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Websitet forblev opdateret i stedet for stille at ældes, og hovedproduktets brugervenlighed blev bedre gennem stabil, velinformeret forfinelse — den slags, der kommer af faktisk at bruge og tænke over tingen frem for at redesigne den i ét stort greb.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har skabt succes for kunder på nettet ved at kombinere skræddersyet webudvikling og -design med SEO, indholdsstrategi og tekstforfatning.</title>
    <id>https://software.engineer.company/da/portfolio/drove-client-web-success-by-combining-custom-website-91/</id>
    <link href="https://software.engineer.company/da/portfolio/drove-client-web-success-by-combining-custom-website-91/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Brand &amp; marketing" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produkt &amp; krav" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Brand, marketing &amp; SEO" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Skabte succes for kunder på nettet ved at kombinere skræddersyet webudvikling og -design med SEO, indholdsstrategi og tekstforfatning.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Kunder ville ikke egentlig have et website; de ville have det, et website er ment til at gøre for dem — at blive fundet, at trække kunder ind, faktisk at virke som en kanal. Et smukt site, ingen kan finde, er en fiasko, der ligner en succes.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At kombinere opbygningen og vækstsiden i ét tilbud var opgaven, frem for at aflevere et site og ønske dem held og lykke.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; De to halvdele blev sat sammen — skræddersyet webudvikling og -design på den ene side, SEO, indholdsstrategi og tekstforfatning på den anden — så en kunde fik noget, der både var velbygget og faktisk synligt. De bliver som regel behandlet som separate jobs, hvilket er, hvordan man ender med et smukt site, der rangerer ingen steder, eller et veloptimeret site, der er ubehageligt at bruge. At gøre begge dele betød, at sitet var designet fra starten til at blive fundet, ikke optimeret som en eftertanke.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Kunderne endte med stærkere synlighed og mere engagement — deres sites virkede som ægte vækstkanaler frem for online brochurer. At bygge tingen og gøre den findbar i én omgang er det, der gjorde et website fra en omkostning til noget, der faktisk tjente sig ind.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget en lagdelt automatiseret testsuite — 981 Go‑tests, 543 frontend- og browserspecs, 494 SQL‑adfærdstests — med mutationstest, property‑based tests og en tilgængelighedsgate.</title>
    <id>https://software.engineer.company/da/portfolio/built-a-layered-automated-test-suite-across-four-layers-94/</id>
    <link href="https://software.engineer.company/da/portfolio/built-a-layered-automated-test-suite-across-four-layers-94/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk ledelse &amp; rådgivning" scheme="https://software.engineer.company/da/services/" />
    <summary>Byggede en lagdelt testsuite — 981 Go-tests, 543 frontend-specs og 494 SQL-adfærdstests — med gates for mutation, property-based test og tilgængelighed.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; En platform, der holder sin forretningslogik i databasen, har et testproblem, de fleste projekter ikke har. Logikken er ikke i det sprog, testframeworket er godt til — den er i SQL, bag funktionsgrænser, og SQL er præcis den slags kode, der ender utestet, fordi det er akavet at teste. Læg et Go‑API og en Next.js‑frontend oven på det, og &amp;ldquo;de vigtige dele er dækket&amp;rdquo; bliver stille og roligt til &amp;ldquo;de dele, der var nemme at dække, er dækket.&amp;rdquo;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Hvert lag skulle have sin adfærd kontrolleret dér, hvor adfærden faktisk bor, frem for at alt blev kontrolleret udefra gennem en browser.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Fire lag fik fire slags test. Go‑API&amp;rsquo;et bærer 981 testfunktioner fordelt på 310 filer. Frontenden bærer 543 Vitest- og Playwright‑specs, heraf 48 end‑to‑end‑filer og 30 browser‑specs. Databasen bærer 494 adfærdstestfiler — 116.876 linjer SQL, der tjekker sine antagelser gennem 6.654 rejste exceptions — så en stored function bliver testet i databasen frem for gennem tre lag applikation ovenover. Over dem ligger de test, der tester testene: Stryker mutation testing ødelægger med vilje en linje kode og fejler, når intet opdager det, og fast‑check genererer input, ingen tænkte på at skrive ned. En axe‑core‑gate kræver nul WCAG 2.0- og 2.1‑overtrædelser på niveau A og AA, hvilket gør tilgængelighed til noget, der får buildet til at fejle, frem for et revisionsfund måneder senere. Coverage‑tærskler bevæger sig kun opad. Hele suiten kører som 10 jobs i et 612‑linjers workflow.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; At ændre noget strukturelt holdt op med at være skræmmende, og det er det eneste, der holder et kodebase af den størrelse fra at forkalke. Den ærlige omkostning er tid — suiten er langsom, den beskatter hver eneste ændring, og i den størrelse skal den selv vedligeholdes. Det, den køber, er evnen til at blive ved med at bevæge sig hurtigt, og det er mere værd end de minutter, det tager.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget betalings- og rettighedslaget — Stripe side om side med Apple og Google in‑app purchase — så directory, søgning og eksport spærres af en adgangsmodel på 11 tabeller, der tjekkes på serveren.</title>
    <id>https://software.engineer.company/da/portfolio/built-the-payments-and-entitlements-layer-96/</id>
    <link href="https://software.engineer.company/da/portfolio/built-the-payments-and-entitlements-layer-96/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produkt &amp; krav" scheme="https://software.engineer.company/da/categories/" />
    <category term="Sikkerhed" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Databasedesign &amp; datamodellering" scheme="https://software.engineer.company/da/services/" />
    <category term="Produktstrategi &amp; kravspecifikation" scheme="https://software.engineer.company/da/services/" />
    <category term="Sikkerhed &amp; adgangsstyring" scheme="https://software.engineer.company/da/services/" />
    <summary>Byggede betalings- og rettighedslaget — Stripe med Apple og Google in-app purchase — directory, søgning og eksport spærret af en adgangsmodel.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Penge er den del af en platform, ingen har lov til at tage let på. Et abonnement skal overleve, at et kort udløber, en refusion, et planskifte, en webhook, der ankommer to gange, og en webhook, der ankommer i forkert rækkefølge. I det øjeblik betaling kan ske i tre butikker — et kort på nettet, Apple i den ene app store, Google i den anden — findes der tre forskellige udlægninger af, hvad nogen har købt, og produktet har stadig brug for ét svar på ét spørgsmål: hvad må denne person lige nu?&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At tage imod penge og at give adgang skulle være to systemer frem for ét, så det at tilføje en butik ikke betød at omskrive hver eneste gate i produktet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Stripe håndterer kort og abonnementer gennem 18 Go‑filer, og Apple- og Google‑in‑app‑køb kommer ind gennem deres egen kvitteringsverifikation. Alle tre løber sammen i et payments‑skema på 9 tabeller og 34 funktioner — og stopper så dér. Det, produktet faktisk spørger om, er et separat access‑skema på 11 tabeller og 34 funktioner, som svarer på &amp;ldquo;må denne konto det her?&amp;rdquo; uden at vide eller bryde sig om, hvilken butik der har betalt for det. Det svar styrer adgangen til virksomhedskataloget, søgningen og dataeksporten, og det genkontrolleres på serveren ved hver request, for en skjult knap er en høflighed og ikke en kontrol.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; At tilføje en butik rører nu ved payments‑siden og lader alle gates være, og et supportspørgsmål om nogens adgang har én tabel at kigge i frem for tre. Omkostningen er to skemaer, hvor et mindre produkt ville nøjes med ét, plus et rettighedsopslag på requests, der ellers ville have været gratis.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har flyttet langsomt arbejde væk fra request‑stien og over på en River‑jobkø — 15 worker‑moduler, 8 planlagte opgaver og 20 pg_cron‑jobs — så et request vender tilbage, mens arbejdet bag det kører videre.</title>
    <id>https://software.engineer.company/da/portfolio/moved-slow-work-onto-a-river-job-queue-97/</id>
    <link href="https://software.engineer.company/da/portfolio/moved-slow-work-onto-a-river-job-queue-97/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Databasedesign &amp; datamodellering" scheme="https://software.engineer.company/da/services/" />
    <category term="Site reliability &amp; monitorering" scheme="https://software.engineer.company/da/services/" />
    <summary>Flyttede langsomt arbejde væk fra request-stien over på en River-jobkø: 15 worker-moduler, 8 planlagte opgaver og 20 pg_cron-vedligeholdelsesjobs.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Noget arbejde har ingen gang på jorden, mens en bruger venter. At sende mail, at genopbygge et søgeindeks, at generere et dokument, at genberegne placeringer — gør noget af det inde i requesten, og brugeren kigger på en spinner for noget, de aldrig bad om at se. Gør det i stedet i en goroutine, og det forsvinder i det øjeblik processen genstarter, hvilket den gør, midt i en deploy, uden spor af, at det nogensinde skulle være sket.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Baggrundsarbejde havde brug for et holdbart sted at bo: en kø, der overlever en genstart, prøver en fejl igen og kan kigges efter, når noget ikke er sket.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Valget faldt på River, i høj grad fordi den holder sin kø i PostgreSQL — databasen er i forvejen det autoritative register, så et job og de rækker, det rører, committer eller ruller tilbage sammen, og der er ikke et stykke infrastruktur nummer to at køre og ræsonnere om. Bag den ligger 15 worker‑moduler og 8 planlagte opgaver. Under det håndterer 20 pg_cron‑jobs den vedligeholdelse, databasen er bedre placeret til at gøre selv: at beskære partitioner, at rotere salts, at opfriske aggregater. Alt, der var langsomt nok til at blive bemærket, blev flyttet væk fra request‑stien og over på en af de to.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Requests svarer hurtigt, og det langsomme arbejde bliver stadig færdigt, med retries og en synlig historik, når det ikke gør. At holde køen i Postgres frem for i en dedikeret broker er en bevidst begrænsning: det skalerer ikke i det uendelige, og ved en vis mængde bliver det det forkerte svar. For en platform, hvis flaskehals alligevel er databasen, var én bevægelig del mindre mere værd end luft, der ikke ville blive brugt.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget egen error monitoring og OpenTelemetry‑tracing frem for at købe dem — sanitering af payloads, detektion af spikes og regressioner, symbolication og et syntetisk heartbeat — bag 11 operatørvisninger.</title>
    <id>https://software.engineer.company/da/portfolio/built-first-party-error-monitoring-and-tracing-98/</id>
    <link href="https://software.engineer.company/da/portfolio/built-first-party-error-monitoring-and-tracing-98/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Infrastruktur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Monitorering &amp; observability" scheme="https://software.engineer.company/da/categories/" />
    <category term="Sikkerhed" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Site reliability &amp; monitorering" scheme="https://software.engineer.company/da/services/" />
    <summary>Byggede egen error monitoring og OpenTelemetry-tracing — sanitering, detektion af spikes, symbolication og et heartbeat — bag 11 operatørvisninger.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Forskellen på en platform, der er oppe, og en platform, der virker, er, om nogen ville vide det. En fejl, en bruger rammer klokken elleve om aftenen, på en side ingen tester, er usynlig, medmindre noget går ud og samler den op. Det sædvanlige svar er at købe en hosted error tracker, og det er et godt svar — og det betyder også, at platformens egne fejl, stack traces og brugerkontekst rejser af sted til en tredjepart.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Fejl og traces skulle samles, grupperes og gøres til noget, man kunne handle på, uden at platformens indre forlod platformen.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Der blev bygget to stykker. OpenTelemetry står for tracing over OTLP, så en langsom request kan følges på tværs af frontenden, API&amp;rsquo;et og databasen frem for at blive gættet på. Ved siden af ligger en hjemmebygget fejl‑pipeline — en errmon‑service og en ingest‑service — der renser payloads før lagring, grupperer fejl i tilbagevendende problemer frem for en flad liste, opdager spikes og regressioner med en cooldown, så én dårlig deploy ikke kalder nogen ud fyrre gange, oversætter minificerede frontend‑stack traces tilbage til læsbar kode og kører en syntetisk heartbeat for at bevise, at selve pipelinen er i live. Det hele lander i databasen som error events, error groups, en inbox, API‑latens og stack‑samples, og det kommer frem gennem 11 operatørvisninger, heriblandt én til service level objectives.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Fejl bliver til en kø, nogen kan arbejde sig igennem, og en regression melder sig selv i stedet for at blive opdaget af en bruger. At bygge frem for at købe kostede reel tid og betyder, at det er én ting mere at vedligeholde — en købt tracker ville have kørt samme eftermiddag. Det, det købte, var, at intet følsomt forlader platformen, og at alarmreglerne passer til netop denne platform frem for til en generisk.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget fail‑closed misbrugskontroller — 22 Redis‑baserede rate limiters, Cloudflare Turnstile, idempotens på requests og en origin‑lås — så platformen afviser bots og floods i stedet for at stole på sine kaldere.</title>
    <id>https://software.engineer.company/da/portfolio/built-fail-closed-abuse-controls-and-rate-limiting-100/</id>
    <link href="https://software.engineer.company/da/portfolio/built-fail-closed-abuse-controls-and-rate-limiting-100/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Netværk &amp; VPN" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Sikkerhed" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Sikkerhed &amp; adgangsstyring" scheme="https://software.engineer.company/da/services/" />
    <category term="Site reliability &amp; monitorering" scheme="https://software.engineer.company/da/services/" />
    <summary>Byggede fail-closed misbrugskontroller: 22 Redis-baserede rate limiters, Cloudflare Turnstile, idempotens på requests og en origin-lås ved indgangen.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Et offentligt katalog over virksomheder og fagfolk er et mål fra den dag, det går i luften. Scrapere vil have dataene, spamkonti vil have rækkevidden, og et endpoint, der koster platformen rigtige penge at levere — søgning, eksport, alt der rører en ekstern API — er værd at misbruge alene, fordi det er gratis at kalde. Intet af det er ondskab rettet mod netop denne platform; det er baggrundsvejr på det åbne internet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; De dyre stier og dem, der inviterer til misbrug, havde brug for grænser, der holder under pres — også presset fra, at limiterens egen afhængighed ikke er tilgængelig.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Der er 22 rate limitere, hver bygget til den sti, den beskytter, frem for ét globalt loft, for et loginforsøg, en søgning og en bulk‑eksport bliver misbrug ved vildt forskellige hastigheder. Tilstanden bor i Redis, så en grænse deles på tværs af instanser i stedet for at være per proces og trivielt at slippe uden om. Den vigtige beslutning er, hvad der sker, når Redis ikke er der: limiterne er fail‑closed. Trafik afvises frem for at blive vinket igennem, hvilket er det mindre bekvemme svar og det eneste forsvarlige. Omkring dem sidder Cloudflare Turnstile på de stier, der er værd at udfordre, 351 linjers idempotency‑middleware, så en genforsøgt skrivning ikke bliver til to, en origin‑lås, der afviser requests, som ikke kommer ind ad hoveddøren, og en skræddersyet challenge på selve kataloget.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Misbrug bliver dyrt for den, der misbruger, og billigt for platformen, og et udfald i limiterens eget lager degraderer til afvisning frem for til en åben dør. At være fail‑closed betyder ganske vist, at et Redis‑problem bliver et problem, brugeren kan se — accepteret med vilje, fordi alternativet er, at et Redis‑problem bliver et regningsproblem.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget operatørernes back‑office — omkring 40 admin‑ruter og 128 komponenter, der dækker claims, moderation, feature flags, cache og diagnostik — så platformen kan drives uden databaseadgang.</title>
    <id>https://software.engineer.company/da/portfolio/built-the-operator-back-office-for-the-platform-102/</id>
    <link href="https://software.engineer.company/da/portfolio/built-the-operator-back-office-for-the-platform-102/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produkt &amp; krav" scheme="https://software.engineer.company/da/categories/" />
    <category term="Systemadministration" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Produktstrategi &amp; kravspecifikation" scheme="https://software.engineer.company/da/services/" />
    <summary>Byggede operatørernes back-office — omkring 40 admin-ruter og 128 komponenter til claims, moderation, feature flags, cache og diagnostik.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Enhver platform får stille og roligt en applikation nummer to, og det er som regel den, ingen planlægger. Nogen skal godkende et ejerskabskrav, skjule en anmeldelse, slå en funktion til for en delmængde af brugerne, rydde en cache eller finde ud af, hvorfor én konto ser noget mærkeligt. Når den applikation ikke findes, er svaret en engineer med en databasekonsol — hvilket er langsomt, ulogget og én slåfejl fra en hændelse.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; At drive platformen fra dag til dag skulle kunne lade sig gøre uden en shell, så driften hørte til hos den, der havde vagten, frem for hos den, der havde adgangsoplysningerne.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Back‑officen endte på omkring 40 admin‑ruter bygget af 128 komponenter, og den dækker arbejdet, som det faktisk kommer ind: at afgøre ejerskabskrav på virksomheder, moderere anmeldelser og opslag, vippe feature flags, inspicere og rydde caches, læse diagnostik og den rapportering, CEO&amp;rsquo;en beder om. Den kører på det samme designsystem og den samme genererede API‑klient som det offentlige produkt, hvilket var det afgørende valg — et internt værktøj bygget på sin egen stak bliver den del, ingen opdaterer, og derefter den del, ingen stoler på.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; De folk, der driver platformen, kan drive den, og hver handling går gennem den samme autorisation og efterlader det samme spor som alt andet. Det er en stor flade at holde testet og tilgængelig for et lille internt publikum, og den omkostning løber videre. Den er stadig billigere end alternativet, som er en engineer, der taster UPDATE mod produktion klokken ni en søndag aften.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget ejerskabskrav på virksomheder fra ende til anden — en bruger gør krav på en virksomhed, en administrator afgør sagen, og en godkendelse omskriver den autorisationsgraf, der afgør, hvem der må redigere hvad.</title>
    <id>https://software.engineer.company/da/portfolio/built-company-ownership-claims-end-to-end-103/</id>
    <link href="https://software.engineer.company/da/portfolio/built-company-ownership-claims-end-to-end-103/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produkt &amp; krav" scheme="https://software.engineer.company/da/categories/" />
    <category term="Sikkerhed" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Produktstrategi &amp; kravspecifikation" scheme="https://software.engineer.company/da/services/" />
    <category term="Sikkerhed &amp; adgangsstyring" scheme="https://software.engineer.company/da/services/" />
    <summary>Byggede ejerskabskrav på virksomheder fra ende til anden: en bruger gør krav, en administrator afgør, og godkendelsen omskriver autorisationsgrafen.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Et katalog seedet fra offentlige kilder har et strukturelt problem: virksomhederne i det har ikke selv sat sig der. Før eller siden dukker nogen fra en af dem op og vil rette sin egen post — og der er ingen relation mellem den person og den post, kun en påstand om, at der er en. Giver man det for villigt, redigerer en konkurrent din side. Giver man det for langsomt, bliver kataloget ved med at være forkert.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Der skulle være en vej fra &amp;ldquo;det her er min virksomhed&amp;rdquo; til reel myndighed over posten, med en menneskelig beslutning i midten og et spor bagefter.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Ejerskabskrav blev bygget fra ende til anden, over 108 commits og begge applikationer. En bruger indsender et krav med dokumentation; det lander i en kø i back‑officen; en administrator gennemgår det og godkender eller afviser det med en begrundelse, der går tilbage til den, der rejste kravet. Det interessante er, hvad en godkendelse gør — det er ikke et flag på en række. Godkendelsen omskriver autorisationsgrafen, så kontoen får en rigtig relation til organisationen, og det er den samme relation, som hvert eneste rettighedstjek i platformen allerede slår op i. Gaten er afgørelsen, ikke kodestien, og ingen funktion har været nødt til at lære om ejerskabskrav for at respektere den.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; En virksomhed kan overtage og rette sin egen post, uden at nogen redigerer databasen i hånden, og hver tildeling af myndighed har en navngiven godkender og en begrundelse hæftet på. Den menneskelige gennemgang er flaskehalsen med vilje; et automatisk tjek på et domænenavn ville være hurtigere og ville tage fejl i præcis de tilfælde, der betyder mest.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget loyalitets- og omdømmesystemet — 67 funktioner over et ledger på 31 tabeller, med ligaer, badges og en indløsningsshop — med en row lock på saldoen, der lukker double‑spend‑vinduet.</title>
    <id>https://software.engineer.company/da/portfolio/built-the-loyalty-and-reputation-system-105/</id>
    <link href="https://software.engineer.company/da/portfolio/built-the-loyalty-and-reputation-system-105/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produkt &amp; krav" scheme="https://software.engineer.company/da/categories/" />
    <category term="SQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Databasedesign &amp; datamodellering" scheme="https://software.engineer.company/da/services/" />
    <category term="Produktstrategi &amp; kravspecifikation" scheme="https://software.engineer.company/da/services/" />
    <summary>Byggede loyalitets- og omdømmesystemet — 67 funktioner over et ledger på 31 tabeller, ligaer, badges og en shop — med row lock på saldoen.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Professionelt netværk har et cold start‑problem: platformen er værd at bruge, når andre allerede bruger den, og indtil da er der ikke meget grund til at komme tilbage. Den sædvanlige løftestang er et belønningssystem — point for at bidrage, en standing der afspejler omdømme — som er nemt at beskrive og lumsk at bygge, for i det øjeblik point kan bruges, er de penge, og hver eneste fejl, penge kan lave, kan laves her.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Bidrag skulle kunne måles og belønnes, med en saldo, der ikke kunne bruges to gange.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Loyalty‑skemaet løber op i 31 tabeller og 67 funktioner, med standing i yderligere 5 tabeller og 32 funktioner, og discovery- og personalization‑skemaer ved siden af til at afgøre, hvad et givent medlem ser. Oven på ledgeren sidder ligaer, badges og en indløsningsshop, hvor en saldo bliver til noget virkeligt. Det, der krævede omhuen, er den ældste fejl i bogen: tjek saldoen, brug den så, og to requests, der ankommer samtidig, passerer begge tjekket. Hver mutation tager en row lock på walleten, før den læser den, så den anden request venter på, at den første bliver færdig, frem for at kappes med den. At walleten ligger i den samme database som alt andet er det, der overhovedet gør det muligt — saldoen og det, den købte, committer sammen eller slet ikke.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Bidrag bliver målt og belønnet, og en saldo er et regnestykke frem for en tilnærmelse. Row locking er det langsommere svar og blev valgt alligevel: kamp om den samme wallet bliver til en kø, og alternativet er et medlem, der bruger de samme point to gange, og nogen, der afstemmer det i hånden bagefter.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget platformens sociale lag — opslag, feed, grupper, mentions, en følgergraf og et digest over mærkedage — på samme function‑first datalag som resten af produktet.</title>
    <id>https://software.engineer.company/da/portfolio/built-the-platform-s-social-layer-106/</id>
    <link href="https://software.engineer.company/da/portfolio/built-the-platform-s-social-layer-106/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produkt &amp; krav" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Produktstrategi &amp; kravspecifikation" scheme="https://software.engineer.company/da/services/" />
    <summary>Byggede platformens sociale lag — opslag, feed, grupper, mentions, følgergraf og et digest over mærkedage — på samme function-first datalag.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Et katalog over virksomheder er et opslagsværk. Folk slår op i det og går igen. Det, der gør en professionel platform værd at vende tilbage til, er, at der er andre mennesker på den — hvilket betyder opslag, grupper og en grund til at komme tilbage, som ikke er en mail, der beder dig om det.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Der skulle lægges et socialt lag på, uden at det blev til et system nummer to med sine egne regler, sine egne rettigheder og sin egen måde at gemme ting på.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Opslag, et feed, grupper, mentions, en follower‑graf og et digest over mærkedage gik ind over 188 commits, alt sammen på det samme function‑first datalag som resten af platformen. Den begrænsning gjorde det meste af arbejdet: follower‑grafen er tabeller og funktioner som alt andet, en mention slås op gennem det samme identity‑skema, som kataloget bruger, og et opslag arver den moderationskø, der allerede var bygget til anmeldelser. Intet her havde brug for sit eget lager eller sin egen rettighedsmodel. Feedet er det ene sted, der satte sig imod, for at samle en personaliseret timeline effektivt er et oprigtigt anderledes problem end at hente en række, og det er der, personalization- og discovery‑arbejdet gør sig fortjent til sin plads.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Platformen har en grund til at blive åbnet på en dag, hvor ingen har brug for at slå en virksomhed op, og den kom uden en parallel stak at vedligeholde. Om et socialt lag er den rigtige investering for et maritimt katalog, er et produktspørgsmål frem for et engineering‑spørgsmål — det er her, fordi produktet bad om det, og det er bygget på samme måde som alt omkring det.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget rekrutteringsmarkedspladsen og søfarendes karriere‑workspace — 151 stored functions på tværs af 48 tabeller — med ledige stillinger, ansøgninger, certifikater, avancement i grader og verificeret sejltid.</title>
    <id>https://software.engineer.company/da/portfolio/built-the-hiring-marketplace-and-career-workspace-107/</id>
    <link href="https://software.engineer.company/da/portfolio/built-the-hiring-marketplace-and-career-workspace-107/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="PostgreSQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produkt &amp; krav" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Databasedesign &amp; datamodellering" scheme="https://software.engineer.company/da/services/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Produktstrategi &amp; kravspecifikation" scheme="https://software.engineer.company/da/services/" />
    <summary>Byggede jobmarkedspladsen og søfarendes karriereområde — 151 stored functions på tværs af 48 tabeller — stillinger matchet på dokumenterede kvalifikationer.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Det kommercielle argument for et maritimt professionelt netværk er rekruttering: virksomheder har brug for besætning og officerer, og søfarende har brug for hyre. Begge halvdele fandtes allerede på platformen i den forkerte form — virksomhederne lå i kataloget, de professionelle havde profiler, og der var intet, der forbandt en ledig stilling med den person, der var kvalificeret til at udfylde den. Kvalifikationen er den svære del, for i denne branche er det certifikater, grader og dokumenteret sejltid frem for en jobtitel.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Ledige stillinger, ansøgninger og verificerbare kvalifikationsbeviser for søfarende skulle modelleres ordentligt frem for som fritekst på en profil.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; To domæner blev bygget. Rekrutteringssiden løber op i 32 tabeller og 118 funktioner, der dækker ledige stillinger, ansøgninger, shortlisting og arbejdsgiverens billede af en pipeline. Karriere‑workspacet bærer 16 tabeller og 33 funktioner, der rummer certifikater, gradprogression og sejltid, med dokumentupload og en gennemgangskø, så et kvalifikationsbevis bliver kontrolleret frem for påstået. At modellere progression som en graf frem for en liste er det, der gør matchningen brugbar — en grad er nåelig fra en anden grad givet bestemte certifikater og nok registreret tid til søs, og den struktur er det, der lader en ledig stilling blive matchet mod en karriere frem for mod et nøgleord. Karriere‑workspacet sendes bag et feature flag og er ikke fuldt released; rekrutteringssiden er live.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; En ledig stilling kan matches mod dokumenterede kvalifikationer i stedet for en selvbeskrevet jobtitel, og det er hele forskellen mellem et jobopslagssite og et rekrutteringsværktøj i denne branche. Verifikationen er flaskehalsen, med vilje — en gennemgangskø skalerer ikke, som et automatisk tjek ville, og et automatisk tjek ville certificere folk, der ikke burde certificeres.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har kørt hele virksomheden på én vært med 512 MB og én kerne — en git‑forge, en webserver til syv domæner, Tor, to servere til alternative protokoller, backup og udelukkelse af indtrængen — ved at behandle 464 MB brugbar hukommelse som den bindende arkitektoniske begrænsning.</title>
    <id>https://software.engineer.company/da/portfolio/ran-the-whole-company-on-one-512mb-host-109/</id>
    <link href="https://software.engineer.company/da/portfolio/ran-the-whole-company-on-one-512mb-host-109/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Infrastruktur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Linux &amp; servere" scheme="https://software.engineer.company/da/categories/" />
    <category term="Løsningsarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Platformarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Systemadministration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Cloud‑infrastruktur &amp; migrering" scheme="https://software.engineer.company/da/services/" />
    <category term="Infrastructure as Code" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <category term="Systemadministration" scheme="https://software.engineer.company/da/services/" />
    <summary>Hele virksomheden kører på en maskine der koster mindre om måneden end en frokost, og designet er bedre af disciplinen frem for blot billigere.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Virksomhedens produktionsvært er en cloud‑instans med én kerne, 512 MB hukommelse og 10 GB disk, hvoraf omkring 464 MB er anvendelige. Alt hvad forretningen kører offentligt ligger på den: webserveren der terminerer TLS for syv domæner, git‑forgen, en Tor‑onion‑tjeneste, en Gemini‑server, en Gopher‑server, krypterede sikkerhedskopier og indtrængningsblokering. Den sædvanlige reaktion på den liste er at købe en større maskine.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Begrænsningen skulle behandles som et arkitektonisk input frem for et problem man bruger penge på, for det ærlige spørgsmål var ikke om en større maskine ville virke, men om designet havde brug for en.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Hukommelse blev det argument der afgjorde beslutninger. Der er ingen overvågningsagent, ingen metrikpipeline og intet dashboard — rapportering er et pull, syv kommandoer der læser værten og gengiver Markdown, ændrer intet og kun kører når man spørger. Supervisoren er systemd frem for endnu en proceshåndtering lagt oven på den, og containerplanet er Quadlet‑units under den samme supervisor frem for en dæmon med sin egen. Webpanel‑platforme blev udelukket på designstadiet af samme grund. Da spørgsmålet kom op om værten kunne bære en onion‑tjeneste, kom svaret fra en dags målte stikprøver frem for fra en holdning: tilgængelig hukommelse faldt aldrig under omkring 310 MB af 464, swap lå på 2,6 procent og processoren var 99,7 procent inaktiv.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Hele virksomheden kører på en maskine der koster mindre om måneden end en frokost, og designet er bedre af disciplinen frem for blot billigere. Det den kostede er råderum til noget som helst skødesløst — post ligger bevidst slet ikke på denne maskine — den er skrevet som et installationsstillads, der venter på sin egen vært, fordi en mailserver kræver råderum, denne maskine allerede har brugt, og det er skrevet ned frem for opdaget senere.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har udrullet virksomhedens egen git‑forge på Soft Serve, privat som udgangspunkt og uden webpanel, med SSH‑porten bundet til loopback bag en jump‑vært, og har gjort landingssiden foran den til et build‑artefakt af hovedsitet frem for en håndholdt kopi.</title>
    <id>https://software.engineer.company/da/portfolio/deployed-the-companys-own-git-forge-121/</id>
    <link href="https://software.engineer.company/da/portfolio/deployed-the-companys-own-git-forge-121/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps" scheme="https://software.engineer.company/da/categories/" />
    <category term="Infrastruktur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Linux &amp; servere" scheme="https://software.engineer.company/da/categories/" />
    <category term="Systemadministration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Infrastructure as Code" scheme="https://software.engineer.company/da/services/" />
    <category term="Systemadministration" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Virksomheden hoster sin egen kode på sin egen hardware, og siden foran den arver hvert tjek hovedsitet består frem for at drive væk fra det på måder, kun en…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Virksomhedens kildekode lå hos en tredjeparts hostingtjeneste, hvilket er et rimeligt sted til den og en dårlig pasform for en forretning, hvis argument over for kunderne er, at den ikke overlader deres data til mellemled. At køre en forge i stedet betyder at køre en forge: autentificering, adgangskontrol, lagring, sikkerhedskopier og et offentligt ansigt til den.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; En kanonisk git‑server skulle rejses på den eksisterende vært, med den mindst mulige angrebsflade og intet webadministrationspanel, og en landingsside foran den, der ikke rådner.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Forgen er en enkelt binær overvåget af styresystemet, installeret fra leverandørens pakkerepository, bevidst valgt for at være SSH‑først uden administrativ webgrænseflade — jo mindre grænseflade, jo mindre at forsvare. Den er privat som standard: anonym adgang afvises, nøglefri adgang afvises, og hvert erklæret repository er markeret privat frem for at læne sig på uklarhed. Dens SSH‑lytter binder sig kun til loopback‑grænsefladen på port 23231 og nås udefra gennem en jump host, så firewallens erklærede overflade ikke vokser. En protokolmultiplexer, der ville lægge HTTPS og git‑SSH på én offentlig port ved at inspicere de første bytes af en forbindelse, er skrevet og klar bag en hovedafbryder, og den afbryder er slukket: git for flere brugere over den offentlige port er ikke nødvendigt endnu, og en lytter ingen bruger er overflade. Landingssiden foran den var det mere interessante problem. Den havde været en håndholdt kopi af hovedsitets design i sit eget repository, og hver eneste forskel der nogensinde blev fundet mellem de to, viste sig at være et uheld frem for en beslutning: en typeskala der gengav ordmærket omkring ni procent for stort, en fonterklæring der slog to vægte sammen til én på enhver maskine med familien installeret, ornamenter skjult under en bestemt bredde så de var fraværende på hver telefon, en vægt brugt uden en font leveret til den, og intet hovedlandmærke eller overskrift på øverste niveau på nogen side. Fem ud af fem, og ikke én synlig på et skærmbillede. Kopien blev slettet; landingssiden bygges nu af hovedsitets egne skabeloner og leveres som et artefakt.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Virksomheden hoster sin egen kode på sin egen hardware, og siden foran den arver hvert tjek hovedsitet består frem for at drive væk fra det på måder, kun en måling kan se. Afvigelse er stadig mulig og skal nu skrives ned.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget et flersproget statisk site i Hugo på tværs af 108 skabelonfiler heraf 53 partials, der udgiver hver side i fire repræsentationer fra ét indholdstræ på tre sprog, og igen under syv fokuserede subdomæner bygget af det samme træ.</title>
    <id>https://software.engineer.company/da/portfolio/built-a-multilingual-static-site-in-hugo-126/</id>
    <link href="https://software.engineer.company/da/portfolio/built-a-multilingual-static-site-in-hugo-126/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Internationalisering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Internationalisering &amp; lokalisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Sitet leverer tre sprog og fire repræsentationer fra ét træ, har ingen backend at angribe og intet at fakturere, og det ene stykke JavaScript i det holdes til…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Virksomheden havde brug for et offentligt site, der virker på tre sprog, beviser formåen frem for at påstå den, intet koster at drive og ikke overlader sine besøgende til nogen. De fleste af dem er almindelige krav. Tilsammen udelukker de næsten ethvert indholdsstyringssystem, for en backend der kører, er noget der skal sikres, opdateres, betales for og forklares på en privatlivsside.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Sitet skulle genereres udelukkende ved bygningstid og stadig opføre sig som et moderne — søgbart, installerbart, syndikeret, printbart og læsbart af en skærmlæser på hvert sprog det leveres i.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Det er et statisk site: 108 skabelonfiler, hvoraf 53 er partials og 18 er shortcodes, tre sprog, ingen backend der kører, og ét førstepartsscript givet som en afgrænset undtagelse til et porteføljefilter, hvis samtlige kontroller er skjult, indtil det kører. Formåen tilføjes ved bygningstid frem for i browseren, hvilket er en produktbeslutning og er skrevet ned som en. Hver side udgives i fire repræsentationer fra ét indholdstræ — HTML, en Markdown‑tvilling, et Gemini‑dokument og en Gopher‑menupost — hvor forsiden lægger tre syndikeringsfeeds og et manifest for en installerbar applikation oveni. Taksonomierne er bevidst to frem for én, og skelnen er bærende: en kategori er et emnemærke på arbejdet, en ydelse er noget virksomheden sælger, og at slå dem sammen ville have gjort kataloget til en liste over færdigheder i stedet for en liste over tilbud. Det samme træ bygges derefter syv gange til, én gang per fokuseret subdomæne, ved at pege generatoren på et andet indholdskatalog frem for at forgrene noget som helst.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Sitet leverer tre sprog og fire repræsentationer fra ét træ, har ingen backend at angribe og intet at fakturere, og det ene stykke JavaScript i det holdes til en kontrakt, en linter håndhæver. Prisen er, at alt interaktivt skal løses ved bygningstid eller slet ikke, hvilket har udelukket flere ting, der ville have været lette med en server, og er grunden til at søgeindekset blev prissat og parkeret frem for sendt ud.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har skåret sitets browserdrevne kvalitetsgate fra 1.636 sekunder til 615 ved at planlægge dens tjek længst‑først gennem en worker‑pulje begrænset til fire baner, efter at have målt at alfabetisk rækkefølge kostede 320 sekunder mod 224.</title>
    <id>https://software.engineer.company/da/portfolio/cut-the-visual-quality-gate-to-ten-minutes-128/</id>
    <link href="https://software.engineer.company/da/portfolio/cut-the-visual-quality-gate-to-ten-minutes-128/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk ledelse &amp; rådgivning" scheme="https://software.engineer.company/da/services/" />
    <summary>Gaten gik fra 1.636 sekunder til 615, mens tjekkene blev bredere frem for tyndere — den serielle omkostning steg, og den samlede tid faldt.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Elleve af sitets tjek driver en browser uden grænseflade: layout ved hver vinduesform designet tegner, typeskala, udvidelse af oversat tekst, kontrast, tilgængelighedsregler, tvungne farver, maskotstørrelse, bevægelse, print på tværs af seks papirkombinationer, konsolfejl og visuel regression. Kørt én ad gangen tog de 1.636 sekunder, lidt over syvogtyve minutter. En gate der tager syvogtyve minutter er en gate der bliver sprunget over, og et oversprunget tjek kan ikke skelnes fra et der består.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Den samlede tid skulle ned langt nok til, at det at køre dem var standarden frem for en beslutning, uden at svække nogen af dem.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Arbejdet var måling først. Hvert tjek blev tidsmålt enkeltvis på en maskine med tolv kerner: layout på 405 sekunder, type på 301, oversættelse på 282, kontrast på 189, tilgængelighed på 178, og så videre ned til sytten. To fund formede svaret. At køre dem alle på én gang var langsommere end at køre fire ad gangen — 265 sekunder mod 224 — for hvert tjek er selv en browser der arbejder parallelt, og at overbelaste maskinen koster mere, end samtidigheden vinder. Og at ordne efter længste behandlingstid først slog alfabetisk rækkefølge med næsten en tredjedel, 224 sekunder mod 320, hvilket er det klassiske planlægningsresultat og viser sig her, fordi tjekkene varierer med en faktor tyve i omkostning. Så kørslen er en afgrænset arbejderpulje, dimensioneret ud fra kerneantallet med et gulv på to og et loft på fire, fodret med det længste først. Ved siden af den blev tjekkene udvidet frem for indsnævret: de deler nu én viewport‑tabel med toogtyve vinduesformer, udledt af hver medieforespørgsel stylesheetet faktisk indeholder, hvilket tog layouttjekket alene fra 95 sekunder til 405.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Gaten gik fra 1.636 sekunder til 615, mens tjekkene blev bredere frem for tyndere — den serielle omkostning steg, og den samlede tid faldt. Målingen er den del der er værd at beholde: to fornuftigt lydende valg, at køre alt på én gang og at køre tingene i den rækkefølge de blev skrevet, var hver især målbart dårligere end alternativet.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har erstattet 27 gengivne skriftstørrelser, hvis nærmeste naboer lå 0,6 % fra hinanden, med en seks‑trins Major Third‑skala og har skrevet den linter, der fejler på den otteogtyvende.</title>
    <id>https://software.engineer.company/da/portfolio/replaced-27-font-sizes-with-a-six-step-scale-129/</id>
    <link href="https://software.engineer.company/da/portfolio/replaced-27-font-sizes-with-a-six-step-scale-129/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Brand, marketing &amp; SEO" scheme="https://software.engineer.company/da/services/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <summary>Seks størrelser hvor der var syvogtyve, med et oplyst forhold, en oplyst tekstbredde og et tjek der afviser den næste uplanlagte værdi.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; En måling af sitets gengivne tekst fandt syvogtyve forskellige skriftstørrelser i brug. Flere var adskilt af mindre end én procent — fem værdier mellem 0,8 og 0,85 af brødteksten var alle i live på samme tid, hvilket er en forskel ingen læser kan opfatte, og enhver fremtidig redaktør vil lægge til. To af overskrifterne blev slet ikke størrelsessat af stylesheetet og faldt igennem til browserens egne standarder, et forhold på 1,33 der ikke matchede noget andet på siden.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Størrelserne skulle blive til en skala med et oplyst forhold, og noget skulle forhindre den otteogtyvende.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Skalaen er en stor terts, forhold 1,25, seks navngivne trin fra finskrift til display, hvert et token frem for en værdi. Overskrifter er eksplicit knyttet til trin i stedet for at arve hvad browseren nu mener, hvilket er det der rettede de to, som ikke havde nogen størrelse af deres egen. Kun det nederste trin har et gulv, så finskrift forbliver læselig på en telefon uden at hele skalaen er låst fast. Logotyper er undtaget ved navn frem for ved et tilfælde. Linteren er den del der får det til at holde: den gengiver sitet og fejler på den otteogtyvende forskellige størrelse. Den har allerede vist sit værd to gange — den fangede en overskrift der ankom på 1,17 af brødteksten, hvilket ikke er et trin i noget som helst, og navngav forholdet i fejlbeskeden; og den fangede inline‑kode på 0,9, hvilket er præcis den slags værdi skalaen findes for at forhindre. Sammen med skalaen kom en tekstbredde på omkring tooghalvfjerds tegn, der erstattede en nedarvet fast bredde, som frembragte enoghalvfems tegn på en anmeldelsesside og hundrede og ti på kontaktsiden.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Seks størrelser hvor der var syvogtyve, med et oplyst forhold, en oplyst tekstbredde og et tjek der afviser den næste uplanlagte værdi. Begrænsningen er reel og lejlighedsvis ubelejlig: et design der vil have en størrelse mellem to trin, må flytte sig til et trin eller argumentere for at ændre skalaen, og det argument er blevet ført og tabt mere end én gang.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har taget WCAG 2.2 niveau AA på tværs af 32 repræsentative sider — én pr. skabelon pr. sprog — i begge farvetemaer, plus to AAA‑kriterier, med et dokumenteret konformitetsnotat og et tjek, der forsvarer hver påstand.</title>
    <id>https://software.engineer.company/da/portfolio/took-wcag-2-2-level-aa-across-the-whole-site-130/</id>
    <link href="https://software.engineer.company/da/portfolio/took-wcag-2-2-level-aa-across-the-whole-site-130/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Internationalisering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Internationalisering &amp; lokalisering" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Overholdelse påstås på niveau AA på tre sprog og i to temaer, med to AAA-kriterier derudover, og hver påstand har et tjek bag sig.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Et konsulenthus der sælger ingeniørmæssig dømmekraft og leverer et utilgængeligt website, har et troværdighedsproblem, før det har et tilgængelighedsproblem. Sitet har også en usædvanligt bred flade til det: tre sprog, to farvetemaer, et fuldt printstylesheet, en mørk‑først‑palet, håndtegnede annotationer og en illustreret figur — hver eneste af dem er en måde at fejle et kriterium i én opsætning og bestå det i en anden.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Sitet skulle overholde WCAG 2.2 på niveau AA på tværs af hver side, hvert sprog og begge temaer, og overholdelsen skulle forsvares af tjek frem for påstås i et dokument.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Et konformitetsnotat dokumenterer hvert kriterium i omfanget, hvor hver række navngiver hvad der opfylder det, og hvad der tjekker det. To kriterier på niveau AAA tages ud over målet — visuel præsentation i fuld udstrækning, og fokusfremtoning, som tilbydes frem for påstås. Automatiseringen kører en tilgængelighedsregelmotor med dens bedste praksis‑regler slået til frem for kun konformitetsreglerne, hvilket er en forskel på tredive regler og betød noget med det samme: en af de ekstra regler fejlede i det øjeblik den blev slået til, fordi mærket lå uden for hvert landmærke på hver indre side. Et andet, langsommere tjek kører toogtredive repræsentative sider på tværs af to farveskemaer og to bredder, og det det efterprøver er usædvanligt: fokus bevises i pixels frem for i dokumentet, ved at trykke på tabulatortasten for alvor og sammenligne skærmbilleder, for identiske pixels betyder, at brugeren ikke kan se hvor fokus er, uanset hvad markuppen siger. Det gennemgår også hele siden på jagt efter en tastaturfælde, anvender de angivne tekstafstandsoverstyringer, fordobler rodskriftstørrelsen og måler linjelængde, lige margener, centrering og afsnitsafstand.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Overholdelse påstås på niveau AA på tre sprog og i to temaer, med to AAA‑kriterier derudover, og hver påstand har et tjek bag sig. Hvad sitet siger om det på sin egen kreditside, er den ærlige del: intet automatisk værktøj finder mere end omkring en tredjedel af WCAG‑fejlene, og der har ikke været testet med rigtige hjælpemidler — den grænse står skrevet, hvor en læser vil se den, frem for udeladt af påstanden.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har fundet og rettet 11 tilgængelighedsfejl, som browseren meldte sunde — otte footer‑links stadig i tab‑rækkefølgen bag pointer‑events, en scroll‑tidslinje, der klippede kolofonen af tre sider, og en regelmotor, der kørte 70 af sine 105 regler.</title>
    <id>https://software.engineer.company/da/portfolio/fixed-11-accessibility-defects-the-browser-called-healthy-131/</id>
    <link href="https://software.engineer.company/da/portfolio/fixed-11-accessibility-defects-the-browser-called-healthy-131/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Elleve defekter rettet og, mere nyttigt, fire regler der overlever dem: en vagtpost der tester én akse, forsvarer én akse, et regelsæt der ikke indeholder…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Sitet bestod sine automatiske tilgængelighedsregler. Det havde også elleve defekter, som de regler ikke kunne se, fordi hver af dem var en egenskab ved hvordan siden blev gengivet frem for ved hvad markuppen sagde — den slags som en validator rapporterer som sund, og som en tastaturbruger rammer inden for få sekunder.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Defekterne skulle findes, rettes og skrives op som et regnskab med den regel hver af dem frembragte, så defektklassen lukkes frem for det enkelte tilfælde.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; De faldt i tre grupper. Størrelse: et stylesheet‑nøgleord brugt som var det relativt, låste et helt område til seksten pixels, mens brødteksten løb op til toogtyve; et sænket skrift‑element blev brugt til at betyde &amp;ldquo;mindre&amp;rdquo;; at formindske tekst forlængede en linje, indtil en titel løb til seksoghalvfems tegn; og et målt højdeloft blev overskredet af netop den tekstafstandsoverstyring, sitet påstår at understøtte. Fokus og beskæring: otte fodlinks blev i tabulatorrækkefølgen bag en egenskab, der fjerner pegeinteraktion og intet andet; en overløbsregel skabte en rullebeholder, ingen ville have; og en rulledrevet animation, som ganske enkelt er inaktiv på en side der er for kort til at rulle, beskar permanent foden af tre sider. Og to defekter i vagtposterne selv, som er dem der er værd at navngive — hver vinduesform layouttjekket åbnede, var ni hundrede pixels høj, så en telefon i liggende format på 852 gange 393 gav syv pixels mellem to elementer, og intet tjek havde nogensinde kigget; og regelmotoren havde kørt halvfjerds af sine hundrede og fem regler, så den regel der ville have fanget det manglende landmærke, var ikke i sættet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Elleve defekter rettet og, mere nyttigt, fire regler der overlever dem: en vagtpost der tester én akse, forsvarer én akse, et regelsæt der ikke indeholder reglen, kan ikke håndhæve den, højde er en dimension så test den, og bevis synlighed i pixels frem for i dokumentet. Da layouttjekket blev åbnet ordentligt igen, fejlede det hundrede og otteogtyve gange på tværs af tre sprog, herunder et telefonstort vindue hvor forsidens afsluttende linje lå enogtyve pixels under kanten.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har genereret 495 achievement‑sider på tre sprog fra en skrivebeskyttet SQLite‑eksport, med sidens adresse forfattet som data, så en rettet sætning ikke længere flyttede siden og brød linket.</title>
    <id>https://software.engineer.company/da/portfolio/generated-321-achievement-pages-from-a-sqlite-export-132/</id>
    <link href="https://software.engineer.company/da/portfolio/generated-321-achievement-pages-from-a-sqlite-export-132/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Internationalisering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="SQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Brand, marketing &amp; SEO" scheme="https://software.engineer.company/da/services/" />
    <category term="Internationalisering &amp; lokalisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Udvikling af datapipelines (ETL/ELT)" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Fire hundrede og femoghalvfems sider genereres fra én kilde, at rette et udsagn koster intet, og de adresser dette site nogensinde har udgivet, svarer fortsat.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Virksomhedens porteføljeindhold skrives i en særskilt database — den samme der frembringer CV&amp;rsquo;et — og websitet skal udgive det som sider, på tre sprog, uden at de to kopier driver fra hinanden. Den naive tilgang, at skrive siderne i hånden og holde dem i takt, fejler ved den første rettelse.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Websitet skulle generere sit indhold fra databasen som et byggeinput, med sideadresser der overlever, at sætningerne på dem bliver skrevet om.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; En eksportør læser databasen skrivebeskyttet og skriver én side per achievement per sprog — 495 sider — plus de taksonomi- og ydelsesdata skabelonerne har brug for. Den bruger kun standardbiblioteket, så sitets bygning ikke afhænger af generatorens miljø, og det committede output betyder, at sitet bygger selvstændigt. Den mest konsekvensrige beslutning i den handler om adresser. Sitet plejede at udlede en sides URL fra de indledende ord i dens engelske udsagn, så at rette en sætning flyttede tavst siden og ødelagde hvert link til den — et site hvis argument for sig selv er, at det retter ting, og som opkrævede sig selv et dødt link, hver gang det gjorde. Adressen skrives nu som data: én række per adresse per achievement, den første er den aktuelle, og hver senere er en pensioneret adresse, sitet udsender som en omdirigering. To andre fælder er noteret fra det samme arbejde. En periodesammenligning mod en tekstkolonne matchede tavst alle toogtredive rækker på grund af, hvordan databasen tildeler typeaffinitet på tværs af en sammenligning. Og sproglisten er nu den ene akse, som skriveløkken, datafilerne og forespørgslerne alle udledes af, så at tilføje et fjerde sprog er én opslagspost frem for en søgning.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Fire hundrede og femoghalvfems sider genereres fra én kilde, at rette et udsagn koster intet, og de adresser dette site nogensinde har udgivet, svarer fortsat. Eksportøren ejer også præcis én præsentationsbeslutning — hvordan ydelser grupperes i tematiske afsnit — og det er bevidst: alt andet den skriver, tilhører databasen, og en gruppeoverskrift der mangler et sprog, fejler eksporten frem for at gengive engelsk oven på oversat indhold.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har lukket farvesystemet ved 28 dokumenterede farver med en linter, der fejler på en værdi, der er malet men udokumenteret, dokumenteret men umalet, fejlmålt, omstavet som en literal eller inden for en perceptuel afstand på 0,02 fra en, der allerede findes.</title>
    <id>https://software.engineer.company/da/portfolio/closed-the-colour-system-at-28-colours-133/</id>
    <link href="https://software.engineer.company/da/portfolio/closed-the-colour-system-at-28-colours-133/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Brand, marketing &amp; SEO" scheme="https://software.engineer.company/da/services/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <summary>Paletten er et lukket, målt sæt, der ikke tavst kan vokse, og de to næsten enslydende stavemåder, der foranledigede den, er væk.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Farve på et site med en mørk standard, et lyst tema, et printstylesheet, en tvungne farver‑tilstand og et illustreret mærke forbliver ikke et lille sæt af sig selv. Det var allerede begyndt at drive på den måde det altid gør: to stavemåder af den samme farve liggende tæt nok på, at ingen kunne skelne dem, værdier gentastet som literaler ved siden af de tokens der definerede dem, og dokumenterede farver som intet malede.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Paletten skulle blive et lukket sæt med en oplyst tærskel for særpræg, og noget skulle håndhæve lukningen.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Otteogtyve farver, hver dokumenteret med det kontrastforhold den måler på den flade den optræder på, og elleve mærkeværdier erklæret én gang som tokens. Tærsklen er talmæssig frem for redaktionel: to farver tættere på hinanden end en perceptuel afstand på 0,02 i et ensartet farverum er én farve med to stavemåder. Linteren fejler på fem forskellige måder — en værdi malet men udokumenteret, dokumenteret men umalet, noteret med det forkerte forhold, inden for tærsklen af en der allerede findes, eller en mærkeværdi gentastet som en literal. Den fandt to med det samme: en temafarve der fandtes i to stavemåder 0,018 fra hinanden, og en baggrundsfarve der stod for en væg, den lå 0,021 fra. Gennemsigtighed bruger relativ farvesyntaks frem for blandingsfunktionen, netop fordi vagtposten ikke kan se gennem en blanding, og en paletvagt der kan omgås, er ikke en vagt. Reglen der følger med er kort: ret et token frem for en regel, tilføj kun en farve når ingen passer, og sænk aldrig et dokumenteret forhold for at få et design til at virke.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Paletten er et lukket, målt sæt, der ikke tavst kan vokse, og de to næsten enslydende stavemåder, der foranledigede den, er væk. Det er en begrænsning der lejlighedsvis siger nej — et design der vil have en lidt anden blå, må tage den der findes eller føre sagen for en niogtyvende farve, og den sag skal indeholde forholdet.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har fundet, at det lyse tema havde manglet et fuldsides overlay‑lag siden den dag, det blev skrevet, ved at hævde at begge temaer maler hver lagdelt flade med det samme antal lag.</title>
    <id>https://software.engineer.company/da/portfolio/found-the-light-theme-missing-an-overlay-layer-134/</id>
    <link href="https://software.engineer.company/da/portfolio/found-the-light-theme-missing-an-overlay-layer-134/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <summary>Et lag der mangler i ét tema, fejler nu et commit, og et der havde manglet siden det blev skrevet, males.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Sitet leverer to farvetemaer. Det mørke er standarden og bliver set på hele tiden; det lyse er en overstyring der kun optræder under en systemindstilling, hvilket betyder at det ses langt sjældnere og af ingen der tjekker det. Temaparitet er en defektklasse, hvor en flade bygges én gang og gentages én gang, og gentagelsen tavst taber et lag.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Pariteten havde brug for en assertion, for det eneste alternativ er en person der husker at skifte indstilling og kigge.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Tjekket er lille og strukturelt: for hver lagdelt flade tælles de lag hvert tema maler, og det fejler når tallene er forskellige. Det sammenligner ikke udseender — temaer er ment til at se forskellige ud — det sammenligner sammensætning, hvilket er det der bør være identisk. Det fandt defekten ved sin første kørsel. Sitets helsidesdække er tre lag i det mørke tema, et facetmønster over et slør over væggen, og det lyse tema gentog det med to. Facetoverlægget havde været fraværende fra det lyse tema fra den dag det blev skrevet, og intet havde nogensinde sagt det, for en side der mangler et af tre baggrundslag, ligner en designbeslutning frem for en fejl. Rettelsen var én regel; opskrivningen bagefter noterede hvad overlægget koster i kontrast, så tilføjelsen er målt frem for antaget gratis.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Et lag der mangler i ét tema, fejler nu et commit, og et der havde manglet siden det blev skrevet, males. Dette er den defektform, hele tjektilgangen sigter mod — intet var i stykker, intet fejlede, siden blev gengivet korrekt, og den havde været forkert i månedsvis.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har gjort reduceret bevægelse ærlig efter at have fundet elleve selektorer, der stadig animerede under præferencen, fordi en universel transition‑none‑regel taber på specificitet til enhver regel, der bærer en klasse.</title>
    <id>https://software.engineer.company/da/portfolio/made-reduced-motion-honest-135/</id>
    <link href="https://software.engineer.company/da/portfolio/made-reduced-motion-honest-135/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Indstillingen respekteres i praksis frem for i hensigt, og elleve levende animationer, som en generel regel så ud til at have dækket, er faktisk dækket.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Sitet respekterede indstillingen om reduceret bevægelse med en enkelt regel, der slog hver overgang fra. Det læste som fuldstændigt, det linter rent, og under en emuleret indstilling om reduceret bevægelse animerede elleve selektorer stadig.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Indstillingen skulle respekteres i praksis, og grunden til at den oplagte regel fejlede, skulle blive til noget den næste person ikke kan gentage.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Årsagen er specificitet. En universel regel scorer i bunden af kaskaden og taber til enhver regel der bærer en klasse, så en generel transition‑none bliver slået af hver gennemtænkt animation på siden — hvilket er hver animation, der er værd at slå fra. Rettelsen var strukturel frem for en lap: alt der bevæger sig, ligger nu i én sen stylesheet‑del, og en linter fejler en overgang på transform alle andre steder. Den skelnen reglen trækker er bevidst og snævrere end den oplagte: reducér bevægelse, ikke farve. En farveovergang er ikke bevægelse, og at slå den fra får grænseflader til at føles i stykker for folk der ikke bad om det, så en overgang der opregner farveegenskaber, består, og en overgang på bevægelse gør ikke. Bevægelse skal også udtrykkes som en overgang frem for en keyframe‑animation, for den første kan trivielt afbrydes, og den anden kan ikke. To beslægtede fælder kom ud af det samme arbejde og er noteret med målinger: et menuornament var enogtredive grader inde i en tres graders drejning, før det var halvt synligt, og fordi formen er periodisk ser en halv drejning identisk ud til en tredjedel af prisen; og fem forskellige egenskaber gør hver især et element til den indeholdende blok for alt, der er placeret i forhold til viewporten, hvilket tavst havde skrumpet et afvisningslag til en brøkdel af skærmen.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Indstillingen respekteres i praksis frem for i hensigt, og elleve levende animationer, som en generel regel så ud til at have dækket, er faktisk dækket. Den generelle lære er den der står øverst i det dokument: en regel der taber på specificitet, fejler tavst, og hver rapport kalder det noget andet.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget et 637 linjer langt printstylesheet mod fire dokumenterede adfærd i gengivelsesmotoren, herunder run‑in‑overskrifter, der printede hvidt på hvidt for enhver læser, hvis browser foretrak mørkt.</title>
    <id>https://software.engineer.company/da/portfolio/built-a-637-line-print-stylesheet-136/</id>
    <link href="https://software.engineer.company/da/portfolio/built-a-637-line-print-stylesheet-136/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Sitet printer på ukendt papir i begge temaer, og de fire motoradfærd er skrevet ned med den defekt, hver af dem frembragte.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Sitets casestudier er det artefakt, nogen printer og tager med til et møde. Det gør papir til et reelt output frem for en høflighed, og papir er et andet medie end en smal skærm — læserens papirstørrelse er ukendt, læserens orientering er ukendt, og browserens printadfærd er forskellig mellem motorer på måder, ingen skærmforhåndsvisning afslører.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Sitet skulle printe korrekt på ukendt papir, i begge farvetemaer, uden at et særskilt dokument skulle vedligeholdes ved siden af webudgaven.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Det er ét stylesheet på 637 linjer med én sideregel og én printblok. Sidereglen sætter en margen og sætter bevidst ingen papirstørrelse, så hvad læseren end vælger i dialogen kommer igennem, og alt andet tilpasser sig det. Rodskriftstørrelsen er fastlåst i punkter, så hver relativ måling har et fysisk anker, og én tekstbredde på omkring tooghalvfjerds tegn anvendes på de fire blokke på øverste niveau — hvilket er arket der vinder over designet, eftersom en liggende side ellers ville lade en linje løbe til omkring hundrede og ti tegn. Fire motoradfærd er dokumenteret som fælder, hver af dem har forårsaget en reel defekt. Viewport‑enheder resolverer til sideboksen i én motor og til vinduet i en anden, så en side printet fra et bredt vindue får en tredjedel af hver linje skåret af i den anden. Fastplacerede elementer males på hvert ark, så de dekorative droppes, og to af dem genbruges som brevhoved og kolofon. Paletten falder tilbage på hvid tekst, fordi standardtemaet er mørkt, hvilket printede de fire indrykkede afsnitsetiketter hvidt på hvidt — ordene var ganske enkelt fraværende. Og paginerede medier kan ikke dele en flex- eller gitterboks, hvilket frembragte et blankt første ark på en achievement‑side. Et tjek i seks dele dækker det og tester seks papir- og orienteringskombinationer, begge farveskemaindstillinger og det virkelige sideantal mod hvad indholdshøjden indebærer.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Sitet printer på ukendt papir i begge temaer, og de fire motoradfærd er skrevet ned med den defekt, hver af dem frembragte. De kendte grænser er noteret frem for skjult: ingen sidetal eller løbende sidehoveder, én motor ignorerer enke- og forældreløs‑kontrol, og initialer er ikke universelle. En efterladt kommentarafslutning fik engang CSS‑linteren til at sluge en hel regel og bestå rent to gange — kun printtjekket bemærkede det.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har spejlet hele sitet som 777 Gemini‑dokumenter og 777 Gopher‑dokumenter ud fra det samme udrullede træ, med nul bytes ændring i HTML&#39;en.</title>
    <id>https://software.engineer.company/da/portfolio/mirrored-the-site-to-gemini-and-gopher-137/</id>
    <link href="https://software.engineer.company/da/portfolio/mirrored-the-site-to-gemini-and-gopher-137/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Infrastruktur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Internationalisering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Internationalisering &amp; lokalisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Sitet kan læses over fire protokoller fra én bygning, med 777 dokumenter hver og nul ændring i HTML&#39;en, og de alternative repræsentationer koster omkring tolv…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Sitet er statisk, har ingen sporing og ingen backend der kører, og dets argument er, at et dokument ikke har brug for en megabyte JavaScript for at blive læst. Det argument er let at fremføre og svært at påvise. To små internetprotokoller påviser det direkte, for ingen af dem kan bære et script overhovedet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Hele sitet skulle udgives over Gemini og Gopher fra det samme indhold, uden et andet indholdstræ og uden at ændre HTML&amp;rsquo;en.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Begge er outputformater af den samme bygning frem for en særskilt pipeline. Sitegeneratoren fik brugerdefinerede medietyper og outputformater, og hver side, hvert afsnit og hvert taksonomibegreb fik to repræsentationer mere ved siden af sin HTML og sin Markdown‑tvilling. Resultatet er 777 Gemini‑dokumenter og 777 Gopher‑menuer frembragt fra den samme kilde, udrullet til det samme træ og leveret af to små dæmoner på den samme vært. To egenskaber gjorde det værd at gøre frem for en kuriositet. Begge formater er markeret som ikke‑alternative repræsentationer, så intet ved HTML&amp;rsquo;en ændrede sig — ikke én byte, og det blev målt frem for antaget. Og Gopher‑formatet har ingen måde at lægge et link inde i en sætning, eftersom en menulinje er tabulatoradskilte felter, så teksten hårdombrydes ved otteogtres kolonner under bygningen; den begrænsning skærpede skrivningen på en måde, HTML&amp;rsquo;en aldrig krævede. Et Tor‑onion‑spejl ligger ved siden af dem, og det er den eneste offentlige flade platformen kunne tilføje uden at åbne en firewallport, for dæmonen ringer ud, og intet ringer ind.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Sitet kan læses over fire protokoller fra én bygning, med 777 dokumenter hver og nul ændring i HTML&amp;rsquo;en, og de alternative repræsentationer koster omkring tolv procent af HTML&amp;rsquo;ens egen vægt på disken. Kun én af de fire måles for trafik, og det står i platformens eget statistikdokument frem for at blive tavst ignoreret.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har erstattet 963 anonyme blokke med strukturerede data, der gentog virksomheden 1.671 gange, med én sammenkædet graf af 16 typer præget fra stabile oprindelsesidentifikatorer.</title>
    <id>https://software.engineer.company/da/portfolio/replaced-963-structured-data-blocks-with-one-graph-138/</id>
    <link href="https://software.engineer.company/da/portfolio/replaced-963-structured-data-blocks-with-one-graph-138/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Brand &amp; marketing" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Brand, marketing &amp; SEO" scheme="https://software.engineer.company/da/services/" />
    <category term="Data governance &amp; datakvalitet" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Én graf med stabil identitet erstatter 963 anonyme gentagelser, og siderne bærer mindre frem for mere.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Sitet udsendte strukturerede data på den måde de fleste sites gør: en blok per side, hver af dem beskrev organisationen forfra igen. På tværs af sitet blev det til 963 blokke, der gentog den samme virksomhed 1.671 gange, anonymt — ingen stabil identifikator nogen steder, så intet der forbrugte det, kunne se at organisationen på én side var organisationen på en anden.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; De strukturerede data skulle blive én graf med stabil identitet frem for en bunke blokke, der tilfældigvis indeholder de samme ord.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Identifikatorer udstedes nu fra sitets oprindelse — én til organisationen, én til sitet, én til personen — og hver blok refererer til dem frem for at gentage deres indhold. Identifikatorerne er fælles for oprindelsen frem for per sprog, for virksomheden er den samme virksomhed på dansk. Seksten typer er i spil og dækker ydelseskataloget og dets tilbud, anmeldelserne og det arbejde de beskriver, samlingerne og deres brødkrummer. To beslutninger holdt vægten nede. Oversigtssider udgiver deres elementer kun ved URL frem for at indlejre dem, hvilket blev målt: at navngive dem på porteføljeoversigten ville have betydet 107 fulde udsagn og en stigning på 52 procent i den komprimerede side. Og det tjek der vogter det, validerer ikke blot syntaks — det efterprøver at hver blok kan parses, at hver identifikator resolverer, og at hver URL grafen navngiver, faktisk blev bygget, så en graf der peger på en side der ikke findes, fejler gaten.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Én graf med stabil identitet erstatter 963 anonyme gentagelser, og siderne bærer mindre frem for mere. Den måling der satte arbejdet i gang, er værd at holde sig for øje: sitet havde udsendt den samme organisationsbeskrivelse 1.671 gange, uden at noget var i stand til at føje dem sammen.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har skåret stylesheet‑bundtet fra 87 KB til 31 KB ved at tage en base64‑skrifttype ud af det og har droppet 756 KB fordelt på 22 filer, der blev udgivet ved hver deploy og refereret af intet.</title>
    <id>https://software.engineer.company/da/portfolio/cut-the-stylesheet-bundle-from-87kb-to-31kb-139/</id>
    <link href="https://software.engineer.company/da/portfolio/cut-the-stylesheet-bundle-from-87kb-to-31kb-139/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Brand, marketing &amp; SEO" scheme="https://software.engineer.company/da/services/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Bundtet er 31 KB i stedet for 87, 756 KB døde aktiver holdt op med at blive udrullet, og hver beslutning har en måling knyttet til sig — herunder den der gik…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Sitets stylesheet‑bundt var 87 KB, hvilket for et dokumentsite uden framework er det meste af en sidevægt brugt, før noget indhold ankommer. Sitet udgav også et katalog af ikoner ved hver udrulning, genereret én gang og siden refereret af intet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Vægten skulle ned uden at designet ændrede sig, og den skulle ned af en grund man kunne pege på frem for ved almindelig oprydning.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Måling først. To tredjedele af det største stylesheet var én base64‑kodet font — omkring 56 KB tekst der koder omkring 42 KB font — indlejret for en gevinst ved første optegning, som en forudindlæst ekstern fil alligevel får, og betalt på hver side, uanset om vægten var nødvendig. At tage den ud tog den fil fra 84 KB til 28 og hele bundtet fra 87 til 31. De tre fontvægte forudindlæses i stedet, og den tredje kom først på listen, da feltdata viste at den lukkede den længste kritiske kæde, frem for fordi tre lød komplet. Særskilt fandt en audit af hvad udrulningen faktisk udgav enogtyve genererede ikoner og en dubleret konfigurationsfil, 756 KB, sendt ud hver gang og refereret fra ingen steder; og sitets ikonfil selv kom ned fra 145 KB til 15. Et moderne billedformat blev vurderet til mærket, målt og afvist — det kom ud større, og udvælgelsesmekanismen vælger efter rækkefølge frem for efter størrelse, så en moderne browser ville have taget den tungere fil overalt. To tjek holder nu linjen: intet fotografi må vises bredere end halvdelen af sine kildepixels, og hver illustration skal udgives i en størrelse dens egne pixels understøtter ved både normal og høj tæthed.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Bundtet er 31 KB i stedet for 87, 756 KB døde aktiver holdt op med at blive udrullet, og hver beslutning har en måling knyttet til sig — herunder den der gik den anden vej, hvilket er den mest nyttige af de to optegnelser.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har rettet et sitemap, hvor 172 af 176 URL&#39;er delte ét ændringstidsstempel, ved at tage datoen fra git‑historikken efter at have fastslået, at eksporten omskriver hver fil ved hver kørsel.</title>
    <id>https://software.engineer.company/da/portfolio/fixed-a-sitemap-with-one-shared-timestamp-140/</id>
    <link href="https://software.engineer.company/da/portfolio/fixed-a-sitemap-with-one-shared-timestamp-140/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Brand &amp; marketing" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Brand, marketing &amp; SEO" scheme="https://software.engineer.company/da/services/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>En gensynkronisering efter en måneds indholdsredigeringer rører nu otte filer af 186 i stedet for dem alle, og sitemappet siger noget sandt.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Sitets sitemap fortalte søgemaskiner, at 172 af dets 176 sider sidst var ændret i det samme øjeblik. Det er ikke en subtil unøjagtighed — en ændringsdato er et løfte til en crawler om, at en sides indhold ændrede sig, og et site der giver det løfte 172 gange samtidig, fortæller enten sandheden om en fuld omskrivning eller fortæller ingen noget brugbart.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Datoerne skulle beskrive indholdet frem for filen, uden at opfinde en præcision repositoryet ikke har.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Årsagen var, at datoen kom fra filens ændringstidspunkt, og indholdseksporten omskriver hver fil ved hver kørsel, så en enkelt synkronisering stemplede hele korpuset. Rettelsen flytter kilden til versionshistorikken med en faldbagkæde, der først prøver et eksplicit felt, så commit‑historikken, så filen. Fælden i den rettelse er værd at notere: det bogstavelige feltnavn skal optræde på listen, ellers læser generatoren det aldrig, så en konfiguration der ser ud til at foretrække en skreven dato, men udelader navnet, ignorerer tavst hver skreven dato. To andre datobeslutninger kom ud af det samme arbejde. Databasen bærer nu hvornår hver post blev skrevet og sidst revideret, holdt bevidst adskilt fra hvornår arbejdet skete — de ligger år fra hinanden, og at slå dem sammen ville datere en side skrevet i år til et årti siden. Og rækker i den fil er valgfrie, og intet udledes, for repositoryets egen historik begynder efter indholdet gjorde: en manglende dato lader feltet stå tomt frem for at registrere en migrering, ud fra det princip at et præcist forkert tal er værre end et fraværende, eftersom det kun er det forkerte der bliver troet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; En gensynkronisering efter en måneds indholdsredigeringer rører nu otte filer af 186 i stedet for dem alle, og sitemappet siger noget sandt. Den generelle regel kom i metadatadokumentet ved siden af, for den samme fælde gælder hvert felt der har en faldbagkæde.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bragt 10.242 linjer kvalitetsgate‑JavaScript under en formatter og en linter efter at have fastslået, at det var kodebasens største kodemængde og den eneste, intet læste, og har rettet 13 fund uden at undertrykke nogen.</title>
    <id>https://software.engineer.company/da/portfolio/brought-the-quality-gate-code-under-a-linter-143/</id>
    <link href="https://software.engineer.company/da/portfolio/brought-the-quality-gate-code-under-a-linter-143/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk ledelse &amp; rådgivning" scheme="https://software.engineer.company/da/services/" />
    <summary>Den største og mest bærende kode i repositoryet er nu formateret, lintet og typetjekket, med tretten fund rettet og nul undertrykkelser.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Sitets kvalitetsgate er toogtredive scripts på i alt 10.242 linjer JavaScript. Den var med god margin den største kodemængde i repositoryet, og den var den eneste kodemængde, intet læste — ingen formatter, ingen linter, ingen typetjek. De programmer der håndhævede hver regel i projektet, var de eneste programmer, der var underlagt ingen af dem.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Tjekkerne skulle holdes til den standard, de findes for at håndhæve, og formatteren skulle tilpasses dem frem for omvendt.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Formatteren kom først, og indrykningsbredden var den interessante beslutning. Repositoryets standard er fire mellemrum; ved fire mellemrum ville formatteren have omskrevet 2.173 linjer af den største tjekker. En overstyring til to mellemrum for de filer reducerede det til 38 linjers ægte drift. Princippet noteret sammen med den er, at formatteren tilpasses koden, ikke koden formatteren — at omformatere to tusind linjer for at tilfredsstille en præference ødelægger evnen til at læse filens historik. Derefter linteren, som frembragte tretten reelle fund, alle rettet og ingen undertrykt. Python‑tjekkerne fik den samme behandling gennem et typetjek konfigureret på et mellemniveau af stringens med tredive enkeltstående regler fra det strengeste niveau slået til ovenpå, valgt ved måling: ved den indstilling er træet tavst, og af de tredive kandidater var niogtyve allerede tavse, og én udløste — og den blev rettet frem for undtaget. Typetjekket fandt to reelle defekter, som linteren havde ladet bestå rent, begge om en værdis form frem for dens syntaks.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Den største og mest bærende kode i repositoryet er nu formateret, lintet og typetjekket, med tretten fund rettet og nul undertrykkelser. Grunden til at det betyder mere, end linjeantallet antyder, står i planen: en defekt i sitets stylesheet viser sig som en side der ser forkert ud, og en defekt i en tjekker viser sig som et tjek der består, når det ikke burde.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget en databasedrevet generator til CV, referencer, portefølje og ansøgninger i Python — 41 moduler, 10.580 linjer — der gengiver seks outputformater fra én SQLite‑kilde med 23 tabeller samlet af en idempotent pipeline i 19 trin.</title>
    <id>https://software.engineer.company/da/portfolio/built-a-database-driven-cv-and-portfolio-generator-144/</id>
    <link href="https://software.engineer.company/da/portfolio/built-a-database-driven-cv-and-portfolio-generator-144/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Internationalisering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Løsningsarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="SQL" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Databasedesign &amp; datamodellering" scheme="https://software.engineer.company/da/services/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Internationalisering &amp; lokalisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <summary>Seks formater, tre sprog og fem temaer kommer ud af én database, og en rettet sætning rettes én gang.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Et CV, et referenceark, en portefølje og en ansøgning er de samme fakta arrangeret på fire måder, og at holde dem som fire dokumenter betyder, at hver rettelse foretages fire gange og til sidst ikke gør. Tre sprog ganger det med tre. Fejltilstanden er ikke, at et dokument er forkert; det er, at to dokumenter er uenige, og intet siger hvilket der er det aktuelle.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Én kilde til fakta skulle frembringe hvert dokument, på hvert sprog, i hvert format, med arrangementet afgjort af kode frem for af den, der sidst redigerede en fil.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Kilden er en SQLite‑database med treogtyve tabeller — achievements, titler, virksomheder, regioner, kategorier, ydelser, profiler, referencer, resuméer — samlet af en pipeline i nitten trin, der kører fra en tom fil til en komplet database med én kommando. Trinnene er ordnede, og hvert er skrevet til at være sikkert at gentage, så pipelinen kan køres mod en eksisterende database uden at duplikere en række. Enogfyrre Python‑moduler på i alt 10.580 linjer gengiver seks outputformater fra den: HTML, PDF i to varianter, ren tekst, Markdown og JSON, gennem seks Jinja‑skabeloner og otte stylesheets. Kørselsafhængigheder blev holdt til præcis to, en skabelonmotor og en PDF‑gengiver, ud fra det argument at en dokumentgenerator, som ikke kan installeres om fem år, ikke har bevaret noget. Målretning er et førsteklasses begreb frem for en manuel redigering: en profil vælger hvilke achievements der optræder og i hvilken rækkefølge, så et dokument rettet mod én slags læser er en forespørgsel frem for en kopi.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Seks formater, tre sprog og fem temaer kommer ud af én database, og en rettet sætning rettes én gang. Prisen er, at systemet nu er den eneste måde at frembringe et dokument på — der er ikke længere en fil at åbne og redigere i en fart, og at tilføje et sprog betyder at tilføje det overalt, før noget som helst bygger.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har holdt generatoren til 981 testtilfælde med et dækningsgulv på 92 % grendækning og advarsler behandlet som fejl, og har hævdet idempotens ved at køre hele build‑pipelinen to gange fra en tom fil og kræve, at anden gennemløb intet ændrer.</title>
    <id>https://software.engineer.company/da/portfolio/held-the-generator-to-964-tests-and-a-coverage-floor-145/</id>
    <link href="https://software.engineer.company/da/portfolio/held-the-generator-to-964-tests-and-a-coverage-floor-145/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Databaser" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk ledelse &amp; rådgivning" scheme="https://software.engineer.company/da/services/" />
    <summary>Pipelinen kan køres igen mod en levende database uden frygt, hvilket er det der overhovedet gør trinvist indholdsarbejde muligt.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; En generator der samler en database fra bunden, har en særlig slags fejl: den virker første gang og korrumperer anden gang. Trin der indsætter uden at tjekke, trin der afhænger af rækkefølgen i et tidligere trins output, trin der er sikre alene og ikke sammen. Intet af det viser sig i en test, der starter fra ingenting og kører én gang.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Bygningen skulle bevises gentagelig frem for blot fungerende, og testsuiten skulle være stor nok og streng nok til, at en regression ikke kunne slippe tavst igennem den.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Idempotenstesten er den stumpe og den mest nyttige: byg hele databasen fra en tom fil, tag et øjebliksbillede, kør hele pipelinen i nitten trin igen over resultatet, og kræv at anden gennemløb ikke ændrer noget. Rækketal, indhold og identifikatorer skal alle stemme. Omkring den ligger 383 testfunktioner — 981 tilfælde når de parametriserede folder sig ud — fordelt på femogfyrre filer og 7.944 linjer, der dækker pipelinen, gengiverne, indholdsindlæserne, målretningslogikken og tjekkerne. Grendækning bærer et gulv på tooghalvfems procent håndhævet i bygningen frem for rapporteret i et sammendrag, og suiten måler i øjeblikket omkring 95 procent, så gulvet har luft uden at være dekorativt. Advarsler er konfigureret som fejl, hvilket er den indstilling der betyder mest i praksis — en udfasningsmeddelelse der udskrives i to år, er en udfasningsmeddelelse ingen læser, og den kørsel der forvandler den til en rød test, er den kørsel der får den rettet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Pipelinen kan køres igen mod en levende database uden frygt, hvilket er det der overhovedet gør trinvist indholdsarbejde muligt. Gulvet er et gulv, ikke et mål, og det er værd at sige, at tooghalvfems procent grendækning stadig efterlader grene, intet nogensinde har taget — tallet afgrænser risikoen, det fjerner den ikke, og to af de defekter der senere blev fundet i projektet, lå i kode, dækningsrapporten viste som dækket.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har etableret PDF/UA‑1‑konformitet på tværs af ni dokumenter ved 106 af 106 regler og har fundet arkivvarianten fejle én regel ud af 146 — et nærved‑resultat, der læses som bestået af enhver, der ikke kører validatoren.</title>
    <id>https://software.engineer.company/da/portfolio/established-pdf-ua-1-conformance-across-nine-documents-146/</id>
    <link href="https://software.engineer.company/da/portfolio/established-pdf-ua-1-conformance-across-nine-documents-146/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Teknisk dokumentation" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>Tilgængelighedsoverholdelse er bevist med fuldt hus, og arkivpåstanden er oplyst ærligt som en nærved-fejl med det konkrete hul navngivet.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; En PDF der ser rigtig ud på skærmen, fortæller intet om, hvorvidt en skærmlæser kan læse den, om dens overskrifter danner en struktur, om dens sprog er erklæret, eller om den stadig kan åbnes om tyve år. Tilgængelig PDF og arkiv‑PDF er begge maskintjekbare standarder, og et dokument der aldrig er kørt gennem validatoren, er et dokument der fremsætter en uverificeret påstand.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; De genererede dokumenter skulle måles mod begge standarder, med resultatet noteret som et tal frem for som en hensigt.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Ni dokumenter — CV&amp;rsquo;et i sine varianter, referencearket, porteføljen og ansøgningen, på tværs af sprog — blev kørt gennem en uafhængig validator for tilgængelighedsprofilen og arkivprofilen hver for sig. Tilgængelighedsprofilen består med 106 af 106 regler, hvilket krævede tagget struktur, erklæret dokumentsprog, alternativ tekst på hver ikke‑dekorativ grafik, en rigtig titel i metadataene og en eksplicit læserækkefølge frem for den, layoutet tilfældigvis frembringer. Arkivprofilen er det mere interessante resultat: den fejler præcis én regel af 146. Det er den slags resultat, der er let at fejlrapportere. Hundrede og femogfyrre beståede læser som overholdelse i et sammendrag, og det er ikke overholdelse; det er et dokument der vil blive afvist af et system, der håndhæver standarden. Den fejlende regel er noteret med hvad den er, og hvorfor den ikke er lukket, frem for rundet væk.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Tilgængelighedsoverholdelse er bevist med fuldt hus, og arkivpåstanden er oplyst ærligt som en nærved‑fejl med det konkrete hul navngivet. Den grænse der er værd at være direkte om, er at begge tal kommer fra én validator; en anden implementering kan være uenig, og en regel der består, er kun bevis for, at denne tjekker intet havde at sige om den.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har valgt hver eneste regel, Python‑linteren har, som fejl og har arbejdet 1.815 fund ned til nul, hvor hver af de få undtagelser bærer en skreven begrundelse og to af dem er understøttet af et tjek frem for en kommentar.</title>
    <id>https://software.engineer.company/da/portfolio/enabled-every-python-linter-rule-as-an-error-147/</id>
    <link href="https://software.engineer.company/da/portfolio/enabled-every-python-linter-rule-as-an-error-147/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="DevOps" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk ledelse &amp; rådgivning" scheme="https://software.engineer.company/da/services/" />
    <summary>Linteren kører ved fuld styrke med nul fund, og hver afvigelse er dokumenteret på den linje, hvor den tages.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; De fleste projekter vælger en behagelig delmængde af deres linters regler, og delmængden vælges af hvilke regler der var tavse den dag, den blev konfigureret. Det gør konfigurationen til en optegnelse over kodens eksisterende vaner frem for en standard koden holdes til, og hver regel der er slået fra, er en defektklasse, ingen nogensinde får besked om.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Standarden skulle vendes om — hver regel værktøjet implementerer slået til som en fejl — og den resulterende efterslæb arbejdes ned til nul frem for forhandlet ned ved at slå regler fra igen.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; At vælge det komplette regelsæt frembragte 1.815 fund ved første kørsel. De blev arbejdet igennem efter kategori frem for efter fil, for kategorierne fortæller noget: ubrugte argumenter og skyggede indbyggede navne er støj, men sikkerhedskategorien, kategorien for foranderlige standardværdier og kategorien for undtagelseshåndtering pegede hver især på reel adfærd. Der findes ægte uforeneligheder — en formatter og en linter kan være uenige om den samme linje, og nogle få regler modsiger projektets egne bevidste valg — og hver af det lille antal undtagelser bærer en skreven begrundelse dér hvor undtagelsen tages, som siger hvad reglen ville, og hvorfor denne kode gør noget andet. To af dem går videre og er understøttet af et tjek frem for en kommentar, så undtagelsen ikke tavst kan udvide sig: reglen er slået fra, og en test efterprøver netop den egenskab, reglen ville have håndhævet. Typetjek kører i streng tilstand ved siden af, hvilket er en særskilt og hårdere standard, og det er den, der fangede defekter, linteren ikke kunne se, fordi de handler om hvad en værdi er frem for hvordan den er skrevet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Linteren kører ved fuld styrke med nul fund, og hver afvigelse er dokumenteret på den linje, hvor den tages. Prisen er reel og værd at nævne: den strengeste indstilling frembringer fund, der oprigtigt ikke er værd at handle på, og nogen skal træffe den vurdering 1.815 gange frem for én gang.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har indlejret en QR‑encoder — Reed‑Solomon over GF(256), fast modullayout, otte maskemønstre — på 522 linjer frem for at tage en tredje runtime‑afhængighed, og har verificeret den ved at læse den færdige matrix tilbage med en uafhængigt skrevet dekoder.</title>
    <id>https://software.engineer.company/da/portfolio/vendored-a-qr-encoder-in-522-lines-148/</id>
    <link href="https://software.engineer.company/da/portfolio/vendored-a-qr-encoder-in-522-lines-148/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <summary>Antallet af kørselsafhængigheder forblev to, og indkoderen er den eneste medleverede komponent i projektet.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Dokumenterne havde brug for en QR‑kode, der henviser til onlineversionen. Ethvert tilgængeligt bibliotek gør dette, og at tage et ville have tilføjet en tredje kørselsafhængighed til et projekt, der bevidst havde holdt sig til to — en skabelonmotor og en PDF‑gengiver — ud fra det argument, at en dokumentgenerator stadig skal kunne installeres om flere år.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Enten skulle afhængigheden accepteres eller formatet implementeres, og implementeringen skulle efterprøves som korrekt frem for blot at frembringe noget firkantet og sort.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Indkoderen er på 522 linjer og implementerer de dele af specifikationen, som anvendelsen faktisk har brug for: byte‑tilstandsindkodning, Reed‑Solomon‑fejlkorrektion over Galois‑legemet med 256 elementer med generatorpolynomiet bygget i den krævede grad, det faste modullayout med dets søgemønstre, timingmønstre og justeringsmønstre, format- og versionsinformation samt alle otte datamaskemønstre vurderet mod specifikationens fire strafregler, så den lavest scorende maske vælges frem for en fast. Efterprøvningen er den del, der gjorde det forsvarligt. At teste en indkoder mod dens egen logik beviser intet, så den færdige modulmatrix læses tilbage af en afkoder skrevet uafhængigt ud fra specifikationens læserækkefølge, og testen fastslår, at den afkodede streng er lig med inddata. Det gør &amp;ldquo;den frembringer et sandsynligt billede&amp;rdquo; til &amp;ldquo;den frembringer en kode, der afkoder til den rigtige URL&amp;rdquo;, og det tjekkes ved hver kørsel frem for én gang med øjet og en telefon.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Antallet af kørselsafhængigheder forblev to, og indkoderen er den eneste medleverede komponent i projektet. Det skal siges ligeud, at dette ikke er en almen implementering — den understøtter de tilstande og versioner, dokumenterne bruger, og intet andet, og den ærlige begrundelse er afhængighedsbudgettet frem for nogen påstand om, at resultatet er bedre end et modent bibliotek.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har flyttet hver brugervendt streng ud af Python og ind i et indholdstræ på 874 filer på tre sprog, efter at have fundet døde oversættelser, ingen kunne se var døde, og et tjek, der i stilhed bedømte en tredjedel af achievements.</title>
    <id>https://software.engineer.company/da/portfolio/moved-every-user-facing-string-into-a-content-tree-152/</id>
    <link href="https://software.engineer.company/da/portfolio/moved-every-user-facing-string-into-a-content-tree-152/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Internationalisering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Migrering &amp; modernisering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Data governance &amp; datakvalitet" scheme="https://software.engineer.company/da/services/" />
    <category term="Databasemigrering &amp; modernisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Internationalisering &amp; lokalisering" scheme="https://software.engineer.company/da/services/" />
    <summary>Prosaen kan nu redigeres uden at røre kode og sammenlignes på tværs af sprog ved at tælle. Prisen er, at tilføjelsen af et sprog nu er utvetydig frem for…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Hver brugervendt streng i generatoren — hver bedrift, hver anmeldelse, hver afsnitsoverskrift, hvert resumé, på tre sprog — lå inde i Python‑kildekode. Det gør redigeringen af en sætning til en kodeændring, gør gennemgangen af en oversættelse til en diff mod kildekode og gør det umuligt at se med et blik, om et sprog er komplet. Det skjuler også den fejltilstand, der betyder noget: en oversættelse kan være til stede, forkert og uopnåelig på samme tid.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Strengene skulle flyttes ud af koden og ind i et indholdstræ, der kan tælles, sammenlignes på tværs af sprog og tjekkes uden at køre gengiveren.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Resultatet er 874 filer under en indholdsmappe, ordnet efter art og derefter efter sprog: bedrifter, anmeldelser, resuméer, titler, virksomheder, regioner, kategorier, ydelser, profiler, referencer og ansøgningsbrudstykker. Tabulatorseparerede filer, hvor enheden er en linje med en identifikator, enkeltfiler hvor enheden er et afsnit. Indlæseren læser dem ved bygningstid, og databasen samles ud fra dem, så træet er kilden og databasen er afledt. To fund kom direkte ud af at kunne tælle. Nogle oversatte strenge havde ikke længere nogen engelsk modpart — døde poster, som intet gengav, og som ingen kunne have bemærket, mens de var indlejret i kode, for en urefereret ordbogsnøgle ser præcis ud som en refereret. Og et indholdstjek, der skulle bedømme hver bedrift, læste kun den delmængde, det kunne opløse, bedømte syvogtredive ud af treoghalvfems og meldte succes. At gøre korpusset til en mappe gjorde begge dele synlige som en uoverensstemmelse i filtal.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Prosaen kan nu redigeres uden at røre kode og sammenlignes på tværs af sprog ved at tælle. Prisen er, at tilføjelsen af et sprog nu er utvetydig frem for gradvis — træet gør et ufuldstændigt sprog åbenlyst, hvilket er pointen, men det betyder også, at delvise oversættelser ikke kan udsendes stille, mens de færdiggøres.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget et tværsprogligt indholdstjek, der fejler, når en oversættelse taber et tal, det engelske angiver, og når et sprog bruger notation, det ikke bruger — og har fundet to danske beskrivelser, der manglede en metrik, og seksten ukrainske spænd, der citerede på engelsk vis.</title>
    <id>https://software.engineer.company/da/portfolio/built-a-cross-language-figure-and-notation-check-153/</id>
    <link href="https://software.engineer.company/da/portfolio/built-a-cross-language-figure-and-notation-check-153/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Internationalisering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Python" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="Data governance &amp; datakvalitet" scheme="https://software.engineer.company/da/services/" />
    <category term="Internationalisering &amp; lokalisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk dokumentation" scheme="https://software.engineer.company/da/services/" />
    <summary>Atten reelle defekter lukket og klassen lukket med dem, da hver fremtidig oversættelse sammenlignes med sin engelske kilde, før den kan committes.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Den mest skadelige slags oversættelsesfejl i et CV er ikke en kejtet vending. Det er et tal, der forsvinder. En engelsk sætning, der hævder en halvtredsindstyvedobbelt forbedring, oversat til en sætning, der siger &amp;ldquo;betydeligt&amp;rdquo;, er en påstand stille trukket tilbage på ét marked og fastholdt på et andet — og ingen stavekontrol, grammatikkontrol eller menneskelig læsning af målsproget alene vil nogensinde bemærke det, for den oversatte sætning er fuldkommen god prosa.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Der var brug for et tjek, som læser sprogene mod hinanden frem for hvert enkelt for sig, på de to ting, der skal overleve oversættelse: tallene og den notation, hvert sprog bruger til at skrive dem.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Taltjekket udtrækker hvert tal, hver procentdel, hver multiplikator og hver enhed fra den engelske streng og kræver, at hver af dem optræder i hver oversættelse af den streng, med multiplikatorformerne kortlagt pr. sprog frem for matchet ordret — den engelske halvtredsindstyve‑gange‑form svarer til en bestemt dansk vending og en bestemt ukrainsk vending, og tjekket kender kortlægningen frem for at kræve cifrene alene. Notationstjekket er spejlbilledet af det: hvert sprog har konventioner, det skal bruge, og konventioner, det ikke må bruge, herunder decimalskilletegn, tusindgruppering og anførselstegn. Ukrainsk bruger vinkelanførselstegn; engelske dobbelte anførselstegn i en ukrainsk sætning er lige så forkerte som et manglende tal og langt lettere at indføre ved kopiering. Den første fulde kørsel fandt to danske beskrivelser, hvor et måltal til stede på engelsk var faldet ud, og seksten ukrainske spænd med anførsel i engelsk stil.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Atten reelle defekter lukket og klassen lukket med dem, da hver fremtidig oversættelse sammenlignes med sin engelske kilde, før den kan committes. Hvad tjekket ikke kan, er at bedømme mening: det beviser, at tallet overlevede, og at tegnsætningen er hjemmevant, og en oversættelse, der bevarer hvert tal, mens den vender påstanden om, består det uden videre.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget en native macOS‑beskedklient i Swift 6 og SwiftUI — 11.141 linjer fordelt på 53 filer — oven på C‑grænsefladen til en Rust‑kerne linket som et statisk arkiv fra en fastlåst revision.</title>
    <id>https://software.engineer.company/da/portfolio/built-a-native-macos-messaging-client-in-swift-6-154/</id>
    <link href="https://software.engineer.company/da/portfolio/built-a-native-macos-messaging-client-in-swift-6-154/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Full stack‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Løsningsarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Full stack‑produktudvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <summary>En hjemmehørende klient, der starter som et Mac-program, bruger platformens egne materialer og kontroller og bærer ingen indlejret browser.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Beskedprotokollen havde en velafprøvet kerne skrevet i Rust og klienter på flere platforme, men skrivebordsoplevelsen på macOS var en skal på tværs af platforme — den så ikke ud som et Mac‑program, opførte sig ikke som et, og bar en køretid, et hjemmehørende program ikke har brug for. Kernen blotlægger sin formåen gennem en C‑grænseflade, hvilket betyder, at ethvert sprog, der kan kalde C, kan bygge på den, og det kan Swift.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; En hjemmehørende klient skulle bygges direkte på den C‑grænseflade, i platformens nuværende sprog og nuværende grænsefladeramme, med kernen sammenkædet frem for udsendt ved siden af.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Programmet er 11.141 linjer Swift fordelt på treoghalvtreds filer i app‑målet, bygget på SwiftUI med kernen sammenkædet som et statisk arkiv oversat fra en fastlåst opstrømsrevision. At fastlåse revisionen frem for at følge en gren er den beslutning, der gør bygningen gentagelig: C‑grænsefladen er kontrakten, og en kerne i bevægelse ændrer kontrakten uden at ændre en linje Swift. Lagdelingen holder den usikre overflade lille — en tynd indpakning ejer hver pegepind og hver streng, der krydser grænsen, modeller over den er almindelige Swift‑værdier, og grænsefladelaget ser aldrig en rå pegepind. Alt, hvad C‑grænsefladen returnerer, har en ejerskabsregel, og at få en af dem forkert frembringer enten en lækage eller et nedbrud uden nogen oversætteradvarsel imellem, så indpakningen er der, hvor hele projektets hukommelsesdisciplin bor. Bygningen drives af en opgavekører med seksoghalvtreds mål, der dækker kerneoversættelsen, Swift‑bygningen, testsuiterne, linterne og pakningen.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; En hjemmehørende klient, der starter som et Mac‑program, bruger platformens egne materialer og kontroller og bærer ingen indlejret browser. Det, der ikke er gjort, bør siges: dette er ikke en udsendt udgivelse. Der er ingen notariseret distribution, ingen opdateringskanal og ét sprog i grænsefladen, så det er et fungerende program frem for et produkt, nogen anden kører.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har stoppet en applikation i at fylde hukommelsen med 41 MB i sekundet — registrerede 111 GB komprimerede sider på en maskine med 36 GB — ved at begrænse hver hændelsesstrøm, abonnere efter hændelsestype og lægge et ratebudget på logning, hvilket tog 610.996 loglinjer ned til 1.411.</title>
    <id>https://software.engineer.company/da/portfolio/stopped-an-application-filling-memory-at-41mb-a-second-155/</id>
    <link href="https://software.engineer.company/da/portfolio/stopped-an-application-filling-memory-at-41mb-a-second-155/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Løsningsarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Monitorering &amp; observability" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <category term="Site reliability &amp; monitorering" scheme="https://software.engineer.company/da/services/" />
    <summary>Hukommelsen holder sig flad under vedvarende belastning, og den samme session, der frembragte 610.996 loglinjer, frembringer 1.411.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Programmet fyldte hukommelsen, indtil styresystemet slog det ihjel. Den registrerede hændelse nåede 111 GB komprimerede sider på en maskine med 36 GB, stigende med omkring 41 MB i sekundet, og logfilen for en enkelt kort session rummede 610.996 linjer. En maskine i den tilstand er ikke langsom, den er ubrugelig — nedlukningen kommer, efter at swap allerede har fået alt andet på skrivebordet til at holde op med at svare.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Væksten skulle findes frem for gættes på, og hver ubegrænset vej skulle gives en grænse, for én afgrænset kø ved siden af tre uafgrænsede er ikke en rettelse.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Der var tre gangende årsager, og gangningen er grunden til, at det gik så hurtigt. Hændelsesstrømmen fra kernen blev forbrugt uden nogen grænse, så hændelser ankom hurtigere, end grænsefladen kunne anvende dem, og efterslæbet blev bevaret frem for kasseret. Hver abonnent modtog hver hændelse og filtrerede bagefter, så omkostningen ved én hændelse blev ganget med antallet af lyttere, og hver lytters filtrering allokerede. Og logning var ubudgetteret, så hver hændelse frembragte loglinjer — hvilket er det sammensatte led, for logningens omfang var proportionalt med omfanget af det, der gik galt. Rettelsen tog fat på alle tre: afgrænsede buffere med en udtrykkelig politik for, hvad der sker når de fyldes, abonnement efter hændelsestype så en lytter kun vækkes for hændelser, den vil have, og et hastighedsbudget på logning, der falder gentagelser sammen frem for at skrive hver enkelt. En regressionstest driver en høj hændelseshastighed og efterprøver, at hukommelsesloftet holder, så grænsen er en egenskab ved bygningen frem for en kommentar.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Hukommelsen holder sig flad under vedvarende belastning, og den samme session, der frembragte 610.996 loglinjer, frembringer 1.411. Den ærlige bemærkning er, at hastighedsbudgettet på logning kasserer information: når noget går galt hurtigt nu, er optegnelsen over det bevidst ufuldstændig, og det er en handel indgået med åbne øjne mod alternativet, en maskine der går i stå.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har taget Swift 6 fuldstændig streng samtidighed i brug uden aktører og har bygget bro fra en blokerende C‑hændelsesløkke til hovedaktøren gennem én producent, én forbruger og én rækkefølge — efter at have fastslået, at en opgave pr. hændelse mister den rækkefølge, grænsefladen afhænger af.</title>
    <id>https://software.engineer.company/da/portfolio/adopted-swift-6-strict-concurrency-over-a-c-event-loop-156/</id>
    <link href="https://software.engineer.company/da/portfolio/adopted-swift-6-strict-concurrency-over-a-c-event-loop-156/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Løsningsarkitektur" scheme="https://software.engineer.company/da/categories/" />
    <category term="Performanceoptimering" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="Platform- &amp; løsningsarkitektur" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk ledelse &amp; rådgivning" scheme="https://software.engineer.company/da/services/" />
    <summary>Programmet oversættes under fuldstændigt strengt samtidighedstjek uden undertrykkelser, og hændelsesrækkefølgen er en strukturel egenskab frem for et håb.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Swift 6&amp;rsquo;s fuldstændige strenge samtidighedstjek gør datakapløb til oversættelsesfejl i stedet for lejlighedsvise nedbrud. At indføre det over for et C‑bibliotek er der, hvor det bliver svært: kernens hændelsesløkke er et blokerende kald, der skal køre uden for hovedtråden for altid, og de værdier, den leverer tilbage, er pegepinde uden nogen som helst samtidighedsgarantier. Oversætteren kan ikke ræsonnere om noget af det og vil afvise alt, indtil grænsen er beskrevet udtrykkeligt.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Fuldstændigt tjek skulle slås til uden nogen nødudgange, hvilket betød at udforme overgangen fra en blokerende C‑løkke til hovedaktøren frem for at sætte påtegninger uden om den.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Den nærliggende fremgangsmåde er en aktør pr. delsystem, og den blev forkastet på måling frem for smag. At starte en opgave pr. indkommende hændelse lader køretiden planlægge dem i vilkårlig rækkefølge, og kernens hændelsesstrøm er ordnet — en besked‑ændret‑hændelse, der overhaler den besked‑oprettet‑hændelse, den henviser til, frembringer en grænseflade, der viser en redigering af noget, der endnu ikke findes. Aktørers genindtræden gør dette værre, ikke bedre, for en aktør kan afbryde midt i en metode og behandle et andet kald. Det, der erstattede den, er bevidst enkelt: én producenttråd, der ejer den blokerende løkke, én forbruger, én kø imellem dem og et enkelt hop over på hovedaktøren til sidst. Rækkefølgen bevares, fordi der er præcis én vej, og intet overhaler noget. De usikre typer, der krydser den grænse, er pakket ind i typer, hvis trådsikkerhed efterprøves ved indpakningen frem for antages, og efterprøvningen er dokumenteret med hvorfor den holder — pegepinden ejes af én tråd og kopieres, før den overdrages.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Programmet oversættes under fuldstændigt strengt samtidighedstjek uden undertrykkelser, og hændelsesrækkefølgen er en strukturel egenskab frem for et håb. Prisen er, at udformningen er mindre parallel, end den kunne være: alt ledes gennem én forbruger, og hvis den forbruger nogensinde bliver en flaskehals, vil rettelsen kræve, at man på ny udleder, hvilke hændelser der trygt kan omordnes, hvilket er præcis den analyse, dette undgik.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har skrevet en parser, der læser den rigtige C‑header på 7.308 linjer og verificerer hvert kaldssted, hver enum‑konstant og at hver pegerejende klasse er final, efter at en håndskrevet pladsholder‑header lod kald til tre fjernede funktioner kompilere, linke og crashe.</title>
    <id>https://software.engineer.company/da/portfolio/wrote-a-parser-that-verifies-every-ffi-call-site-157/</id>
    <link href="https://software.engineer.company/da/portfolio/wrote-a-parser-that-verifies-every-ffi-call-site-157/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Sikkerhed" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk dokumentation" scheme="https://software.engineer.company/da/services/" />
    <summary>Den defektklasse, der frembragte det oprindelige nedbrud, kan ikke gentage sig, for en forældet henvisning er nu en bygningsfejl frem for en kørselsfejl.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Tidligt i projektet blev C‑grænsefladen repræsenteret af en håndskrevet header, der beskrev de funktioner, programmet forventede. Den header oversatte, programmet blev sammenkædet, og kald til tre funktioner, der ikke længere fandtes i kernen, nåede frem til at blive kaldt og brød ned. Både oversætteren og sammenkæderen var blevet tilfredsstillet af en beskrivelse af biblioteket frem for af biblioteket, og kløften viste sig først ved kørsel.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Den rigtige header — 7.308 linjer og 268 erklæringer — skulle blive myndigheden, og hver anvendelse af den i Swift‑koden skulle efterprøves mod den automatisk frem for ved gennemgang.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Tjekket er en parser, der læser den faktiske opstrøms‑header og opbygger mængden af funktioner, enum‑konstanter og typer, den erklærer, og derefter læser Swift‑kildekoden og opløser hvert kaldested og hver konstanthenvisning mod den mængde. Et kald til en funktion, headeren ikke erklærer, fejler bygningen. En henvisning til en enum‑konstant, der er blevet omdøbt, fejler bygningen. Det nuværende tal er 132 af de 268 erklæringer henvist til, og at vide hvilke 136 der er ubrugte, er i sig selv nyttigt, for det siger præcis, hvor meget af kernen klienten ikke har nået. Parseren håndhæver også en regel, oversætteren ikke kan: hver Swift‑klasse, der ejer en pegepind ind i kernen, skal være endelig. En ikke‑endelig klasse, der ejer en pegepind, kan nedarves, og en underklasse, der tilsidesætter deinitialisering eller tilføjer sin egen levetid, ændrer, hvornår pegepinden frigives — en brug efter frigivelse uden noget usikkert nøgleord i nærheden. Reglen tjekkes ved navn på tværs af hele træet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Den defektklasse, der frembragte det oprindelige nedbrud, kan ikke gentage sig, for en forældet henvisning er nu en bygningsfejl frem for en kørselsfejl. Begrænsningen er, at parseren forstår headerens erklæringer og ikke dens betydning: den beviser, at en funktion findes med et matchende navn, og en funktion, hvis betydning eller ejerskabsregel ændrede sig opstrøms, mens signaturen blev bevaret, slipper igennem uden bemærkning.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har navngivet hver eneste ikonknap i grænsefladen for skærmlæsere efter at have fundet send‑knappen annonceret som &#34;arrow up circle, button&#34;, og har skrevet den linter, der kræver etiketten inden for otte linjer fra ikonet.</title>
    <id>https://software.engineer.company/da/portfolio/named-all-seventeen-interface-icons-for-screen-readers-159/</id>
    <link href="https://software.engineer.company/da/portfolio/named-all-seventeen-interface-icons-for-screen-readers-159/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <summary>Alle sytten kontroller annoncerer deres funktion, og en attende kan ikke tilføjes uden en. Reglens upræcished er reel og angivet dér, hvor den defineres: den…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Grænsefladen brugte systemsymboler til sine kontroller, og et symbol uden en tilgængelighedsetiket læses op af skærmlæseren med sit eget interne navn. Send‑knappen blev annonceret som &amp;ldquo;pil op cirkel, knap&amp;rdquo;. Det gjorde hver anden kontrol med kun et ikon i programmet også, på sin egen måde — sytten af dem beskrev deres eget billede i stedet for deres funktion.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Hver kontrol med kun et ikon havde brug for en etiket, der beskriver hvad den gør, og rettelsen skulle følges af et tjek, for det næste ikon, der blev tilføjet, ville ellers genindføre defekten med det samme.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Hver af de sytten fik en etiket, der navngiver handlingen frem for formen, og hvor kontrollens betydning afhænger af tilstand, følger etiketten tilstanden i stedet for at være fast. Tjekket er den del, der er værd at beskrive, for en almen regel om &amp;ldquo;er dette tilgængeligt&amp;rdquo; findes ikke til dette. Linteren leder efter den konstruktion, der skaber en kontrol med kun et ikon, og kræver derefter en tilgængelighedsetiket inden for otte linjer af den. Otte linjer er en bevidst grov tommelfingerregel, og den blev valgt ved måling: den er lang nok til at spænde over hver legitim måde, kodebasen skriver en af disse kontroller med dens modifikatorer, og kort nok til at en etiket knyttet til en anden visning længere nede ikke ved et uheld opfylder den. En præcis regel her ville skulle forstå SwiftUI&amp;rsquo;s modifikatorkæder som et træ, og den billige nærhedsregel fanger den faktiske fejl — som ikke er en fejlmærket kontrol, det er en umærket.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Alle sytten kontroller annoncerer deres funktion, og en attende kan ikke tilføjes uden en. Reglens upræcished er reel og angivet dér, hvor den defineres: den kan opfyldes af en etiket på en nabovisning, så den beviser, at en etiket findes i nærheden, frem for at bevise at etiketten er korrekt, og korrekthed kræver stadig, at nogen lytter til den.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget et designsystem på 48 tokens oven på platformens eget glasmateriale og har skrevet den linter, der afviser et magisk tal, en hårdkodet skriftstørrelse eller en animation, der ignorerer præferencen for reduceret bevægelse.</title>
    <id>https://software.engineer.company/da/portfolio/built-a-48-token-design-system-160/</id>
    <link href="https://software.engineer.company/da/portfolio/built-a-48-token-design-system-160/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Brand, marketing &amp; SEO" scheme="https://software.engineer.company/da/services/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <summary>Otteogfyrre tokens beskriver hele grænsefladen, udseendet følger systemet, og ingen af de tre former for smuldren kan committes.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; En grænseflade bygget ved at tilføje visninger ophober værdier: en hjørneradius her, en fjortenpunktsskrift der, en animation på to tiendedele sekund et andet sted. Hver for sig er hver af dem rimelig, og tilsammen er de et design, der ikke kan ændres, for der findes ikke noget, der hedder &amp;ldquo;hjørneradiussen&amp;rdquo; at ændre — der er fyrre af dem, en smule forskellige, spredt over halvtreds filer.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Det visuelle ordforråd skulle skæres ned til en navngiven mængde, udtrykt mod platformens eget materiale frem for genopfundet, og forsvaret af et tjek, så det forbliver nedskåret.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Systemet er otteogfyrre tokens i seks grupper: mellemrum, typografi, farve, radius, ophøjning og bevægelse. Farve og materiale er bygget på platformens semantiske farver og dens glasmateriale frem for faste værdier, hvilket er det, der får grænsefladen til at følge systemets udseende, accentfarven og kontrastindstillingerne uden nogen kode, der holder øje med dem. Typografi kortlægges til platformens tekststile, så den skalerer med brugerens størrelsespræference i stedet for at fastnagle en punktværdi. Linteren afviser tre ting: en talliteral hvor et mellemrums- eller radiustoken hører til, en hårdkodet skriftstørrelse hvor som helst, og en animation erklæret uden at respektere præferencen for reduceret bevægelse. Den tredje er den, der ellers ville smuldre hurtigst, for en animation tilføjes i et øjeblik af finpudsning, og præferencetjekket er den del, der bliver sprunget over — så reglen gør selve animationen umulig at skrive uden det frem for at bede nogen huske det.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Otteogfyrre tokens beskriver hele grænsefladen, udseendet følger systemet, og ingen af de tre former for smuldren kan committes. Begrænsningen er, at et tokensystem begrænser ensartethed og ikke kvalitet — alt passer nu sammen, og at passe sammen er ikke det samme som at være veludformet, hvilket er en vurdering, ingen linter i dette projekt foretager.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har nået den halvdel af beskedkernen, applikationen aldrig havde brugt — backupoverførsel, forsvindende beskeder, redigering og gensendelse af beskeder, verificerede invitationer, proxyer og krypteringspolitik — og har drevet hver test mod det rigtige bibliotek uden mocks.</title>
    <id>https://software.engineer.company/da/portfolio/reached-the-unused-half-of-the-messaging-core-161/</id>
    <link href="https://software.engineer.company/da/portfolio/reached-the-unused-half-of-the-messaging-core-161/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="API&#39;er &amp; integration" scheme="https://software.engineer.company/da/categories/" />
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Drift &amp; backup" scheme="https://software.engineer.company/da/categories/" />
    <category term="Sikkerhed" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="Backend- &amp; API‑udvikling" scheme="https://software.engineer.company/da/services/" />
    <category term="DevOps &amp; CI/CD‑automatisering" scheme="https://software.engineer.company/da/services/" />
    <category term="Sikkerhed &amp; adgangsstyring" scheme="https://software.engineer.company/da/services/" />
    <summary>Den tidligere uopnåede halvdel af kernen drives af test mod det rigtige bibliotek, og indpakningen bærer det højeste gulv i projektet.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Klienten brugte omtrent halvdelen af det, beskedkernen tilbyder. Den ubrugte halvdel var ikke obskur — sikkerhedskopioverførsel mellem enheder, forsvindende beskeder, redigering og gensendelse af beskeder, verificerede indbydelseslinks, proxykonfiguration og krypteringspolitikken for en samtale. Hver af dem er en funktion, en bruger ville forvente, og hver af dem var et utestet område af C‑grænsefladen, hvilket er den farligere kendsgerning, for et utestet område af en C‑grænseflade er der, hvor ejerskabsfejlene bor.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Den uopnåede formåen skulle drives og dækkes, og testene skulle køre mod det rigtige bibliotek frem for mod en stedfortræder.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Reglen, der blev vedtaget, var ingen attrapper for kernen. En attrap af en C‑grænseflade indkoder udviklerens tro om, hvad biblioteket gør, og hver defekt værd at finde her er et sted, hvor den tro er forkert — så en bestået attrapbaseret test er bevis om attrappen. I stedet opretter testene rigtige konti i midlertidige mapper, driver det rigtige bibliotek og efterprøver, hvad det faktisk returnerer, hvor hver suite rydder op efter sin egen tilstand. Det var det, der gjorde dækningen meningsfuld: at udøve sikkerhedskopioverførsel betød at håndtere en rigtig overførsels tilstandsmaskine og dens fejlveje, og at udøve verificerede indbydelser betød at konstruere det rigtige linkformat og få biblioteket til at fortolke det. Dækningsgulve blev sat pr. lag frem for som ét tal, ved fireogfirs procent for kerneindpakningen, femoghalvfjerds for hjælpefunktioner og femogtres for modeller, ud fra den betragtning at det lag, der rører rå pegepinde, bør holdes højest, og at en model, der mest består af lagrede egenskaber, ikke bør polstres med test for at ramme et gennemsnit.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Den tidligere uopnåede halvdel af kernen drives af test mod det rigtige bibliotek, og indpakningen bærer det højeste gulv i projektet. Prisen er hastighed og forudsigelighed: test mod det rigtige bibliotek er langsommere end attrapper, og de kan fejle af miljømæssige grunde, hvilket er prisen for, at de kan fejle af rigtige.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har omskrevet applikationens fejlbeskeder efter en skreven tonestandard, efter at et afvist login gav brugeren skylden for at have tastet forkert, mens udbyderen i virkeligheden krævede en applikationsspecifik adgangskode, og har dækket det med en test, der nævner udbyderen.</title>
    <id>https://software.engineer.company/da/portfolio/rewrote-the-error-messages-against-a-tone-standard-162/</id>
    <link href="https://software.engineer.company/da/portfolio/rewrote-the-error-messages-against-a-tone-standard-162/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Dokumentation" scheme="https://software.engineer.company/da/categories/" />
    <category term="Frontend‑udvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produkt &amp; krav" scheme="https://software.engineer.company/da/categories/" />
    <category term="Sikkerhed" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Produktstrategi &amp; kravspecifikation" scheme="https://software.engineer.company/da/services/" />
    <category term="Teknisk dokumentation" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <summary>Fejlfladen følger en angivet standard, og det tilfælde, der foranledigede den, er dækket af en test, der fejler på den gamle tekst.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; En indlogning mod en stor mailudbyder mislykkedes, og programmet fortalte brugeren, at adgangskoden var forkert. Den var ikke forkert. Den udbyder kræver en programspecifik adgangskode til tredjepartsklienter og afviser kontoens adgangskode uanset hvor omhyggeligt den tastes. Beskeden sendte brugeren ud i at genindtaste noget, der aldrig kunne virke, og den faktiske anvisning — gå hen og frembring en anden slags adgangskode — optrådte intetsteds.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Fejlbeskederne skulle omskrives efter en skreven standard frem for lappes én ad gangen, eftersom denne var det synlige tilfælde af en vane, der løb gennem dem alle.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; Standarden har tre krav: sig hvad der skete, antyd aldrig at brugeren gjorde noget forkert, når årsagen ligger andetsteds, og giv den næste handling, når der findes en. Anvendt på tværs af fejlfladen overtrådte de fleste beskeder mindst ét — flere var det underliggende biblioteks fejlstreng ført videre, hvilket beskriver en tilstand for en programmør frem for en situation for et menneske. Udbydertilfældet blev omskrevet til at navngive udbyderen, angive at den kræver en programspecifik adgangskode til andre klienter, og sige hvor man opretter en. Testen er det, der forhindrer tilbagefald, og den er bevidst konkret: den driver en mislykket indlogning mod den udbyder og efterprøver, at beskeden indeholder udbyderens navn og den vending, der beskriver den krævede legitimationstype. En test, der kun efterprøvede at en fejl viste sig, ville bestå på den oprindelige forkerte besked, så efterprøvningen ligger på indholdet, hvilket er den eneste del, der nogensinde var i stykker.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; Fejlfladen følger en angivet standard, og det tilfælde, der foranledigede den, er dækket af en test, der fejler på den gamle tekst. Det, der forbliver uafklaret, er omfanget: standarden håndhæves ved gennemgang og ved én test på én besked, og de øvrige udbydere med deres egne særlige krav har ingen tilsvarende test, så klassen er dokumenteret frem for lukket.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Har bygget virksomhedens ikon- og favicon‑sæt ud fra to håndlavede tegninger, hvor hvert afledt aktiv genskabes af et script og et tjek fejler, når en afledt fil er committet før sin kilde.</title>
    <id>https://software.engineer.company/da/portfolio/built-the-visual-identity-from-two-drawings-164/</id>
    <link href="https://software.engineer.company/da/portfolio/built-the-visual-identity-from-two-drawings-164/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automatisering &amp; CI/CD" scheme="https://software.engineer.company/da/categories/" />
    <category term="Brand &amp; marketing" scheme="https://software.engineer.company/da/categories/" />
    <category term="Designsystemer &amp; UI" scheme="https://software.engineer.company/da/categories/" />
    <category term="Test &amp; QA" scheme="https://software.engineer.company/da/categories/" />
    <category term="UX/UI‑design" scheme="https://software.engineer.company/da/categories/" />
    <category term="Webudvikling" scheme="https://software.engineer.company/da/categories/" />
    <category term="Brand, marketing &amp; SEO" scheme="https://software.engineer.company/da/services/" />
    <category term="UI/UX‑design &amp; designsystemer" scheme="https://software.engineer.company/da/services/" />
    <category term="Webstedsudvikling &amp; CMS" scheme="https://software.engineer.company/da/services/" />
    <summary>To tegninger frembringer hvert udgivet ikon, genskabelse er én kommando, og et forældet aktiv fejler bygningen.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Et lille firmas visuelle identitet købes som regel, frembringes maskinelt eller sættes sammen af arkivmateriale, og resultatet er en identitet, der tilhører ingen. Det alternative problem er værre: håndlavet grafik, der kun findes som eksporterede filer, hvor kildetegningen er gået tabt, eksporterne redigeres direkte, og inden for et år er de versioner, der er i brug, uenige med hinanden, og der er ingen original tilbage til at afgøre det.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Opgave.&lt;/strong&gt; Identiteten skulle tegnes frem for skaffes, og rørledningen fra tegning til udgivet aktiv skulle være gentagelig, så hver fil på webstedet kan udledes frem for opbevares.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Handling.&lt;/strong&gt; To håndlavede tegninger ligger til grund for det frembragte billedmateriale — firmamærket og tandhjulet, der blev til faviconet — og hvert ikon sitet udgiver frembringes ud fra dem. Mærket er en rastertegning; tandhjulet er en vektor. Ud fra disse frembringer skripter hver afledt form: favicon‑sættet i dets krævede størrelser, berøringsikonerne, billederne til social forhåndsvisning, de tilpassede rastervarianter i hver bredde og i hvert moderne format samt de temaspecifikke versioner. Frembringelsen er en opgave, enhver kan køre, så spørgsmålet &amp;ldquo;hvor kommer denne fil fra&amp;rdquo; har et svar, der er en kommando. Forældelsestjekket er det stykke, der får det til at holde: det sammenligner ændringstidspunktet for hvert afledt aktiv med dets kilde og fejler, når en afledt fil er ældre, hvilket fanger netop den fejl, denne udformning findes for at forhindre — nogen redigerer kilden, glemmer at genskabe, og det udgivne websted bliver ved med at vise grafik, der ikke længere svarer til originalen. Reglen om, at afledte filer aldrig redigeres i hånden, er angivet dér, hvor kilderne bor.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resultat.&lt;/strong&gt; To tegninger frembringer hvert udgivet ikon, genskabelse er én kommando, og et forældet aktiv fejler bygningen. Afvejningen er en hård afhængighed af værktøjskæden: de afledte filer er committet, så webstedet bygger hvor som helst, men at ændre identiteten kræver, at frembringelsesværktøjet stadig virker, og et kildeformat, der holder op med at kunne læses, tager hele identiteten med sig.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Sådan åbner man en dApp i Solana-mobilwallets</title>
    <id>https://software.engineer.company/da/notes/solana-mobile-wallet-deeplinks/</id>
    <link href="https://software.engineer.company/da/notes/solana-mobile-wallet-deeplinks/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-08-10T00:00:00Z</published>
    <summary>Hvorfor browse-deeplinks til Phantom, Solflare og Backpack fejler på mobilen — og de formater, regler og rettelser, der får dem til at virke.</summary>
    <content type="html">&lt;p&gt;En React-dApp bygget på &lt;code&gt;@solana/wallet-adapter-react&lt;/code&gt; forbinder&#xA;desktop-wallets uden problemer, men på en telefon falder det samme flow fra&#xA;hinanden: wallet&amp;rsquo;en skal åbne dApp&amp;rsquo;en i sin egen indbyggede browser, og de&#xA;deeplinks, der skulle klare det, virker bare ikke. Backpack lander på en &amp;ldquo;hent&#xA;appen&amp;rdquo;-side; Solflare åbner appen, men aldrig sitet; alle varianter ser ud til&#xA;at fejle. Vi skilte problemet ad, og det viste sig at være fire adskilte&#xA;problemer med ét fælles symptom.&lt;/p&gt;&#xA;&lt;h2 id=&#34;de-fire-problemer&#34;&gt;De fire problemer&lt;/h2&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Backpack-linket var forkert bygget.&lt;/strong&gt; Det eneste dokumenterede format er&#xA;&lt;code&gt;https://backpack.app/ul/v1/browse/&amp;lt;url&amp;gt;?ref=&amp;lt;ref&amp;gt;&lt;/code&gt; — et universelt link med&#xA;mål-URL&amp;rsquo;en i stien og et påkrævet &lt;code&gt;ref&lt;/code&gt;. Et gæt med eget skema som&#xA;&lt;code&gt;backpack://ul/v1/browse?url=...&lt;/code&gt; matcher ingen rute i appen, så brugeren&#xA;ender på wallet&amp;rsquo;ens installationsside.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Solflare skal også bruge sit universelle link:&lt;/strong&gt;&#xA;&lt;code&gt;https://solflare.com/ul/v1/browse/&amp;lt;url&amp;gt;?ref=&amp;lt;ref&amp;gt;&lt;/code&gt; — ikke det rå&#xA;&lt;code&gt;solflare://&lt;/code&gt;-skema. Et råt skema kan starte appen uden at dirigere den —&#xA;hvilket er præcis &amp;ldquo;appen åbner, men site-fanen må åbnes med hånden&amp;rdquo;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Begge parametre skal være kodet.&lt;/strong&gt; &lt;code&gt;url&lt;/code&gt; er dApp&amp;rsquo;ens fulde absolutte&#xA;adresse, og &lt;code&gt;ref&lt;/code&gt; er den kaldende origin, hver især gennem&#xA;&lt;code&gt;encodeURIComponent&lt;/code&gt;. Et ukodet &lt;code&gt;?&lt;/code&gt; eller &lt;code&gt;&amp;amp;&lt;/code&gt; i målet ødelægger&#xA;fortolkningen, og wallet&amp;rsquo;en åbner på sin forside i stedet for browserfanen.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Udløsningen betyder lige så meget som linket.&lt;/strong&gt; Universelle links skifter&#xA;kun app ved en navigation, styresystemet stoler på — og de gør med vilje&#xA;ingenting, når de indsættes i adresselinjen, hvilket også er sådan, et helt&#xA;korrekt link &amp;ldquo;fejler&amp;rdquo; under test.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;de-dokumenterede-formater&#34;&gt;De dokumenterede formater&lt;/h2&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Phantom: &lt;code&gt;https://phantom.app/ul/browse/&amp;lt;url&amp;gt;?ref=&amp;lt;ref&amp;gt;&lt;/code&gt; — uden &lt;code&gt;/v1&lt;/code&gt; i&#xA;netop dette.&lt;/li&gt;&#xA;&lt;li&gt;Solflare: &lt;code&gt;https://solflare.com/ul/v1/browse/&amp;lt;url&amp;gt;?ref=&amp;lt;ref&amp;gt;&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Backpack: &lt;code&gt;https://backpack.app/ul/v1/browse/&amp;lt;url&amp;gt;?ref=&amp;lt;ref&amp;gt;&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Ét mønster dækker alle tre:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;const WALLET_BROWSE = {&#xA;  phantom: (url, ref) =&amp;gt;&#xA;    `https://phantom.app/ul/browse/${url}?ref=${ref}`,&#xA;  solflare: (url, ref) =&amp;gt;&#xA;    `https://solflare.com/ul/v1/browse/${url}?ref=${ref}`,&#xA;  backpack: (url, ref) =&amp;gt;&#xA;    `https://backpack.app/ul/v1/browse/${url}?ref=${ref}`,&#xA;};&#xA;&#xA;function walletBrowseLink(&#xA;  walletName,&#xA;  targetUrl = window.location.href,&#xA;) {&#xA;  const build = WALLET_BROWSE[walletName.toLowerCase()];&#xA;  if (!build) return null;&#xA;  return build(&#xA;    encodeURIComponent(targetUrl),&#xA;    encodeURIComponent(window.location.origin),&#xA;  );&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;udløs-linket-så-ios-og-android-accepterer-det&#34;&gt;Udløs linket, så iOS og Android accepterer det&lt;/h2&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Render et rigtigt anker, beregnet på forhånd.&lt;/strong&gt; Et almindeligt&#xA;&lt;code&gt;&amp;lt;a href={walletBrowseLink(&#39;phantom&#39;)}&amp;gt;&lt;/code&gt; er den mest pålidelige udløser på&#xA;begge platforme.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Skal det ske programmatisk&lt;/strong&gt;, så tildel &lt;code&gt;window.location.href&lt;/code&gt; synkront&#xA;inde i tryk-handleren — ingen &lt;code&gt;await&lt;/code&gt;, ingen &lt;code&gt;fetch&lt;/code&gt;, ingen &lt;code&gt;setTimeout&lt;/code&gt;&#xA;først. Efter asynkront arbejde er gestus-konteksten væk, og iOS falder&#xA;tilbage til wallet&amp;rsquo;ens websted. Aldrig &lt;code&gt;window.open&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Test aldrig ved at indsætte i adresselinjen.&lt;/strong&gt; Universelle links udløses&#xA;med vilje ikke dér; test med et link, der trykkes på, eller en QR-kode, som&#xA;kameraet scanner.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Pas på messenger-webviews.&lt;/strong&gt; Åbnet i Telegrams eller Instagrams indbyggede&#xA;browser bliver universelle links ofte slugt, og wallet&amp;rsquo;ens almindelige&#xA;websted indlæses i stedet. User-agent-detektion er i bedste fald et gæt, så&#xA;giv også brugerne en synlig nødudgang: &amp;ldquo;åbn i Safari eller Chrome, og&#xA;forbind derefter&amp;rdquo;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;den-større-løsning-på-android&#34;&gt;Den større løsning på Android&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Håndbyggede deeplinks er iOS-historien. På Android lader Solana Mobiles Mobile&#xA;Wallet Adapter en dApp i mobilbrowseren forbinde direkte til den installerede&#xA;wallet-app, helt uden omvejen om den indbyggede browser. Nyere versioner af&#xA;&lt;code&gt;@solana/wallet-adapter-react&lt;/code&gt; registrerer mobiladapteren automatisk, så en&#xA;opgradering af wallet-adapter-pakkerne kan løse Android alene. Målarkitekturen:&#xA;Mobile Wallet Adapter på Android, universelle browse-links på iOS, hvor Apple&#xA;ikke tillader en tilsvarende løsning.&lt;/p&gt;&#xA;&lt;h2 id=&#34;efterprøv-på-en-enhed&#34;&gt;Efterprøv på en enhed&lt;/h2&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Rigtig enhed, wallet installeret, link åbnet fra systembrowseren — ikke fra&#xA;en messenger.&lt;/li&gt;&#xA;&lt;li&gt;Tryk på et renderet link, eller scan en QR-kode; indsæt aldrig i&#xA;adresselinjen.&lt;/li&gt;&#xA;&lt;li&gt;Bekræft, at wallet&amp;rsquo;en åbner, og at dApp&amp;rsquo;en indlæses i dens indbyggede&#xA;browserfane — anden halvdel er den, der fejler.&lt;/li&gt;&#xA;&lt;li&gt;Gentag uden wallet&amp;rsquo;en installeret: det universelle link skal falde tilbage&#xA;til wallet&amp;rsquo;ens websted. Ser du dén side, mens appen er installeret, er&#xA;linket eller udløsningen stadig forkert.&lt;/li&gt;&#xA;&lt;li&gt;Test derefter messenger-vejen, og tilføj &amp;ldquo;åbn i browser&amp;rdquo;-hjælpen, hvis den&#xA;fejler dér.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;kilder&#34;&gt;Kilder&lt;/h2&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.phantom.com/phantom-deeplinks/deeplinks-ios-and-android&#34;&gt;Phantom: deeplinks på iOS og Android&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.solflare.com/solflare/technical/deeplinks/other-methods/browse&#34;&gt;Solflare: Browse-deeplinket&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.backpack.app/deeplinks/other-methods/browse&#34;&gt;Backpack: Browse-deeplinket&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.solanamobile.com/mobile-wallet-adapter/mobile-apps&#34;&gt;Solana Mobile: Mobile Wallet Adapter&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</content>
  </entry>
</feed>
