<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Engineer — Platform — Portefølje og noter</title>
    <link>https://platform.engineer.company/da/</link>
    <description>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.</description>
    <language>da</language>
    <copyright>Copyright © 2025 – nu · Engineer ApS</copyright>
    <generator>Hugo 0.166.0</generator>
    <docs>https://www.rssboard.org/rss-specification</docs>
    <ttl>60</ttl>
    <lastBuildDate>Sun, 13 Sep 2026 01:45:52 +0200</lastBuildDate>
    <atom:link href="https://platform.engineer.company/da/index.xml" rel="self" type="application/rss+xml" />
    <image>
      <url>https://platform.engineer.company/assets/icons/apple/apple-touch-icon-144x144.png</url>
      <title>Engineer — Platform — Portefølje og noter</title>
      <link>https://platform.engineer.company/da/</link>
    </image>
    <item>
      <title>Har udviklet og lanceret virksomhedens første observability‑dashboard, der leverer indsigt i systemets ydeevne i realtid og datavisualisering på det store kontor‑TV.</title>
      <link>https://platform.engineer.company/da/portfolio/developed-and-launched-the-company-s-first-observability-9/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/developed-and-launched-the-company-s-first-observability-9/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Byggede virksomhedens første observability-dashboard til realtidsindsigt — teams opdagede og løste incidents 40 % hurtigere.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Containere (Docker/Kubernetes)</category>
      <category domain="https://platform.engineer.company/da/categories/">Dataanalyse</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Monitorering &amp; observability</category>
      <category domain="https://platform.engineer.company/da/services/">Dataanalyse &amp; BI‑dashboards</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Virksomheden havde udfordringer med at overvåge systemets ydeevne i realtid, hvilket ofte førte til forsinket incidenthåndtering og reduceret indblik i infrastrukturens tilstand. Der fandtes ingen central løsning, hvor teams kunne få indsigt i driftsmetrikker.</p>
<p><strong>Opgave.</strong> Opgaven var at udvikle en løsning, der ville gøre det muligt for både tekniske og ikke‑tekniske interessenter at overvåge centrale systemmetrikker i realtid med fokus på tilgængelighed, klarhed og proaktiv fejlopsporing.</p>
<p><strong>Handling.</strong> Virksomhedens første observability‑dashboard blev designet og implementeret og indsamlede alle væsentlige systemmetrikker — CPU, RAM, HDD, temperatur med mere — fra fjerne Linux‑servere via SSH, og selv Docker‑containere blev overvåget på denne måde. Senere blev en anden version designet og implementeret med Grafana og Prometheus til mere avanceret visualisering. Samarbejde med DevOps- og engineering‑teams identificerede kritiske metrikker, datapipelines blev konfigureret til at indsamle og behandle ydeevnemetrikker, og dashboardet udrullet på en stor kontor‑TV‑skærm for maksimal synlighed. Alarmering ved overskridelse af tærskler blev også integreret.</p>
<p><strong>Resultat.</strong> Dashboardet forbedrede markant systemets gennemsigtighed og responstiden på driftsproblemer. Teams kunne opdage og løse incidents 40 % hurtigere. Det fremmede også en kultur af fælles ejerskab over systemets tilstand ved at gøre ydeevnedata tilgængelige for alle på kontoret, hvilket i sidste ende bidrog til et mere stabilt og effektivt produktionsmiljø.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har designet, idriftsat og vedligeholdt 10 PostgreSQL- og MS SQL‑servere på Ubuntu Linux VPS og sikret optimal serverydeevne og pålidelighed.</title>
      <link>https://platform.engineer.company/da/portfolio/designed-deployed-and-maintained-10-postgresql-and-ms-13/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/designed-deployed-and-maintained-10-postgresql-and-ms-13/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Designede og vedligeholdt 10 PostgreSQL- og MS SQL-servere på Ubuntu Linux VPS med 99,9 % oppetid og 30 % hurtigere forespørgsler.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Databaser</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Monitorering &amp; observability</category>
      <category domain="https://platform.engineer.company/da/categories/">Performanceoptimering</category>
      <category domain="https://platform.engineer.company/da/categories/">PostgreSQL</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Databaseadministration (DBA)</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Som DevOps‑ingeniør i en mellemstor teknologivirksomhed var opgaven at administrere og optimere databaseinfrastrukturen til støtte for en voksende brugerbase og forretningskritiske applikationer. Organisationen var stærkt afhængig af PostgreSQL og Microsoft SQL Server og krævede høj tilgængelighed, skalerbarhed og sikkerhed.</p>
<p><strong>Opgave.</strong> Det primære ansvar var at arkitektere, udrulle, konfigurere og vedligeholde 10 PostgreSQL- og MS SQL Server‑instanser i Ubuntu Linux VPS‑miljøer med optimal ydeevne, robuste sikkerhedsprotokoller og proaktiv overvågning, samt at skalere infrastrukturen til fremtidig vækst uden at gå på kompromis med omkostninger og compliance.</p>
<p><strong>Handling.</strong> PostgreSQL 14 og MS SQL Server 2019 blev installeret og konfigureret på Ubuntu 20.04 LTS, automatiserede backups sat op med pg_dump og SQL Server Agent‑jobs med retention og offsite‑lagring, og serverkonfigurationer optimeret (hukommelsesallokering, query caching, connection pooling). Overvågning blev implementeret med Prometheus og Grafana, regelmæssig patching af databaser og OS udført, firewalls (UFW) og RBAC konfigureret og disaster recovery‑procedurer dokumenteret, herunder point‑in‑time‑gendannelse og failover.</p>
<p><strong>Resultat.</strong> 99,9 % oppetid blev opnået på tværs af alle 10 databaseservere, svartider forbedret med 30 % gennem konfigurationstuning og indeksoptimering, manuelt vedligeholdelsesarbejde reduceret med 50 % via automatisering (over 10 timer om måneden frigjort) og infrastrukturen skaleret til at understøtte en 40 % stigning i brugertrafik uden servicetab — hvilket bidrog til 20 % omsætningsvækst i det følgende kvartal. CTO&rsquo;en anerkendte implementeringen af sikkerheds‑best‑practices, der forhindrede potentielle databrud.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har forbedret datasikkerheden ved at implementere 1.000 RBAC‑regler for udviklere, applikationsinstanser, PostgreSQL, MS SQL og andre Linux‑servere for at forhindre uautoriseret adgang; dokumenteret med Ansible‑automatisering.</title>
      <link>https://platform.engineer.company/da/portfolio/enhanced-data-security-by-implementing-1-000-rbac-14/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/enhanced-data-security-by-implementing-1-000-rbac-14/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Styrkede datasikkerheden med 1.000 RBAC-regler på tværs af udviklere, apps og Linux/DB-servere — 85 % lavere adgangsrisiko, Ansible-drevet.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Databaser</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Databaseadministration (DBA)</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Organisationen havde behov for at styrke adgangskontrollen på tværs af flere systemer, herunder udviklermiljøer, applikationsinstanser, PostgreSQL, MS SQL og Linux‑servere. Selvom den underliggende RBAC‑model var enkel, lå udfordringen i at håndtere over 1.000 individuelle regler for forskellige brugerroller og systemkrav uden at introducere kompleksitet.</p>
<p><strong>Opgave.</strong> At implementere en skalerbar RBAC‑løsning ved at definere og håndhæve over 1.000 regler for adgangskontrol. Det indebar at mappe rettigheder til specifikke roller (udviklere, applikationsinstanser, databaseadministratorer) og at anvende reglerne konsistent på tværs af alle systemer, samt at dokumentere reglerne og automatisere deres udrulning.</p>
<p><strong>Handling.</strong> Tilgangen fokuserede på at skabe en enkel, modulær RBAC‑struktur, med rettigheder brudt ned i klare, genanvendelige kategorier (f.eks. &ldquo;read‑only‑adgang til produktionsdatabaser&rdquo;). Med Ansible blev konfigurationen af hver regel automatiseret og konsistens sikret på tværs af miljøer: udviklere fik kun adgang til deres tildelte servere, mens applikationsinstanser havde begrænsede rettigheder for at forhindre lateral bevægelse. Processen prioriterede klarhed frem for kompleksitet, med hver regel eksplicit knyttet til en rolle og et system.</p>
<p><strong>Resultat.</strong> Implementeringen sikrede over 1.000 regler uden unødvendig kompleksitet og reducerede risikoen for uautoriseret adgang med 85 %. Automatiseringen strømlinede udrulningen og reducerede opsætningstiden med 60 % sammenlignet med manuelle metoder. Den dokumenterede ramme gjorde det muligt for teams hurtigt at revidere eller ændre regler og sikrede skalerbarhed, efterhånden som infrastrukturen voksede.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har automatiseret udrulning af GIS SaaS‑applikationer, databehandling og rapporteringssystem ved hjælp af GitHub Actions CI/CD, Python, Bash og SQL.</title>
      <link>https://platform.engineer.company/da/portfolio/automated-gis-saas-application-deployment-data-processing-and-16/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/automated-gis-saas-application-deployment-data-processing-and-16/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Automatiserede GIS SaaS-udrulning, databehandling og rapportering med GitHub Actions CI/CD, Python, Bash og SQL — pålidelige releases.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Cloud</category>
      <category domain="https://platform.engineer.company/da/categories/">Data engineering</category>
      <category domain="https://platform.engineer.company/da/categories/">Datapipelines (ETL/ELT)</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">GIS / Geospatial</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/categories/">SQL</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">GIS &amp; geospatiale løsninger</category>
      <category domain="https://platform.engineer.company/da/services/">Udvikling af datapipelines (ETL/ELT)</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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 &ldquo;det virker på min maskine&rdquo;-overraskelserne, for der holder op med at være en &ldquo;min maskine&rdquo;, der er anderledes end produktion.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har automatiseret levering af 20 GIS‑datapipelines og ETL‑processer for appdata og strømlinet infrastrukturautomatisering og rapportering.</title>
      <link>https://platform.engineer.company/da/portfolio/automated-delivery-of-20-gis-data-pipelines-and-17/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/automated-delivery-of-20-gis-data-pipelines-and-17/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Automatiserede 20 GIS-datapipelines og ETL-processer for appdata — strømlinet infrastrukturautomatisering og pålidelige, aktuelle data.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Data engineering</category>
      <category domain="https://platform.engineer.company/da/categories/">Datapipelines (ETL/ELT)</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">GIS / Geospatial</category>
      <category domain="https://platform.engineer.company/da/categories/">Monitorering &amp; observability</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">GIS &amp; geospatiale løsninger</category>
      <category domain="https://platform.engineer.company/da/services/">Udvikling af datapipelines (ETL/ELT)</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har automatiseret 100 kritiske databackups ved hjælp af Barman, Google Cloud, Bash og Python og sikret dataintegritet på tværs af databaser.</title>
      <link>https://platform.engineer.company/da/portfolio/automated-100-critical-data-backups-using-barman-google-18/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/automated-100-critical-data-backups-using-barman-google-18/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Automatiserede 100 kritiske databackups med Barman, Google Cloud, Bash og Python — datagenoprettelse gik fra antagelse til testet faktum.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Cloud</category>
      <category domain="https://platform.engineer.company/da/categories/">Databaser</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">PostgreSQL</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/services/">Backup &amp; disaster recovery</category>
      <category domain="https://platform.engineer.company/da/services/">Databaseadministration (DBA)</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> De kritiske GIS‑data, applikationsinstanserne og databaserne var spredt over systemer med backups, der var inkonsistente og delvist manuelle. For et produkt, der lever på sine data, er det ikke en risiko, man kan lade ligge — og den dag, man faktisk har brug for en backup, er præcis den værste dag at finde ud af, at den var ufuldstændig.</p>
<p><strong>Opgave.</strong> Opgaven var at garantere, at alle de kritiske data kunne gendannes, hvilket betød at automatisere omfattende, verificerede backups på tværs af hele estatet — verificerede som det ord, der betyder noget.</p>
<p><strong>Handling.</strong> Backup‑regimet blev bygget fra ende til anden. Hundrede kritiske databackups blev automatiseret, med Barman på PostgreSQL‑siden og Google Cloud, der holdt offsite‑kopierne, og det hele blev orkestreret og valideret med Bash og Python — for en backup, man har taget, men aldrig tjekket, er ikke rigtig en backup, det er et håb. Så der var retention‑politikker til at holde dem aktuelle og integritetstjek til at bekræfte, at hver enkelt faktisk var god, ikke bare til stede.</p>
<p><strong>Resultat.</strong> Backups kørte automatisk og kunne verificeres på tværs af hver database, hvilket gjorde datagenoprettelighed fra en antagelse til noget testet. En væsentlig driftsrisiko kom af forretningen og blev erstattet af en genopretningsvej, man faktisk kunne stole på — forskellen var, at denne var tjekket, ikke bare konfigureret.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har udrullet og vedligeholdt 20 Docker‑containeriserede applikationer, fejlfundet med Podman og Kubernetes og administreret R‑baserede apps på Google Cloud og AWS.</title>
      <link>https://platform.engineer.company/da/portfolio/deployed-and-maintained-20-docker-containerized-applications-troubleshooting-19/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/deployed-and-maintained-20-docker-containerized-applications-troubleshooting-19/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Udrullede og vedligeholdt 20 Docker-containeriserede apps på Google Cloud og AWS — fejlfinding med Podman og Kubernetes, stabile releases.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Cloud</category>
      <category domain="https://platform.engineer.company/da/categories/">Containere (Docker/Kubernetes)</category>
      <category domain="https://platform.engineer.company/da/categories/">Dataanalyse</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/services/">Cloud‑infrastruktur &amp; migrering</category>
      <category domain="https://platform.engineer.company/da/services/">Containerisering &amp; orkestrering</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Der var et voksende sæt containeriserede applikationer — herunder nogle R‑baserede analyseapps — der kørte på tværs af både Google Cloud og AWS. Spredt over to clouds og et par container‑runtimes skulle de udrulles konsistent og kunne diagnosticeres hurtigt, når noget gik galt, hvilket er sværere, end det lyder, når ikke to miljøer er helt ens.</p>
<p><strong>Opgave.</strong> At udrulle og vedligeholde de workloads pålideligt, og at kunne diagnosticere problemer hurtigt på tværs af runtimes og clouds, var jobbet.</p>
<p><strong>Handling.</strong> Det containeriserede estate blev administreret på tværs af begge clouds — tyve Docker‑applikationer udrullet og vedligeholdt med konsistent konfiguration og overvågning, så de ikke hver var deres eget snefnug. Når ting gik galt, gik fejlfindingen gennem Podman og orkestreringsdebugging gennem Kubernetes. De R‑baserede analyseapps fik dedikeret opmærksomhed i Google Cloud- og AWS‑produktionsmiljøerne, holdt stabile og reproducerbare, hvilket for analyse betyder noget — et resultat, man ikke kan reproducere, er ikke meget af et resultat.</p>
<p><strong>Resultat.</strong> Det containeriserede estate kørte pålideligt på tværs af begge clouds, problemer blev diagnosticeret hurtigere, og udrulninger forblev stabile og reproducerbare. De applikationer, produktet lænede sig op ad, forblev pålidelige uanset hvilken cloud de nu tilfældigvis kørte i.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har administreret 30 Ubuntu Linux VPS‑instanser, implementeret disaster recovery‑strategier og sikret optimale netværkskonfigurationer.</title>
      <link>https://platform.engineer.company/da/portfolio/managed-30-ubuntu-linux-vps-instances-implementing-disaster-20/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/managed-30-ubuntu-linux-vps-instances-implementing-disaster-20/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Administrerede 30 Ubuntu Linux VPS-instanser med testede disaster recovery-strategier og solid netværksdrift — et robust vækstfundament.</description>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Netværk &amp; VPN</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Backup &amp; disaster recovery</category>
      <category domain="https://platform.engineer.company/da/services/">Netværk &amp; VPN‑opsætning</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Utiligize kørte på en flåde af Ubuntu Linux VPS‑instanser, hvis opsætning var vokset organisk over tid — hvilket er en pæn måde at sige, den var akkumuleret frem for designet. Det efterlod huller: inkonsistente konfigurationer og genopretnings- og netværksarrangementer, der var mere historisk tilfældighed end plan.</p>
<p><strong>Opgave.</strong> Opgaven var at få flåden under ordentlig styring, styrke disaster recovery‑siden og gøre netværkskonfigurationen konsistent og fornuftig på tværs af hver instans.</p>
<p><strong>Handling.</strong> De tredive instanser kom under bevidst styring — behandlet som én sammenhængende flåde frem for tredive individuelle kæledyr. Rigtig disaster recovery gik ind: backups, og gendannelsesprocedurer, der faktisk blev testet, for en utestet gendannelse er bare en teori. Og netværkskonfigurationen blev standardiseret for sikkerhed og ydeevne, så hver instans fulgte den samme hærdede baseline i stedet for, hvad den nu tilfældigvis var endt med.</p>
<p><strong>Resultat.</strong> Infrastrukturen blev robust og konsistent, med genopretningsveje, der var testet, og netværksdrift, man kunne stole på. Nedetidsrisikoen faldt, og forretningen endte med et solidt fundament at vokse på frem for en lappeløsning, den skulle blive ved med at passe.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har forhindret sikkerhedsbrud ved at lede initiativer inden for adgangsstyring med M365, 1Password, Red Hat SSO og OKTA SSO.</title>
      <link>https://platform.engineer.company/da/portfolio/prevented-security-breaches-by-leading-access-management-initiatives-21/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/prevented-security-breaches-by-leading-access-management-initiatives-21/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Ledede adgangsstyring med M365, 1Password, Red Hat SSO og OKTA — markant lavere risiko for uautoriseret adgang og sporbar adgang.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Cloud</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Adgang til systemer og tjenester på tværs af Utiligize blev håndteret inkonsistent — rettigheder givet ad hoc, over tid, af forskellige folk. Det er et dobbelt problem: det åbner døren for adgang, ingen havde tænkt sig, og det gør revision næsten umulig, for ingen kan faktisk sige, hvem der kan nå hvad, eller hvorfor de kan.</p>
<p><strong>Opgave.</strong> Målet var at lukke sikkerhedseksponeringen ved at centralisere og stramme adgangsstyringen på tværs af hele organisationen.</p>
<p><strong>Handling.</strong> Eftersynet konsoliderede identiteterne og adgangen på tværs af M365, 1Password, Red Hat SSO og OKTA SSO, så der var et sammenhængende billede i stedet for spredte rettigheder pr. system. Least privilege blev håndhævet — personer og systemer havde præcis, hvad de havde brug for, og intet i overskud — og on- og offboarding standardiseret, så adgang blev givet og, lige så vigtigt, tilbagekaldt hurtigt og konsistent frem for at hænge ved, efter nogen var gået videre.</p>
<p><strong>Resultat.</strong> Risikoen for uautoriseret adgang faldt markant, og adgang blev sporbar og konsistent — man kunne endelig svare på &ldquo;hvem kan nå det her, og hvorfor.&rdquo; Det mærkelige er, at det også gjorde hverdagen enklere for teamet: de rigtige døre åbnede let, og de forkerte forblev lukkede, hvilket er, hvad god adgangsstyring faktisk føles som.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har reduceret driftsrisici ved at implementere et monitoreringsdashboard med Grafana og Prometheus og forbedret systemets pålidelighed.</title>
      <link>https://platform.engineer.company/da/portfolio/mitigated-operational-risks-by-implementing-a-monitoring-dashboard-22/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/mitigated-operational-risks-by-implementing-a-monitoring-dashboard-22/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Byggede et Grafana &#43; Prometheus-monitoreringsdashboard, der fanger problemer, før de eskalerer — fra brandslukning til forebyggelse.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Monitorering &amp; observability</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Problemer hos Utiligize blev som regel først bemærket, efter de allerede havde ramt brugerne, fordi der ikke fandtes ét samlet overblik over, hvordan systemerne havde det. Uden det indblik var teamet permanent på bagfod — reagerede på ting, der allerede var gået galt, i stedet for at se dem komme.</p>
<p><strong>Opgave.</strong> Målet var at skære driftsrisikoen ned ved at give teamet realtidsindblik i de systemer, de var afhængige af.</p>
<p><strong>Handling.</strong> Observability‑laget blev bygget ud. Et monitoreringsdashboard på Grafana og Prometheus, de centrale tjenester instrumenteret, og — den del, der faktisk betyder noget — metrikker, der betød noget, frem for forfængelighedstal, der ser travle ud og fortæller en ingenting. Så alarmtærskler sat på dem, synliggjort der, hvor teamet faktisk ville se dem og kunne handle, mens der stadig var tid at handle i.</p>
<p><strong>Resultat.</strong> Problemer begyndte at blive fanget og håndteret, før de eskalerede, og systemets pålidelighed blev bedre for det. Teamet skiftede fra reaktiv brandslukning til noget roligere og mere proaktivt — fangede problemer, mens de stadig var små nok til at være kedelige.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har administreret og fejlfundet 8 WireGuard VPN- og IPSEC VPN‑forbindelser og sikret sikker kommunikation på tværs af Google Cloud og Linux‑systemer.</title>
      <link>https://platform.engineer.company/da/portfolio/managed-and-troubleshooted-8-wireguard-vpn-and-ipsec-23/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/managed-and-troubleshooted-8-wireguard-vpn-and-ipsec-23/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Administrerede og fejlfandt 8 WireGuard- og IPSEC VPN-forbindelser på Google Cloud og Linux — stoppede tilbagevendende forbindelsesudfald.</description>
      <category domain="https://platform.engineer.company/da/categories/">Cloud</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Netværk &amp; VPN</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Netværk &amp; VPN‑opsætning</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Sikker forbindelse mellem cloud&rsquo;en og on‑premises‑Linux‑systemerne kørte over flere VPN‑tunneler, og de var skrøbelige og bøvlede at diagnosticere, når de faldt. En død tunnel kunne kappe kommunikationen mellem miljøer, og at fejlfinde en var langsomt og usikkert — man var aldrig helt sikker på, om man havde fundet den rigtige årsag.</p>
<p><strong>Opgave.</strong> At administrere og fejlfinde de forbindelser, for at garantere sikker og uafbrudt kommunikation, var jobbet.</p>
<p><strong>Handling.</strong> VPN‑estatet kom under kontrol — otte WireGuard- og IPSec‑tunneler på tværs af Google Cloud og Linux‑systemerne, administreret og fejlfundet som et sæt frem for otte separate mysterier. Deres konfiguration blev standardiseret, så de var konsistente og forståelige i stedet for hver at være sit eget særtilfælde, og deres tilstand blev overvåget, med de tilbagevendende routing- og key‑exchange‑problemer tacklet ved roden frem for lappet over med en genstart.</p>
<p><strong>Resultat.</strong> Alle otte tunneler kørte sikkert og pålideligt, kommunikationen mellem miljøer forblev beskyttet, og de tilbagevendende forbindelsesproblemer, der plejede at afbryde arbejdet, holdt op med at ske. At rette rodårsagerne frem for at pleje symptomerne er det, der gjorde dem fra en tilbagevendende hovedpine til noget, der bare virkede.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har forbedret teamets kommunikation og samarbejde ved at implementere Slack, Mattermost, 1Password og Jira og sparet 8.000 arbejdstimer.</title>
      <link>https://platform.engineer.company/da/portfolio/improved-team-communication-and-collaboration-by-implementing-slack-34/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/improved-team-communication-and-collaboration-by-implementing-slack-34/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Sparede ~8.000 timer ved at indføre Slack, Mattermost, 1Password og Jira — mindre jagt på information, mere faktisk levering.</description>
      <category domain="https://platform.engineer.company/da/categories/">Agile &amp; Scrum</category>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Projektledelse</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Teamledelse</category>
      <category domain="https://platform.engineer.company/da/services/">Projektledelse (Agile)</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Teamopbygning &amp; mentoring</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Efterhånden som teamet blev større, havde kommunikationen og værktøjerne ikke fulgt med, og det kunne mærkes. Ting blev sagt ét sted og overset af dem, der havde brug for dem, arbejde blev lavet dobbelt, fordi ingen kunne se, hvad en anden allerede havde gjort, og at koordinere noget som helst tog længere tid end selve arbejdet. Den slags friktion er usynlig fra dag til dag, men den løber op i en masse tabt tid.</p>
<p><strong>Opgave.</strong> Målet var at rette op på, hvordan teamet kommunikerede og arbejdede sammen, og kradse den tid tilbage, der stille og roligt blev blødt til al den friktion.</p>
<p><strong>Handling.</strong> Værktøjerne blev indført og standardiseret, og — det er den del, der faktisk betyder noget — praksis for at bruge dem blev sat, så de ikke bare blev endnu et sted at tjekke. Slack og Mattermost til kommunikation, 1Password, så delte secrets ikke blev sendt rundt på måder, ingen kunne holde styr på, Jira, så arbejdet blev tracket ét sted i stedet for at leve i folks hoveder og indbakker. Værktøjerne var den nemme del; at få alle til faktisk at bruge dem på samme måde var det egentlige arbejde.</p>
<p><strong>Resultat.</strong> Kommunikation og samarbejde blev mærkbart bedre, og det strømlinede opsæt sparede noget i størrelsesordenen 8.000 arbejdstimer — tid, der havde gået til at jage information og lave arbejde om, som nu gik til faktisk levering.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har gennemgribende fornyet interne processer og sparet 8.000 timer ved at forbedre softwarearkitektur, systemer og planlægningseffektivitet.</title>
      <link>https://platform.engineer.company/da/portfolio/overhauled-internal-processes-saving-8-000-hours-by-38/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/overhauled-internal-processes-saving-8-000-hours-by-38/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Fornyede interne processer og sparede ~8.000 timer ved at forbedre softwarearkitektur, systemer og planlægningseffektivitet.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Løsningsarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Performanceoptimering</category>
      <category domain="https://platform.engineer.company/da/categories/">Platformarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Projektledelse</category>
      <category domain="https://platform.engineer.company/da/categories/">Teknisk ledelse</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Platform- &amp; løsningsarkitektur</category>
      <category domain="https://platform.engineer.company/da/services/">Projektledelse (Agile)</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk ledelse &amp; rådgivning</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har administreret netværksinfrastruktur for over 1.000 servere og sikret optimal systemudrulning, sikkerhed og fejlfinding.</title>
      <link>https://platform.engineer.company/da/portfolio/administered-network-infrastructure-for-over-1-000-servers-39/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/administered-network-infrastructure-for-over-1-000-servers-39/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Administrerede netværksinfrastruktur for 1.000&#43; servere — pålidelig udrulning, solid sikkerhed og prompt fejlfinding.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Netværk &amp; VPN</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Netværk &amp; VPN‑opsætning</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Virksomhedens drift sad oven på et stort serverestate — over tusind af dem — og et estate af den størrelse holder sig ikke pålideligt af sig selv. Udrulning, sikkerhed og den stadige strøm af ting, der går galt, kræver alle en, der kører dem med faktisk disciplin, ellers bliver det hele ustabilt, og ingen er helt sikre på hvorfor.</p>
<p><strong>Opgave.</strong> At administrere den netværksinfrastruktur var jobbet — at holde den sikker, holde den pålidelig, holde den konsistent i en skala, hvor inkonsistens er det, der slår en ihjel.</p>
<p><strong>Handling.</strong> Netværksinfrastrukturen kørte på tværs af mere end tusind servere. Hvordan systemer blev udrullet blev standardiseret, så en server kom op på den samme forudsigelige måde i stedet for hver at være en lille smule specialbygget; sikkerheden blev hærdet frem for at stole på, at ingen ville komme og lede; og fejlfindingen blev håndteret, når noget først gik i stykker. I den skala er standardiseringen det, der redder en — tusind snefnug er uadministrerbart, tusind af den samme ting er bare arbejde.</p>
<p><strong>Resultat.</strong> Estatet kørte med pålidelig udrulning, solid sikkerhed og problemer, der blev håndteret prompte i stedet for at ulme. Det er den slags infrastrukturarbejde, der er usynligt, når det går godt, hvilket er pointen — det var den stabile rygrad, alt andet i virksomheden kørte på.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har automatiseret oprettelse af SSL/TLS‑certifikater for 100 Docker‑applikationer og sikret sikre forbindelser på tværs af Ubuntu Linux‑hosts.</title>
      <link>https://platform.engineer.company/da/portfolio/automated-ssl-tls-certificate-creation-for-100-docker-41/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/automated-ssl-tls-certificate-creation-for-100-docker-41/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Automatiserede SSL/TLS-certifikater for 100 Docker-apps på Ubuntu Linux — slut med manuelle fornyelser og udløbsnedbrud.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Containere (Docker/Kubernetes)</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Containerisering &amp; orkestrering</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Hundrede Docker‑applikationer havde alle brug for SSL/TLS‑certifikater, og certifikater er den slags, der er fint lige indtil de ikke er. At udstede og forny hundrede af dem i hånden er langsomt, det er kedeligt, og det er præcis den slags manuelle job, hvor én glemt fornyelse tager en app ned med en udløbsfejl på det værst tænkelige tidspunkt.</p>
<p><strong>Opgave.</strong> Målet var oprettelse og fornyelse af certifikater automatiseret — hver app med gyldig, betroet kryptering, og ingen der skulle huske at gøre noget.</p>
<p><strong>Handling.</strong> Et ACME‑baseret workflow håndterede hele livscyklussen for de hundrede Docker‑applikationer — oprettede certifikaterne og fornyede dem, før de udløb — og udrullede dem automatisk på tværs af Ubuntu Linux‑hostene, der kørte en blanding af Apache og Nginx. Hele målet var at tage mennesket ud af det, for mennesket er den del, der glemmer.</p>
<p><strong>Resultat.</strong> Alle hundrede applikationer holdt gyldige certifikater og sikre forbindelser af sig selv. Det manuelle certifikatarbejde forsvandt bare, og med det hele den kategori af nedbrud, hvor noget går i stykker, ikke fordi det fejlede, men fordi et certifikat stille og roligt udløb, og ingen bemærkede det.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har strømlinet CI/CD‑processer og sparet 4.000 timer ved at indføre automatisering i softwareudviklingspipelines.</title>
      <link>https://platform.engineer.company/da/portfolio/streamlined-ci-cd-processes-saving-4-000-hours-42/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/streamlined-ci-cd-processes-saving-4-000-hours-42/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Strømlinede CI/CD og sparede ~4.000 timer — hurtigere, mere pålidelige releases, så teamet kunne udgive med tillid.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Teknisk ledelse</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk ledelse &amp; rådgivning</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> At få software ud ad døren afhang af manuelle, inkonsistente trin — nogen der huskede rækkefølgen og gjorde det en anelse forskelligt hver gang — og det bremsede releases og åd engineering‑timer, der skulle være gået til at bygge ting.</p>
<p><strong>Opgave.</strong> Målet var at strømline CI/CD‑processen og få automatisering ind i pipelines, så releases holdt op med at være et manuelt ritual.</p>
<p><strong>Handling.</strong> Automatiserede build-, test- og udrulningspipelines blev sat op, så vejen fra en ændring til, at den kørte i produktion, var standardiseret i stedet for improviseret. De gentagne manuelle trin — dem, der var langsomme og, værre, blev gjort forskelligt afhængigt af, hvem der gjorde dem — kom ud. Når først pipelinen gør det på samme måde hver gang, holder en hel klasse af &ldquo;det virkede på min maskine&rdquo; og halvt huskede udrulningstrin bare op med at ske.</p>
<p><strong>Resultat.</strong> Automatiseringen gav omkring 4.000 timer tilbage og gjorde releases både hurtigere og mere pålidelige. Teamet kunne udgive uden at spænde ben for det — tilliden kom fra, at processen var konsistent, ikke fra at alle var forsigtige.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har strømlinet processer for dataanalyse og softwareudvikling og sparet 4.000 timer ved at indføre CI/CD‑praksis med GitHub, GitLab, Bash og Python.</title>
      <link>https://platform.engineer.company/da/portfolio/streamlined-data-analysis-and-software-development-processes-saving-43/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/streamlined-data-analysis-and-software-development-processes-saving-43/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Sparede ~4.000 timer ved at indføre CI/CD med GitHub, GitLab, Bash og Python — hurtigere dataanalyse og udvikling, mere konsistent.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Data engineering</category>
      <category domain="https://platform.engineer.company/da/categories/">Datapipelines (ETL/ELT)</category>
      <category domain="https://platform.engineer.company/da/categories/">Dataanalyse</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/services/">Dataanalyse &amp; BI‑dashboards</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Udvikling af datapipelines (ETL/ELT)</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Både dataanalysearbejdet og softwareudviklingen blev holdt tilbage af det samme: manuelle processer. Arbejde bevægede sig fra udvikling til levering på en langsom, inkonsistent måde, og analysesiden havde sin egen bunke gentagne trin, som nogen lavede i hånden hver gang.</p>
<p><strong>Opgave.</strong> Målet var at strømline begge dele ved at bringe moderne automatisering og CI/CD‑praksis til workflows, der ikke havde haft dem.</p>
<p><strong>Handling.</strong> CI/CD‑praksis blev indført, bygget på GitHub og GitLab, med Bash og Python, der lavede automatiseringsarbejdet nedenunder. De gentagne trin på tværs af både dataanalyse- og udviklingsworkflows blev automatiseret, og hvordan arbejdet bevægede sig fra udvikling og hele vejen til levering blev standardiseret, så det var det samme hver gang frem for genopfundet pr. projekt. At bringe analysesiden ind i den samme disciplinerede pipeline som udviklingsarbejdet var en stor del af det — den var blevet behandlet som en separat, mere manuel verden.</p>
<p><strong>Resultat.</strong> De strømlinede processer sparede omkring 4.000 timer og satte fart på både dataanalysen og softwareudviklingen, og lige så nyttigt gjorde de det, der blev sendt ud, mere konsistent — færre overraskelser fra arbejde, der var blevet gjort en anelse forskelligt hver gang.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har automatiseret databehandlingsopgaver med shell‑scripting, PL/pgSQL, Python og Transact‑SQL og øget produktiviteten og effektiviteten.</title>
      <link>https://platform.engineer.company/da/portfolio/automated-data-processing-tasks-using-shell-scripting-pl-45/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/automated-data-processing-tasks-using-shell-scripting-pl-45/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Automatiserede databehandling med Shell, PL/pgSQL, Python og Transact-SQL — højere produktivitet og slut med små, tilbagevendende fejl.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Data engineering</category>
      <category domain="https://platform.engineer.company/da/categories/">Databaser</category>
      <category domain="https://platform.engineer.company/da/categories/">Datapipelines (ETL/ELT)</category>
      <category domain="https://platform.engineer.company/da/categories/">PostgreSQL</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/categories/">SQL</category>
      <category domain="https://platform.engineer.company/da/services/">Databaseadministration (DBA)</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Udvikling af datapipelines (ETL/ELT)</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Der var en stabil mængde tilbagevendende databehandlingsarbejde, der blev lavet i hånden. Manuelt dataarbejde har to problemer på én gang: det æder tid, og det er inkonsistent — lav den samme opgave i hånden nok gange, og den bliver gjort en anelse forskelligt, og nogle af de forskelle er fejl.</p>
<p><strong>Opgave.</strong> Målet var at automatisere de opgaver, både for at få tiden tilbage og for at gøre dem pålidelige.</p>
<p><strong>Handling.</strong> Databehandlingsarbejdet blev automatiseret på tværs af de databaser og systemer, det rørte, med hvad end der passede til jobbet — shell‑scripting til limen, PL/pgSQL og Transact‑SQL nede i databaserne, Python, hvor det krævede mere, end SQL kunne give. Manuelle trin blev erstattet med jobs, der kørte på samme måde hver gang, hvilket er hele pointen: et script bliver ikke træt, springer ikke et trin over og gør det ikke anderledes en fredag eftermiddag.</p>
<p><strong>Resultat.</strong> Produktiviteten og effektiviteten gik begge op, det manuelle arbejde kom af folks bord, og databehandlingen blev konsistent og pålidelig i stedet for en kilde til små, tilbagevendende fejl.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har konfigureret og idriftsat 1.000 Wi‑Fi‑routere og forbedret netværkstilgængeligheden og -ydeevnen for kunderne.</title>
      <link>https://platform.engineer.company/da/portfolio/configured-and-deployed-1-000-wi-fi-routers-48/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/configured-and-deployed-1-000-wi-fi-routers-48/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Konfigurerede og idriftsatte 1.000 Wi-Fi-routere med standardopsætning — pålidelig trådløs adgang og ydeevne for kunderne.</description>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Netværk &amp; VPN</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">IT‑support &amp; helpdesk</category>
      <category domain="https://platform.engineer.company/da/services/">Netværk &amp; VPN‑opsætning</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Kunder havde brug for trådløst, der bare virkede, og det kom ned til at konfigurere og rulle et stort antal Wi‑Fi‑routere ud — og gøre det på den samme omhyggelige måde hver gang, for en router sat sjusket op er enten usikker eller langsom, og som regel finder man ud af hvilken en senere.</p>
<p><strong>Opgave.</strong> At konfigurere og udrulle de routere for at give kunderne bedre netværksadgang og -ydeevne var jobbet.</p>
<p><strong>Handling.</strong> Tusind Wi‑Fi‑routere blev konfigureret og udrullet. Kunsten ved det antal er at standardisere opsætningen — en konsistent, sikker, fornuftig konfiguration — frem for at tune hver enkelt fra bunden på dagen, for tusind håndlavede routere er tusind forskellige ting at supportere senere. Så de blev sat op for sikkerhed og ydeevne på samme måde hver gang og rullet pålideligt ud på tværs af kundelokationer.</p>
<p><strong>Resultat.</strong> De tusind routere gav kunderne pålideligt trådløst — bedre adgang, bedre ydeevne — og gjorde det konsistent, fordi opsætningen var standard frem for improviseret. En router, ingen skal tænke over igen, er målet; de fleste af disse nåede dertil.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har administreret 100 barebone‑servere, fysiske netværk og IP‑telefonisystemer og sikret en robust infrastruktur til virksomhedens vækst.</title>
      <link>https://platform.engineer.company/da/portfolio/administered-100-bare-bone-servers-physical-networks-and-50/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/administered-100-bare-bone-servers-physical-networks-and-50/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Administrerede 100 barebone-servere, fysiske netværk og IP-telefoni — det robuste fundament, virksomheden voksede på.</description>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Netværk &amp; VPN</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Netværk &amp; VPN‑opsætning</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Under alt, hvad virksomheden lavede, lå det fysiske — servere, de faktiske netværk, IP‑telefonien — og det skulle bare køre. Det lag er usynligt, når det virker, og ekstremt synligt i det øjeblik, det ikke gør, og virksomhedens vækst hvilede på, at det holdt sig pålideligt.</p>
<p><strong>Opgave.</strong> At administrere den infrastruktur og holde den stabil, efterhånden som virksomheden voksede, var jobbet.</p>
<p><strong>Handling.</strong> Hundrede barebone‑servere sammen med de fysiske netværk og IP‑telefonisystemerne blev passet — opsætningen, vedligeholdelsen, fejlfindingen, når noget gik galt. Barebone‑servere betyder, at man har med hardwaren direkte at gøre, så der er en hands‑on, fysisk side af det: kablingen, kasserne, telefonsystemet, som alle bemærker i det sekund, et opkald falder. Jobbet var at holde det hele kedeligt, i den gode forstand.</p>
<p><strong>Resultat.</strong> Serverne, netværkene og telefonien kørte pålideligt, og det pålidelige fysiske fundament er det, der lod virksomheden blive ved med at vokse, uden at grunden flyttede sig under den.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har administreret 40 websites på Ubuntu Linux‑hostingservere med Apache og Nginx og sikret høj tilgængelighed og ydeevne.</title>
      <link>https://platform.engineer.company/da/portfolio/administered-40-websites-on-ubuntu-linux-hosting-servers-53/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/administered-40-websites-on-ubuntu-linux-hosting-servers-53/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Administrerede 40 websites på Ubuntu Linux med Apache og Nginx — høj tilgængelighed og ydeevne, hosting man ikke behøvede tænke over.</description>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Performanceoptimering</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/categories/">Webudvikling</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Webstedsudvikling &amp; CMS</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> At administrere de sites og holde dem højt tilgængelige og hurtige var jobbet.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/architected-developed-implemented-supported-infrastructure-data-processing-and-55/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/architected-developed-implemented-supported-infrastructure-data-processing-and-55/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Arkitekterede, byggede og driftede infrastruktur, databehandling og kortapp i to år uden pause — produktets pålidelige rygrad.</description>
      <category domain="https://platform.engineer.company/da/categories/">Data engineering</category>
      <category domain="https://platform.engineer.company/da/categories/">Datapipelines (ETL/ELT)</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Full stack‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">GIS / Geospatial</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Platformarkitektur</category>
      <category domain="https://platform.engineer.company/da/services/">Full stack‑produktudvikling</category>
      <category domain="https://platform.engineer.company/da/services/">GIS &amp; geospatiale løsninger</category>
      <category domain="https://platform.engineer.company/da/services/">Platform- &amp; løsningsarkitektur</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <category domain="https://platform.engineer.company/da/services/">Udvikling af datapipelines (ETL/ELT)</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/optimized-budget-costs-10-times-with-zero-loss-56/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/optimized-budget-costs-10-times-with-zero-loss-56/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Reducerede infrastrukturbudgettet 10× uden produktivitetstab for en saudiarabisk virksomhed ved at nytænke stacken og forlade AWS.</description>
      <category domain="https://platform.engineer.company/da/categories/">Cloud</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Løsningsarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Migrering &amp; modernisering</category>
      <category domain="https://platform.engineer.company/da/categories/">Platformarkitektur</category>
      <category domain="https://platform.engineer.company/da/services/">Cloud‑infrastruktur &amp; migrering</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Platform- &amp; løsningsarkitektur</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/designed-an-organization-context-switching-system-with-client-59/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/designed-an-organization-context-switching-system-with-client-59/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Byggede organisationskontekst-skift med localStorage og server-cookie-spejling — brugere agerer som administrerede orgs under least-privilege.</description>
      <category domain="https://platform.engineer.company/da/categories/">API&#39;er &amp; integration</category>
      <category domain="https://platform.engineer.company/da/categories/">Backend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Frontend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Full stack‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Platformarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Backend- &amp; API‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">Frontend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">Platform- &amp; løsningsarkitektur</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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å.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/built-a-request-schema-validation-contract-with-automated-61/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/built-a-request-schema-validation-contract-with-automated-61/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Genererede API-kontrakten ud fra databasen — OpenAPI, en typet TypeScript-klient, mock handlers og UI-grænser — med en guard i hvert eneste led.</description>
      <category domain="https://platform.engineer.company/da/categories/">API&#39;er &amp; integration</category>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Backend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">Backend- &amp; API‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> Kæden starter ved databasen og løber udad. Skemaet og dets funktioner definerer formerne; Go‑typerne definerer API&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&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&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 &ldquo;mangler&rdquo; og &ldquo;null&rdquo; bliver forvekslet, og query‑parameter‑enums, hvor de to sider stille og roligt kan være uenige om de tilladte værdier.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/built-email-as-a-platform-capability-with-failover-62/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/built-email-as-a-platform-capability-with-failover-62/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Byggede e-mail som en kapabilitet i platformen: tre udbydere med failover, delivery-webhooks, logning af afsendelse og levering, templating og kampagner.</description>
      <category domain="https://platform.engineer.company/da/categories/">API&#39;er &amp; integration</category>
      <category domain="https://platform.engineer.company/da/categories/">Backend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Cloud</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Backend- &amp; API‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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å &ldquo;fik det her menneske sin verificeringsmail&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.</p>
<p><strong>Resultat.</strong> En hel kategori af lydløs fejl flyttede fra &ldquo;en bruger opdager det dage senere&rdquo; til &ldquo;deployet stopper&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.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har provisioneret Azure‑infrastruktur som kode med Bicep — Container Apps, PostgreSQL Flexible Server, Front Door/WAF og netværk — på tværs af udviklings-, staging- og produktionsmiljøer.</title>
      <link>https://platform.engineer.company/da/portfolio/provisioned-azure-infrastructure-as-code-with-bicep-container-68/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/provisioned-azure-infrastructure-as-code-with-bicep-container-68/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Provisionerede Azure-infrastruktur som kode med Bicep — Container Apps, PostgreSQL, Front Door/WAF — reproducerbar på tværs af miljøer.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Cloud</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Netværk &amp; VPN</category>
      <category domain="https://platform.engineer.company/da/categories/">Platformarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Cloud‑infrastruktur &amp; migrering</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Netværk &amp; VPN‑opsætning</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> NextMariner lever på Azure, og Azure lavet i hånden — klik gennem portalen, en indstilling justeret her og der — er en fælde. Det driver, ingen husker hvorfor noget er, som det er, og at genopbygge det efter en dårlig dag er langsomt og nervepirrende. Med mere end ét miljø at holde i takt bliver det kun værre.</p>
<p><strong>Opgave.</strong> Læg det hele i kode, så et miljø er noget, man kan læse, reviewe og genskabe frem for en bunke manuel tilstand.</p>
<p><strong>Handling.</strong> Estatet er defineret i Bicep. Hvert miljø — testing, staging, product — kommer ud af de samme templates: api&rsquo;et og www kørende som Azure Container Apps på et managed environment, en PostgreSQL Flexible Server, Redis til caching, Front Door med en WAF‑politik ude foran og netværket under det (VNet, NSG, private DNS), med Log Analytics koblet på til diagnostik. Images hentes fra projektets Azure Container Registry. Fordi det hele er parametriseret, er det at rejse et nyt miljø eller ændre et eksisterende en pull request, ikke en supportsag til en selv.</p>
<p><strong>Resultat.</strong> Miljøerne blev reproducerbare og reviderbare. Drift holdt op med at være et mysterium, fordi kilden til sandhed er koden, og at bringe infrastruktur op eller tilbage er et spørgsmål om at anvende templates frem for at huske, hvad der blev klikket sidst. Det er forskellen mellem infrastruktur, man ejer, og infrastruktur, der ejer én.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har bygget GitHub Actions CI/CD‑pipelines med et distroless produktions‑frontend‑image og promovering på tværs af flere miljøer.</title>
      <link>https://platform.engineer.company/da/portfolio/built-github-actions-ci-cd-pipelines-with-a-69/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/built-github-actions-ci-cd-pipelines-with-a-69/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Byggede GitHub Actions CI/CD med et distroless produktions-frontend-image og promovering på tværs af miljøer — rutinemæssige releases.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Cloud</category>
      <category domain="https://platform.engineer.company/da/categories/">Containere (Docker/Kubernetes)</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">Containerisering &amp; orkestrering</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Levering bør ikke afhænge af, at nogen husker trinene, og det, der ender med at køre i produktion, bør ikke være en fed general‑purpose‑container, der bærer en shell og en package manager, den aldrig vil bruge — det er bare angrebsflade, der sidder der uden grund.</p>
<p><strong>Opgave.</strong> Gør vejen fra commit til kørende‑i‑Azure automatisk, og hold produktions‑images så små og låst ned, som hver workload tillader.</p>
<p><strong>Handling.</strong> Pipelinen er GitHub Actions. Separate workflows håndterer kodekvalitets‑gaten, testene og de miljøspecifikke deploys, med CodeQL, dependency review og et SBOM‑trin ved siden af, så intet når et miljø uden først at passere tjekkene. Images er multi‑stage‑builds, og basen for hver del blev valgt efter dens fortjeneste frem for ét blankt valg: frontenden sendes på et distroless image (gcr.io/distroless/cc‑debian13 — ingen shell, ingen package manager), Go‑API&rsquo;et på en slank Alpine og database‑imaget på postgres‑slim. Promovering flytter et build gennem miljøerne ad en defineret rute frem for i hånden.</p>
<p><strong>Resultat.</strong> Releases holdt op med at være et omhyggeligt manuelt ritual og blev en rutinemæssig, kedelig hændelse, hvilket er præcis, hvad man vil have fra releases. Produktions‑frontenden kører på omtrent så lidt, som man kan give den, tjekkene fanger problemer, før de lander, og &ldquo;deploy&rdquo; er noget, pipelinen gør, frem for noget, nogen sveder sig igennem.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har skrevet 578 go‑task‑automatiseringsmål på tværs af native-, Docker- og HTTPS‑udviklingstilstande, linting, test, database og deployment.</title>
      <link>https://platform.engineer.company/da/portfolio/authored-578-go-task-automation-targets-70/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/authored-578-go-task-automation-targets-70/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Skrev 578 go-task-mål på tværs af native-, Docker- og HTTPS-tilstande — linting, test, database og deployment i én værktøjskæde.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Teknisk ledelse</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk dokumentation</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> NextMariner er et polyglot‑monorepo — Go, TypeScript, SQL, Python, shell — og hvert af dem medbringer sin egen måde at bygge, teste, linte og køre på. Overladt til sig selv betyder det, at alle går rundt med et mentalt spikseddel af værktøjsspecifikke kommandoer, og at nytilkomne bruger deres første dag på bare at finde ud af, hvordan man får tingene til at køre.</p>
<p><strong>Opgave.</strong> Giv hele projektet én hoveddør: én konsistent måde at køre hvad som helst på, uanset hvilket sprog det tilfældigvis er skrevet i.</p>
<p><strong>Handling.</strong> Det er bygget ud med go‑task — et Taskfile‑lag, der er vokset til 578 navngivne mål, 50 i rodfilen og 528 i namespacede filer under den. Der er udviklingstilstandene (native, Docker, en HTTPS‑variant til at teste PWA og mobil), kodekvalitetssiden (lint, format, test, fix på tværs af alle sprogene), databasehåndtering og de miljøspecifikke build- og deploy‑opgaver. Der er endda en low‑memory‑tilstand til maskiner, der ikke kan undvære den RAM, det kræver at bygge frontenden på den sædvanlige måde. Pointen var aldrig at have mange tasks; den var, at man aldrig behøver at kende den underliggende kommando.</p>
<p><strong>Resultat.</strong> Enhver kan køre task &ndash;list og se hele værktøjskæden lagt frem og køre en hvilken som helst del af den på samme måde uanset, hvad der er under motorhjelmen. Onboarding blev kortere, og de små, dumme fejl — forkert flag, forkert mappe, halvt husket kommando — forsvandt for det meste. Tallet er også en advarsel: 578 mål er forbi, hvad nogen kan holde i hovedet, så navngivningen og namespacingen er det, der holder det brugbart, frem for at antallet er noget at være stolt af.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har haft ansvaret for end‑to‑end‑deployments af platformen til Azure og styret releases på tværs af udviklings-, staging- og produktionsmiljøer.</title>
      <link>https://platform.engineer.company/da/portfolio/owned-end-to-end-deployments-of-the-platform-71/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/owned-end-to-end-deployments-of-the-platform-71/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Havde ansvaret for end-to-end Azure-deployments — releases gennem dev, staging og produktion ad en defineret, gentagelig vej.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Cloud</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Cloud‑infrastruktur &amp; migrering</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Platformen skulle nå brugerne på tværs af flere Azure‑miljøer, og deployment er den søm, hvor infrastrukturen, build‑pipelinen og applikationen alle mødes. Det er også der, hvor en lille fejl holder op med at være en bug og bliver til et nedbrud, så det er den del, man mindst af alt vil lave i hånden og halvt efter hukommelsen.</p>
<p><strong>Opgave.</strong> Deployment blev ejet fra ende til anden, så en ændring flyttede ud til hvert miljø på den samme forudsigelige måde hver gang.</p>
<p><strong>Handling.</strong> Releases bevæger sig ad en fast rute — udvikling, så staging, så produktion — frem for at nogen pusher direkte til et live miljø. CI/CD‑pipelinen bygger images og sender dem, og Bicep‑templates holder målinfrastrukturen ens fra det ene miljø til det næste, så et build ikke promoveres ind i et lidt anderledes sted hver gang. Konfiguration, der er forskellig pr. miljø, holdes adskilt fra secrets, hvilket betyder, at det samme byggede artefakt kan promoveres gennem miljøerne og bare samler de rette indstillinger op, hvor det lander, i stedet for at blive bygget om for hvert.</p>
<p><strong>Resultat.</strong> Ændringer når hvert miljø forudsigeligt, ad en defineret vej, uden ad hoc‑manuelle deploys i blandingen. At release blev til et kontrolleret, gentageligt trin i stedet for et med tilbageholdt vejrtrækning, og det er en stor del af, hvad der holdt den live platform stabil, mens den stadig ændrede sig hurtigt nedenunder.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har konfigureret opbevaring af databasebackups som infrastructure‑as‑code, gennemgået genopretningsberedskabet og dokumenteret restore‑proceduren — med de resterende huller navngivet frem for fundet under en hændelse.</title>
      <link>https://platform.engineer.company/da/portfolio/configured-database-backup-retention-as-infrastructure-as-code-72/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/configured-database-backup-retention-as-infrastructure-as-code-72/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Implementerede databasebackups og en disaster recovery-strategi via infrastructure-as-code — hurtig, reproducerbar genopretning.</description>
      <category domain="https://platform.engineer.company/da/categories/">Cloud</category>
      <category domain="https://platform.engineer.company/da/categories/">Databaser</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">PostgreSQL</category>
      <category domain="https://platform.engineer.company/da/services/">Backup &amp; disaster recovery</category>
      <category domain="https://platform.engineer.company/da/services/">Databaseadministration (DBA)</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Et produkt, der lever på sine data, har ikke råd til at miste nogen, og &ldquo;der er backups et sted&rdquo; er et håb, ikke en genopretningsplan. Den eneste backup, der er noget værd, er en, man ved gendanner, ind i et miljø, man ved, man kan genopbygge. NextMariner havde ingen af de to halvdele skrevet ned.</p>
<p><strong>Opgave.</strong> Få den genoprettelige position defineret i stedet for antaget — dataene, miljøet omkring dem, og et ærligt billede af, hvor langt det faktisk rækker i dag.</p>
<p><strong>Handling.</strong> Backup‑retention er konfigureret i Bicep ved siden af den database, den beskytter, så gendannelse til et tidspunkt er en egenskab ved templaten frem for en indstilling, nogen engang klikkede i en portal. Miljøet omkring den er også defineret som infrastructure‑as‑code, hvilket er den stille halvdel, folk glemmer: at gendanne en database ind i et miljø, man skulle genopbygge i hånden efter hukommelsen, er ikke rigtig genopretning. Derefter blev positionen gennemgået og skrevet op — gendannelsesproceduren, den øvelse, der ville måle den, og de huller, der stadig står åbne: geo‑redundans er slået fra, og målet for genopretningstid er foreslået frem for målt, fordi ingen øvelse er kørt endnu.</p>
<p><strong>Resultat.</strong> Genopretning holdt op med at være en vag beroligelse og blev en dokumenteret position med sine huller navngivet. Det lyder mindre imponerende end &ldquo;disaster recovery: klaret&rdquo;, og det er væsentligt mere værd — den næste, der rører ved det, ved, hvad der er dækket, hvad der ikke er, og præcis hvilken øvelse der lukker forskellen. Et navngivet hul kan man lukke; et unavngivet bliver opdaget under en hændelse.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har hærdet applikationen med nonce‑baseret CSP, HSTS, SameSite‑cookies, least‑privilege‑databaseroller og server‑side‑genkontrol af rettigheder.</title>
      <link>https://platform.engineer.company/da/portfolio/hardened-the-application-with-nonce-based-csp-hsts-77/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/hardened-the-application-with-nonce-based-csp-hsts-77/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Hærdede appen med nonce-baseret CSP, HSTS, SameSite-cookies, least-privilege-databaseroller og server-side-genkontrol af rettigheder.</description>
      <category domain="https://platform.engineer.company/da/categories/">API&#39;er &amp; integration</category>
      <category domain="https://platform.engineer.company/da/categories/">Backend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Databaser</category>
      <category domain="https://platform.engineer.company/da/categories/">Frontend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Platformarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Backend- &amp; API‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> I frontenden sætter Next.js&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&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&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å.</p>
<p><strong>Resultat.</strong> Sikkerhed afhænger ikke af, at UI&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.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har sat en zero‑warnings‑kvalitetsstandard på tværs af seks sprog — Go, TypeScript, SQL, Python, Shell og Markdown — håndhævet af pre‑commit‑hooks.</title>
      <link>https://platform.engineer.company/da/portfolio/set-a-zero-warnings-quality-bar-across-six-79/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/set-a-zero-warnings-quality-bar-across-six-79/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Satte en zero-warnings-kvalitetsstandard på tværs af Go, TypeScript, SQL, Python, Shell og Markdown — håndhævet af pre-commit-hooks.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Teknisk ledelse</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk ledelse &amp; rådgivning</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Advarsler, der hober sig op, er stille og roligt ætsende. Hver diagnostik, man ignorerer, sænker barren en smule, og når først buildet spytter fyrre af dem ud, læser ingen nogen af dem, og et reelt problem sidder i den liste i fuldt dagslys, fordi &ldquo;advarsler&rdquo; er blevet til baggrundsstøj. I et polyglot‑kodebase er der så mange flere kilder til støj til at lade det ske.</p>
<p><strong>Opgave.</strong> Repoet skulle have én kompromisløs kvalitetsstandard på tværs af hvert sprog, så ting blev rettet i stedet for at hobe sig op.</p>
<p><strong>Handling.</strong> En zero‑warnings‑politik gik ind, med værktøjerne som det, der håndhæver den, for en politik, der bygger på alles årvågenhed, taber til den første travle uge. Hver linter‑diagnostik er en fejl — der er intet &ldquo;warn&rdquo;-niveau at gemme sig i — og det er det samme på tværs af hele stakken: Go med golangci‑lint, TypeScript med ESLint, SQL med SQLFluff, Python med Ruff, shell med ShellCheck, Markdown med markdownlint. Inline‑suppressions er forbudt, så man kan ikke papre hen over en diagnostik; man er nødt til faktisk at rette tingen. Pre‑commit- og pre‑push‑hooks kører linterne og testene, så en commit, der ville introducere et problem, slet ikke bliver lavet i første omgang. Der er endda grænser for funktions- og fillængde for at holde moduler fra at brede sig ud over det punkt, hvor de er læsbare.</p>
<p><strong>Resultat.</strong> Problemer bliver rettet ved kilden i stedet for udskudt til en backlog, ingen rydder, og kodebasen forbliver ren som standard frem for ved periodiske heltemodige indsatser. Standarden er identisk, uanset hvilket sprog man er i, og det er værktøjerne, der holder den — ikke nogens viljestyrke — hvilket er derfor, den faktisk holder.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har leveret døgnbemandet 24/7‑infrastruktursupport til en IPTV/OTT‑streamingplatform og administreret ca. 1.000 servere samt kundeejede systemer for globale kunder i Kina, USA og Tyskland.</title>
      <link>https://platform.engineer.company/da/portfolio/provided-round-the-clock-24-7-infrastructure-support-82/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/provided-round-the-clock-24-7-infrastructure-support-82/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Leverede 24/7-infrastruktursupport til en IPTV/OTT-streamingplatform — ~1.000 servere plus kundesystemer i Kina, USA og Tyskland.</description>
      <category domain="https://platform.engineer.company/da/categories/">Cloud</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Monitorering &amp; observability</category>
      <category domain="https://platform.engineer.company/da/categories/">Netværk &amp; VPN</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">IT‑support &amp; helpdesk</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Det her var en IPTV/OTT‑streamingplatform med kunder spredt over Kina, USA og Tyskland, hvilket betød, at der ikke var nogen stille time at lave vedligeholdelse i — nogen, et eller andet sted, kiggede altid med. Nedetid på sådan en platform er ikke en abstrakt måltal; det er nogens fjernsyn, der bare stopper, og de er ligeglade med hvorfor.</p>
<p><strong>Opgave.</strong> At holde platformens infrastruktur tilgængelig døgnet rundt var jobbet — reelt døgnet rundt, ikke &ldquo;kontortid plus en tilkaldevagt, ingen svarer på.&rdquo;</p>
<p><strong>Handling.</strong> 24/7‑support kørte for omkring tusind servere, plus et pænt antal kundeejede systemer oveni — administreret, overvåget, holdt sikret og konfigureret på tværs af hele streaming‑estatet. Fordi kunderne sad i tre vidt forskellige tidszoner, fandtes &ldquo;efter arbejdstid&rdquo; ikke rigtig; et problem klokken 3 om natten lokalt var primetime for nogen andre, så det blev behandlet som primetime. En stor del af arbejdet var at bemærke noget, der drev af, før det blev til et nedbrud, for på en live streamingplatform får man ikke lov at rette ting stille bagefter.</p>
<p><strong>Resultat.</strong> Platformen forblev kontinuerligt tilgængelig for et globalt publikum, med problemer fanget og håndteret på hvilken time end de dukkede op, før de nåede en seers skærm. På en 24/7‑tjeneste er det hele jobbet — succes ser ud som ingenting, der sker, hvilket er præcis, hvad seerne ville have.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har sikret uafbrudt levering af IPTV‑streamingsignaler mellem leverandører og kunder og overvåget og vedligeholdt streamingnetværket og IP‑telefonien døgnet rundt.</title>
      <link>https://platform.engineer.company/da/portfolio/ensured-uninterrupted-delivery-of-iptv-streaming-signals-between-83/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/ensured-uninterrupted-delivery-of-iptv-streaming-signals-between-83/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Sikrede uafbrudt IPTV-streaming mellem leverandører og kunder — overvågede og vedligeholdt streamingnetværk og IP-telefoni døgnet rundt.</description>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Monitorering &amp; observability</category>
      <category domain="https://platform.engineer.company/da/categories/">Netværk &amp; VPN</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Netværk &amp; VPN‑opsætning</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> IPTV lever eller dør på, at signalet kommer igennem. Streamsene flyder fra leverandører, gennem platformen, til kunderne, og ethvert brud hvor som helst i den kæde er en sort skærm for nogen. IP‑telefonien sad ved siden af, med det samme krav: den skulle bare virke.</p>
<p><strong>Opgave.</strong> At garantere, at signalleveringen og telefonien forblev uafbrudt, var jobbet.</p>
<p><strong>Handling.</strong> Streamingnetværket og IP‑telefonien blev overvåget, fejlfundet og vedligeholdt døgnet rundt. Pointen med at holde konstant øje er, at streamingproblemer melder sig som forringelse, før de bliver til et decideret drop — en stream, der begynder at hakke, et link, der bliver ustabilt — og hvis man er opmærksom, kan man fange det ved hakket i stedet for ved den sorte skærm. Så en stor del af det var at være foran signalet frem for at reagere på klager over det.</p>
<p><strong>Resultat.</strong> Streamsene og opkaldene forblev pålidelige på tværs af platformen, med problemer opdaget og rettet, før de blev til en tjeneste, nogen bemærkede faldt ud. At holde et signal flydende mellem leverandører og slutkunder uden et synligt hul er stille, konstant arbejde, og stille er, hvad det bør være.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/planned-and-implemented-new-infrastructure-functionality-for-internal-85/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/planned-and-implemented-new-infrastructure-functionality-for-internal-85/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Planlagde og byggede infrastruktur til interne og eksterne systemer — robust nok til stadig at køre år efter med minimale ændringer.</description>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Løsningsarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Platformarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Platform- &amp; løsningsarkitektur</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> At planlægge og bygge infrastrukturfunktionalitet, der faktisk ville holde, var opgaven — ikke bare virke nu, men blive ved med at virke.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/as-one-of-the-first-hires-designed-and-86/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/as-one-of-the-first-hires-designed-and-86/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>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.</description>
      <category domain="https://platform.engineer.company/da/categories/">Cloud</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Løsningsarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Platformarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Cloud‑infrastruktur &amp; migrering</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Platform- &amp; løsningsarkitektur</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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å.</p>
<p><strong>Opgave.</strong> At bygge kerneinfrastrukturen og processerne omkring den, fra bunden, var jobbet.</p>
<p><strong>Handling.</strong> 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 &ldquo;få noget til at køre&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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har automatiseret teamsamarbejde, adgangskodehåndtering, opgave- og tidsstyring og bygget et semi‑automatisk projektvisningssystem, hvilket øgede teamets produktivitet.</title>
      <link>https://platform.engineer.company/da/portfolio/automated-team-collaboration-password-management-task-and-time-89/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/automated-team-collaboration-password-management-task-and-time-89/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Automatiserede samarbejde, adgangskode-, opgave- og tidsstyring og byggede et semi-automatisk projektvisningssystem — højere produktivitet.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Projektledelse</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Teknisk ledelse</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Projektledelse (Agile)</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> En stor del af teamets driftsarbejde — at koordinere, håndtere adgangskoder, tracke opgaver og tid — blev lavet i hånden, og manuel koordinering er en stille skat: det er aldrig det, man bemærker, men det æder støt timer, der kunne gå et bedre sted hen.</p>
<p><strong>Opgave.</strong> At automatisere det gentagne driftsarbejde var målet.</p>
<p><strong>Handling.</strong> De dele, der egnede sig til det, blev automatiseret — teamsamarbejde, adgangskodehåndtering, opgavestyring, tidsstyring — med et semi‑automatisk projektvisningssystem oveni. Idéen på tværs af det hele var at tage rutinekoordineringen af folks bord, så den kørte af sig selv, og lade dem bruge den genvundne opmærksomhed på arbejde, der faktisk krævede et menneske. Visningssystemet var det samme instinkt anvendt på noget mere synligt: at gøre det at præsentere arbejdet mest muligt automatisk frem for en manuel pligt hver gang.</p>
<p><strong>Resultat.</strong> Driftseffektiviteten steg, og teamet blev mere produktivt, fordi den rutinekoordinering, der før krævede konstant menneskelig opmærksomhed, nu i vid udstrækning kørte af sig selv. Den tid, der lækkede ud i pseudoarbejde, gik tilbage i det faktiske arbejde.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har integreret et virksomhedsdækkende adgangskodehåndteringssystem, der styrkede sikkerheden og strømlinede adgangskontrollen.</title>
      <link>https://platform.engineer.company/da/portfolio/integrated-a-company-wide-password-management-system-strengthening-90/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/integrated-a-company-wide-password-management-system-strengthening-90/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Integrerede et virksomhedsdækkende adgangskodehåndteringssystem — stærkere sikkerhed og strømlinet adgangskontrol i hele organisationen.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Adgangsoplysninger blev håndteret inkonsistent — forskellige folk lagrede og delte dem på forskellige, ad hoc‑måder — og den inkonsistens er i sig selv sikkerhedsrisikoen. Det er sjældent et dramatisk brud; det er en adgangskode i en chatbesked, et delt login, ingen roterer, den langsomme ophobning af små eksponeringer.</p>
<p><strong>Opgave.</strong> At centralisere oplysningerne og gøre dem sikre var opgaven.</p>
<p><strong>Handling.</strong> Et virksomhedsdækkende adgangskodehåndteringssystem gik ind, så der var én konsistent, sikker måde, oplysninger blev lagret og delt på, i stedet for hver enkelts personlige vane. Værdien af virksomhedsdækkende er præcis, at det ikke er valgfrit pr. person — en adgangskodehåndtering, kun halvdelen af teamet bruger, hjælper knap nok, for risikoen bor i den halvdel, der ikke gjorde. Så pointen var at gøre den sikre måde til standardmåden, overalt.</p>
<p><strong>Resultat.</strong> Sikkerheden blev bedre, og adgangskontrollen blev enklere og mere konsistent i hele organisationen. Når først oplysningerne alle bor ét administreret sted, holder et helt sæt små, kedelige eksponeringer bare op med at være mulige — hvilket er det meste af, hvad sikkerhed i den virkelige verden faktisk er.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/built-a-layered-automated-test-suite-across-four-layers-94/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/built-a-layered-automated-test-suite-across-four-layers-94/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>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.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Backend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Frontend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">PostgreSQL</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">Backend- &amp; API‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk ledelse &amp; rådgivning</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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 &ldquo;de vigtige dele er dækket&rdquo; bliver stille og roligt til &ldquo;de dele, der var nemme at dække, er dækket.&rdquo;</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> Fire lag fik fire slags test. Go‑API&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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har bygget kodebasens guard‑motor — 268 registrerede commit‑tjek, 277 lint‑regler og 15 egne ESLint‑regler — plus 146 tests af selve tjekkene, så det er builden, der holder standarden, ikke reviewet.</title>
      <link>https://platform.engineer.company/da/portfolio/built-the-repository-s-guard-engine-of-268-checks-95/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/built-the-repository-s-guard-engine-of-268-checks-95/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Byggede en guard-motor med 268 registrerede commit-tjek, 277 lint-regler og 15 egne ESLint-regler — plus 146 tests af selve tjekkene.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Teknisk ledelse</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk dokumentation</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk ledelse &amp; rådgivning</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Standarder, der er skrevet ned i en contributing‑guide, er forslag. Alle er enige i dem, og så er det fredag, ændringen er lille, og guiden taber. Zero‑warnings‑barren ville kun nogensinde holde, hvis noget andet end velvilje holdt den — og de lintere, der følger med hvert sprog, når slet ikke frem til de projektspecifikke regler, der faktisk betyder noget, dem om, hvordan netop dette kodebase er ment at virke.</p>
<p><strong>Opgave.</strong> De regler, projektet gik op i, skulle kunne eksekveres, så det at bryde en fik en commit til at fejle frem for at vente på en reviewer med tid og hukommelse nok til at fange det.</p>
<p><strong>Handling.</strong> Det, der voksede ud af det, er en guard‑motor. Der er 274 check‑scripts, 268 af dem registreret i commit‑hooks, ved siden af 277 JavaScript‑lintere og 96 shell- og 17 Python‑validatorer, der dækker de ting, hyldevareværktøj ikke har nogen mening om — at en migration kan rulles tilbage, at en oversættelsesnøgle findes i begge locales, at en registreret rute optræder i OpenAPI‑beskrivelsen, at ingen stille og roligt har tilføjet en inline‑suppression. Femten custom ESLint‑regler holder husets mønstre på plads i TypeScript. Én regel er værd at nævne for sig: enhver commit med præfikset fix: skal bære en test, der fejler uden den, så en fejl, der er rettet, bliver ved med at være rettet. Og fordi en ødelagt guard er værre end slet ingen guard — den lader alt passere, og ingen opdager det — har selve guard‑laget 146 test.</p>
<p><strong>Resultat.</strong> Review‑tiden flyttede fra mekanik til design, fordi de mekaniske indvendinger allerede var fremsat af en maskine, før branchen blev pushet. Trade‑off&rsquo;et er reelt og værd at sige højt: det er langsomt at committe, og en dårligt skrevet guard er oprigtigt irriterende at arbejde uden om. De 146 test findes, fordi netop det skete.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/built-the-payments-and-entitlements-layer-96/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/built-the-payments-and-entitlements-layer-96/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Byggede betalings- og rettighedslaget — Stripe med Apple og Google in-app purchase — directory, søgning og eksport spærret af en adgangsmodel.</description>
      <category domain="https://platform.engineer.company/da/categories/">API&#39;er &amp; integration</category>
      <category domain="https://platform.engineer.company/da/categories/">Backend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Databaser</category>
      <category domain="https://platform.engineer.company/da/categories/">PostgreSQL</category>
      <category domain="https://platform.engineer.company/da/categories/">Produkt &amp; krav</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Backend- &amp; API‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">Databasedesign &amp; datamodellering</category>
      <category domain="https://platform.engineer.company/da/services/">Produktstrategi &amp; kravspecifikation</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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?</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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å &ldquo;må denne konto det her?&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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/moved-slow-work-onto-a-river-job-queue-97/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/moved-slow-work-onto-a-river-job-queue-97/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Flyttede langsomt arbejde væk fra request-stien over på en River-jobkø: 15 worker-moduler, 8 planlagte opgaver og 20 pg_cron-vedligeholdelsesjobs.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Backend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Databaser</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Performanceoptimering</category>
      <category domain="https://platform.engineer.company/da/categories/">PostgreSQL</category>
      <category domain="https://platform.engineer.company/da/services/">Backend- &amp; API‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">Databasedesign &amp; datamodellering</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/built-first-party-error-monitoring-and-tracing-98/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/built-first-party-error-monitoring-and-tracing-98/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Byggede egen error monitoring og OpenTelemetry-tracing — sanitering, detektion af spikes, symbolication og et heartbeat — bag 11 operatørvisninger.</description>
      <category domain="https://platform.engineer.company/da/categories/">Backend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Monitorering &amp; observability</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Backend- &amp; API‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> Fejl og traces skulle samles, grupperes og gøres til noget, man kunne handle på, uden at platformens indre forlod platformen.</p>
<p><strong>Handling.</strong> 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&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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har holdt skemaet ærligt på tværs af 1.022 migrationer med en CI‑gate, der bygger databasen begge veje — en frisk installation og en installation plus hver eneste migration — og fejler, når de to ikke stemmer overens.</title>
      <link>https://platform.engineer.company/da/portfolio/kept-the-schema-honest-across-1022-migrations-99/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/kept-the-schema-honest-across-1022-migrations-99/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Holdt skemaet ærligt på tværs af 1.022 migrationer med en CI-gate, der bygger databasen begge veje og fejler, når de to ikke stemmer overens.</description>
      <category domain="https://platform.engineer.company/da/categories/">Data governance</category>
      <category domain="https://platform.engineer.company/da/categories/">Databaser</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Migrering &amp; modernisering</category>
      <category domain="https://platform.engineer.company/da/categories/">PostgreSQL</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">Databaseadministration (DBA)</category>
      <category domain="https://platform.engineer.company/da/services/">Databasemigrering &amp; modernisering</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Et skema er beskrevet to gange i de fleste projekter: én gang af den indledende opsætning, der bygger det fra bunden, og én gang af de ophobede migrationer, der har fået det til at vokse. Begge er ment at producere den samme database. Intet tjekker, at de gør det, så de driver fra hinanden — og afdriften er usynlig, indtil et friskt miljø opfører sig anderledes end produktion, som regel på det værst tænkelige tidspunkt.</p>
<p><strong>Opgave.</strong> De to beskrivelser skulle beviseligt være identiske, automatisk, frem for periodisk at blive troet at være det.</p>
<p><strong>Handling.</strong> Databasen er versioneret som 1.022 migrationer, nummereret fra 036 til 1102, og rækkefølgedisciplinen omkring dem er kedelig og ikke til forhandling. Det, der får den til at holde, er et CI‑job, der bygger databasen to gange ved hver ændring: én gang fra det friske initielle skema, én gang fra det initielle skema plus hver eneste migration afspillet i rækkefølge — og så sammenligner de to. Ikke bare strukturen, som er den nemme halvdel, men også de seedede data, for en migration, der backfiller en opslagstabel forkert, er præcis lige så skadelig som en, der glemmer en kolonne, og kun den ene af dem dukker op i en skema‑diff. Enhver uenighed får buildet til at fejle med forskellen printet ud.</p>
<p><strong>Resultat.</strong> Et friskt miljø og et langtlevende er den samme database, og det bliver tjekket frem for antaget. Omkostningen lander hos den, der skriver en migration: den skal virke afspillet, og den skal virke fra koldt, hvilket er mere tanke, end et hurtigt ALTER som regel får. Det er netop pointen — alternativet er at finde ud af det under en gendannelse, hvor svaret betyder noget, og der ikke er tid til at regne det ud.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/built-fail-closed-abuse-controls-and-rate-limiting-100/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/built-fail-closed-abuse-controls-and-rate-limiting-100/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Byggede fail-closed misbrugskontroller: 22 Redis-baserede rate limiters, Cloudflare Turnstile, idempotens på requests og en origin-lås ved indgangen.</description>
      <category domain="https://platform.engineer.company/da/categories/">API&#39;er &amp; integration</category>
      <category domain="https://platform.engineer.company/da/categories/">Backend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Netværk &amp; VPN</category>
      <category domain="https://platform.engineer.company/da/categories/">Performanceoptimering</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Backend- &amp; API‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/built-company-ownership-claims-end-to-end-103/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/built-company-ownership-claims-end-to-end-103/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Byggede ejerskabskrav på virksomheder fra ende til anden: en bruger gør krav, en administrator afgør, og godkendelsen omskriver autorisationsgrafen.</description>
      <category domain="https://platform.engineer.company/da/categories/">Backend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Frontend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Full stack‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Produkt &amp; krav</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Full stack‑produktudvikling</category>
      <category domain="https://platform.engineer.company/da/services/">Produktstrategi &amp; kravspecifikation</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> Der skulle være en vej fra &ldquo;det her er min virksomhed&rdquo; til reel myndighed over posten, med en menneskelig beslutning i midten og et spor bagefter.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har etableret et løbende sikkerhedsprogram — code scanning, DAST, afhængigheds- og sårbarhedstjek, SBOM‑generering, secret scanning og SHA‑pinnede actions — sammen med 21 skrevne sikkerhedsaudits.</title>
      <link>https://platform.engineer.company/da/portfolio/established-a-continuous-security-programme-104/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/established-a-continuous-security-programme-104/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Etablerede et løbende sikkerhedsprogram — code scanning, DAST, afhængighedstjek, SBOM, secret scanning og pinnede actions — plus 21 audits.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk dokumentation</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Sikkerhedsarbejdet inde i applikationen — Content‑Security‑Policy&rsquo;en, least‑privilege‑databaserollerne, gentjekket af rettigheder — beskytter platformen ved runtime. Intet af det siger noget om det, der bliver sendt afsted: om en dependency samlede en kendt sårbarhed op i tirsdags, om en adgangsoplysning blev committet og rullet tilbage, eller om en third‑party‑action pinnet til et tag stille og roligt er blevet til et andet stykke kode.</p>
<p><strong>Opgave.</strong> Supply chain- og kodesikkerhed skulle være løbende og automatiseret, så tilstanden af det var et build‑resultat frem for en holdning.</p>
<p><strong>Handling.</strong> Statisk analyse kører gennem CodeQL, dynamisk test mod en kørende instans gennem ZAP, og Go‑dependencies tjekkes med govulncheck. En SBOM genereres ved hvert build med Anchore og Syft, så det, der blev sendt afsted, er kendt frem for rekonstrueret bagefter. Gitleaks scanner historikken for adgangsoplysninger. Hver third‑party GitHub Action er pinnet til en commit‑hash frem for et tag, hvilket er den uglamourøse kontrol, der forhindrer, at et tag bliver flyttet under dig. Dependabot holder øje med 6 økosystemer. Ved siden af automatiseringen ligger 21 skrevne sikkerhedsaudits, heriblandt en threat model og en vurdering op mod OWASP‑testguiden — for scannere finder de klasser af problemer, nogen allerede har beskrevet, og en threat model er der, hvor dem, der er specifikke for netop denne platform, får et navn.</p>
<p><strong>Resultat.</strong> En sårbarhed, der bliver offentliggjort upstream, dukker op som et fejlende build frem for som en nyhed. Mængden af fund er den reelle omkostning — en scanner, der rapporterer alt, træner folk i at ignorere den, og at holde signalet brugbart kræver løbende triage frem for en engangsopsætning.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har bygget virksomhedens egen infrastruktur som 19 Ansible‑playbooks og 34 roller fordelt på 12.065 linjer YAML, der konvergerer en levende vært til en erklæret tilstand med hvert play idempotent.</title>
      <link>https://platform.engineer.company/da/portfolio/built-the-companys-infrastructure-as-code-108/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/built-the-companys-infrastructure-as-code-108/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Miljøet kan reproduceres fra repositoryet, og de dele af det, der kun nogensinde var sande fordi nogen huskede dem, er nu assertions der fejler en kørsel.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Platformarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Cloud‑infrastruktur &amp; migrering</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Engineer ApS driver sit eget miljø — en webtilstedeværelse, en git‑forge, en database, sikkerhedskopier, mailtransport og DNS — og der var ingen at overdrage driften til. Et enmandsfirma har de samme fejltilstande som et stort og ingen af redundansen, hvilket gør det sædvanlige svar, en person der husker hvordan værten blev sat op, til den mindst tilgængelige mulighed der findes.</p>
<p><strong>Opgave.</strong> Hele miljøet skulle beskrives i et repository frem for i et hoved, og beskrives i en form der konvergerer en rigtig vært frem for at dokumentere en.</p>
<p><strong>Handling.</strong> Det der voksede ud af det er 19 playbooks og 34 roller fordelt på 12.065 linjer YAML. Formen betyder mere end størrelsen. Sammensætning er data frem for flag: en vært ligger i en tier‑gruppe, hvis variabler erklærer hvilke roller den kører, så provisionering uden argumenter konvergerer hver vært til dens erklærede tilstand. Idempotens er en kontrakt frem for en ambition — en konvergeret vært rapporterer nul ændringer, og et play der ikke kan sige det, er ikke færdigt. Fire kommandonavnerum holder løfterne adskilt: en gate der ikke rører nogen vært, rapporter der læser en og aldrig ændrer den, provisionering der ændrer en vært så den matcher repositoryet, og verifikation der ændrer en vært med vilje og returnerer en dom.</p>
<p><strong>Resultat.</strong> Miljøet kan reproduceres fra repositoryet, og de dele af det, der kun nogensinde var sande fordi nogen huskede dem, er nu assertions der fejler en kørsel. Prisen er reel: hver ændring er langsommere at lave end at redigere en fil på serveren ville være, og en konvergering der halvt gennemføres er værre end en der nægter, hvilket er grunden til at et preflight‑play senere blev sat foran den. Den afvejning blev truffet bevidst, og den har holdt.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/ran-the-whole-company-on-one-512mb-host-109/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/ran-the-whole-company-on-one-512mb-host-109/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>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.</description>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Løsningsarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Performanceoptimering</category>
      <category domain="https://platform.engineer.company/da/categories/">Platformarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Cloud‑infrastruktur &amp; migrering</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Platform- &amp; løsningsarkitektur</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har fundet og lukket tre SSH‑beskyttelser mod brute force, der aldrig havde virket: et bandlysningsfængsel, der holdt øje med port 22, mens dæmonen lyttede på 1986, en ratebegrænsning skygget af en bredere regel over den, og en bandlysningshandling, hvis binærfil aldrig blev fundet, så ingen bandlysning nogensinde var trådt i kraft.</title>
      <link>https://platform.engineer.company/da/portfolio/found-three-ssh-brute-force-protections-that-never-worked-110/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/found-three-ssh-brute-force-protections-that-never-worked-110/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Tre beskyttelser, der aldrig én eneste gang havde udløst, gør det nu, og den fejlklasse de tilhører — en kontrol hvis fejltilstand er, at den bliver ved med at…</description>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Monitorering &amp; observability</category>
      <category domain="https://platform.engineer.company/da/categories/">Netværk &amp; VPN</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Netværk &amp; VPN‑opsætning</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> En hærdningsgennemgang af produktionsværten i august 2026 stillede et spørgsmål, der normalt får et selvsikkert svar: virker SSH‑beskyttelserne mod brute force. Alle tre var konfigureret, alle tre optrådte i hver rapport nogen kiggede i, og alle tre havde været uvirksomme siden den dag værten blev bygget.</p>
<p><strong>Opgave.</strong> Kontrollerne skulle efterprøves mod hvad kernen rent faktisk gør ved en pakke, frem for mod de konfigurationsfiler der beskriver hvad der burde ske med en.</p>
<p><strong>Handling.</strong> At læse konfigurationen ville have bekræftet det forkerte svar tre gange, så gennemgangen læste det kørende system i stedet. Blokeringsfængslet holdt øje med port 22, mens dæmonen var flyttet til 1986 under den indledende hærdning — hver blokering den skrev navngav en port, som intet lyttede på. Firewallens hastighedsbegrænsning var værre på en mere subtil måde: reglen fandtes, og den lå under en bredere regel, der matchede først. Firewallens brugerregler evalueres oppefra og ned, og det første match vinder, så en bred tilladelse over en hastighedsbegrænsning gør begrænsningen til død kode, der stadig står i hver statusoversigt. Den tredje var den mest tavse af dem: blokeringshandlingen kalder ud til et pakkefilterprogram, som pakkesystemet kun anbefaler frem for kræver, så på en vært uden det starter fængslet, tæller og beslutter, og fejler så i det ene øjeblik det forsøger at blokere. Alle tre rettelser var små. Det der kom ud af det var ikke rettelsen, men to regler der nu styrer repositoryet: en sikkerhedskontrol får en assertion frem for en kommentar, og en firewall verificeres på regelplacering frem for på regelforekomst.</p>
<p><strong>Resultat.</strong> Tre beskyttelser, der aldrig én eneste gang havde udløst, gør det nu, og den fejlklasse de tilhører — en kontrol hvis fejltilstand er, at den bliver ved med at rapportere sundt — er den klasse platformens tjek nu er bygget til at fange. Alle tre havde været uvirksomme fra bootstrap. Alle tre stod som sunde alle de steder nogen kiggede, hvilket er hele grunden til at de varede ved.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har hærdet SSH til 24 hævdede direktiver med validering i tre trin — kandidatfilen, den samlede konfiguration og dernæst dæmonens egen tilbagelæsning — efter at tilbagelæsningen fangede den kørende server i stilhed at tilsidesætte to af de fireogtyve.</title>
      <link>https://platform.engineer.company/da/portfolio/hardened-ssh-with-three-stage-validation-111/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/hardened-ssh-with-three-stage-validation-111/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>SSH-positionen er nu dæmonens svar frem for repositoryets påstand, og forskellen er ikke teoretisk — den var allerede to indstillinger bred, da tjekket blev…</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> SSH er den eneste interaktive vej ind på virksomhedens vært, og dens konfiguration skrives af en automatiseringsrolle, der havde kørt rent i måneder. En adgangsrapport i september 2026 læste dæmonens egne resolverede indstillinger og fandt to af dem i uoverensstemmelse med det, rollen havde skrevet ved hver eneste konvergering.</p>
<p><strong>Opgave.</strong> Hærdningen skulle blive noget dæmonen bekræfter frem for noget repositoryet påstår, for afstanden mellem de to havde allerede stået åben i måneder, uden at nogen bemærkede det.</p>
<p><strong>Handling.</strong> Årsagen var konfigurationsrækkefølge. Styresystemet leverer sine egne standarder ukommenterede, over det sted hvor en drop‑in‑fil lander, og for de to omtalte indstillinger vinder den første forekomst. Rettelsen var et filnavnspræfiks, der sorterer foran leverandørens, hvilket er en ændring på ét tegn og præcis den slags, der forbliver i stykker, fordi ingen tænker på at kigge efter. Det der blev bygget omkring den betyder mere: tre valideringstrin ved hver konvergering. Kandidatfilen syntakstjekkes før den installeres, så en ugyldig konfiguration aldrig når værten. Den samlede konfiguration tjekkes efter installationen. Derefter læses dæmonens eget resolverede output tilbage, og 24 direktiver efterprøves mod det, så en indstilling der er skrevet men overskrevet fejler kørslen. To direktiver blev bevidst udeladt, begge fordi dæmonen ikke længere implementerer dem, og at skrive dem ville kun se grundigt ud.</p>
<p><strong>Resultat.</strong> SSH‑positionen er nu dæmonens svar frem for repositoryets påstand, og forskellen er ikke teoretisk — den var allerede to indstillinger bred, da tjekket blev skrevet. En konvergering der ikke kan se om en kontrol tog effekt, har ikke verificeret den, og at søge efter et direktiv beviser kun at det blev skrevet.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har bevist hele bandlysningsstien ved hver hærdningskørsel ved at bandlyse en reserveret testadresse, læse den resulterende kerneregel og ophæve bandlysningen i en garanteret oprydningsblok, så et fængsel, der holder op med at virke, får kørslen til at fejle i stedet for at melde sig rask.</title>
      <link>https://platform.engineer.company/da/portfolio/proved-the-intrusion-banning-path-on-every-converge-112/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/proved-the-intrusion-banning-path-on-every-converge-112/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>En blokeringsvej der holder op med at virke, fejler nu en konvergering i stedet for at blive ved med at rapportere sundt, hvilket var den eneste egenskab der…</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Indtrængningsblokeringstjenesten var allerede blevet grebet i at blokere en port, som SSH‑dæmonen ikke lyttede på. At rette porten lukkede det tilfælde. Det gjorde intet ved grunden til at fejlen overlevede så længe, nemlig at en blokeringsvej ikke har nogen synlig fejl: tjenesten kører, fængslet står som aktivt, og intet noget sted siger, om en blokering nogensinde når kernen.</p>
<p><strong>Opgave.</strong> Blokeringsvejen skulle afprøves ved hver konvergering, mod det levende regelsæt, frem for udledes af at tjenesten var oppe.</p>
<p><strong>Handling.</strong> Konvergeringen blokerer nu en adresse fra den blok, standarderne reserverer til dokumentation, læser den resulterende regel tilbage i kernens pakkefilter og ophæver blokeringen i en oprydningsblok, der kører uanset om tjekket bestod eller fejlede. Det reserverede område er det bærende valg — testadressen tilhører ingen, så en efterladt blokering, der overlever en fejlet kørsel, ikke kan lukke et rigtigt netværk ude. Tilbagelæsningen fra kernen er den anden halvdel: tjenestens egen statusudskrift ville rapportere succes for en blokering, der ikke frembragte nogen regel, hvilket er præcis den fejl der testes for. Ved siden af den er blokeringsbackenden fastlåst frem for overladt til tjenestens egen detektion, og logbackenden er sat til detektion, fordi styresystemet ikke leverer nogen traditionel autentificeringslog, og det forkerte valg fejler tavst ved at holde øje med en fil, der aldrig dukker op.</p>
<p><strong>Resultat.</strong> En blokeringsvej der holder op med at virke, fejler nu en konvergering i stedet for at blive ved med at rapportere sundt, hvilket var den eneste egenskab der betød noget. Det koster nogle få sekunder ved hver kørsel, og det skriver og trækker en firewallregel tilbage mod produktion hver gang, hvilket er et reelt indgreb i et levende system og blev accepteret på den baggrund, at alternativet allerede var påvist at være værre.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har verificeret firewallregler efter position frem for tilstedeværelse ved at læse den nummererede regelliste og den levende pakkefilterkæde, for en regel, der findes, er ikke en regel, nogen pakke når frem til.</title>
      <link>https://platform.engineer.company/da/portfolio/verified-firewall-rules-by-position-113/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/verified-firewall-rules-by-position-113/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Firewallpositionen tjekkes nu på den måde en pakke oplever den. Det mest nyttige udfald var ikke tjekket, men hvad det afslørede om den rapportering der gik…</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Netværk &amp; VPN</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">Netværk &amp; VPN‑opsætning</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> En firewallstatusoversigt viser et sæt regler. Et pakkefilter evaluerer en ordnet liste og standser ved det første match. Det er forskellige ting, og forskellen er usynlig i hvert eneste værktøj der udskriver et sammendrag — hvilket er sådan værten kørte et år med en hastighedsbegrænsning, som ingen pakke nogensinde nåede, liggende under en bredere regel der matchede først.</p>
<p><strong>Opgave.</strong> Firewallverifikation skulle læse placering frem for medlemskab, for forekomst var allerede påvist ikke at bevise noget.</p>
<p><strong>Handling.</strong> Tjekkene læser nu den nummererede regeloversigt og den levende filterkæde og efterprøver mod rækkefølge. Der findes præcis én regel per port og altid med en protokol, for en regel uden en udvider tavst overfladen. SSH‑porten bærer en hastighedsbegrænsning og aldrig en tilladelse ved siden af, eftersom en tilladelse over en begrænsning er præcis den overskygning der blev fundet. Den erklærede offentlige overflade er en kort liste på fem porte, efterprøvet som en helhed frem for tjekket enkeltvis, så en port der dukker op uden at være erklæret, fejler frem for at blive bemærket. Sikkerhedsrapporten gengiver reglerne i matchrækkefølge med en advarsel øverst i afsnittet om hvordan den læses, for den næste der åbner den fil, vil ellers læse et sæt.</p>
<p><strong>Resultat.</strong> Firewallpositionen tjekkes nu på den måde en pakke oplever den. Det mest nyttige udfald var ikke tjekket, men hvad det afslørede om den rapportering der gik forud: hvert eneste involveret værktøj havde udskrevet hastighedsbegrænsningen i et år, korrekt, og ingen af dem var blevet stillet det ene spørgsmål der betød noget.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har bygget krypteret backup uden for værten på restic med opbevaringsbeskæring, et integritetstjek og en månedlig automatiseret gendannelsesøvelse, og har derefter auditeret gendannelsespositionen og skrevet hullerne ned frem for at lade dem blive fundet under en hændelse.</title>
      <link>https://platform.engineer.company/da/portfolio/built-encrypted-backups-with-a-monthly-restore-drill-114/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/built-encrypted-backups-with-a-monthly-restore-drill-114/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Virksomheden kan miste værten og få sine data tilbage, og den sætning hviler på en gendannelse der kørte sidste måned frem for på en sikkerhedskopi der kørte i…</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Backup &amp; disaster recovery</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Alt hvad virksomheden rummer — git‑repositorierne, databasen, sitet — lå på én cloud‑instans, hvis udbyder‑snapshot var hele gendannelsespositionen. Et udbyder‑snapshot er en fin ting at have og en dårlig ting at læne sig på: det ligger i den samme konto som den maskine det beskytter, det er ikke krypteret af nogen her, og ingen havde nogensinde gendannet fra et.</p>
<p><strong>Opgave.</strong> Sikkerhedskopier skulle være krypterede, uden for værten, beskåret efter en opbevaringspolitik, og — den del der som regel springes over — faktisk gendannet fra, efter en plan, uden at en person skulle huske at gøre det.</p>
<p><strong>Handling.</strong> Sikkerhedskopieringen kører på en systemd‑timer: et databasedump hvor et sådant findes, derefter et krypteret dedupliceret snapshot til lager hos en anden udbyder over SFTP, derefter en beskæring efter opbevaringspolitik, derefter et integritetstjek. En dead man&rsquo;s switch pinges kun ved succes, hvilket er den skelnen der gør den til en alarm frem for en log — en kørsel der fejler siger intet, og at sige intet er det der udløser alarmen. Særskilt kører en gendannelsesøvelse månedligt: den trækker en kendt fil ud af repositoryet og sammenligner den, så det der tjekkes er en gendannelse frem for en sikkerhedskopi. Adgangssætningen skrives til en fil, som unitsene læser, frem for at blive sendt gennem miljøet, for supervisoren behandler undvigetegn i miljøværdier, og en adgangssætning med en omvendt skråstreg ville tavst have været en anden end den, der skabte repositoryet. Bagefter blev gendannelsespositionen auditeret og skrevet op, og de tilbageværende huller blev navngivet i dokumentet frem for efterladt til at blive opdaget under en hændelse.</p>
<p><strong>Resultat.</strong> Virksomheden kan miste værten og få sine data tilbage, og den sætning hviler på en gendannelse der kørte sidste måned frem for på en sikkerhedskopi der kørte i nat. Auditens mest værdifulde output var listen over ting der stadig ikke er dækket, hvilket er den del en grøn sikkerhedskopirapport strukturelt er ude af stand til at fortælle nogen.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har bygget dødmandsknap‑monitorering, der kun pinger, mens hukommelse og disk er sunde, så en svækket vært udløser en alarm ved at gå tavs — og fangede seks variabelnavne, der sagde &#34;free&#34;, hvor tjekket korrekt målte &#34;available&#34;, en størrelsesorden fra hinanden på en boks med 464 MB.</title>
      <link>https://platform.engineer.company/da/portfolio/built-dead-mans-switch-monitoring-115/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/built-dead-mans-switch-monitoring-115/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Værten har nu en alarm, hvis fejltilstand er at udløse, og den navngivning der ville have ødelagt den, er rettet.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Monitorering &amp; observability</category>
      <category domain="https://platform.engineer.company/da/categories/">Performanceoptimering</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> En vært på 464 MB der kører en forge, en database og en webserver har to realistiske måder at dø på: den løber tør for hukommelse, eller den løber tør for diskplads. Ingen af dem melder sig selv. Begge er fuldt forudsigelige nogle timer i forvejen, hvis noget kigger, og intet kiggede.</p>
<p><strong>Opgave.</strong> Værten havde brug for en alarm der virker, når værten ikke gør — hvilket udelukker alt der skal sende en besked i selve fejløjeblikket.</p>
<p><strong>Handling.</strong> Svaret er en dead man&rsquo;s switch på en timer. Hvert kvarter med jitter måler et lille script tilgængelig hukommelse og fri diskplads og pinger kun en ekstern tjeneste, hvis begge ligger over deres tærskler. Tavshed er alarmen. En maskine der er løbet tør for hukommelse, har mistet sit netværk eller er holdt op med at starte, frembringer præcis det samme signal som en der er usund, hvilket er den rigtige opførsel og grunden til at denne form blev valgt frem for en agent der rapporterer en status. Målingen er tilgængelig hukommelse, ikke fri hukommelse, og den skelnen blev til den mest lærerige del af arbejdet: scriptet havde læst den rigtige kolonne hele tiden, mens seks variabelnavne omkring det sagde &ldquo;fri&rdquo;. På en sund Linux‑maskine er fri hukommelse tæt på nul, fordi kernen bruger ledig hukommelse til cache, så en læser der holdt de navne op mod en tærskel på ti procent, ville se tolv megabyte fri på en maskine med 464 MB, konkludere at tjekket var i stykker, og rette det med en ændring på ét tegn, der forvandler en fungerende alarm til en der bryder permanent og bliver slået fra inden for en uge.</p>
<p><strong>Resultat.</strong> Værten har nu en alarm, hvis fejltilstand er at udløse, og den navngivning der ville have ødelagt den, er rettet. Switchens reelle begrænsning står i dens egen dokumentation: den beviser at maskinen er sund, ikke at sitet leverer, og det er forskellige spørgsmål.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har fået check mode til at sige sandheden på hele platformen efter at have fundet seks sonder, der traf beslutning på en værdi, værten aldrig gav, fordi Ansibles command‑modul melder succes under --check, mens det springer kommandoen helt over.</title>
      <link>https://platform.engineer.company/da/portfolio/made-ansible-check-mode-tell-the-truth-116/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/made-ansible-check-mode-tell-the-truth-116/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>En prøvekørsel måler nu enten noget eller siger at den ikke gjorde, og ingen af de to er den tredje mulighed den plejede at have.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> En prøvekørsel mod produktion er ment som den sikre måde at finde ud af, hvad en ændring vil gøre. I september 2026 fejlede en prøvekørsel på en assertion, der ganske enkelt tog fejl om værten, og rådede operatøren til at sætte et flag, der ville have lempet en sikkerhedssandkasse. Prøvekørslen havde ikke læst værten. Den havde læst en værdi, værten aldrig gav, og draget en konklusion af den.</p>
<p><strong>Opgave.</strong> Hver sonde, hvis resultat fodrer en beslutning, skulle gøres ærlig under check‑tilstand, og de der ikke kunne, skulle sige det højt frem for at forblive tavse.</p>
<p><strong>Handling.</strong> Årsagen er en egenskab ved værktøjet, som er dokumenteret og let at glemme: kommandomodulet udføres ikke under check‑tilstand, og det den registrerer er ikke et tomt resultat — det er en succes med tomt output. Enhver betingelse der læser den registrering, beslutter derfor på en værdi der aldrig blev målt, og den beslutter i den retning dens egen logik tilfældigvis peger. En gennemgang af hver registreret sonde fandt seks af dem, hver med sin egen løgn: en rapporterede at supervisoren accepterer hvert unit‑direktiv uden at have spurgt supervisoren, en anden rapporterede intet at gøre på en vært med firewallen slået fra. Hver af dem fik en af to former. En sonde der læser eksisterende tilstand, som kørslen ikke har rørt, markeres til at køre også under check‑tilstand. En sonde der ikke kan køre, springes over, og en besked navngiver hvad der specifikt ikke blev verificeret — for tavshed i en kørselslog læses præcis som en bestået.</p>
<p><strong>Resultat.</strong> En prøvekørsel måler nu enten noget eller siger at den ikke gjorde, og ingen af de to er den tredje mulighed den plejede at have. Den generelle regel kom i udviklingsvejledningen i samme ændring: check‑tilstand må ikke lyve, og en sonde der ikke kan se, er forpligtet til at melde sin blindhed frem for at udlede en dom af den.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har tilføjet et preflight‑play, der kører den samme kode som konvergensen mod operatørens lokale hemmeligheder på omkring et sekund, efter at en halvt anvendt produktionskørsel døde på sin niende opgave med swap‑indstillingerne allerede skrevet til den levende vært.</title>
      <link>https://platform.engineer.company/da/portfolio/added-a-preflight-play-for-secrets-117/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/added-a-preflight-play-for-secrets-117/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>En hemmelighed der ikke resolverer, koster nu en to-sekunders afvisning på en bærbar i stedet for en delvist gennemført ændring på en levende server.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Driftshemmeligheder var lige blevet delt op, så hver vært bærer sit eget sikkerhedskopi‑repository, sin egen adgangssætning og sin egen alarmswitch. Repository‑koden var korrekt. Operatørens krypterede boks holdt stadig den tidligere enkeltværtsværdi, og intet kunne se uoverensstemmelsen, for boksen er bevidst lokal for operatørens maskine og usynlig for repositoryets egen kvalitetsgate.</p>
<p><strong>Opgave.</strong> Den fejlklasse havde brug for et sted at fejle billigt, for den havde lige fejlet dyrt.</p>
<p><strong>Handling.</strong> Den første konvergering efter ændringen forbandt til den levende vært, kørte otte opgaver og nægtede på den niende — korrekt, men inde fra en kørsel der allerede havde skrevet swap‑indstillinger til produktion. En halvt gennemført konvergering er et værre svar end en afvisning, så et preflight‑play blev skrevet: det når slet ingen vært, kører lokalt, indsamler ingen facts og udfører de samme to opgavefiler, som den rigtige konvergering bruger, mod operatørens boks. Det svarer på omkring et sekund, og provisionering kører det først. Den bærende beslutning er, at det er den samme kode frem for en anden implementering af den samme regel, for et tjek der gentager en regel på et andet sprog, ender med at være uenig med den, og at være uenig tavst. At skrive det bragte en fælde frem, som det næsten selv skabte: facts sat under et play overlever det play, så at kæde preflight og konvergering sammen i én kørsel ville have givet den rigtige rolle en adgangssætning, som preflight allerede havde resolveret, og bestået tjekket på en boks der stadig var forkert. Det blev reproduceret før det blev afværget, i begge opgavefiler.</p>
<p><strong>Resultat.</strong> En hemmelighed der ikke resolverer, koster nu en to‑sekunders afvisning på en bærbar i stedet for en delvist gennemført ændring på en levende server. Preflight er bevidst ikke mærket til altid at køre og bevidst ikke serialiseret, og begge dele er noteret som beslutninger frem for standarder.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har afstemt en DNS‑zone med 20 poster deklarativt mod Cloudflares API med separate indgange til audit og BIND‑eksport, og har slået CDN‑proxyen fra igen af hensyn til privatlivet efter at have bygget den.</title>
      <link>https://platform.engineer.company/da/portfolio/reconciled-a-dns-zone-declaratively-118/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/reconciled-a-dns-zone-declaratively-118/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Zonen er versioneret, sammenlignelig og eksporterbar, og den ene beslutning der gik imod den oplagte standard, er skrevet ned med sin begrundelse, så ingen…</description>
      <category domain="https://platform.engineer.company/da/categories/">API&#39;er &amp; integration</category>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Netværk &amp; VPN</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Netværk &amp; VPN‑opsætning</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Virksomhedens DNS bar omkring tyve poster fordelt på en webtilstedeværelse, et git‑underdomæne, to personlige omdirigeringer, mailrouting gennem en hosted postkasseudbyder, et transaktionsafsendelsesdomæne og autentificeringsposterne for begge. Det hele lå i en udbyders webkonsol, hvilket betyder at den aktuelle tilstand var, hvad den sidste person der klikkede havde efterladt.</p>
<p><strong>Opgave.</strong> Zonen skulle blive til en erklæring i repositoryet, med en måde at sammenligne den erklæring med det, udbyderen faktisk leverer.</p>
<p><strong>Handling.</strong> Zonen er skrevet som data — levende poster, applikationsposter, transportpolitikposter og en særskilt liste over poster der afventer fjernelse, hvilket er den ærlige måde at registrere en sletning der endnu ikke er sket. Ét play afstemmer den mod udbyderens API. To yderligere indgange ligger bag eksplicitte tilvalgsmærker: en audit der rapporterer forskellen uden at ændre noget, og en eksport der skriver zonen ud i det standardiserede zonefilformat, så den kan læses af noget der ikke er dette repository. Den mest interessante beslutning var en tilbagerulning. At sende de to webflader gennem udbyderens indholdsnetværk blev bygget, virkede, og blev derefter slået fra igen — for det koster den ene sætning, virksomhedens privatlivsside handler om. Med en proxy foran håndterer en anden virksomhed hver besøgendes adresse og hver URL de beder om, før vi gør, under deres politik frem for vores. For en forretning hvis kendetegnende påstand er, at ingen kigger med, er det en dårligere handel end de angreb den forsvarer imod.</p>
<p><strong>Resultat.</strong> Zonen er versioneret, sammenlignelig og eksporterbar, og den ene beslutning der gik imod den oplagte standard, er skrevet ned med sin begrundelse, så ingen genoptager sagen ved et uheld. Auditvejen er den del der bruges mest, for at kende forskellen er oftere det man vil have end at lukke den.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har skåret systemd‑sandkassens eksponering ned på hver eneste unit, platformen selv installerer — en dødmandsknap‑tjeneste fra 9,6 UNSAFE til 1,5, en internetvendt git‑forge fra 8,3 EXPOSED til 1,5 — og har tilføjet et parsertjek ved konvergens efter at have fundet et stavefejlsbehæftet direktiv ignoreret i stilhed i tre unit‑skabeloner.</title>
      <link>https://platform.engineer.company/da/portfolio/cut-systemd-sandbox-exposure-across-every-unit-119/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/cut-systemd-sandbox-exposure-across-every-unit-119/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Hver unit kører med de privilegier den har brug for og ikke dem den ikke har, tallene er målte frem for påståede, og den fejlklasse hvor en tastefejl bliver…</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Containere (Docker/Kubernetes)</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">Containerisering &amp; orkestrering</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Tretten unit‑filer blev installeret af dette repository og kører på produktionsværten med de privilegier, supervisoren giver som standard, hvilket er de fleste af dem. En hærdningsscore satte dead man&rsquo;s switch‑tjenesten til 9,6 og kaldte den usikker; den internetvendte git‑forge scorede 8,3 og eksponeret. Begge tal var korrekte, og ingen af dem havde foranlediget noget, for en score uden en tærskel knyttet til sig er et tal, folk lærer at springe over.</p>
<p><strong>Opgave.</strong> Hver unit havde brug for en sandkasse proportional med hvad den faktisk gør, og sandkasserne havde brug for et tjek, for fejltilstanden ved en forkert sandkasse er, at unitten starter og så går i stykker et sted, parseren ikke kan se.</p>
<p><strong>Handling.</strong> Privilegiebegrænsninger kom ind i hver unit‑skabelon — et privilegieloft fastlåst ved unittens eget, et systemkaldsfilter, begrænsede adressefamilier og hukommelse der er skrivbar eller eksekverbar, men aldrig begge dele. De målte resultater: dead man&rsquo;s switch gik fra 9,6 til 1,5, forgen fra 8,3 til 1,5, og begge sikkerhedskopi‑units fra 9,6 til 2,3 og 2,5. At skrive dem bragte noget bedre frem end scorerne. Ét direktiv havde været stavet forkert i tre unit‑skabeloner, så længe de roller havde eksisteret — et plausibelt udseende navn der ikke findes, hvilket supervisoren svarer på ved at logge at den ikke genkender nøglen og starte unitten alligevel. At søge efter et direktiv beviser at det blev skrevet; kun parseren beviser at det tog effekt. Så en verifikationsrolle kører nu hver unit gennem supervisorens egen verifikator under konvergeringen og inkluderes af hver rolle der installerer en unit. Hvad det stadig ikke kan se, står klart i de samme dokumenter: hvert direktiv der kan ødelægge disse units, ødelægger dem ved kørsel, ikke ved parsning, og en score kan ikke sige om et script stadig når sin sidste linje.</p>
<p><strong>Resultat.</strong> Hver unit kører med de privilegier den har brug for og ikke dem den ikke har, tallene er målte frem for påståede, og den fejlklasse hvor en tastefejl bliver til en tavst fraværende kontrol, fejler nu en kørsel. Målingens grænser er noteret ved siden af den, hvilket er den del der holder den næste læser fra at overfortolke et grønt bånd.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har bygget syv skrivebeskyttede rapporteringsroller, der gengiver en levende vært som Markdown — fakta, adgang, git, metrikker, trafik, sikkerhed og udbyderinventar — under en regel om, at intet tal printes, som kørslen ikke har målt.</title>
      <link>https://platform.engineer.company/da/portfolio/built-seven-read-only-host-reporting-roles-120/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/built-seven-read-only-host-reporting-roles-120/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Miljøet kan beskrives fra repositoryet på forlangende, og rapporterne har fundet virkelige ting: de to døde sikkerhedskontroller, en uerklæret lyttende port,…</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Monitorering &amp; observability</category>
      <category domain="https://platform.engineer.company/da/categories/">Stakeholder &amp; rapportering</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk dokumentation</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Værten havde intet dashboard og fik ikke et, for en metrikstak passer ikke på 464 MB og ville ikke have været sin pris værd, hvis den gjorde. Det efterlod et ærligt hul: der var ingen måde at besvare spørgsmål som hvem har adgang, hvor meget er dette repository vokset, hvordan ser trafikken ud, eller er hærdningen faktisk håndhævet.</p>
<p><strong>Opgave.</strong> De spørgsmål havde brug for svar, der kunne frembringes på forlangende, ikke kostede værten noget mens ingen spurgte, og aldrig kunne ændre det de beskrev.</p>
<p><strong>Handling.</strong> Syv skrivebeskyttede roller, hver der gengiver en levende vært til Markdown i repositoryet. Et faktabillede der dækker styresystem, hardware, lagring, netværk, tjenester, pakker, lyttende sockets og processorudnyttelse beregnet ud fra to stikprøver af kernens egen tæller. En adgangsrapport der dækker konti, sudo‑omfang, nøglefingeraftryk, forge‑brugere og databaseroller. En git‑rapport per repository. En metrikrapport over dagens indsamlede stikprøver. En trafikrapport bygget på webserverens privatlivsmaskerede log. En udbyderoversigt på tværs af fire udbyderflader — DNS, to cloud‑API&rsquo;er og et API til dedikerede servere. Og en sikkerhedsrapport der besvarer, om hærdningen er håndhævet frem for konfigureret, og udskriver firewallreglerne i matchrækkefølge og det levende blokeringsregelsæt. Den styrende regel på tværs af alle syv er, at intet tal udskrives, som kørslen ikke målte — en rapport der fylder et hul med et plausibelt tal, er værre end en der lader det stå tomt, for det er kun det plausible der bliver troet.</p>
<p><strong>Resultat.</strong> Miljøet kan beskrives fra repositoryet på forlangende, og rapporterne har fundet virkelige ting: de to døde sikkerhedskontroller, en uerklæret lyttende port, og den iagttagelse at trafikarkivet kun er så gammelt som sidste gang nogen huskede at høste det. Den sidste er skrevet op som en begrænsning med en konkret pris noteret — seksten dages historik for ét site, der roterede væk mellem høstninger og ikke findes nogen steder.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/deployed-the-companys-own-git-forge-121/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/deployed-the-companys-own-git-forge-121/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>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…</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/categories/">Webudvikling</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <category domain="https://platform.engineer.company/da/services/">Webstedsudvikling &amp; CMS</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har udrullet et containerplan på Podman og Quadlet under systemd frem for Docker, fordi Docker publicerer containerporte over værtens egne firewallregler — og har givet deploys en uprivilegeret bruger med én fast kommando i stedet for root.</title>
      <link>https://platform.engineer.company/da/portfolio/deployed-a-container-plane-on-podman-and-quadlet-122/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/deployed-a-container-plane-on-podman-and-quadlet-122/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Containere kører under den supervisor, der allerede var betroet, bag den firewall der allerede var erklæret, og en rutinemæssig release kræver ingen…</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Containere (Docker/Kubernetes)</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Cloud‑infrastruktur &amp; migrering</category>
      <category domain="https://platform.engineer.company/da/services/">Containerisering &amp; orkestrering</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Platformen havde brug for et sted at køre applikationscontainere. Det oplagte valg var branchestandarden, og det oplagte valg var forkert for denne vært på en bestemt måde: den omskriver kernens pakkefilterregler og publicerer containerporte over de firewallregler, hærdningsrollen installerer, så en container tavst bliver tilgængelig fra internettet uanset hvad firewallen fik at vide.</p>
<p><strong>Opgave.</strong> Der skulle vælges et containerplan, som ikke går uden om firewallen, ikke tilføjer endnu en supervisor ved siden af den, der allerede var betroet, og ikke kræver at en person er root for at sende en release ud.</p>
<p><strong>Handling.</strong> Planet er en dæmonløs containermotor, der driver units genereret af styresystemets egen supervisor. Der er ingen anden proceshåndtering: containere er tjenester, de starter som tjenester starter, og de beskrives i den samme deklarative form som alt andet. Containerne bruger værtens netværk uden nogen publicerede porte overhovedet, hvilket fjerner spørgsmålet om firewall‑omgåelse frem for at afbøde det. Units kører på systemniveau frem for rootless, og det er noteret som en afvejning — det holder automatiseringen enkel og normal, på bekostning af den strengere isolation rootless ville give, og noten siger hvilken vej man skal gå, hvis containerudbrud nogensinde kommer til at betyde mere end enkel automatisering. Udrulning blev adskilt fra provisionering: root sætter udrulningsstien op én gang, og derefter genudruller en uprivilegeret bruger ved at køre ét fast script gennem en afgrænset regel, der tillader den kommando og ingen argumenter. Byg imaget, genstart tjenesten. Ingen root‑shell, ingen vilkårlige kommandoer.</p>
<p><strong>Resultat.</strong> Containere kører under den supervisor, der allerede var betroet, bag den firewall der allerede var erklæret, og en rutinemæssig release kræver ingen privilegeret adgang. Valget mod standarden er skrevet ned med sin begrundelse, hvilket betyder mere end valget — den næste person vil få at vide, at man skal bruge standarden, af hver eneste artikel de læser.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har automatiseret provisioneringen af en anden server hos en anden cloududbyder og oprettet firewallen før maskinen, så den fødes bag en, med begge udbyderes firewalls skrevet direkte mod deres REST‑API&#39;er for at undgå en tredjepartssamling.</title>
      <link>https://platform.engineer.company/da/portfolio/provisioned-a-second-server-from-code-123/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/provisioned-a-second-server-from-code-123/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>En anden vært kan oprettes, eller genadopteres, fra repositoryet, bag en firewall der allerede findes, til en pris filen oplyser.</description>
      <category domain="https://platform.engineer.company/da/categories/">API&#39;er &amp; integration</category>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Cloud</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Cloud‑infrastruktur &amp; migrering</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Netværk &amp; VPN‑opsætning</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Der var brug for endnu en maskine til et applikationslag, hos en anden udbyder end den første, og den første maskines egen historie var argumentet for hvordan: den var blevet oprettet i hånden, og dens firewall var blevet tilføjet bagefter, hvilket efterlader et vindue, hvor en frisk vært med en standardadgangskodepolitik er tilgængelig fra internettet.</p>
<p><strong>Opgave.</strong> Maskinen skulle oprettes fra repositoryet, og den skulle fødes bag sin firewall frem for at få en kort tid efter.</p>
<p><strong>Handling.</strong> Rækkefølgen bar designet. Firewall‑playet kører før server‑playet, så regelsættet findes, før der er noget for det at beskytte; hos den anden udbyder kører tagging før cloud‑firewallen, fordi en firewall der retter sig mod tags har brug for, at taggene findes først. Begge udbyderes firewalls skrives direkte mod deres REST‑API&rsquo;er gennem en generisk HTTP‑opgave frem for gennem en leverandørsamling, hvilket fjerner en afhængighed og dens versionsdrift på bekostning af at skrive forespørgselsformerne i hånden. Den rolle der opretter maskinen, adopterer en eksisterende frem for at duplikere den, hvis den allerede er der, så genkørsel er sikker. Den er også dokumenteret, i sin egen fil, som den ene rolle i repositoryet der bruger penge — instanstypen, regionen, specifikationen og den månedlige omkostning i euro står alle skrevet, for et play der sender nogen en regning, bør sige det, hvor de vil læse det. Det play er også det, der ikke kan afprøves på den sædvanlige måde: den generiske HTTP‑opgave erklærer ingen understøttelse af check‑tilstand, så en prøvekørsel springer hver opgave i den over. Afprøvningen sker mod firewall‑playet i stedet, hvilket er gratis og kan rulles tilbage.</p>
<p><strong>Resultat.</strong> En anden vært kan oprettes, eller genadopteres, fra repositoryet, bag en firewall der allerede findes, til en pris filen oplyser. Den ene ting prøvekørsel ikke kan dække, er navngivet i den samme fil frem for efterladt som en overraskelse.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har skrevet en scoperegel ind i kodebasen, efter at en omstrukturering bar en anden virksomheds inventar, firewalltilladelser og prosa med ind i den — og har holdt det karantæneramte restmateriale under hemmelighedsscanneren frem for at udelukke det.</title>
      <link>https://platform.engineer.company/da/portfolio/wrote-a-scope-rule-after-a-credential-leak-124/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/wrote-a-scope-rule-after-a-credential-leak-124/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Omfangsgrænsen er en skreven regel med en oplyst test, resterne er synlige frem for begravet, og den konkrete form for legitimationsoplysning der slap igennem,…</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Data governance</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Data governance &amp; datakvalitet</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk dokumentation</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Arbejde udført for en anden virksomhed kørte med gennem en omstrukturering af repositoryet og blev liggende. Det der fulgte med var ikke abstrakt: en kladdelog med levende legitimationsoplysninger i klartekst, som lå i træet forbi hver eneste vagtpost gennem det meste af repositoryets historie; en forældet inventarliste der navngav den virksomheds vært; og en firewall‑opgavefil der åbnede porte til seksten af dens kundenetværk. Intet af det kørte. Det er præcis derfor det overlevede — noget der ikke kører nogen steder, bliver aldrig gennemgået igen.</p>
<p><strong>Opgave.</strong> Grænsen skulle blive til en regel med en test knyttet til sig frem for en hensigt, og resterne skulle håndteres på en måde, der ikke blot skjulte dem.</p>
<p><strong>Handling.</strong> Reglen er nu åbningsafsnittet i repositoryets instruktionssæt: dette repository håndterer én virksomheds infrastruktur og kun den, og en anden parts vært, inventarliste, firewalltilladelse, DNS‑zone eller legitimationsoplysning hører ikke hjemme i det — ikke engang deaktiveret, udkommenteret eller parkeret i en fil, ingen playbook importerer. Den praktiske test står ved siden af: ville denne virksomhed stadig være ansvarlig for dette, hvis forholdet ophørte. Resterne blev sat i karantæne i et tydeligt navngivet katalog frem for slettet, så historikken forbliver læselig, og karantænen er bevidst delvis — de to strukturelle linters springer den over, og hemmelighedsskanneren, boksvagten og emoji‑tjekket læser den bevidst stadig, for det er de tre, der ville fange det, der slap ind. Selve lækagen frembragte en linterregel: et brugerdefineret mønster der markerer en legitimationsoplysning sendt som et kommandolinjeflag, hvilket er den form den lækkede havde, og som standardregelsættet ikke matchede.</p>
<p><strong>Resultat.</strong> Omfangsgrænsen er en skreven regel med en oplyst test, resterne er synlige frem for begravet, og den konkrete form for legitimationsoplysning der slap igennem, fejler nu et commit. Læren noteret ved siden af er den generelle: det farlige artefakt er ikke det der kører, det er det der ikke gør, for det er det, ingen læser igen.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har delt de fire hemmeligheder, der hører til den enkelte vært, efter at have fastslået, at to værter, der deler én dødmandsknap, alarmerer mindre end to knapper, ikke mere, og at en delt backup‑adgangssætning gør to værter til ét repository.</title>
      <link>https://platform.engineer.company/da/portfolio/split-every-operational-secret-per-host-125/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/split-every-operational-secret-per-host-125/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Hemmeligheder er per vært ved konstruktion, og de to fejltilstande, der ville være fulgt af at dele dem, er skrevet ned, hvor den næste person redigerer filen.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Løsningsarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Backup &amp; disaster recovery</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Platformen var bygget til én vært og var ved at få to. Flere driftshemmeligheder var skrevet som enkeltværdier på den antagelse: ét sikkerhedskopi‑repository, én adgangssætning, én alarmswitch. At udvide dem til en anden vært ved at dele dem er vejen med mindst modstand, og den er forkert på to adskilte måder, som begge fejler tavst.</p>
<p><strong>Opgave.</strong> Hver hemmelighed skulle blive til et opslag med værten som nøgle, og begrundelsen skulle skrives ned, for den delte udgave ser korrekt ud og koster intet, indtil den dag det betyder noget.</p>
<p><strong>Handling.</strong> To argumenter afgjorde det, og begge er noteret ved siden af konfigurationen. En dead man&rsquo;s switch delt af to værter alarmerer mindre end to switches, ikke mere: hvis blot den ene vært stadig pinger, holder den tjekket grønt mens den anden er død, så at føje en vært til en delt switch reducerer aktivt dækningen for den, der allerede var der. Og en sikkerhedskopi‑repositorystreng er kun en placering — adgangssætningen er hele krypteringen, så to værter der deler en adgangssætning, er ikke to repositorier med en fælles hemmelighed, de er ét repository med to kataloger i sig. Hver værdi blev til et opslag med inventarværtsnavnet som nøgle, resolveret per vært af en delt opgavefil, som både konvergeringen og preflight kører. Den eksisterende vært blev derefter navngivet i alle fire opslag med sit repository og begge switches efterladt tomme, hvilket er den sandfærdige tilstand og holder de to åbne initiativer ærlige om, at de skylder operatøren halvdelen af arbejdet frem for koden.</p>
<p><strong>Resultat.</strong> Hemmeligheder er per vært ved konstruktion, og de to fejltilstande, der ville være fulgt af at dele dem, er skrevet ned, hvor den næste person redigerer filen. De tomme poster er den del, der er værd at beholde: de siger, at ledningsføringen findes og værdien ikke gør, hvilket er et andet og mere nyttigt udsagn end en manglende nøgle.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har bygget en commit‑gate af 22 en‑linjes lintere plus fem, der fortjener et afsnit, uden et advarselsniveau og uden tilladte inline‑undertrykkelser, med dækning af HTML, CSS, JavaScript, Python, YAML, Markdown, shell, links, stavning, hemmeligheder og typografi.</title>
      <link>https://platform.engineer.company/da/portfolio/built-a-22-linter-commit-gate-127/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/built-a-22-linter-commit-gate-127/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Mekaniske indvendinger fremsættes af en maskine, før et commit findes, og gaten er den eneste anmelder dette projekt har.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Frontend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Produktstrategi &amp; kravspecifikation</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk dokumentation</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> En bidragsvejledning er et sæt forslag. Alle er enige i den, og så er det fredag, ændringen er lille, og vejledningen taber. På et enmandsprojekt er det værre frem for bedre, for der er slet ingen anmelder — det eneste mellem en dårlig ændring og produktion er den person der skrev den, i det øjeblik hvor de er mindst tilbøjelige til at skændes med sig selv.</p>
<p><strong>Opgave.</strong> Standarderne skulle være eksekverbare, så at bryde en fejler et commit frem for at vente på at blive bemærket.</p>
<p><strong>Handling.</strong> Det der voksede frem er en gate på 22 linters uden advarselsniveau: hver diagnostik er en fejl, og sitegeneratoren selv kører med advarsler forfremmet til fejl, så selv en udfasning standser bygningen. De oplagte er der — HTML‑validering, CSS, JavaScript, Python, YAML, Markdown, shell, stavning, hemmeligheder, døde links. De interessante er de projektspecifikke tjek, som intet standardværktøj har en holdning til: at begge farvetemaer maler hver lagdelt flade med det samme antal lag, at intet fotografi vises bredere end halvdelen af sine kildepixels, at det udrullede træ ikke indeholder nogen privat sti eller værtsnavn, at teksten adlyder toneregelsættet på alle tre sprog, at en side har en Markdown‑tvilling og en gyldig repræsentation i et alternativt protokolformat. Inline‑undertrykkelser er direkte forbudt — ingen ignorér‑kommentar, intet deaktiveringsdirektiv, ingen omgåelse af hooket og ingen omdøbning af en fil for at undvige en matcher. Reglen der holder det ærligt er, at en allerede eksisterende fejl ikke er en undskyldning: et tjek der bringer en defekt frem, som ingen indførte, bliver rettet i samme omgang.</p>
<p><strong>Resultat.</strong> Mekaniske indvendinger fremsættes af en maskine, før et commit findes, og gaten er den eneste anmelder dette projekt har. Prisen er oplyst frem for skjult: det er langsomt at committe, og en dårligt skrevet vagtpost er oprigtigt irriterende at arbejde uden om, hvilket er grunden til at vagtposterne selv senere kom under en formatter og en linter af deres egen.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/cut-the-visual-quality-gate-to-ten-minutes-128/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/cut-the-visual-quality-gate-to-ten-minutes-128/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Gaten gik fra 1.636 sekunder til 615, mens tjekkene blev bredere frem for tyndere — den serielle omkostning steg, og den samlede tid faldt.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Frontend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Performanceoptimering</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Frontend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk ledelse &amp; rådgivning</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/mirrored-the-site-to-gemini-and-gopher-137/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/mirrored-the-site-to-gemini-and-gopher-137/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>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…</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Frontend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Internationalisering</category>
      <category domain="https://platform.engineer.company/da/categories/">Webudvikling</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Internationalisering &amp; lokalisering</category>
      <category domain="https://platform.engineer.company/da/services/">Webstedsudvikling &amp; CMS</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> Hele sitet skulle udgives over Gemini og Gopher fra det samme indhold, uden et andet indholdstræ og uden at ændre HTML&rsquo;en.</p>
<p><strong>Handling.</strong> 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&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&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.</p>
<p><strong>Resultat.</strong> Sitet kan læses over fire protokoller fra én bygning, med 777 dokumenter hver og nul ændring i HTML&rsquo;en, og de alternative repræsentationer koster omkring tolv procent af HTML&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.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/fixed-a-sitemap-with-one-shared-timestamp-140/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/fixed-a-sitemap-with-one-shared-timestamp-140/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>En gensynkronisering efter en måneds indholdsredigeringer rører nu otte filer af 186 i stedet for dem alle, og sitemappet siger noget sandt.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Brand &amp; marketing</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/categories/">Webudvikling</category>
      <category domain="https://platform.engineer.company/da/services/">Brand, marketing &amp; SEO</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Webstedsudvikling &amp; CMS</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> Datoerne skulle beskrive indholdet frem for filen, uden at opfinde en præcision repositoryet ikke har.</p>
<p><strong>Handling.</strong> Å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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/brought-the-quality-gate-code-under-a-linter-143/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/brought-the-quality-gate-code-under-a-linter-143/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Den største og mest bærende kode i repositoryet er nu formateret, lintet og typetjekket, med tretten fund rettet og nul undertrykkelser.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Frontend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Frontend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk ledelse &amp; rådgivning</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> Tjekkerne skulle holdes til den standard, de findes for at håndhæve, og formatteren skulle tilpasses dem frem for omvendt.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/held-the-generator-to-964-tests-and-a-coverage-floor-145/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/held-the-generator-to-964-tests-and-a-coverage-floor-145/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Pipelinen kan køres igen mod en levende database uden frygt, hvilket er det der overhovedet gør trinvist indholdsarbejde muligt.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Databaser</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">Backend- &amp; API‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk ledelse &amp; rådgivning</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/enabled-every-python-linter-rule-as-an-error-147/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/enabled-every-python-linter-rule-as-an-error-147/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Linteren kører ved fuld styrke med nul fund, og hver afvigelse er dokumenteret på den linje, hvor den tages.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">Backend- &amp; API‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk ledelse &amp; rådgivning</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har skrevet tests af selve tjekkene efter at have fastslået, at et tjek, der kun fodres med rent input, en dag melder rent, fordi det intet læste — ved at plante en stavefejl for at bekræfte, at stavekontrollen finder den, og ved at tage et id‑interval fra databasen frem for fra et tal i testen.</title>
      <link>https://platform.engineer.company/da/portfolio/wrote-tests-for-the-checkers-themselves-149/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/wrote-tests-for-the-checkers-themselves-149/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Hvert tjek i projektet har nu en test, der beviser, at det fejler på dårlige inddata, og områdeforventningerne læses fra sandhedskilden.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Data governance</category>
      <category domain="https://platform.engineer.company/da/categories/">Databaser</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">Data governance &amp; datakvalitet</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk ledelse &amp; rådgivning</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Projektet kører en række egne tjek over sit eget indhold — en stavekontrol, et tjek af identifikatorernes talområde, et stemmetjek, et tjek af taloverensstemmelse. Hvert af dem havde kørt grønt i månedsvis. Et tjek, der kun nogensinde har set rene inddata og kun nogensinde har meldt rent, kan ikke skelnes fra et tjek, der slet intet læser, og der fandtes ingen test i suiten, som kunne kende forskel på de to.</p>
<p><strong>Opgave.</strong> Tjekkene skulle bringes til at bevise, at de kan fejle, og de fikstursdata, de tjekker imod, skulle holde op med at være håndholdte kopier af det, de beskriver.</p>
<p><strong>Handling.</strong> Mønsteret, der er anvendt hele vejen igennem, er at plante netop den defekt, tjekket findes for at fange, og kræve at tjekket finder den. Stavekontrollen fodres med et bevidst fejlstavet ord, og testen fejler, hvis kørslen kommer rent tilbage. Stemmetjekket fodres med prosa i første person og skal afvise den. Buzzword‑tjekket fodres med et forbudt ord. Hvert af disse er en lille test, og hver af dem lukkede en reel blind vinkel, for to af tjekkene viste sig at læse et snævrere sæt filer end deres dokumentation påstod og havde tavst sprunget indhold over. Den anden ændring handler om, hvor en test henter sine forventninger: tjekket af identifikatorernes talområde sammenlignede før med et tal skrevet i testfilen, hvilket betød, at enhver tilføjelse af indhold krævede en redigering af en test, og en redaktør, der opdaterede tallet uden at se efter, havde slået tjekket fra. Det udleder nu området fra databasen, så tjekket beskriver dataene frem for en forældet erindring om dem.</p>
<p><strong>Resultat.</strong> Hvert tjek i projektet har nu en test, der beviser, at det fejler på dårlige inddata, og områdeforventningerne læses fra sandhedskilden. Det ubehagelige er, hvad dette blotlagde: et grønt tjek havde været meningsløst mindst to steder i et ukendt tidsrum, og der er ingen måde at finde ud af med tilbagevirkende kraft, hvad der slap igennem.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har fundet commit‑hooks og kvalitetsgaten køre forskellige tjek, mens et dokument lovede, at de var de samme, ved at sammenligne de to lister i en test — de fem, der kun nogensinde kørte i hånden, var dem, der læste CV‑prosaen.</title>
      <link>https://platform.engineer.company/da/portfolio/found-the-commit-hooks-and-the-gate-disagreeing-150/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/found-the-commit-hooks-and-the-gate-disagreeing-150/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Hooken og porten kører beviseligt de samme tjek, og prosatjekkene kører nu ved hver commit. Afvejningen er commit-hookens køretid, som voksede og vil blive ved…</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk dokumentation</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk ledelse &amp; rådgivning</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Projektet havde en commit‑hook, der kører tjek, før en commit accepteres, og en fuld kvalitetsport kørt efter behov. Et dokument angav, at hooken kører porten, så intet kunne nå historikken uden at bestå alt. Begge lister blev vedligeholdt i hånden, i to forskellige filer, og intet sammenlignede dem.</p>
<p><strong>Opgave.</strong> Påstanden skulle gøres til en efterprøvning, hvilket betød at opregne begge mængder programmatisk og fejle, når de afviger.</p>
<p><strong>Handling.</strong> Testen læser hook‑konfigurationen og portens opgavedefinitioner, opløser hver af dem til den mængde tjek, den faktisk kalder, og sammenligner. De stemte ikke. Fem tjek fandtes kun i porten og kørte aldrig ved commit, og de fem var ikke tilfældige — det var dem, der læser selve CV&rsquo;ets prosa: stemmetjekket, der holder anmeldelser upersonlige, buzzword‑tjekket, tjekket af taloverensstemmelse på tværs af sprog, notationstjekket og stavekontrollen over indhold. Med andre ord kørte hvert tjek, der beskytter kode, automatisk, og hvert tjek, der beskytter skriften, kørte kun, når nogen huskede det. Da skriften er hele produktet, var udsattheden vendt om i forhold til, hvor nogen ville have gættet. Rettelsen var at bringe de fem ind i hooken, hvilket krævede at gøre to af dem hurtige nok til at overleve et budget før commit, og derefter at holde sammenligningstesten på plads, så de to lister ikke kan glide fra hinanden igen. Dokumentet, der havde beskrevet en hensigt, beskriver nu noget håndhævet.</p>
<p><strong>Resultat.</strong> Hooken og porten kører beviseligt de samme tjek, og prosatjekkene kører nu ved hver commit. Afvejningen er commit‑hookens køretid, som voksede og vil blive ved med at vokse, efterhånden som indholdet vokser, og der findes et punkt, hvor en langsom hook bliver omgået — så denne rettelse har en holdbarhed målt i, hvor længe tjekkene forbliver hurtige.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har prøvekørt CI‑hooken på forge‑siden og har fundet to fejl, der ikke kunne nås ved at læse filen: en fallback, der lagde et uopløseligt argument på hookens input, og gits egen miljøvariabel, der fulgte gaten ind i checkouten og gjorde 19 tests røde.</title>
      <link>https://platform.engineer.company/da/portfolio/rehearsed-the-forge-side-ci-hook-151/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/rehearsed-the-forge-side-ci-hook-151/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Hooken virker på begge veje, og begge defekter blev fundet, før noget rigtigt push mødte dem. Begrænsningen er, at en prøve stadig er en simulering: den…</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Infrastruktur</category>
      <category domain="https://platform.engineer.company/da/categories/">Linux &amp; servere</category>
      <category domain="https://platform.engineer.company/da/categories/">Python</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Infrastructure as Code</category>
      <category domain="https://platform.engineer.company/da/services/">Systemadministration</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Den selvhostede git‑forge tager imod pushes og kan køre en hook på serversiden for at afvise arbejde, der ikke består porten. En hook på serversiden er det ene stykke automatik, der ikke kan testes ved at køre den lokalt: den udføres i et bart lager, uden arbejdstræ, under et miljø, forgen sætter, og læser de pushede referencer fra sin standardinddata. At læse skriptet og konkludere, at det er korrekt, er et gæt.</p>
<p><strong>Opgave.</strong> Hooken skulle prøves af mod et rigtigt bart lager og et rigtigt push, før den blev betroet, frem for at blive udrullet og opdaget.</p>
<p><strong>Handling.</strong> Prøven opretter et bart lager, installerer hooken, kloner det, committer, pusher og efterprøver både accept- og afvisningsvejen. Den fandt to defekter, hvoraf ingen af dem var synlige i filen. Den første var en nødløsning i argumenthåndteringen: når hooken ikke kunne bestemme en reference, indsatte den en pladsholder, der ikke var et opløseligt objekt, og fordi værdien ankommer på hookens standardinddata frem for som en parameter, viste fejlen sig som en urelateret fejl meget længere nede. Den anden er den, der er værd at huske. Git eksporterer en miljøvariabel, der navngiver lagermappen, når den kalder en hook, og den variabel nedarves af alt, hvad hooken kører. Porten tjekker den pushede revision ud og kører testsuiten inde i den, og testsuiten nedarvede pegepinden til det bare lager — så nitten test, der rører git, opløste mod det forkerte lager og gik røde på kode, der var korrekt. Miljøet skal ryddes ved grænsen, og den grænse er usynlig, medmindre tingen faktisk køres.</p>
<p><strong>Resultat.</strong> Hooken virker på begge veje, og begge defekter blev fundet, før noget rigtigt push mødte dem. Begrænsningen er, at en prøve stadig er en simulering: den beviser, at hooken overlever én pushform, og forgen ser i drift pushes, som denne prøve ikke konstruerer, herunder tvungne opdateringer og sletning af grene.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/stopped-an-application-filling-memory-at-41mb-a-second-155/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/stopped-an-application-filling-memory-at-41mb-a-second-155/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Hukommelsen holder sig flad under vedvarende belastning, og den samme session, der frembragte 610.996 loglinjer, frembringer 1.411.</description>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Frontend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Løsningsarkitektur</category>
      <category domain="https://platform.engineer.company/da/categories/">Monitorering &amp; observability</category>
      <category domain="https://platform.engineer.company/da/categories/">Performanceoptimering</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">Frontend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">Platform- &amp; løsningsarkitektur</category>
      <category domain="https://platform.engineer.company/da/services/">Site reliability &amp; monitorering</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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å.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/wrote-a-parser-that-verifies-every-ffi-call-site-157/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/wrote-a-parser-that-verifies-every-ffi-call-site-157/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>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.</description>
      <category domain="https://platform.engineer.company/da/categories/">API&#39;er &amp; integration</category>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Backend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">Backend- &amp; API‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk dokumentation</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har taget testsuiten fra seks tests over en grænse på tres sekunder til 135 beståede på 8,9 sekunder ved at profilere hovedtråden og fjerne de to kald, den sad inde i i 3.989 ud af 4.017 stikprøver.</title>
      <link>https://platform.engineer.company/da/portfolio/took-the-test-suite-under-nine-seconds-158/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/took-the-test-suite-under-nine-seconds-158/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Suiten gik fra seks test over tres sekunder — 74 sekunders vægur — til 135 test bestået på 8,9, hvilket bringer den inden for det vindue, hvor den kører ved…</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Performanceoptimering</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk ledelse &amp; rådgivning</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Testsuiten havde en tidsgrænse på tres sekunder, og seks test lå over den. En testsuite, der tager over et minut, holder op med at blive kørt før hver ændring, og en suite, der ikke køres før hver ændring, er en rapport om fortiden. Instinktet i den situation er at hæve grænsen, og at hæve grænsen er, hvordan en suite når ti minutter.</p>
<p><strong>Opgave.</strong> Tiden skulle findes frem for budgetteres til, hvilket betød at profilere suiten i stedet for at ræsonnere om, hvilke test der så dyre ud.</p>
<p><strong>Handling.</strong> Profilen blev taget på hovedtråden, mens suiten kørte, og resultatet modsagde gættet. Hovedtråden sad inde i to kald i 3.989 stikprøver ud af 4.017 — så de langsomme test var ikke dem, der udførte mest arbejde, og næsten hver eneste test kom gennem de samme to steder. Det første var en fast ventetid brugt til at lade asynkront arbejde falde til ro før efterprøvning — reelt en søvn, betalt af hver test, der rørte hændelsesvejen, uanset om arbejdet allerede var færdigt. Den blev erstattet af at vente på den faktiske betingelse med en tidsfrist, så en test, der er klar på fem millisekunder, tager fem millisekunder, og kun en test, der reelt sidder fast, betaler den fulde ventetid. Det andet var opsætning pr. test, der genopbyggede et dyrt fikstur hver gang, hvor fiksturet var skrivebeskyttet og kunne bygges én gang for suiten. Ingen af dem lå i en test, nogen ville have udpeget som langsom; begge lå i den fælles vej, hvilket er grunden til, at hele suiten var ensartet langsom frem for at nogle få test var afvigere.</p>
<p><strong>Resultat.</strong> Suiten gik fra seks test over tres sekunder — 74 sekunders vægur — til 135 test bestået på 8,9, hvilket bringer den inden for det vindue, hvor den kører ved hver gemning. Forbeholdet er, at det fælles skrivebeskyttede fikstur nu er et koblingspunkt — en test, der ændrer det, vil frembringe en fejl i en anden test, og suitens hastighed afhænger af en disciplin, oversætteren ikke håndhæver.</p>
]]></content:encoded>
    </item>
    <item>
      <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>
      <link>https://platform.engineer.company/da/portfolio/reached-the-unused-half-of-the-messaging-core-161/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/reached-the-unused-half-of-the-messaging-core-161/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Den tidligere uopnåede halvdel af kernen drives af test mod det rigtige bibliotek, og indpakningen bærer det højeste gulv i projektet.</description>
      <category domain="https://platform.engineer.company/da/categories/">API&#39;er &amp; integration</category>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Backend‑udvikling</category>
      <category domain="https://platform.engineer.company/da/categories/">Drift &amp; backup</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/categories/">Test &amp; QA</category>
      <category domain="https://platform.engineer.company/da/services/">Backend- &amp; API‑udvikling</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> 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.</p>
<p><strong>Opgave.</strong> 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.</p>
<p><strong>Handling.</strong> 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.</p>
<p><strong>Resultat.</strong> 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.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har auditeret 644 Rust‑crates for licenskompatibilitet ved hvert build og har bevist, at tjekket udløses, ved at omskrive én crates licens og ved at flytte den fastlåste kernerevision uden at regenerere.</title>
      <link>https://platform.engineer.company/da/portfolio/audited-644-rust-crates-for-licence-compatibility-163/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/audited-644-rust-crates-for-licence-compatibility-163/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Distributionspositionen tjekkes ved hver bygning, og tjekket vides at virke, fordi det blev bragt til at fejle, frem for fordi det aldrig har sagt noget.</description>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">Data governance</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Sikkerhed</category>
      <category domain="https://platform.engineer.company/da/services/">Data governance &amp; datakvalitet</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Sikkerhed &amp; adgangsstyring</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> At sammenkæde en Rust‑kerne ind i et udsendt program betyder at udsende alt, den kerne afhænger af. Afhængighedsgrafen er 644 crates. Hver af dem bærer en licens, nogle bærer mere end én, og en enkelt copyleft‑crate, der ankommer tre niveauer nede gennem en rutinemæssig versionsopdatering, ændrer, hvad programmet som helhed må distribueres under — tavst, i en låsefil ingen læser linje for linje.</p>
<p><strong>Opgave.</strong> Licenspositionen skulle efterprøves ved hver bygning frem for gennemgås én gang, med en udtrykkelig tilladelsesliste, så en ændring i grafen er en bygningsfejl og ikke en opdagelse gjort senere af en anden.</p>
<p><strong>Handling.</strong> Revisionen opløser den fulde transitive graf og tjekker hver crates licensudtryk mod en liste over vilkår, projektet accepterer, og evaluerer de booleske udtryk korrekt — en crate, der tilbyder et valg mellem to licenser, er acceptabel, hvis en af dem står på listen, og en crate, der kræver begge, er kun acceptabel, hvis begge gør. Alt uden match fejler bygningen frem for at advare, og at føje et vilkår til tilladelseslisten er en bevidst redigering med en begrundelse. Et tjek, der aldrig har fejlet, kan ikke skelnes fra et, der ikke kan fejle, så det blev bragt til at fejle med vilje, to gange. Én gang ved at omskrive en crates licensudtryk til noget, listen ikke accepterer, hvilket er formen på en crate, der ændrer sine vilkår opstrøms mellem versioner — det tilfælde ingen menneskelig gennemgang fanger, fordi selve craten ikke er ny. Én gang ved at flytte den fastlåste kernerevision uden at genskabe revisionen, hvilket er formen på en kerneopdatering, der stille bringer en ny afhængighed med sig. Begge provokationer fejlede bygningen som tilsigtet, og tjekket blev efterladt på plads frem for udvidet.</p>
<p><strong>Resultat.</strong> Distributionspositionen tjekkes ved hver bygning, og tjekket vides at virke, fordi det blev bragt til at fejle, frem for fordi det aldrig har sagt noget. Før det fandtes, fremsatte pakken, licensfilen og projektets eget README alle en påstand om 644 crates, som intet havde efterprøvet. Begrænsningen er præcis og bør ikke overdrives: tjekket læser de erklærede licensmetadata, og metadata kan være forkerte eller ufuldstændige. Det beviser intet om en crate, der fejlerklærer sig selv, og det er ikke juridisk rådgivning.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Har holdt fire kodebaser til én historikstandard — konventionel, uden emojis, uden attributionslinjer, håndhævet af en commit‑message‑hook — sammen med 46 instruktionsdokumenter, der styrer, hvordan arbejdet udføres.</title>
      <link>https://platform.engineer.company/da/portfolio/held-five-repositories-to-one-history-standard-165/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/portfolio/held-five-repositories-to-one-history-standard-165/</guid>
      <pubDate>Sun, 13 Sep 2026 01:45:50 +0200</pubDate>
      <description>Fem lagre deler ét historikformat og én anvisningsstruktur, begge håndhævet af hooks frem for af disciplin.</description>
      <category domain="https://platform.engineer.company/da/categories/">Agile &amp; Scrum</category>
      <category domain="https://platform.engineer.company/da/categories/">Automatisering &amp; CI/CD</category>
      <category domain="https://platform.engineer.company/da/categories/">DevOps</category>
      <category domain="https://platform.engineer.company/da/categories/">Dokumentation</category>
      <category domain="https://platform.engineer.company/da/categories/">Projektledelse</category>
      <category domain="https://platform.engineer.company/da/categories/">Teknisk ledelse</category>
      <category domain="https://platform.engineer.company/da/services/">DevOps &amp; CI/CD‑automatisering</category>
      <category domain="https://platform.engineer.company/da/services/">Projektledelse (Agile)</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk dokumentation</category>
      <category domain="https://platform.engineer.company/da/services/">Teknisk ledelse &amp; rådgivning</category>
      <content:encoded><![CDATA[<p><strong>Situation.</strong> Fem lagre bygget over atten måneder af én person er den situation, hvor proces er lettest at springe over, for der er ingen at koordinere med, og prisen for en ulæselig historik betales helt af et fremtidigt jeg, der endnu ikke har beklaget sig. Det er også den situation, hvor en usammenhængende historik er mest sandsynlig, eftersom hvert lager kan glide ind i sine egne vaner uden noget, der trækker dem sammen.</p>
<p><strong>Opgave.</strong> Én standard for historik og én standard for anvisninger skulle gælde på tværs af hvert lager, arbejdet skrives i, og den skulle håndhæves maskinelt frem for huskes.</p>
<p><strong>Handling.</strong> Commit‑standarden er et konventionelt præfiks, der navngiver ændringens art, og et virkefelt, en emnelinje under en fast længde, ingen emojis og ingen tilskrivningslinjer af nogen art — det sidste fordi en linje, der krediterer et værktøj, ikke er en kendsgerning om ændringen, og historik er til kendsgerninger om ændringer. En hook på commit‑beskeden afviser alt, der ikke retter sig efter det, i hvert lager, der bærer arbejde, så standarden er en egenskab ved lageret frem for ved den, der committer. Fordelingen i det største lager viser, hvad arbejdet faktisk var: 156 funktions‑commits, 133 rettelser, 128 dokumentation, 81 husholdning, 26 omskrivninger, 20 stil, 5 ydeevne og 3 test. Dokumentation ligger tæt nok på rettelser til at være værd at bemærke, og det er en følge af den anden halvdel af dette — 46 anvisningsdokumenter på tværs af de fire, hvert dækkende ét område, hvert skrevet som regler frem for beskrivelse, alle nåelige fra ét indgangsdokument pr. lager, så der er ét sted at begynde. En dokumentationslinter håndhæver størrelsesbudgetter pr. fil og medlemskab af indekset, så mængden forbliver overskuelig frem for at vokse til et arkiv.</p>
<p><strong>Resultat.</strong> Fem lagre deler ét historikformat og én anvisningsstruktur, begge håndhævet af hooks frem for af disciplin. Hvad dette ikke gør, er at gøre historikken god: formatet tjekkes, og indholdet gør ikke, så en emnelinje, der retter sig efter formatet og beskriver intet, slipper igennem præcis lige så godt som en, der forklarer ændringen.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sådan åbner man en dApp i Solana-mobilwallets</title>
      <link>https://platform.engineer.company/da/notes/solana-mobile-wallet-deeplinks/</link>
      <guid isPermaLink="true">https://platform.engineer.company/da/notes/solana-mobile-wallet-deeplinks/</guid>
      <pubDate>Mon, 10 Aug 2026 00:00:00 +0000</pubDate>
      <description>Hvorfor browse-deeplinks til Phantom, Solflare og Backpack fejler på mobilen — og de formater, regler og rettelser, der får dem til at virke.</description>
      <content:encoded><![CDATA[<p>En React-dApp bygget på <code>@solana/wallet-adapter-react</code> forbinder
desktop-wallets uden problemer, men på en telefon falder det samme flow fra
hinanden: wallet&rsquo;en skal åbne dApp&rsquo;en i sin egen indbyggede browser, og de
deeplinks, der skulle klare det, virker bare ikke. Backpack lander på en &ldquo;hent
appen&rdquo;-side; Solflare åbner appen, men aldrig sitet; alle varianter ser ud til
at fejle. Vi skilte problemet ad, og det viste sig at være fire adskilte
problemer med ét fælles symptom.</p>
<h2 id="de-fire-problemer">De fire problemer</h2>

<ul>
<li><strong>Backpack-linket var forkert bygget.</strong> Det eneste dokumenterede format er
<code>https://backpack.app/ul/v1/browse/&lt;url&gt;?ref=&lt;ref&gt;</code> — et universelt link med
mål-URL&rsquo;en i stien og et påkrævet <code>ref</code>. Et gæt med eget skema som
<code>backpack://ul/v1/browse?url=...</code> matcher ingen rute i appen, så brugeren
ender på wallet&rsquo;ens installationsside.</li>
<li><strong>Solflare skal også bruge sit universelle link:</strong>
<code>https://solflare.com/ul/v1/browse/&lt;url&gt;?ref=&lt;ref&gt;</code> — ikke det rå
<code>solflare://</code>-skema. Et råt skema kan starte appen uden at dirigere den —
hvilket er præcis &ldquo;appen åbner, men site-fanen må åbnes med hånden&rdquo;.</li>
<li><strong>Begge parametre skal være kodet.</strong> <code>url</code> er dApp&rsquo;ens fulde absolutte
adresse, og <code>ref</code> er den kaldende origin, hver især gennem
<code>encodeURIComponent</code>. Et ukodet <code>?</code> eller <code>&amp;</code> i målet ødelægger
fortolkningen, og wallet&rsquo;en åbner på sin forside i stedet for browserfanen.</li>
<li><strong>Udløsningen betyder lige så meget som linket.</strong> Universelle links skifter
kun app ved en navigation, styresystemet stoler på — og de gør med vilje
ingenting, når de indsættes i adresselinjen, hvilket også er sådan, et helt
korrekt link &ldquo;fejler&rdquo; under test.</li>
</ul>
<h2 id="de-dokumenterede-formater">De dokumenterede formater</h2>

<ul>
<li>Phantom: <code>https://phantom.app/ul/browse/&lt;url&gt;?ref=&lt;ref&gt;</code> — uden <code>/v1</code> i
netop dette.</li>
<li>Solflare: <code>https://solflare.com/ul/v1/browse/&lt;url&gt;?ref=&lt;ref&gt;</code></li>
<li>Backpack: <code>https://backpack.app/ul/v1/browse/&lt;url&gt;?ref=&lt;ref&gt;</code></li>
</ul>
<p>Ét mønster dækker alle tre:</p>
<pre tabindex="0"><code>const WALLET_BROWSE = {
  phantom: (url, ref) =&gt;
    `https://phantom.app/ul/browse/${url}?ref=${ref}`,
  solflare: (url, ref) =&gt;
    `https://solflare.com/ul/v1/browse/${url}?ref=${ref}`,
  backpack: (url, ref) =&gt;
    `https://backpack.app/ul/v1/browse/${url}?ref=${ref}`,
};

function walletBrowseLink(
  walletName,
  targetUrl = window.location.href,
) {
  const build = WALLET_BROWSE[walletName.toLowerCase()];
  if (!build) return null;
  return build(
    encodeURIComponent(targetUrl),
    encodeURIComponent(window.location.origin),
  );
}
</code></pre><h2 id="udløs-linket-så-ios-og-android-accepterer-det">Udløs linket, så iOS og Android accepterer det</h2>

<ul>
<li><strong>Render et rigtigt anker, beregnet på forhånd.</strong> Et almindeligt
<code>&lt;a href={walletBrowseLink('phantom')}&gt;</code> er den mest pålidelige udløser på
begge platforme.</li>
<li><strong>Skal det ske programmatisk</strong>, så tildel <code>window.location.href</code> synkront
inde i tryk-handleren — ingen <code>await</code>, ingen <code>fetch</code>, ingen <code>setTimeout</code>
først. Efter asynkront arbejde er gestus-konteksten væk, og iOS falder
tilbage til wallet&rsquo;ens websted. Aldrig <code>window.open</code>.</li>
<li><strong>Test aldrig ved at indsætte i adresselinjen.</strong> Universelle links udløses
med vilje ikke dér; test med et link, der trykkes på, eller en QR-kode, som
kameraet scanner.</li>
<li><strong>Pas på messenger-webviews.</strong> Åbnet i Telegrams eller Instagrams indbyggede
browser bliver universelle links ofte slugt, og wallet&rsquo;ens almindelige
websted indlæses i stedet. User-agent-detektion er i bedste fald et gæt, så
giv også brugerne en synlig nødudgang: &ldquo;åbn i Safari eller Chrome, og
forbind derefter&rdquo;.</li>
</ul>
<h2 id="den-større-løsning-på-android">Den større løsning på Android</h2>

<p>Håndbyggede deeplinks er iOS-historien. På Android lader Solana Mobiles Mobile
Wallet Adapter en dApp i mobilbrowseren forbinde direkte til den installerede
wallet-app, helt uden omvejen om den indbyggede browser. Nyere versioner af
<code>@solana/wallet-adapter-react</code> registrerer mobiladapteren automatisk, så en
opgradering af wallet-adapter-pakkerne kan løse Android alene. Målarkitekturen:
Mobile Wallet Adapter på Android, universelle browse-links på iOS, hvor Apple
ikke tillader en tilsvarende løsning.</p>
<h2 id="efterprøv-på-en-enhed">Efterprøv på en enhed</h2>

<ol>
<li>Rigtig enhed, wallet installeret, link åbnet fra systembrowseren — ikke fra
en messenger.</li>
<li>Tryk på et renderet link, eller scan en QR-kode; indsæt aldrig i
adresselinjen.</li>
<li>Bekræft, at wallet&rsquo;en åbner, og at dApp&rsquo;en indlæses i dens indbyggede
browserfane — anden halvdel er den, der fejler.</li>
<li>Gentag uden wallet&rsquo;en installeret: det universelle link skal falde tilbage
til wallet&rsquo;ens websted. Ser du dén side, mens appen er installeret, er
linket eller udløsningen stadig forkert.</li>
<li>Test derefter messenger-vejen, og tilføj &ldquo;åbn i browser&rdquo;-hjælpen, hvis den
fejler dér.</li>
</ol>
<h2 id="kilder">Kilder</h2>

<ul>
<li><a href="https://docs.phantom.com/phantom-deeplinks/deeplinks-ios-and-android">Phantom: deeplinks på iOS og Android</a></li>
<li><a href="https://docs.solflare.com/solflare/technical/deeplinks/other-methods/browse">Solflare: Browse-deeplinket</a></li>
<li><a href="https://docs.backpack.app/deeplinks/other-methods/browse">Backpack: Browse-deeplinket</a></li>
<li><a href="https://docs.solanamobile.com/mobile-wallet-adapter/mobile-apps">Solana Mobile: Mobile Wallet Adapter</a></li>
</ul>
]]></content:encoded>
    </item>
  </channel>
</rss>
