<?xml version="1.0" encoding="utf-8" standalone="yes"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Engineer — Platform — Portfolio and notes</title>
  <subtitle>Engineer ApS — software development &amp; IT consulting in Copenhagen, Denmark. A portfolio of proven engineering achievements across software, data, cloud and IT.</subtitle>
  <id>https://platform.engineer.company/</id>
  <updated>2026-09-13T01:45:50+02:00</updated>
  <author>
    <name>Engineer ApS</name>
    <uri>https://platform.engineer.company/</uri>
    <email>welcome@engineer.company</email>
  </author>
  <rights>Copyright © 2025 – present · Engineer ApS</rights>
  <generator uri="https://gohugo.io/">Hugo 0.166.0</generator>
  <icon>https://platform.engineer.company/assets/icons/apple/apple-touch-icon.png</icon>
  <logo>https://platform.engineer.company/assets/images/brand/card.webp</logo>
  <link href="https://platform.engineer.company/" rel="alternate" type="text/html" />
  <link href="https://platform.engineer.company/atom.xml" rel="self" type="application/atom+xml" />
  <entry>
    <title>Developed and launched the company&#39;s first observability dashboard, providing real‑time system performance insights and data visualization on the large office TV.</title>
    <id>https://platform.engineer.company/portfolio/developed-and-launched-the-company-s-first-observability-9/</id>
    <link href="https://platform.engineer.company/portfolio/developed-and-launched-the-company-s-first-observability-9/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Containers (Docker/Kubernetes)" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Analytics" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Monitoring &amp; Observability" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Analytics &amp; BI Dashboards" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <summary>Built the company&#39;s first observability dashboard for real-time system insight, helping teams detect and resolve incidents 40% faster.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The company was facing challenges in monitoring real‑time system performance, which often led to delayed incident responses and reduced visibility into infrastructure health. There was no centralized solution in place for teams to gain insights into operational metrics.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The task was to develop a solution that would enable technical and non‑technical stakeholders to monitor key system metrics in real time, with a focus on accessibility, clarity, and proactive issue detection.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The company&amp;rsquo;s first observability dashboard was designed and implemented, collecting all essential system metrics — such as CPU, RAM, HDD, temperature, and more — from remote Linux servers via SSH. Even Docker containers were monitored using this method. Later, a second version was designed and implemented using Grafana and Prometheus for more advanced visualization and monitoring capabilities. Collaboration with DevOps and engineering teams identified the critical metrics, such as CPU utilization, memory usage, service uptime, and API latency. Data pipelines were configured to ingest and process performance metrics from various systems, and the dashboard deployed on a large office TV screen for maximum visibility. Alerting mechanisms for threshold breaches were also integrated to enable immediate action.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The dashboard significantly improved system transparency and response time to operational issues. Teams were able to detect and resolve incidents 40% faster. It also fostered a culture of shared ownership over system health by making performance data accessible to everyone in the office, ultimately contributing to a more stable and efficient production environment.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Designed, deployed, and maintained 10 PostgreSQL and MS SQL servers on Ubuntu Linux VPS, ensuring optimal server performance and reliability.</title>
    <id>https://platform.engineer.company/portfolio/designed-deployed-and-maintained-10-postgresql-and-ms-13/</id>
    <link href="https://platform.engineer.company/portfolio/designed-deployed-and-maintained-10-postgresql-and-ms-13/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Databases" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Monitoring &amp; Observability" scheme="https://platform.engineer.company/categories/" />
    <category term="Performance Tuning" scheme="https://platform.engineer.company/categories/" />
    <category term="PostgreSQL" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Database Administration (DBA)" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>Designed and maintained 10 PostgreSQL and MS SQL servers on Ubuntu Linux VPS at 99.9% uptime, with 30% faster queries via tuning.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; As a DevOps engineer at a mid‑sized tech company, the task was managing and optimizing database infrastructure to support a growing user base and critical business applications. The organization relied heavily on PostgreSQL and Microsoft SQL Server for data storage and analytics, requiring high availability, scalability, and security.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The primary responsibility was to architect, deploy, configure, and maintain 10 PostgreSQL and MS SQL Server instances on Ubuntu Linux VPS environments. This included ensuring optimal performance, implementing robust security protocols, and establishing proactive monitoring to prevent outages. Additionally, the task included scaling the infrastructure to accommodate future growth while minimizing costs and maintaining compliance with industry standards.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; 1. Deployment &amp;amp; Configuration:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Installed and configured PostgreSQL 14 and MS SQL Server 2019 on Ubuntu 20.04 LTS VPS instances, ensuring compatibility with the company’s applications.&lt;/li&gt;&#xA;&lt;li&gt;Set up automated backups using &lt;code&gt;pg_dump&lt;/code&gt; for PostgreSQL and SQL Server Agent jobs for MS SQL, with retention policies and offsite storage.&lt;/li&gt;&#xA;&lt;li&gt;Optimized server configurations (e.g., memory allocation, query caching, and connection pooling) to improve query performance and reduce latency.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;ol start=&#34;2&#34;&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Monitoring &amp;amp; Maintenance:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Implemented monitoring tools like Prometheus, Grafana, to track CPU, memory, disk I/O, and query performance metrics in real time.&lt;/li&gt;&#xA;&lt;li&gt;Conducted regular patching and updates for both databases and the Ubuntu OS to address security vulnerabilities and ensure compliance.&lt;/li&gt;&#xA;&lt;li&gt;Created custom scripts for log analysis.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Security &amp;amp; Scalability:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Configured firewalls (UFW), enforced role‑based access control (RBAC) to protect sensitive data.&lt;/li&gt;&#xA;&lt;li&gt;Documented procedures for disaster recovery, including point‑in‑time restores and failover protocols.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; - Achieved 99.9% uptime across all 10 database servers.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Improved query response times by 30% through configuration tuning and index optimization, enhancing application performance.&lt;/li&gt;&#xA;&lt;li&gt;Reduced manual maintenance tasks by 50% via automation, freeing up 10+ hours per month for strategic projects.&lt;/li&gt;&#xA;&lt;li&gt;Successfully scaled the infrastructure to support a 40% increase in user traffic without service degradation, contributing to a 20% revenue growth in the following quarter.&lt;/li&gt;&#xA;&lt;li&gt;Received recognition from the CTO for implementing security best practices that prevented potential data breaches.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This experience solidified deep expertise in database management, DevOps automation, and infrastructure optimization, delivering reliable, secure, and scalable solutions for complex enterprise environments.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Enhanced data security by implementing 1,000 RBAC rules for developers, application instances, PostgreSQL, MS SQL, and other Linux servers, preventing unauthorized access; documented with Ansible automation.</title>
    <id>https://platform.engineer.company/portfolio/enhanced-data-security-by-implementing-1-000-rbac-14/</id>
    <link href="https://platform.engineer.company/portfolio/enhanced-data-security-by-implementing-1-000-rbac-14/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Databases" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Database Administration (DBA)" scheme="https://platform.engineer.company/services/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>Hardened security with 1,000 RBAC rules across developers, apps and Linux/DB servers — unauthorised-access risk down 85%, Ansible-automated.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The organization needed to strengthen access controls across multiple systems, including developer environments, application instances, PostgreSQL, MS SQL, and Linux servers. While the underlying RBAC model was straightforward, the challenge lay in managing over 1,000 individual rules to cover diverse user roles and system requirements. The goal was to ensure strict access restrictions without introducing complexity.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Implement a scalable RBAC solution by defining and enforcing 1,000+ rules for access control. This involved mapping permissions to specific roles (e.g., developers, application instances, database admins) and ensuring rules were applied consistently across all systems. The task also required documenting the rules and automating their deployment to avoid manual errors.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The approach focused on creating a simple, modular RBAC structure, breaking down permissions into clear, reusable categories (e.g., &amp;ldquo;read‑only access to production databases&amp;rdquo;). Using Ansible, the configuration of each rule was automated, ensuring consistency across environments. For example, developers were granted access only to their designated servers, while application instances had limited permissions to prevent lateral movement. The process prioritized clarity over complexity, with each rule explicitly tied to a specific role and system.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The implementation secured over 1,000 rules without introducing unnecessary complexity, reducing unauthorized access risks by 85%. Automation streamlined deployment, cutting setup time by 60% compared to manual methods. The documented framework allowed teams to quickly audit or modify rules, ensuring scalability as the infrastructure grew. By focusing on simplicity and volume, the solution achieved robust security while maintaining operational efficiency.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Automated GIS SaaS application deployment, data processing, and reporting system using GitHub Actions CI/CD, Python, Bash, and SQL.</title>
    <id>https://platform.engineer.company/portfolio/automated-gis-saas-application-deployment-data-processing-and-16/</id>
    <link href="https://platform.engineer.company/portfolio/automated-gis-saas-application-deployment-data-processing-and-16/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Pipelines (ETL/ELT)" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="GIS / Geospatial" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="SQL" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Pipeline Development (ETL/ELT)" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="GIS &amp; Geospatial Solutions" scheme="https://platform.engineer.company/services/" />
    <summary>Automated GIS SaaS deployment, data processing and reporting with GitHub Actions CI/CD, Python, Bash and SQL — shorter, reliable releases.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; At Utiligize, getting the GIS SaaS app deployed, processing its data and producing the reports were all manual steps — and manual steps are both slow and quietly dangerous. Every release ate engineering time and carried the chance of a slip, and the recurring data and reporting work sat there eating capacity week after week.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Automating the whole path from code to production, plus the recurring data‑processing and reporting, was the task — the goal being releases that were fast, safe and repeatable rather than a careful manual ritual each time.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The whole path got automated. GitHub Actions pipelines took over the test‑build‑deploy cycle, so a release stopped depending on someone remembering the steps. The recurring data processing and the reports moved into scheduled Python, Bash and SQL jobs, so they just ran instead of being someone&amp;rsquo;s chore. And the configuration and secrets were standardised so every environment behaved identically — which is what kills the &amp;ldquo;works on my machine&amp;rdquo; surprises, because there stops being a &amp;ldquo;my machine&amp;rdquo; that&amp;rsquo;s different from production.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Deployment, data processing and reporting all became automated and reliable, the manual toil came off the team&amp;rsquo;s plate, and the release cycle got shorter. The team could put its attention on the product instead of the operations wrapped around it.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Automated delivery of 20 GIS data pipelines and app data ETL processes, streamlining infrastructure automation and reporting.</title>
    <id>https://platform.engineer.company/portfolio/automated-delivery-of-20-gis-data-pipelines-and-17/</id>
    <link href="https://platform.engineer.company/portfolio/automated-delivery-of-20-gis-data-pipelines-and-17/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Pipelines (ETL/ELT)" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="GIS / Geospatial" scheme="https://platform.engineer.company/categories/" />
    <category term="Monitoring &amp; Observability" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Pipeline Development (ETL/ELT)" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="GIS &amp; Geospatial Solutions" scheme="https://platform.engineer.company/services/" />
    <summary>Automated 20 GIS data pipelines and app-data ETL processes, streamlining infrastructure automation and delivering dependable, current data.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The platform ran on a lot of GIS data pipelines and application‑data ETL processes, and they were being delivered and watched by hand. Hand‑run pipelines create bottlenecks, they drift out of consistency, and worst of all they carry a constant low risk that one quietly fails and nobody notices until the data&amp;rsquo;s already wrong downstream.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Automating the delivery of those pipelines and ETL processes — so the data flowed reliably and predictably without someone shepherding it — was the task.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Twenty GIS data pipelines and the application‑data ETL came under automated delivery, end to end. The scheduling, the logging and the failure handling got standardised, so every pipeline behaved the same way and, crucially, you could see when one didn&amp;rsquo;t — a silent failure is only silent if nothing&amp;rsquo;s watching. And they were folded into the existing infrastructure automation and reporting, so they were part of one coherent system rather than a drawer full of scripts someone had to remember to run.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; All twenty pipelines and their ETL ran automatically and predictably, and the whole infrastructure‑automation and reporting picture got tidier for it. The business got dependable, current data without anyone having to walk it through by hand — and without the quiet‑failure risk hanging over it.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Automated 100 critical data backups using Barman, Google Cloud, Bash, and Python, ensuring data integrity across databases.</title>
    <id>https://platform.engineer.company/portfolio/automated-100-critical-data-backups-using-barman-google-18/</id>
    <link href="https://platform.engineer.company/portfolio/automated-100-critical-data-backups-using-barman-google-18/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud" scheme="https://platform.engineer.company/categories/" />
    <category term="Databases" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="PostgreSQL" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Backup &amp; Disaster Recovery" scheme="https://platform.engineer.company/services/" />
    <category term="Database Administration (DBA)" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <summary>Automated 100 critical database backups with Barman, Google Cloud, Bash and Python — turning data recoverability into a tested fact.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The critical GIS data, the application instances and the databases were scattered across systems with backups that were inconsistent and partly manual. For a product that lives on its data, that&amp;rsquo;s not a risk you can leave sitting — and the day you actually need a backup is precisely the worst day to find out it was incomplete.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The task was to guarantee that all the critical data could be recovered, which meant automating comprehensive, verified backups across the whole estate — verified being the word that matters.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The backup regime was built end to end. A hundred critical data backups got automated, with Barman handling the PostgreSQL side and Google Cloud holding the offsite copies, and the whole thing was orchestrated and validated with Bash and Python — because a backup you&amp;rsquo;ve taken but never checked isn&amp;rsquo;t really a backup, it&amp;rsquo;s a hope. So there were retention policies to keep them current and integrity checks to confirm each one was actually good, not just present.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Backups ran automatically and were verifiable across every database, which turned data recoverability from an assumption into something tested. A major operational risk came off the business and got replaced with a recovery path you could actually trust — the difference being that this one had been checked, not just configured.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Deployed and maintained 20 Docker containerized applications, troubleshooting with Podman and Kubernetes, and managing R‑based apps on Google Cloud and AWS.</title>
    <id>https://platform.engineer.company/portfolio/deployed-and-maintained-20-docker-containerized-applications-troubleshooting-19/</id>
    <link href="https://platform.engineer.company/portfolio/deployed-and-maintained-20-docker-containerized-applications-troubleshooting-19/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud" scheme="https://platform.engineer.company/categories/" />
    <category term="Containers (Docker/Kubernetes)" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Analytics" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud Infrastructure &amp; Migration" scheme="https://platform.engineer.company/services/" />
    <category term="Containerization &amp; Orchestration" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <summary>Deployed and maintained 20 Docker containerized apps across Google Cloud and AWS, troubleshooting with Podman and Kubernetes for stable releases.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; There was a growing set of containerised applications — including some R‑based analytics apps — running across both Google Cloud and AWS. Spread over two clouds and a few container runtimes, they needed to deploy consistently and to be diagnosable quickly when something went wrong, which is harder than it sounds when no two environments are quite the same.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Deploying and maintaining those workloads reliably, and being able to diagnose problems fast across the runtimes and clouds, was the job.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The containerised estate was managed across both clouds — twenty Docker applications deployed and maintained with consistent configuration and monitoring, so they weren&amp;rsquo;t each their own snowflake. When things went wrong, troubleshooting went through Podman and the orchestration debugging through Kubernetes. The R‑based analytics apps got dedicated attention in the Google Cloud and AWS production environments, kept stable and reproducible, which for analytics matters — a result you can&amp;rsquo;t reproduce isn&amp;rsquo;t much of a result.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The containerised estate ran reliably across both clouds, problems got diagnosed faster, and deployments stayed stable and reproducible. The applications the product leaned on stayed dependable no matter which cloud they happened to be running in.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Managed 30 Ubuntu Linux VPS instances, implementing disaster recovery strategies and ensuring optimal network configurations.</title>
    <id>https://platform.engineer.company/portfolio/managed-30-ubuntu-linux-vps-instances-implementing-disaster-20/</id>
    <link href="https://platform.engineer.company/portfolio/managed-30-ubuntu-linux-vps-instances-implementing-disaster-20/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Backup &amp; Disaster Recovery" scheme="https://platform.engineer.company/services/" />
    <category term="Networking &amp; VPN Setup" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>Managed 30 Ubuntu Linux VPS instances with tested disaster-recovery strategies and solid networking — a resilient foundation to grow on.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Utiligize ran on a fleet of Ubuntu Linux VPS instances whose setup had grown organically over time — which is a polite way of saying it had accumulated rather than been designed. That left gaps: inconsistent configurations, and recovery and networking arrangements that were more historical accident than plan.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The task was to get the fleet under proper management, harden the disaster‑recovery side, and make the network configuration consistent and sensible across every instance.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The thirty instances came under deliberate management — treated as one coherent fleet rather than thirty individual pets. Real disaster‑recovery went in: backups, and restore procedures that were actually tested, because an untested restore is just a theory. And the network configuration was standardised for security and performance, so every instance followed the same hardened baseline instead of whatever it had happened to end up with.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The infrastructure became resilient and consistent, with recovery paths that had been tested and networking you could rely on. The downtime risk dropped, and the business ended up with a dependable foundation to grow on rather than a patchwork it had to keep nursing along.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Prevented security breaches by leading access management initiatives, utilizing M365, 1Password, Red Hat SSO, and OKTA SSO.</title>
    <id>https://platform.engineer.company/portfolio/prevented-security-breaches-by-leading-access-management-initiatives-21/</id>
    <link href="https://platform.engineer.company/portfolio/prevented-security-breaches-by-leading-access-management-initiatives-21/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>Led access management with M365, 1Password, Red Hat SSO and OKTA, sharply cutting unauthorised-access risk and making access auditable.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Access to systems and services across Utiligize was managed inconsistently — permissions granted ad hoc, over time, by different people. That&amp;rsquo;s a double problem: it opens the door to access nobody intended, and it makes auditing nearly impossible, because nobody can actually say who can reach what, or why they can.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The goal was to close off the security exposure by centralising and tightening access management across the whole organisation.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The overhaul consolidated the identities and access across M365, 1Password, Red Hat SSO and OKTA SSO, so there was a coherent picture instead of scattered per‑system permissions. Least privilege was enforced — people and systems having exactly what they needed and nothing spare — and the onboarding and offboarding standardised, so access got granted and, just as importantly, revoked promptly and consistently rather than lingering after someone had moved on.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The unauthorised‑access risk dropped sharply and access became auditable and consistent — you could finally answer &amp;ldquo;who can reach this, and why.&amp;rdquo; The odd part is it also made daily life simpler for the team: the right doors opened easily and the wrong ones stayed shut, which is what good access management actually feels like.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Mitigated operational risks by implementing a monitoring dashboard using Grafana and Prometheus, improving system reliability.</title>
    <id>https://platform.engineer.company/portfolio/mitigated-operational-risks-by-implementing-a-monitoring-dashboard-22/</id>
    <link href="https://platform.engineer.company/portfolio/mitigated-operational-risks-by-implementing-a-monitoring-dashboard-22/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Monitoring &amp; Observability" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <summary>Built a Grafana + Prometheus monitoring dashboard that catches problems before they escalate, shifting the team from firefighting to prevention.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Problems at Utiligize usually got noticed after they&amp;rsquo;d already hit users, because there was no single view of how the systems were doing. Without that visibility the team was permanently on the back foot — reacting to things that had already gone wrong instead of seeing them coming.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The aim was to cut the operational risk by giving the team real‑time visibility into the systems they depended on.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The observability layer was built out. A monitoring dashboard on Grafana and Prometheus, the key services instrumented, and — the part that actually matters — metrics that meant something rather than vanity numbers that look busy and tell you nothing. Then alert thresholds set on those, surfaced where the team would actually see them and could act while there was still time to act.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Problems started getting caught and dealt with before they escalated, and system reliability improved for it. The team shifted from reactive firefighting to something calmer and more proactive — catching issues while they were still small enough to be boring.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Managed and troubleshooted 8 WireGuard VPN and IPSEC VPN connections, ensuring secure communication across Google Cloud and Linux systems.</title>
    <id>https://platform.engineer.company/portfolio/managed-and-troubleshooted-8-wireguard-vpn-and-ipsec-23/</id>
    <link href="https://platform.engineer.company/portfolio/managed-and-troubleshooted-8-wireguard-vpn-and-ipsec-23/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Cloud" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN Setup" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>Managed and troubleshot 8 WireGuard and IPSEC VPN connections across Google Cloud and Linux, ending recurring connectivity outages.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Secure connectivity between the cloud and the on‑premises Linux systems ran over several VPN tunnels, and they were fragile and awkward to diagnose when they dropped. A dead tunnel could cut communication between environments, and troubleshooting one was slow and uncertain — you were never quite sure you&amp;rsquo;d found the real cause.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Managing and troubleshooting those connections, to guarantee secure and uninterrupted communication, was the job.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The VPN estate came under control — eight WireGuard and IPSec tunnels across Google Cloud and the Linux systems, managed and troubleshot as a set rather than eight separate mysteries. Their configuration was standardised so they were consistent and understandable instead of each being its own special case, and their health was monitored, with the recurring routing and key‑exchange problems tackled at the root rather than papered over with a restart.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; All eight tunnels ran securely and reliably, communication between environments stayed protected, and the recurring connectivity incidents that used to interrupt work stopped happening. Fixing the root causes rather than nursing the symptoms is what turned them from a recurring headache into something that just worked.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Improved team communication and collaboration by implementing Slack, Mattermost, 1Password, and Jira, saving 8,000 hours of labor.</title>
    <id>https://platform.engineer.company/portfolio/improved-team-communication-and-collaboration-by-implementing-slack-34/</id>
    <link href="https://platform.engineer.company/portfolio/improved-team-communication-and-collaboration-by-implementing-slack-34/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Agile &amp; Scrum" scheme="https://platform.engineer.company/categories/" />
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Project Management" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Team Leadership" scheme="https://platform.engineer.company/categories/" />
    <category term="Project Management (Agile)" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="Team Building &amp; Mentoring" scheme="https://platform.engineer.company/services/" />
    <summary>Saved ~8,000 hours by rolling out Slack, Mattermost, 1Password and Jira, turning chased information and redone work into real delivery.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; As the team got bigger, the communication and the tooling hadn&amp;rsquo;t kept up, and it showed. Things got said in one place and missed by the people who needed them, work got duplicated because nobody could see what someone else had already done, and coordinating anything took longer than the work itself. That kind of friction is invisible day to day, but it adds up to a lot of lost time.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The aim was to fix how the team communicated and worked together, and claw back the time being quietly bled to all that friction.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The tools got brought in and standardised, and — this is the part that actually matters — the practices for using them were set so they didn&amp;rsquo;t just become another place to check. Slack and Mattermost for communication, 1Password so shared secrets weren&amp;rsquo;t being passed around in ways nobody could track, Jira so work was tracked in one place instead of living in people&amp;rsquo;s heads and inboxes. The tools were the easy bit; getting everyone to actually use them the same way was the real work.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Communication and collaboration got noticeably better, and the streamlined setup saved something on the order of 8,000 hours of labour — time that had been going into chasing information and redoing work, now going into actual delivery.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Overhauled internal processes, saving 8,000 hours by improving software architecture, systems, and scheduling efficiency.</title>
    <id>https://platform.engineer.company/portfolio/overhauled-internal-processes-saving-8-000-hours-by-38/</id>
    <link href="https://platform.engineer.company/portfolio/overhauled-internal-processes-saving-8-000-hours-by-38/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Performance Tuning" scheme="https://platform.engineer.company/categories/" />
    <category term="Platform Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="Project Management" scheme="https://platform.engineer.company/categories/" />
    <category term="Solution Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="Technical Leadership" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Platform &amp; Solution Architecture" scheme="https://platform.engineer.company/services/" />
    <category term="Project Management (Agile)" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Leadership &amp; Consulting" scheme="https://platform.engineer.company/services/" />
    <summary>Overhauled internal processes to save ~8,000 hours, improving software architecture, systems and scheduling efficiency.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The way things were done internally had accumulated the usual cruft — software architecture that had grown by accretion rather than design, systems that worked but not efficiently, scheduling that left people either waiting or slammed. None of it was on fire, which is exactly why it had been left alone, but it was quietly costing a lot of time.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The aim was to overhaul those processes — to go find the waste and take it out rather than keep paying for it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The internal processes got reworked across three fronts: the software architecture, so it was something you could reason about and build on instead of work around; the systems, streamlined so the routine work stopped taking longer than it should; and the scheduling, so capacity was actually matched to the work. And the changes were made to stick — embedded in how the team operated rather than left as a memo everyone nodded at and forgot — because process improvements that aren&amp;rsquo;t made permanent just decay back to the old way.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The overhaul saved roughly 8,000 hours by making the architecture, systems and scheduling meaningfully more efficient. That&amp;rsquo;s capacity that went straight back into higher‑value work instead of into overhead nobody had thought to question.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Administered network infrastructure for over 1,000 servers, ensuring optimal system deployment, security, and troubleshooting.</title>
    <id>https://platform.engineer.company/portfolio/administered-network-infrastructure-for-over-1-000-servers-39/</id>
    <link href="https://platform.engineer.company/portfolio/administered-network-infrastructure-for-over-1-000-servers-39/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN Setup" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>Administered network infrastructure for 1,000+ servers, ensuring reliable deployment, solid security and prompt troubleshooting.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The company&amp;rsquo;s operations sat on top of a big server estate — over a thousand of them — and an estate that size doesn&amp;rsquo;t stay reliable on its own. Deployment, security and the steady stream of things that go wrong all need someone running them with actual discipline, or the whole thing gets flaky and nobody&amp;rsquo;s quite sure why.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Administering that network infrastructure was the job — keeping it secure, keeping it reliable, keeping it consistent at a scale where inconsistency is what kills you.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The network infrastructure ran across more than a thousand servers. How systems got deployed was standardised, so a server came up the same predictable way instead of each one being a little bit bespoke; the security was hardened rather than trusting that nobody would come looking; and the troubleshooting got handled when something did break. At that scale the standardisation is what saves you — a thousand snowflakes is unmanageable, a thousand of the same thing is just work.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The estate ran with reliable deployment, solid security and problems that got dealt with promptly instead of festering. That&amp;rsquo;s the kind of infrastructure work that&amp;rsquo;s invisible when it&amp;rsquo;s going well, which is the point — it was the stable backbone everything else at the company ran on.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Automated SSL/TLS certificate creation for 100 Docker applications, ensuring secure connections across Ubuntu Linux hosts.</title>
    <id>https://platform.engineer.company/portfolio/automated-ssl-tls-certificate-creation-for-100-docker-41/</id>
    <link href="https://platform.engineer.company/portfolio/automated-ssl-tls-certificate-creation-for-100-docker-41/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Containers (Docker/Kubernetes)" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Containerization &amp; Orchestration" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <summary>Automated SSL/TLS certificates for 100 Docker apps on Ubuntu Linux, ending manual renewals and the outages expired certs cause.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A hundred Docker applications all needed SSL/TLS certificates, and certificates are the kind of thing that&amp;rsquo;s fine right up until they aren&amp;rsquo;t. Issuing and renewing a hundred of them by hand is slow, it&amp;rsquo;s dull, and it&amp;rsquo;s exactly the sort of manual job where one forgotten renewal takes an app down with an expiry error at the worst possible moment.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The goal was certificate creation and renewal automated — every app with valid, trusted encryption, and nobody having to remember to do anything.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; An ACME‑based workflow handled the whole lifecycle for the hundred Docker applications — creating the certificates and renewing them before they lapsed — and deployed them automatically across the Ubuntu Linux hosts, which were running a mix of Apache and Nginx. The whole aim was to take the human out of it, because the human is the part that forgets.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; All hundred applications kept valid certificates and secure connections on their own. The manual certificate work just disappeared, and with it the whole category of outage where something breaks not because it failed but because a cert quietly expired and nobody noticed.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Streamlined CI/CD processes, saving 4,000 hours by introducing automation in software development pipelines.</title>
    <id>https://platform.engineer.company/portfolio/streamlined-ci-cd-processes-saving-4-000-hours-42/</id>
    <link href="https://platform.engineer.company/portfolio/streamlined-ci-cd-processes-saving-4-000-hours-42/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Technical Leadership" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Leadership &amp; Consulting" scheme="https://platform.engineer.company/services/" />
    <summary>Streamlined CI/CD to save ~4,000 hours, making releases faster and more reliable so the team could ship with confidence.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Getting software out the door relied on manual, inconsistent steps — someone remembering the sequence, doing it slightly differently each time — and it slowed releases down and ate engineering hours that should have gone into building things.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The aim was to streamline the CI/CD process and get automation into the pipelines, so releases stopped being a manual ritual.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Automated build, test and deployment pipelines went in, so the path from a change to it running in production was standardised instead of improvised. The repetitive manual steps — the ones that were slow and, worse, done differently depending on who was doing them — came out. Once the pipeline is doing it the same way every time, a whole class of &amp;ldquo;it worked on my machine&amp;rdquo; and half‑remembered deploy steps just stops happening.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The automation gave back roughly 4,000 hours and made releases both faster and more reliable. The team could ship without bracing for it — the confidence came from the process being consistent, not from everyone being careful.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Streamlined data analysis and software development processes, saving 4,000 hours by introducing GitHub, GitLab, Bash, and Python CI/CD practices.</title>
    <id>https://platform.engineer.company/portfolio/streamlined-data-analysis-and-software-development-processes-saving-43/</id>
    <link href="https://platform.engineer.company/portfolio/streamlined-data-analysis-and-software-development-processes-saving-43/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Analytics" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Pipelines (ETL/ELT)" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Analytics &amp; BI Dashboards" scheme="https://platform.engineer.company/services/" />
    <category term="Data Pipeline Development (ETL/ELT)" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <summary>Saved ~4,000 hours by introducing GitHub, GitLab, Bash and Python CI/CD, speeding data analysis and development while adding consistency.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Both the data‑analysis work and the software development were being held back by the same thing: manual processes. Work moved from development to delivery in a slow, inconsistent way, and the analysis side had its own pile of repetitive steps someone was doing by hand every time.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The aim was to streamline both by bringing modern automation and CI/CD practices to workflows that hadn&amp;rsquo;t had them.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; CI/CD practices went in, built on GitHub and GitLab, with Bash and Python doing the automation work underneath. The repetitive steps across both the data‑analysis and the development workflows got automated, and how work moved from development through to delivery got standardised so it was the same every time rather than reinvented per project. Bringing the analysis side into the same disciplined pipeline as the dev work was a big part of it — it had been treated as a separate, more manual world.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The streamlined processes saved roughly 4,000 hours and sped up both the data analysis and the software development, and just as usefully made what got shipped more consistent — fewer surprises from work that had been done a slightly different way each time.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Automated data processing tasks using Shell scripting, PL/pgSQL, Python, and Transact‑SQL, increasing productivity and efficiency.</title>
    <id>https://platform.engineer.company/portfolio/automated-data-processing-tasks-using-shell-scripting-pl-45/</id>
    <link href="https://platform.engineer.company/portfolio/automated-data-processing-tasks-using-shell-scripting-pl-45/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Pipelines (ETL/ELT)" scheme="https://platform.engineer.company/categories/" />
    <category term="Databases" scheme="https://platform.engineer.company/categories/" />
    <category term="PostgreSQL" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="SQL" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Pipeline Development (ETL/ELT)" scheme="https://platform.engineer.company/services/" />
    <category term="Database Administration (DBA)" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <summary>Automated data-processing tasks with Shell, PL/pgSQL, Python and Transact-SQL, lifting productivity and ending small recurring errors.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; There was a steady load of recurring data‑processing work being done by hand. Manual data work has two problems at once: it eats time, and it&amp;rsquo;s inconsistent — do the same task by hand enough times and it&amp;rsquo;ll get done slightly differently, and some of those differences are errors.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The aim was to automate these tasks, both to get the time back and to make them reliable.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The data‑processing work got automated across the databases and systems it touched, using whatever fit the job — Shell scripting for the glue, PL/pgSQL and Transact‑SQL down in the databases, Python where it needed more than SQL could give. Manual steps got replaced with jobs that ran the same way every time, which is the whole point: a script doesn&amp;rsquo;t get bored, doesn&amp;rsquo;t skip a step, and doesn&amp;rsquo;t do it differently on a Friday afternoon.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Productivity and efficiency both went up, the manual effort came off people&amp;rsquo;s plates, and the data processing became consistent and dependable instead of a source of small, recurring errors.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Configured and deployed 1,000 Wi‑Fi routers, improving network accessibility and performance for clients.</title>
    <id>https://platform.engineer.company/portfolio/configured-and-deployed-1-000-wi-fi-routers-48/</id>
    <link href="https://platform.engineer.company/portfolio/configured-and-deployed-1-000-wi-fi-routers-48/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="IT Support &amp; Helpdesk" scheme="https://platform.engineer.company/services/" />
    <category term="Networking &amp; VPN Setup" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>Configured and deployed 1,000 Wi-Fi routers with a standard setup, giving clients dependable wireless access and performance.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Clients needed wireless that just worked, and that came down to configuring and rolling out a large number of Wi‑Fi routers — and doing it the same careful way every time, because a router set up sloppily is either insecure or slow, and usually you find out which one later.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Configuring and deploying those routers to give clients better network access and performance was the job.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; A thousand Wi‑Fi routers got configured and deployed. The trick at that number is standardising the setup — a consistent, secure, sensible configuration — rather than tuning each one from scratch on the day, because a thousand hand‑crafted routers is a thousand different things to support later. So they were set up for security and performance the same way each time, and rolled out reliably across client sites.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The thousand routers gave clients dependable wireless — better access, better performance — and did it consistently, because the setup was standard rather than improvised. A router nobody has to think about again is the goal; most of these got there.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Administered 100 Bare Bone servers, physical networks, and IP telephony systems, ensuring robust infrastructure for company growth.</title>
    <id>https://platform.engineer.company/portfolio/administered-100-bare-bone-servers-physical-networks-and-50/</id>
    <link href="https://platform.engineer.company/portfolio/administered-100-bare-bone-servers-physical-networks-and-50/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN Setup" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>Administered 100 bare-bone servers, physical networks and IP telephony, providing the robust foundation the company grew on.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Underneath everything the company did was the physical stuff — servers, the actual networks, the IP‑telephony — and it all had to just run. That layer is invisible when it works and extremely visible the moment it doesn&amp;rsquo;t, and the company&amp;rsquo;s growth was resting on it staying dependable.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Administering that infrastructure and keeping it stable as the company grew was the job.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; A hundred bare‑bone servers, along with the physical networks and the IP‑telephony systems, were looked after — the setup, the maintenance, the troubleshooting when something went wrong. Bare‑bone servers mean dealing with the hardware directly, so there&amp;rsquo;s a hands‑on, physical side to it: the cabling, the boxes, the phone system that everyone notices the second a call drops. The job was to keep all of it boring, in the good sense.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The servers, the networks and the telephony ran reliably, and that dependable physical foundation is what let the company keep growing without the ground shifting underneath it.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Administered 40 websites on Ubuntu Linux hosting servers with Apache and Nginx, ensuring high availability and performance.</title>
    <id>https://platform.engineer.company/portfolio/administered-40-websites-on-ubuntu-linux-hosting-servers-53/</id>
    <link href="https://platform.engineer.company/portfolio/administered-40-websites-on-ubuntu-linux-hosting-servers-53/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Performance Tuning" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Web Development" scheme="https://platform.engineer.company/categories/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <category term="Website Development &amp; CMS" scheme="https://platform.engineer.company/services/" />
    <summary>Administered 40 websites on Ubuntu Linux with Apache and Nginx at high availability and performance — hosting clients never had to think about.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; There was a portfolio of live websites that needed to stay up and stay fast — and hosting is another of those jobs that&amp;rsquo;s invisible until a site goes down, at which point it&amp;rsquo;s the only thing anyone cares about.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Administering those sites and keeping them highly available and quick was the job.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Forty websites ran on Ubuntu Linux hosting servers, on a mix of Apache and Nginx — the configuration, the performance tuning, the ongoing maintenance to keep them reliable under real traffic. Real traffic is the operative bit: a site that&amp;rsquo;s fine when nobody&amp;rsquo;s using it and falls over when they are hasn&amp;rsquo;t been administered, it&amp;rsquo;s just been left alone. So the work was keeping them healthy under actual load.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; All forty ran with high availability and good performance, which gave clients hosting they didn&amp;rsquo;t have to think about. Stable and dependable under real use is the entire point of hosting, and that&amp;rsquo;s what these delivered.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Architected, developed, implemented, supported infrastructure, data processing, and the map application for 2 years non‑stop without any weekends, holidays, or vacations, 10–14 hours a day.</title>
    <id>https://platform.engineer.company/portfolio/architected-developed-implemented-supported-infrastructure-data-processing-and-55/</id>
    <link href="https://platform.engineer.company/portfolio/architected-developed-implemented-supported-infrastructure-data-processing-and-55/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Data Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Pipelines (ETL/ELT)" scheme="https://platform.engineer.company/categories/" />
    <category term="Full‑Stack Development" scheme="https://platform.engineer.company/categories/" />
    <category term="GIS / Geospatial" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Platform Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Pipeline Development (ETL/ELT)" scheme="https://platform.engineer.company/services/" />
    <category term="Full‑Stack Product Development" scheme="https://platform.engineer.company/services/" />
    <category term="GIS &amp; Geospatial Solutions" scheme="https://platform.engineer.company/services/" />
    <category term="Platform &amp; Solution Architecture" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <summary>Architected, built and ran the infrastructure, data processing and map app for two years non-stop — the dependable backbone of the product.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; An early‑stage green‑energy startup depended on a single platform to track, monitor, and optimize renewable energy assets, yet had neither a dedicated infrastructure team nor an established engineering organization to build and operate it. The entire technical foundation — cloud infrastructure, data‑processing pipelines, and the customer‑facing GIS map application — had to be created and kept running continuously, in a market where any downtime or data gap directly eroded customer trust and revenue.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The task was to single‑handedly architect, build, and operate the whole system end to end, spanning platform and data engineering, DevOps, and site reliability. Beyond writing the software, this meant owning production: provisioning and hardening infrastructure, designing the data‑processing layer that fed the map, and guaranteeing the application stayed available around the clock for a growing customer base — all within the constraints and relentless pace of a fast‑moving startup.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; For two years the infrastructure, data pipelines, and map application were designed, implemented, and supported without interruption — no weekends, holidays, or vacations, often ten to fourteen hours a day. A pragmatic, modular architecture was chosen to keep a one‑person operation maintainable, with automated provisioning, monitoring, and alerting so issues could be detected and resolved quickly. Data processing was continuously tuned for reliability and performance, releases were shipped incrementally, and every layer — from servers to the user‑facing map — was personally maintained and improved in response to real customer usage.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The platform stayed continuously available and evolved from a fragile early prototype into the dependable backbone of the product, sustaining the company through its critical growth phase on the strength of a single engineer&amp;rsquo;s ownership. This hands‑on stewardship kept infrastructure, data, and the map application reliable enough to support upsells, data licensing, and new‑customer acquisition, and demonstrated a rare degree of commitment, breadth, and end‑to‑end accountability across the full stack.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Optimized budget costs 10 times with zero loss in productivity for the Saudi Arabia company by reimagining the overall infrastructure, eliminating unnecessary services, and relocating from the AWS cloud.</title>
    <id>https://platform.engineer.company/portfolio/optimized-budget-costs-10-times-with-zero-loss-56/</id>
    <link href="https://platform.engineer.company/portfolio/optimized-budget-costs-10-times-with-zero-loss-56/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Cloud" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Migrations &amp; Modernization" scheme="https://platform.engineer.company/categories/" />
    <category term="Platform Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="Solution Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud Infrastructure &amp; Migration" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Platform &amp; Solution Architecture" scheme="https://platform.engineer.company/services/" />
    <summary>Cut infrastructure budget 10x with zero productivity loss for a Saudi company by re-imagining the stack and moving off AWS.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A company operating out of Saudi Arabia was carrying badly bloated infrastructure costs. Their AWS setup had been over‑provisioned and had collected services they no longer used, so the cloud bill had drifted completely out of proportion to what the business actually needed. It&amp;rsquo;s a common story — nobody sets out to overspend, it just accretes when no one&amp;rsquo;s watching the meter.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The engagement was to cut the costs substantially without losing any productivity, which meant rethinking the infrastructure properly rather than trimming round the edges — edge‑trimming rarely moves a bill that&amp;rsquo;s structurally too big.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; So the work went end to end. First came an audit of what was actually being used — which is where the duplicated and unnecessary services show themselves — and those got cut. Then whatever was left was right‑sized to match real demand instead of the worst‑case guesses the original setup had been built on. And the big move was relocating the workloads off AWS entirely, onto a more cost‑effective hosting arrangement — done carefully, in stages, so the running business never felt the migration happening underneath it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The budget costs fell roughly ten‑fold, with zero loss in productivity — the same capability at a fraction of what they&amp;rsquo;d been paying. It freed up a real amount of money that had quietly been leaking into an oversized cloud bill month after month, which for the business was money straight back to the bottom line.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Designed an organization context‑switching system with client localStorage and server‑side cookie mirroring, letting users act as managed organizations while enforcing least‑privilege authorization.</title>
    <id>https://platform.engineer.company/portfolio/designed-an-organization-context-switching-system-with-client-59/</id>
    <link href="https://platform.engineer.company/portfolio/designed-an-organization-context-switching-system-with-client-59/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="APIs &amp; Integration" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Frontend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Full‑Stack Development" scheme="https://platform.engineer.company/categories/" />
    <category term="Platform Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend &amp; API Development" scheme="https://platform.engineer.company/services/" />
    <category term="Frontend Development" scheme="https://platform.engineer.company/services/" />
    <category term="Platform &amp; Solution Architecture" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <summary>Built organization context-switching with localStorage and server cookie mirroring, letting users act as managed orgs under least-privilege auth.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; On NextMariner a maritime professional can manage organizations — companies, academies — that don&amp;rsquo;t have their own logins. The person is the account; the organization is something they act on behalf of. So a user needs to move through the whole app as any organization they manage, switching between them freely, and that convenience can&amp;rsquo;t turn into a hole in the authorization.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Context‑switching had to be quick and unobtrusive for the user while making sure the active context could never, on its own, hand someone access they weren&amp;rsquo;t entitled to.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; An OrganizationContext handles it, with storage on both sides. On the client, localStorage is the source of truth for which organization you&amp;rsquo;re currently acting as, so switching is instant — no round‑trip. A server‑side cookie mirrors it so that server‑rendered pages resolve the same context during SSR; there&amp;rsquo;s a getServerViewMode on the server that reads it. The important part is that none of that is trusted for access decisions. Authorization gets re‑checked on the server on every request. The frontend context is there for the experience — showing you the right thing — and the server is the only authority on what you&amp;rsquo;re allowed to do.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; A user can act as any organization they manage without friction, and the interface stays in sync on both client and server. But because permissions are verified server‑side every time, none of that convenience weakens the security. Someone tampering with what&amp;rsquo;s in localStorage changes what their own UI shows them and nothing more — the server still says no.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Generated the API contract outward from the database — OpenAPI, a 44,076‑line typed TypeScript client, 61 mock handlers and the limits the UI enforces — with a guard at every hop that fails on drift.</title>
    <id>https://platform.engineer.company/portfolio/built-a-request-schema-validation-contract-with-automated-61/</id>
    <link href="https://platform.engineer.company/portfolio/built-a-request-schema-validation-contract-with-automated-61/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="APIs &amp; Integration" scheme="https://platform.engineer.company/categories/" />
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend &amp; API Development" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <summary>Generated the API contract from the database outward — OpenAPI, a typed TypeScript client, mock handlers and UI limits — with a guard at every hop.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Frontend and backend move at their own pace, and their assumptions about a request payload can drift apart without anyone noticing. The way you usually find out is a 422 in the browser — after the mismatch has already shipped, which is the most expensive moment to learn about it. Writing the two sides by hand from the same document does not fix it; it just moves the drift to whoever forgot to reread the document.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The two sides had to be generated from one source rather than agreed between two, with every step of the generation checked instead of trusted.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The chain starts at the database and runs outward. The schema and its functions define the shapes; the Go types define the API; Huma emits the OpenAPI description from those; a typed TypeScript client — 44,076 lines of it — is generated from that description; 61 mock handlers are generated alongside it so the frontend&amp;rsquo;s own tests run against the real contract rather than a hand‑written fixture; and the limits the UI enforces on a form come from the same place instead of being retyped into a validator. Every hop has a guard. A contract check in CI compares what the frontend sends against what the API expects and fails the build on divergence, with a schema probe underneath it that checks the real shapes rather than a description of them. It deliberately covers where drift likes to hide: optional body fields, where &amp;ldquo;missing&amp;rdquo; and &amp;ldquo;null&amp;rdquo; get confused, and query‑parameter enums, where the two sides can quietly disagree on the allowed values.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; A field cannot change on one side only — it fails at the first hop that notices, in a build, minutes after the change. That took out a recurring and genuinely annoying class of bug, the kind invisible in code review that only shows up at runtime. The cost is a generation step in the middle of everything: regenerating is a chore, and the chain is only as trustworthy as its least‑guarded link, which is why each hop got one.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Built email as a platform capability — three providers with failover, delivery webhooks, send and delivery logging, templating and campaigns — behind a startup check that will not boot without one.</title>
    <id>https://platform.engineer.company/portfolio/built-email-as-a-platform-capability-with-failover-62/</id>
    <link href="https://platform.engineer.company/portfolio/built-email-as-a-platform-capability-with-failover-62/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="APIs &amp; Integration" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend &amp; API Development" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <summary>Built email as a platform capability: three providers with failover, delivery webhooks, send and delivery logging, templating and campaign broadcasts.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Email carries a lot of weight on NextMariner — verification, notifications, digests, campaigns, the things a user actually waits for. And a mail provider is exactly the kind of dependency that fails quietly: the config looks fine, the app boots, and you only find out something&amp;rsquo;s broken when a real person never gets the message they were promised. That&amp;rsquo;s the worst way to learn about it. One provider makes it worse, because the failure is total and someone else&amp;rsquo;s to fix.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Email had to be treated as a capability the platform owns rather than a client library it calls — able to survive a provider outage, able to say what happened to a given message, and loud at startup in the environments where silence is dangerous.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Three providers sit behind one interface — SendGrid as primary, with SMTP2GO and Azure Communication Services behind it — and failover between them is automatic rather than a configuration change made under pressure. Delivery is not assumed: inbound webhooks report what each provider did with a message, and both sides are recorded, in a send log and a delivery event table, so &amp;ldquo;did this person get their verification mail&amp;rdquo; is a query rather than a guess. Templating keeps the message bodies out of the code, and a separate broadcast schema — 5 tables and 24 functions — carries campaigns to segments of users, which is a different problem from transactional mail and was built as one. In front of all of it, a startup check sends a real message through the stack, behind a flag: in development it logs a warning and carries on, because nobody wants their laptop refusing to start over an expired sandbox key, and in staging and production a failure is fatal and the process exits rather than deploy a build that cannot send mail. The send path itself goes through an SSRF‑protected client with a 30‑second timeout, and the async delivery path has retries and backoff so a momentary blip doesn&amp;rsquo;t drop a message.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; A whole category of silent failure moved from &amp;ldquo;a user notices days later&amp;rdquo; to &amp;ldquo;the deploy stops&amp;rdquo;, and a provider having a bad afternoon became a degraded path rather than an outage. The cost is three integrations to keep working instead of one, and delivery logs that grow and have to be pruned — both accepted, because email is the channel the platform cannot route around.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Provisioned Azure infrastructure as code with Bicep — Container Apps, PostgreSQL Flexible Server, Front Door/WAF and networking — across the development, staging and production environments.</title>
    <id>https://platform.engineer.company/portfolio/provisioned-azure-infrastructure-as-code-with-bicep-container-68/</id>
    <link href="https://platform.engineer.company/portfolio/provisioned-azure-infrastructure-as-code-with-bicep-container-68/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN" scheme="https://platform.engineer.company/categories/" />
    <category term="Platform Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud Infrastructure &amp; Migration" scheme="https://platform.engineer.company/services/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="Networking &amp; VPN Setup" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <summary>Provisioned Azure infrastructure as code with Bicep — Container Apps, PostgreSQL, Front Door/WAF — reproducible across dev, staging and prod.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; NextMariner lives on Azure, and Azure done by hand — clicking through the portal, tweaking a setting here and there — is a trap. It drifts, nobody remembers why something is the way it is, and rebuilding it after a bad day is slow and nerve‑wracking. With more than one environment to keep in step, that only gets worse.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Put the whole thing in code, so an environment is something you can read, review and recreate rather than a pile of manual state.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The estate is defined in Bicep. Each environment — testing, staging, product — comes out of the same templates: the api and www running as Azure Container Apps on a managed environment, a PostgreSQL Flexible Server, Redis for caching, Front Door with a WAF policy out in front, and the networking underneath it (VNet, NSG, private DNS), with Log Analytics wired in for diagnostics. Images are pulled from the project&amp;rsquo;s Azure Container Registry. Because it&amp;rsquo;s all parameterised, standing up a fresh environment or changing an existing one is a pull request, not a support ticket to yourself.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The environments became reproducible and reviewable. Drift stopped being a mystery, because the source of truth is the code, and bringing infrastructure up or back is a matter of applying the templates rather than remembering what got clicked last time. It&amp;rsquo;s the difference between infrastructure you own and infrastructure that owns you.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Built GitHub Actions CI/CD pipelines with a distroless production frontend image and multi‑environment promotion.</title>
    <id>https://platform.engineer.company/portfolio/built-github-actions-ci-cd-pipelines-with-a-69/</id>
    <link href="https://platform.engineer.company/portfolio/built-github-actions-ci-cd-pipelines-with-a-69/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud" scheme="https://platform.engineer.company/categories/" />
    <category term="Containers (Docker/Kubernetes)" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Containerization &amp; Orchestration" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <summary>Built GitHub Actions CI/CD with a distroless production frontend image and multi-environment promotion, making releases routine and boring.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Shipping shouldn&amp;rsquo;t depend on someone remembering the steps, and what ends up running in production shouldn&amp;rsquo;t be a fat general‑purpose container carrying a shell and a package manager it&amp;rsquo;ll never use — that&amp;rsquo;s just attack surface sitting there for no reason.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Make the path from commit to running‑in‑Azure automatic, and keep the production images as small and locked‑down as each workload allows.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The pipeline is GitHub Actions. Separate workflows handle the code‑quality gate, the tests, and the per‑environment deploys, with CodeQL, dependency review and an SBOM step alongside them, so nothing reaches an environment without passing the checks first. The images are multi‑stage builds, and the base for each part was picked on its merits rather than as one blanket choice: the frontend ships on a distroless image (gcr.io/distroless/cc‑debian13 — no shell, no package manager), the Go API on a slim Alpine, and the database image on postgres‑slim. Promotion moves a build through the environments along a defined route rather than by hand.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Releases stopped being a careful manual ritual and became a routine, boring event, which is exactly what you want from releases. The production frontend runs on about as little as you can give it, the checks catch problems before they land, and &amp;ldquo;deploy&amp;rdquo; is something the pipeline does rather than something anyone sweats through.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Authored 578 go‑task automation targets spanning native, Docker and HTTPS dev modes, linting, testing, database and deployment.</title>
    <id>https://platform.engineer.company/portfolio/authored-578-go-task-automation-targets-70/</id>
    <link href="https://platform.engineer.company/portfolio/authored-578-go-task-automation-targets-70/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Technical Leadership" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Documentation" scheme="https://platform.engineer.company/services/" />
    <summary>Authored 578 go-task automation targets across native, Docker and HTTPS modes — linting, testing, database and deployment behind one toolchain.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; NextMariner is a polyglot monorepo — Go, TypeScript, SQL, Python, shell — and every one of those brings its own way to build, test, lint and run. Left alone, that means everyone carrying a mental cheat‑sheet of tool‑specific commands, and newcomers spending their first day just working out how to make things go.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Give the whole project one front door: a single, consistent way to run anything, whatever language it happens to be written in.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; That&amp;rsquo;s built out with go‑task — a Taskfile layer that has grown to 578 named targets, 50 in the root file and 528 in namespaced files beneath it. There are the development modes (native, Docker, an HTTPS variant for testing PWA and mobile), the code‑quality side (lint, format, test, fix across all the languages), database management, and the environment‑specific build and deploy tasks. There&amp;rsquo;s even a low‑memory mode for machines that can&amp;rsquo;t spare the RAM to build the frontend the usual way. The point was never to have a lot of tasks; it was that you never have to know the underlying command.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Anyone can run task &amp;ndash;list and see the whole toolchain laid out, and run any part of it the same way regardless of what&amp;rsquo;s under the hood. Onboarding got shorter, and the small, stupid mistakes — wrong flag, wrong directory, half‑remembered command — mostly went away. The number is also a warning: 578 targets is past what anyone can hold in their head, so the naming and the namespacing are what keep it usable rather than the count being something to be proud of.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Owned end‑to‑end deployments of the platform to Azure, managing releases across development, staging and production environments.</title>
    <id>https://platform.engineer.company/portfolio/owned-end-to-end-deployments-of-the-platform-71/</id>
    <link href="https://platform.engineer.company/portfolio/owned-end-to-end-deployments-of-the-platform-71/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud Infrastructure &amp; Migration" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <summary>Owned end-to-end Azure deployments, moving releases through dev, staging and production along a defined, repeatable path.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The platform had to reach users across several Azure environments, and deployment is the seam where the infrastructure, the build pipeline and the application all meet. It&amp;rsquo;s also where a small mistake stops being a bug and becomes an outage, so it&amp;rsquo;s the part you least want to be doing by hand and half from memory.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Deployment was owned end to end, so that a change moved out to each environment the same predictable way every time.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Releases move along a fixed route — development, then staging, then production — rather than anyone pushing straight to a live environment. The CI/CD pipeline builds the images and ships them, and the Bicep templates keep the target infrastructure identical from one environment to the next, so a build isn&amp;rsquo;t promoted into a subtly different place each time. Configuration that differs per environment is kept separate from the secrets, which means the same built artefact can be promoted through the environments and just picks up the right settings where it lands, instead of being rebuilt for each one.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Changes reach each environment predictably, along a defined path, with no ad‑hoc manual deploys in the mix. Releasing turned into a controlled, repeatable step instead of a held‑breath moment, and that&amp;rsquo;s a big part of what kept the live platform stable while it was still changing quickly underneath.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Configured database backup retention as infrastructure‑as‑code, then audited the recovery position and documented the restore procedure — naming the remaining gaps rather than leaving them to be found during an incident.</title>
    <id>https://platform.engineer.company/portfolio/configured-database-backup-retention-as-infrastructure-as-code-72/</id>
    <link href="https://platform.engineer.company/portfolio/configured-database-backup-retention-as-infrastructure-as-code-72/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Cloud" scheme="https://platform.engineer.company/categories/" />
    <category term="Databases" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="PostgreSQL" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Backup &amp; Disaster Recovery" scheme="https://platform.engineer.company/services/" />
    <category term="Database Administration (DBA)" scheme="https://platform.engineer.company/services/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <summary>Implemented database backups and an infrastructure-as-code disaster-recovery strategy for fast, reproducible recovery.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A product that lives on its data can&amp;rsquo;t afford to lose any, and &amp;ldquo;there are backups somewhere&amp;rdquo; is a hope, not a recovery plan. The only backup worth having is one you know restores, into an environment you know you can rebuild. NextMariner had neither half written down.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Get the recoverable position defined instead of assumed — the data, the environment around it, and an honest account of how far that actually reaches today.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Backup retention is configured in the Bicep beside the database it protects, so point‑in‑time restore is a property of the template rather than a setting someone once clicked in a portal. The environment around it is defined as infrastructure‑as‑code too, which is the quiet half people forget: restoring a database into an environment you&amp;rsquo;d have to rebuild by hand from memory isn&amp;rsquo;t really recovery. Then the position was audited and written up — the restore procedure, the drill that would measure it, and the gaps still open: geo‑redundancy is switched off, and the recovery‑time objective is proposed rather than measured, because no drill has been run yet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Recovery stopped being a vague reassurance and became a documented position with its gaps named. That reads less impressively than &amp;ldquo;disaster recovery: done&amp;rdquo;, and it is worth considerably more — whoever touches it next knows what is covered, what isn&amp;rsquo;t, and exactly which drill closes the difference. A named gap is one you can close; an unnamed one is discovered during an incident.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Hardened the application with nonce‑based CSP, HSTS, SameSite cookies, least‑privilege database roles and server‑side entitlement re‑checks.</title>
    <id>https://platform.engineer.company/portfolio/hardened-the-application-with-nonce-based-csp-hsts-77/</id>
    <link href="https://platform.engineer.company/portfolio/hardened-the-application-with-nonce-based-csp-hsts-77/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="APIs &amp; Integration" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Databases" scheme="https://platform.engineer.company/categories/" />
    <category term="Frontend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Platform Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend &amp; API Development" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <summary>Hardened the app with nonce-based CSP, HSTS, SameSite cookies, least-privilege database roles and server-side entitlement re-checks.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; NextMariner holds professional and organizational data, the kind people expect to be handled properly, so a single line of defence was never going to be enough. The working assumption has to be that the client is hostile — that anything the browser enforces can be switched off by whoever&amp;rsquo;s holding the browser — and the security has to hold up anyway.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The platform had to be hardened at every layer — frontend, API, database — so that security was enforced by the server independently of whatever the interface happened to allow.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; On the frontend, the Next.js proxy middleware — proxy.ts — sets a Content‑Security‑Policy with a per‑request nonce and strict‑dynamic, plus HSTS and SameSite cookies, so the browser is locked down about what it&amp;rsquo;ll run and send. At the API, there&amp;rsquo;s rate limiting, CORS, request‑size limits, input validation before anything touches the database, and logging of the security‑relevant events. In the database, the API logs in as a least‑privilege role that can only EXECUTE the app functions, the functions run SECURITY DEFINER, and everything is parameterised. And the entitlements — tier, role, organization, ship scoping — are re‑checked on the server on every request, with the frontend gates treated as UX only. The gates decide what you see; the server decides what you can do.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Security doesn&amp;rsquo;t depend on the UI behaving. The protections are layered so that getting past one doesn&amp;rsquo;t get you past the rest, and the whole thing is built on the assumption that the client can&amp;rsquo;t be trusted — which is the right assumption for data people are handing over in confidence.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Set a zero‑warnings quality bar across six languages — Go, TypeScript, SQL, Python, Shell and Markdown — enforced by pre‑commit hooks.</title>
    <id>https://platform.engineer.company/portfolio/set-a-zero-warnings-quality-bar-across-six-79/</id>
    <link href="https://platform.engineer.company/portfolio/set-a-zero-warnings-quality-bar-across-six-79/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Technical Leadership" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Leadership &amp; Consulting" scheme="https://platform.engineer.company/services/" />
    <summary>Set a zero-warnings quality bar across Go, TypeScript, SQL, Python, Shell and Markdown, enforced by pre-commit hooks.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Warnings that pile up are quietly corrosive. Every diagnostic you ignore lowers the bar a little, and once the build spits out forty of them nobody reads any of them, and a real problem sits in that list in plain sight because &amp;ldquo;warnings&amp;rdquo; have become background noise. In a polyglot codebase there are that many more sources of noise to let it happen.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The repo needed one uncompromising quality bar across every language, so things got fixed instead of accumulating.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; A zero‑warnings policy went in, with the tooling as the thing that enforces it, because a policy that relies on everyone&amp;rsquo;s vigilance loses to the first busy week. Every linter diagnostic is an error — there&amp;rsquo;s no &amp;ldquo;warn&amp;rdquo; tier to hide in — and it&amp;rsquo;s the same across the whole stack: Go with golangci‑lint, TypeScript with ESLint, SQL with SQLFluff, Python with Ruff, shell with ShellCheck, Markdown with markdownlint. Inline suppressions are banned, so you can&amp;rsquo;t paper over a diagnostic; you have to actually fix the thing. Pre‑commit and pre‑push hooks run the linters and the tests, so a commit that would introduce a problem doesn&amp;rsquo;t get made in the first place. There are even function- and file‑length limits, to keep modules from sprawling past the point of being readable.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Problems get fixed at the source instead of deferred into a backlog nobody clears, and the codebase stays clean by default rather than by periodic heroics. The standard is identical whatever language you&amp;rsquo;re in, and it&amp;rsquo;s the tooling holding it — not anyone&amp;rsquo;s willpower — which is why it actually holds.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Provided round‑the‑clock 24/7 infrastructure support for an IPTV/OTT streaming platform, administering ~1,000 servers plus client‑owned systems for global customers in China, the US and Germany.</title>
    <id>https://platform.engineer.company/portfolio/provided-round-the-clock-24-7-infrastructure-support-82/</id>
    <link href="https://platform.engineer.company/portfolio/provided-round-the-clock-24-7-infrastructure-support-82/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Cloud" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Monitoring &amp; Observability" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="IT Support &amp; Helpdesk" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>Provided 24/7 infrastructure support for an IPTV/OTT streaming platform — ~1,000 servers plus client systems across China, the US and Germany.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; This was an IPTV/OTT streaming platform with customers spread across China, the US and Germany, which meant there was no quiet hour to do maintenance in — someone, somewhere, was always watching. Downtime on a platform like that isn&amp;rsquo;t an abstract metric; it&amp;rsquo;s someone&amp;rsquo;s television just stopping, and they don&amp;rsquo;t care why.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Keeping the platform&amp;rsquo;s infrastructure available around the clock was the job — genuinely around the clock, not &amp;ldquo;business hours plus an on‑call rota nobody answers.&amp;rdquo;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; 24/7 support ran for roughly a thousand servers, plus a good number of client‑owned systems on top of that — administering them, monitoring them, keeping them secured and configured across the whole streaming estate. Because customers sat in three very different time zones, &amp;ldquo;after hours&amp;rdquo; didn&amp;rsquo;t really exist; a problem at 3am local was primetime for someone else, so it got treated as primetime. A lot of the work was noticing something drifting before it became an outage, because on a live streaming platform you don&amp;rsquo;t get to fix things quietly after the fact.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The platform stayed continuously available for a global audience, with problems caught and dealt with at whatever hour they turned up, before they reached a viewer&amp;rsquo;s screen. On a 24/7 service that&amp;rsquo;s the whole job — success looks like nothing happening, which is exactly what the viewers wanted.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Ensured uninterrupted delivery of IPTV streaming signals between suppliers and clients, monitoring and maintaining the streaming network and IP telephony around the clock.</title>
    <id>https://platform.engineer.company/portfolio/ensured-uninterrupted-delivery-of-iptv-streaming-signals-between-83/</id>
    <link href="https://platform.engineer.company/portfolio/ensured-uninterrupted-delivery-of-iptv-streaming-signals-between-83/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Monitoring &amp; Observability" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN Setup" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>Ensured uninterrupted IPTV streaming between suppliers and clients, monitoring and maintaining the streaming network and IP telephony 24/7.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; IPTV lives or dies on the signal getting through. The streams flow from suppliers, through the platform, to the clients, and any break anywhere in that chain is a black screen for someone. The IP telephony sat alongside it, with the same requirement: it just had to work.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Guaranteeing that the signal delivery and the telephony stayed uninterrupted was the job.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The streaming network and the IP telephony were monitored, troubleshot and maintained around the clock. The point of watching it constantly is that streaming problems announce themselves as degradation before they become an outright drop — a stream that starts stuttering, a link that&amp;rsquo;s getting flaky — and if you&amp;rsquo;re paying attention you can catch it at the stutter instead of the black screen. So a lot of it was staying ahead of the signal rather than reacting to complaints about it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The streams and the calls stayed reliable across the platform, with problems detected and fixed before they turned into service anyone noticed dropping. Keeping a signal flowing between suppliers and end clients without a visible gap is quiet, constant work, and quiet is what it should be.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Planned and implemented new infrastructure functionality for internal and external systems, building solutions durable enough to still run years later with minimal change.</title>
    <id>https://platform.engineer.company/portfolio/planned-and-implemented-new-infrastructure-functionality-for-internal-85/</id>
    <link href="https://platform.engineer.company/portfolio/planned-and-implemented-new-infrastructure-functionality-for-internal-85/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Platform Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Solution Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Platform &amp; Solution Architecture" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>Planned and built infrastructure for internal and external systems durable enough to still run years later with minimal change.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; As the organisation grew, its internal and external systems kept needing new capabilities bolted on. The easy way to do that is whatever&amp;rsquo;s quickest today; the trouble with the easy way is you&amp;rsquo;re back fixing it in six months.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Planning and building infrastructure functionality that would actually last was the task — not just work now, but keep working.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; New infrastructure functionality was planned and implemented across the internal and external systems, designed to be durable — the kind of thing you build once, properly, so it keeps running for years with minimal touching rather than needing constant attention. That&amp;rsquo;s a deliberate choice each time: spend a bit more thought up front so you&amp;rsquo;re not signing yourself up to babysit it forever.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The systems stayed functional and effective long after they were built, running for years with barely any change. That longevity is the real measure of infrastructure work — anyone can make something that works today; making something that&amp;rsquo;s still quietly working years later is the harder and more useful thing.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>As one of the first hires, designed and built the entire core infrastructure and supporting processes from scratch for a green‑energy SaaS startup, laying the foundation for rapid growth.</title>
    <id>https://platform.engineer.company/portfolio/as-one-of-the-first-hires-designed-and-86/</id>
    <link href="https://platform.engineer.company/portfolio/as-one-of-the-first-hires-designed-and-86/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Cloud" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Platform Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Solution Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud Infrastructure &amp; Migration" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Platform &amp; Solution Architecture" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>As one of the first hires, designed and built a green-energy SaaS startup&#39;s entire core infrastructure from scratch, enabling rapid growth.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; This was a green‑energy SaaS startup with a promising idea and essentially no technical foundation under it yet. Coming in as one of the first hires meant the stage where there&amp;rsquo;s nothing to maintain because nothing exists — building the ground everyone else will stand on.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Building the core infrastructure and the processes around it, from scratch, was the job.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The entire core infrastructure and its supporting processes were designed and built — the servers, the networks, the data flow, the security, the operations side. Doing that at a startup means making decisions that are hard to unmake later, so the goal wasn&amp;rsquo;t just &amp;ldquo;get something running,&amp;rdquo; it was to lay a foundation that could take the weight of rapid growth without needing to be ripped out the moment the company got bigger. Early infrastructure choices either become the thing that lets you scale or the thing you spend a year undoing; the aim was firmly the first kind.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The startup came away with a solid technical foundation, and it&amp;rsquo;s what let the business grow quickly afterward. Being the person who builds that base from nothing is a particular kind of responsibility — get it right and nobody notices, get it wrong and everyone does — and this one held up.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Automated team collaboration, password management, task and time management, and built a semi‑automatic project‑showcase system, raising team productivity.</title>
    <id>https://platform.engineer.company/portfolio/automated-team-collaboration-password-management-task-and-time-89/</id>
    <link href="https://platform.engineer.company/portfolio/automated-team-collaboration-password-management-task-and-time-89/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Project Management" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Technical Leadership" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Project Management (Agile)" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <summary>Automated collaboration, password, task and time management and built a semi-automatic project-showcase system, raising team productivity.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A lot of the team&amp;rsquo;s operational work — coordinating, managing passwords, tracking tasks and time — was being done by hand, and manual coordination is a quiet tax: it&amp;rsquo;s never the thing you notice, but it steadily eats hours that could go somewhere better.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Automating that repetitive operational work was the goal.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The pieces that lent themselves to it got automated — team collaboration, password management, task management, time management — with a semi‑automatic project‑showcase system on top. The idea across all of it was to take the routine coordination off people&amp;rsquo;s plates so it ran itself, and let them spend the recovered attention on work that actually needed a human. The showcase system was the same instinct applied to something more visible: make presenting the work mostly automatic rather than a manual chore each time.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Operational efficiency went up and the team got more productive, because the routine coordination that used to need constant human attention now largely ran on its own. The time that was leaking into busywork went back into the actual work.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Integrated a company‑wide password‑management system, strengthening security and streamlining access control.</title>
    <id>https://platform.engineer.company/portfolio/integrated-a-company-wide-password-management-system-strengthening-90/</id>
    <link href="https://platform.engineer.company/portfolio/integrated-a-company-wide-password-management-system-strengthening-90/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>Integrated a company-wide password-management system, strengthening security and streamlining access control across the organisation.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Credentials were being handled inconsistently — different people storing and sharing them in different, ad‑hoc ways — and that inconsistency is itself the security risk. It&amp;rsquo;s rarely a dramatic breach; it&amp;rsquo;s a password in a chat message, a shared login nobody rotates, the slow accumulation of small exposures.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Centralising the credentials and making them secure was the task.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; A company‑wide password‑management system went in, so there was one consistent, secure way credentials got stored and shared instead of everyone&amp;rsquo;s personal habit. The value of company‑wide is exactly that it&amp;rsquo;s not optional per person — a password manager only half the team uses barely helps, because the risk lives in the half that didn&amp;rsquo;t. So the point was to make the secure way the default way, everywhere.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Security improved and access control got simpler and more consistent across the organisation. Once the credentials all live in one managed place, a whole set of small, boring exposures just stop being possible — which is most of what real‑world security actually is.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Built a layered automated test suite — 981 Go tests, 543 frontend and browser specs, 494 SQL behavioural tests — with mutation testing, property‑based tests and an accessibility gate.</title>
    <id>https://platform.engineer.company/portfolio/built-a-layered-automated-test-suite-across-four-layers-94/</id>
    <link href="https://platform.engineer.company/portfolio/built-a-layered-automated-test-suite-across-four-layers-94/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Frontend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="PostgreSQL" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend &amp; API Development" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Leadership &amp; Consulting" scheme="https://platform.engineer.company/services/" />
    <summary>Built a layered automated test suite — 981 Go tests, 543 frontend specs and 494 SQL behavioural tests — with mutation, property and accessibility gates.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A platform that keeps its business logic in the database has a testing problem most projects do not. The logic is not in the language the test framework is good at — it is in SQL, behind function boundaries, and SQL is exactly the sort of code that goes untested because testing it is awkward. Add a Go API and a Next.js frontend on top of that, and &amp;ldquo;the important parts are covered&amp;rdquo; quietly turns into &amp;ldquo;the parts that were easy to cover are covered.&amp;rdquo;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Each layer needed its behaviour checked where that behaviour actually lives, rather than everything being checked from the outside through a browser.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Four layers got four kinds of test. The Go API carries 981 test functions across 310 files. The frontend carries 543 Vitest and Playwright specs, including 48 end‑to‑end files and 30 browser specs. The database carries 494 behavioural test files — 116,876 lines of SQL asserting through 6,654 raised exceptions — so a stored function is tested in the database instead of through three layers of application above it. Above those sit the tests that test the tests: Stryker mutation testing deliberately breaks a line and fails when nothing notices, and fast‑check generates inputs nobody thought to write down. An axe‑core gate asserts zero WCAG 2.0 and 2.1 A and AA violations, which makes accessibility a build failure rather than an audit finding months later. Coverage thresholds only ever move upward. The whole suite runs as 10 jobs in a 612‑line workflow.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Changing something structural stopped being frightening, which is the only thing that keeps a codebase this size from calcifying. The honest cost is time — the suite is slow, it taxes every change, and at this size it needs maintenance of its own. What it buys is the ability to keep moving quickly, and that is worth more than the minutes it takes.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Built the repository&#39;s guard engine — 268 registered commit checks, 277 lint rules and 15 custom ESLint rules — plus 146 tests of the guards themselves, so the build holds the standard, not review.</title>
    <id>https://platform.engineer.company/portfolio/built-the-repository-s-guard-engine-of-268-checks-95/</id>
    <link href="https://platform.engineer.company/portfolio/built-the-repository-s-guard-engine-of-268-checks-95/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Technical Leadership" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Documentation" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Leadership &amp; Consulting" scheme="https://platform.engineer.company/services/" />
    <summary>Built a guard engine of 268 registered commit checks, 277 lint rules and 15 custom ESLint rules, with 146 tests of the guards themselves.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Standards written down in a contributing guide are suggestions. Everyone agrees with them, and then it is Friday, the change is small, and the guide loses. The zero‑warnings bar was only ever going to hold if something other than goodwill was holding it — and the linters that ship with each language stop well short of the project‑specific rules that actually matter, the ones about how this codebase in particular is meant to work.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The rules the project cared about had to be executable, so that breaking one failed a commit rather than waiting for a reviewer with the time and the memory to catch it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; What grew out of that is a guard engine. There are 274 check scripts, 268 of them registered into the commit hooks, alongside 277 JavaScript linters and 96 shell and 17 Python validators covering the things off‑the‑shelf tooling has no opinion about — that a migration can be rolled back, that a translation key exists in both locales, that a registered route appears in the OpenAPI description, that nobody quietly added an inline suppression. Fifteen custom ESLint rules hold the house patterns in TypeScript. One rule is worth naming on its own: any commit prefixed fix: has to carry a test that fails without it, so a bug that is fixed stays fixed. And because a broken guard is worse than no guard at all — it passes everything and nobody finds out — the guards have 146 tests of their own.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Review time moved off mechanics and onto design, because the mechanical objections were already made by a machine before the branch was pushed. The trade‑off is real and worth stating: committing is slow, and a badly written guard is genuinely infuriating to work around. Those 146 tests exist because that happened.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Built the payments and entitlements layer — Stripe alongside Apple and Google in‑app purchase — gating the directory, search and export through an 11‑table access model checked on the server.</title>
    <id>https://platform.engineer.company/portfolio/built-the-payments-and-entitlements-layer-96/</id>
    <link href="https://platform.engineer.company/portfolio/built-the-payments-and-entitlements-layer-96/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="APIs &amp; Integration" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Databases" scheme="https://platform.engineer.company/categories/" />
    <category term="PostgreSQL" scheme="https://platform.engineer.company/categories/" />
    <category term="Product &amp; Requirements" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend &amp; API Development" scheme="https://platform.engineer.company/services/" />
    <category term="Database Design &amp; Modeling" scheme="https://platform.engineer.company/services/" />
    <category term="Product Strategy &amp; Requirements" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <summary>Built the payments and entitlements layer — Stripe with Apple and Google in-app purchase — gating directory, search and export from an access model.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Money is the part of a platform nobody gets to be casual about. A subscription has to survive a card expiring, a refund, a plan change, a webhook that arrives twice and a webhook that arrives out of order. The moment payment can happen on three storefronts — a card on the web, Apple in one app store, Google in the other — there are three different accounts of what somebody bought, and the product still needs one answer to one question: what is this person allowed to do right now?&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Taking money and granting permission had to be two systems rather than one, so that adding a storefront would not mean rewriting every gate in the product.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Stripe handles cards and subscriptions through 18 Go files, and Apple and Google in‑app purchases arrive through their own receipt verification. All three converge on a payments schema of 9 tables and 34 functions — and then stop there. What the product actually asks is a separate access schema, 11 tables and 34 functions, which answers &amp;ldquo;may this account do this?&amp;rdquo; without knowing or caring which storefront paid for it. That answer gates the company directory, search and data export, and it is re‑checked on the server on every request, because a hidden button is a courtesy and not a control.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Adding a storefront now touches the payments side and leaves the gates alone, and a support question about someone&amp;rsquo;s access has one table to look at rather than three. The cost is two schemas where a smaller product would want one, plus an entitlement lookup on requests that would otherwise have been free.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Moved slow work off the request path onto a River job queue — 15 worker modules, 8 scheduled tasks and 20 pg_cron jobs — so a request returns while the work behind it carries on.</title>
    <id>https://platform.engineer.company/portfolio/moved-slow-work-onto-a-river-job-queue-97/</id>
    <link href="https://platform.engineer.company/portfolio/moved-slow-work-onto-a-river-job-queue-97/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Databases" scheme="https://platform.engineer.company/categories/" />
    <category term="Performance Tuning" scheme="https://platform.engineer.company/categories/" />
    <category term="PostgreSQL" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend &amp; API Development" scheme="https://platform.engineer.company/services/" />
    <category term="Database Design &amp; Modeling" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <summary>Moved slow work off the request path onto a River job queue: 15 worker modules, 8 scheduled tasks and 20 pg_cron maintenance jobs.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Some work has no business happening while a user waits. Sending mail, rebuilding a search index, generating a document, recalculating standings — do any of it inside the request and the user watches a spinner for something they never asked to see. Do it in a goroutine instead and it disappears the moment the process restarts, which it will, mid‑deploy, with no record that it was ever supposed to happen.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Background work needed somewhere durable to live: a queue that survives a restart, retries a failure, and can be looked at when something has not happened.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; River was the choice, largely because it keeps its queue in PostgreSQL — the database is already the system of record, so a job and the rows it touches commit or roll back together, and there is no second piece of infrastructure to run and reason about. There are 15 worker modules behind it and 8 scheduled tasks. Underneath, 20 pg_cron jobs handle the maintenance the database is better placed to do itself: pruning partitions, rotating salts, refreshing aggregates. Anything slow enough to notice was moved off the request path and onto one of the two.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Requests return quickly and the slow work still finishes, with retries and a visible history when it does not. Keeping the queue in Postgres rather than a dedicated broker is a deliberate limit: it will not scale forever, and at some volume it becomes the wrong answer. For a platform whose bottleneck is the database anyway, one less moving part was worth more than headroom that was not going to be used.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Built first‑party error monitoring and OpenTelemetry tracing rather than buying them — payload sanitising, spike and regression detection, symbolication and a synthetic heartbeat — behind 11 operator views.</title>
    <id>https://platform.engineer.company/portfolio/built-first-party-error-monitoring-and-tracing-98/</id>
    <link href="https://platform.engineer.company/portfolio/built-first-party-error-monitoring-and-tracing-98/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Monitoring &amp; Observability" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend &amp; API Development" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <summary>Built first-party error monitoring and OpenTelemetry tracing — sanitising, spike detection, symbolication and a heartbeat — behind 11 operator views.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The difference between a platform that is up and a platform that is working is whether anyone would know. An error a user hits at eleven at night, on a page nobody tests, is invisible unless something goes and collects it. The usual answer is to buy a hosted error tracker, which is a good answer — and it also means the platform&amp;rsquo;s own errors, stack traces and user context leave for a third party.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Errors and traces had to be collected, grouped and made actionable, without the platform&amp;rsquo;s internals leaving the platform.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Two pieces got built. OpenTelemetry handles tracing over OTLP, so a slow request can be followed across the frontend, the API and the database rather than guessed at. Alongside it sits an in‑house error pipeline — an errmon service and an ingest service — that sanitises payloads before storage, groups errors into recurring problems rather than a flat list, detects spikes and regressions with a cooldown so one bad deploy does not page anyone forty times, symbolicates minified frontend stack traces back into readable code, and runs a synthetic heartbeat to prove that the pipeline itself is alive. It all lands in the database as error events, error groups, an inbox, API latency and stack samples, and it surfaces through 11 operator views, including one for service level objectives.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Errors turn into a queue that someone can work through, and a regression announces itself instead of being discovered by a user. Building rather than buying cost real time and means this is one more thing to maintain — a bought tracker would have been running the same afternoon. What it bought was that nothing sensitive leaves, and that the alerting rules fit this platform rather than a generic one.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Kept the schema honest across 1,022 migrations with a CI gate that builds the database both ways — a fresh install, and an install plus every migration — and fails when the two disagree.</title>
    <id>https://platform.engineer.company/portfolio/kept-the-schema-honest-across-1022-migrations-99/</id>
    <link href="https://platform.engineer.company/portfolio/kept-the-schema-honest-across-1022-migrations-99/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Data Governance" scheme="https://platform.engineer.company/categories/" />
    <category term="Databases" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Migrations &amp; Modernization" scheme="https://platform.engineer.company/categories/" />
    <category term="PostgreSQL" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Database Administration (DBA)" scheme="https://platform.engineer.company/services/" />
    <category term="Database Migration &amp; Modernization" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <summary>Kept the schema honest across 1,022 migrations with a CI gate that builds the database both ways and fails when the two disagree.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A schema is described twice in most projects: once by the initial setup that builds it from scratch, and once by the accumulated migrations that grew it. Both are supposed to produce the same database. Nothing checks that they do, so they drift — and the drift is invisible until a fresh environment behaves differently from production, usually at the worst moment.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The two descriptions had to be provably identical, automatically, rather than periodically believed to be.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The database is versioned as 1,022 migrations, numbered from 036 through 1102, and the ordering discipline around them is unglamorous and non‑negotiable. What makes it hold is a CI job that builds the database twice on every change: once from the fresh initial schema, once from the initial schema plus every migration replayed in order — and then compares the two. Not just the structure, which is the easy half, but the seeded data too, because a migration that backfills a lookup table wrongly is exactly as damaging as one that forgets a column, and only one of those shows up in a schema diff. Any disagreement fails the build with the difference printed.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; A fresh environment and a long‑lived one are the same database, and that is checked rather than assumed. The cost lands on whoever writes a migration: it has to work replayed and it has to work from cold, which is more thought than a quick ALTER usually gets. That is the point — the alternative is finding out during a restore, when the answer matters and there is no time to work it out.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Built fail‑closed abuse controls — 22 Redis‑backed rate limiters, Cloudflare Turnstile, request idempotency and an origin lock — so the platform sheds bots and floods instead of trusting its callers.</title>
    <id>https://platform.engineer.company/portfolio/built-fail-closed-abuse-controls-and-rate-limiting-100/</id>
    <link href="https://platform.engineer.company/portfolio/built-fail-closed-abuse-controls-and-rate-limiting-100/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="APIs &amp; Integration" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN" scheme="https://platform.engineer.company/categories/" />
    <category term="Performance Tuning" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend &amp; API Development" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <summary>Built fail-closed abuse controls: 22 Redis-backed rate limiters, Cloudflare Turnstile, request idempotency and an origin lock on the front door.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A public directory of companies and professionals is a target the day it goes live. Scrapers want the data, spam accounts want the reach, and an endpoint that costs the platform real money to serve — search, export, anything that touches an external API — is worth abusing simply because it is free to call. None of that is malice aimed at this platform in particular; it is background weather on the open internet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The expensive and abusable paths needed limits that hold under pressure, including the pressure of the limiter&amp;rsquo;s own dependency being unavailable.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; There are 22 rate limiters, each constructed for the path it protects rather than one global cap, because a login attempt, a search and a bulk export are abusive at wildly different rates. State lives in Redis so a limit is shared across instances instead of being per‑process and trivially escaped. The important decision is what happens when Redis is not there: the limiters fail closed. Traffic is refused rather than waved through, which is the less convenient answer and the only defensible one. Around them sit Cloudflare Turnstile on the paths worth challenging, 351 lines of idempotency middleware so a retried write does not become two, an origin lock that refuses requests not arriving through the front door, and a bespoke challenge on the directory itself.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Abuse gets expensive for the abuser and cheap for the platform, and an outage in the limiter&amp;rsquo;s own store degrades into refusal rather than into an open door. Failing closed does mean a Redis problem becomes a user‑visible problem — accepted deliberately, because the alternative is a Redis problem becoming a billing one.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Built company ownership claims end to end — a user claims a company, an administrator adjudicates, and an approval rewrites the authorization graph that decides who is allowed to edit what.</title>
    <id>https://platform.engineer.company/portfolio/built-company-ownership-claims-end-to-end-103/</id>
    <link href="https://platform.engineer.company/portfolio/built-company-ownership-claims-end-to-end-103/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Backend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Frontend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Full‑Stack Development" scheme="https://platform.engineer.company/categories/" />
    <category term="Product &amp; Requirements" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Full‑Stack Product Development" scheme="https://platform.engineer.company/services/" />
    <category term="Product Strategy &amp; Requirements" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <summary>Built company ownership claims end to end: a user claims, an administrator adjudicates, and approval rewrites the authorization graph.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A directory seeded from public sources has a structural problem: the companies in it did not put themselves there. Sooner or later somebody from one of them turns up wanting to correct their own entry — and there is no relationship between that person and that record, only an assertion that one exists. Grant it too readily and a competitor edits your page. Grant it too slowly and the directory stays wrong.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; There had to be a route from &amp;ldquo;this is my company&amp;rdquo; to genuine authority over the record, with a human decision in the middle and a trail behind it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Claims were built end to end, across 108 commits and both applications. A user submits a claim with evidence; it enters a queue in the back‑office; an administrator reviews it and approves or rejects it with a reason that goes back to the claimant. The interesting part is what approval does — it is not a flag on a row. Approval rewrites the authorization graph, so the account gains a real relationship to the organization, which is the same relationship every permission check in the platform already consults. The gate is the adjudication, not the code path, and no feature had to learn about claiming in order to respect it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Companies can take over and correct their own entries without anyone editing the database by hand, and every grant of authority has a named approver and a reason attached. Human review is the bottleneck by design; an automated check on a domain name would be faster and would be wrong in exactly the cases that matter most.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Established a continuous security programme — code scanning, DAST, dependency and vulnerability checks, SBOM generation, secret scanning and SHA‑pinned actions — alongside 21 written security audits.</title>
    <id>https://platform.engineer.company/portfolio/established-a-continuous-security-programme-104/</id>
    <link href="https://platform.engineer.company/portfolio/established-a-continuous-security-programme-104/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Documentation" scheme="https://platform.engineer.company/services/" />
    <summary>Established a continuous security programme — code scanning, DAST, dependency checks, SBOM, secret scanning and pinned actions — plus 21 audits.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The security work in the application — the content security policy, the least‑privilege database roles, the entitlement re‑checks — protects the platform at runtime. None of it says anything about the thing being shipped: whether a dependency picked up a known vulnerability last Tuesday, whether a credential was committed and reverted, or whether a third‑party action pinned to a tag has quietly become a different piece of code.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Supply chain and code security had to be continuous and automated, so the state of it was a build result rather than an opinion.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Static analysis runs through CodeQL, dynamic testing against a live instance through ZAP, and Go dependencies are checked with govulncheck. A software bill of materials is generated on every build with Anchore and Syft, so what shipped is known rather than reconstructed later. Gitleaks scans history for credentials. Every third‑party GitHub Action is pinned to a commit hash rather than a tag, which is the unglamorous control that stops a tag being moved under you. Dependabot watches 6 ecosystems. Alongside the automation sit 21 written security audits, including a threat model and an assessment against the OWASP testing guide — because scanners find the classes of problem someone has already described, and a threat model is where the ones specific to this platform get named.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; A vulnerability disclosed upstream shows up as a failing build rather than as news. The volume of findings is the real cost — a scanner that reports everything trains people to ignore it, and keeping the signal usable takes ongoing triage rather than a one‑time setup.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Built the company&#39;s own infrastructure as 19 Ansible playbooks and 34 roles across 12,065 lines of YAML, converging a live host to a declared state with every play idempotent.</title>
    <id>https://platform.engineer.company/portfolio/built-the-companys-infrastructure-as-code-108/</id>
    <link href="https://platform.engineer.company/portfolio/built-the-companys-infrastructure-as-code-108/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Platform Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud Infrastructure &amp; Migration" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>The estate is reproducible from the repository, and the parts of it that were only ever true because somebody remembered them are now assertions that fail a…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Engineer ApS runs its own estate — a web presence, a git forge, a database, backups, mail transport and DNS — and there was nobody to hand the operations to. A one‑person company has the same failure modes as a large one and none of the redundancy, which makes the usual answer, a person who remembers how the host was set up, the least available option there is.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The whole estate had to be described in a repository rather than in a head, and described in a form that converges a real host rather than documenting one.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; What grew from that is 19 playbooks and 34 roles across 12,065 lines of YAML. The shape matters more than the size. Composition is data rather than flags: a host sits in a tier group whose variables declare which roles it runs, so provisioning with no arguments converges every host to its declared state. Idempotence is a contract rather than an aspiration — a converged host reports zero changes, and a play that cannot say that is not finished. Four command namespaces keep the promises apart: a gate that touches no host, reports that read one and never change it, provisioning that changes a host to match the repository, and verification that changes a host on purpose and returns a verdict.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The estate is reproducible from the repository, and the parts of it that were only ever true because somebody remembered them are now assertions that fail a run. The cost is real: every change is slower to make than editing a file on the server would be, and a converge that half‑applies is worse than one that refuses, which is why a preflight play was later added in front of it. That trade was made deliberately and it has held.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Ran the whole company on one 512 MB single‑core host — a git forge, a web server serving seven domains, Tor, two alternate‑protocol servers, backups and intrusion banning — by treating 464 MB of usable memory as the binding architectural constraint.</title>
    <id>https://platform.engineer.company/portfolio/ran-the-whole-company-on-one-512mb-host-109/</id>
    <link href="https://platform.engineer.company/portfolio/ran-the-whole-company-on-one-512mb-host-109/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Performance Tuning" scheme="https://platform.engineer.company/categories/" />
    <category term="Platform Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Solution Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud Infrastructure &amp; Migration" scheme="https://platform.engineer.company/services/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="Platform &amp; Solution Architecture" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>The whole company runs on a machine that costs less per month than a lunch, and the design is better for the discipline rather than merely cheaper.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The company&amp;rsquo;s production host is a single‑core cloud instance with 512 MB of memory and 10 GB of disk, of which about 464 MB is usable. Everything the business runs in public sits on it: the web server terminating TLS for seven domains, the git forge, a Tor onion service, a Gemini server, a Gopher server, encrypted backups and intrusion banning. The usual reaction to that list is to buy a larger box.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The constraint had to be treated as an architectural input rather than a problem to spend money on, because the honest question was not whether a bigger machine would work but whether the design needed one.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Memory became the argument that settled decisions. There is no monitoring agent, no metrics pipeline and no dashboard — reporting is a pull, seven commands that read the host and render Markdown, changing nothing and running only when asked. The supervisor is systemd rather than a second process manager layered on top of it, and the container plane is Quadlet units under the same supervisor rather than a daemon with its own. Web‑panel platforms were ruled out at the design stage for the same reason. When the question came up of whether the host could carry an onion service, the answer came from a day of measured samples rather than an opinion: available memory never fell below about 310 MB of 464, swap sat at 2.6 per cent and the processor was 99.7 per cent idle.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The whole company runs on a machine that costs less per month than a lunch, and the design is better for the discipline rather than merely cheaper. What it cost is headroom for anything careless — mail is deliberately not on this box at all — it is written as an install scaffold awaiting a host of its own, because a mail server needs headroom this machine has already spent, and that is written down rather than discovered later.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Found and closed three SSH brute‑force protections that had never worked: a ban jail watching port 22 while the daemon listened on 1986, a rate limit shadowed by a broader rule above it, and a ban action whose binary never resolved, so no ban had ever applied.</title>
    <id>https://platform.engineer.company/portfolio/found-three-ssh-brute-force-protections-that-never-worked-110/</id>
    <link href="https://platform.engineer.company/portfolio/found-three-ssh-brute-force-protections-that-never-worked-110/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Monitoring &amp; Observability" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN Setup" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <summary>Three protections that had never once fired now do, and the class of defect they belong to — a control whose failure mode is that it keeps reporting healthy —…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A hardening review of the production host in August 2026 asked a question that usually gets a confident answer: are the SSH brute‑force protections working. All three were configured, all three appeared in every report anyone looked at, and all three had been inert since the day the host was built.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The controls had to be checked against what the kernel actually does with a packet, rather than against the configuration files that describe what should happen to one.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Reading the configuration would have confirmed the wrong answer three times, so the review read the running system instead. The intrusion‑banning jail was watching port 22 while the daemon had been moved to 1986 during the initial hardening — every ban it wrote named a port nothing listened on. The firewall&amp;rsquo;s rate limit was worse in a subtler way: the rule existed, and it sat below a broader rule that matched first. Firewall user rules are evaluated top down and the first match wins, so a broad allow above a rate limit makes the limit dead code that still prints in every status listing. The third was the quietest of them: the ban action shells out to a packet‑filter binary that the package system only recommends rather than requires, so on a host without it the jail starts, counts and decides, and then fails at the one moment it tries to ban. All three fixes were small. What came out of it was not the fix but two rules that now govern the repository: a security control gets an assertion rather than a comment, and a firewall is verified by rule position rather than by rule presence.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Three protections that had never once fired now do, and the class of defect they belong to — a control whose failure mode is that it keeps reporting healthy — is the class the platform&amp;rsquo;s checks are now built to catch. All three had been inert from bootstrap. All three printed healthy in every place anyone looked, which is the whole reason they lasted.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Hardened SSH to 24 asserted directives with three‑stage validation — the candidate file, the assembled config, then the daemon&#39;s own read‑back — after the read‑back caught the running server silently overriding two of the twenty‑four.</title>
    <id>https://platform.engineer.company/portfolio/hardened-ssh-with-three-stage-validation-111/</id>
    <link href="https://platform.engineer.company/portfolio/hardened-ssh-with-three-stage-validation-111/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>The SSH posture is now the daemon&#39;s answer rather than the repository&#39;s claim, and the difference is not theoretical — it was already two settings wide when…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; SSH is the only interactive way into the company&amp;rsquo;s host, and its configuration is written by an automation role that had been running clean for months. An access report in September 2026 read the daemon&amp;rsquo;s own resolved settings and found two of them disagreeing with what the role had been writing on every single converge.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The hardening had to become something the daemon confirms rather than something the repository asserts, because the gap between the two had already been open for months without anyone noticing.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The cause was configuration ordering. The operating system ships its own defaults uncommented, above where a drop‑in file lands, and for the two settings in question the first occurrence wins. The fix was a filename prefix that sorts ahead of the vendor&amp;rsquo;s, which is a one‑character class of change and exactly the sort that stays broken because nobody thinks to look. What was built around it matters more: three stages of validation on every converge. The candidate file is syntax‑checked before it is installed, so an invalid config never reaches the host. The assembled configuration is checked after installation. Then the daemon&amp;rsquo;s own resolved output is read back and 24 directives are asserted against it, so a setting that is written but overridden fails the run. Two directives were deliberately left out, both because the daemon no longer implements them and writing them would only look thorough.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The SSH posture is now the daemon&amp;rsquo;s answer rather than the repository&amp;rsquo;s claim, and the difference is not theoretical — it was already two settings wide when the check was written. A converge that cannot see whether a control took effect has not verified it, and grepping for a directive only proves it was written.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Proved the intrusion‑banning path end to end on every hardening run by banning a reserved test address, reading the resulting kernel rule and unbanning in a guaranteed cleanup block, so a jail that stops working fails a run instead of reporting healthy.</title>
    <id>https://platform.engineer.company/portfolio/proved-the-intrusion-banning-path-on-every-converge-112/</id>
    <link href="https://platform.engineer.company/portfolio/proved-the-intrusion-banning-path-on-every-converge-112/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>A banning path that stops working now fails a converge instead of continuing to report healthy, which is the only property that mattered.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The intrusion‑banning service had already been caught banning a port the SSH daemon did not listen on. Fixing the port closed that instance. It did nothing about the reason the fault survived so long, which is that a ban path has no visible failure: the service runs, the jail is listed as active, and nothing anywhere says whether a ban ever reaches the kernel.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The ban path had to be exercised on every converge, against the live rule set, rather than inferred from the service being up.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The converge now bans an address from the block the standards reserve for documentation, reads back the resulting rule in the kernel&amp;rsquo;s packet filter, and unbans it in a cleanup block that runs whether the check passed or failed. The reserved range is the load‑bearing choice — the test address belongs to nobody, so a stray ban that outlives a failed run cannot lock out a real network. The kernel read‑back is the other half: the service&amp;rsquo;s own status output would report success for a ban that produced no rule, which is the exact failure being tested for. Alongside it, the ban backend is pinned rather than left to the service&amp;rsquo;s detection, and the log backend is set to detect because the operating system ships no traditional authentication log and the wrong choice fails silently by watching a file that never appears.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; A banning path that stops working now fails a converge instead of continuing to report healthy, which is the only property that mattered. It costs a few seconds on every run and it writes and withdraws a firewall rule against production every time, which is a real intrusion into a live system and was accepted on the grounds that the alternative had already been demonstrated to be worse.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Verified firewall rules by position rather than presence, reading the numbered rule list and the live packet‑filter chain, because a rule that exists is not a rule any packet reaches.</title>
    <id>https://platform.engineer.company/portfolio/verified-firewall-rules-by-position-113/</id>
    <link href="https://platform.engineer.company/portfolio/verified-firewall-rules-by-position-113/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN Setup" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>The firewall posture is now checked the way a packet experiences it. The most useful outcome was not the check but what it revealed about the reporting that…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A firewall status listing shows a set of rules. A packet filter evaluates an ordered list and stops at the first match. Those are different things, and the difference is invisible in every tool that prints a summary — which is how the host ran for a year with a rate limit that no packet ever reached, sitting below a broader rule that matched first.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Firewall verification had to read position rather than membership, because presence had already been demonstrated to prove nothing.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The checks now read the numbered rule listing and the live filter chain, and assert against order. Exactly one rule exists per port and always with a protocol, because a rule without one silently widens the surface. The SSH port carries a rate limit and never an allow beside it, since an allow above a limit is precisely the shadowing that was found. The declared public surface is a short list of five ports, asserted as a whole rather than checked individually, so a port that appears without being declared fails rather than being noticed. The security report renders the rules in match order with a warning at the top of the section explaining how to read it, because the next person to open that file will otherwise read a set.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The firewall posture is now checked the way a packet experiences it. The most useful outcome was not the check but what it revealed about the reporting that preceded it: every tool involved had been printing the rate limit for a year, correctly, and none of them had been asked the only question that mattered.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Built encrypted off‑host backups on restic with retention pruning, an integrity check and a monthly automated restore drill, then audited the recovery position and wrote down the gaps rather than leaving them to be found during an incident.</title>
    <id>https://platform.engineer.company/portfolio/built-encrypted-backups-with-a-monthly-restore-drill-114/</id>
    <link href="https://platform.engineer.company/portfolio/built-encrypted-backups-with-a-monthly-restore-drill-114/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Backup &amp; Disaster Recovery" scheme="https://platform.engineer.company/services/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>The company can lose the host and get its data back, and that sentence rests on a restore that ran last month rather than on a backup that ran last night.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Everything the company holds — the git repositories, the database, the site — sat on one cloud instance whose provider snapshot was the entire recovery position. A provider snapshot is a fine thing to have and a poor thing to rely on: it is in the same account as the machine it protects, it is not encrypted by anyone here, and nobody had ever restored from one.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Backups had to be encrypted, off‑host, pruned on a retention policy, and — the part that is usually skipped — actually restored from, on a schedule, without a person remembering to do it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The backup runs on a systemd timer: a database dump where one exists, then an encrypted deduplicated snapshot to storage at a different provider over SFTP, then a retention prune, then an integrity check. A dead‑man&amp;rsquo;s switch is pinged on success only, which is the distinction that makes it an alarm rather than a log — a run that fails says nothing, and saying nothing is what raises the alert. Separately, a restore drill runs monthly: it pulls a known file out of the repository and compares it, so the thing being checked is a restore rather than a backup. The passphrase is written to a file the units read rather than passed through the environment, because the supervisor processes escapes in environment values and a passphrase containing a backslash would have been silently different from the one that created the repository. Afterwards the recovery position was audited and written up, and the remaining gaps were named in the document rather than left to be discovered during an incident.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The company can lose the host and get its data back, and that sentence rests on a restore that ran last month rather than on a backup that ran last night. The audit&amp;rsquo;s most valuable output was the list of things still not covered, which is the part a green backup report is structurally unable to tell anyone.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Built dead‑man&#39;s‑switch monitoring that pings only while memory and disk are healthy, so a degraded host raises an alert by going silent — and caught six variable names saying &#34;free&#34; where the check correctly measured &#34;available&#34;, an order of magnitude apart on a 464 MB box.</title>
    <id>https://platform.engineer.company/portfolio/built-dead-mans-switch-monitoring-115/</id>
    <link href="https://platform.engineer.company/portfolio/built-dead-mans-switch-monitoring-115/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Monitoring &amp; Observability" scheme="https://platform.engineer.company/categories/" />
    <category term="Performance Tuning" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>The host now has an alarm whose failure mode is to fire, and the naming that would have destroyed it has been corrected.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A 464 MB host running a forge, a database and a web server has two realistic ways to die: it runs out of memory, or it runs out of disk. Neither announces itself. Both are entirely predictable a few hours in advance if anything is looking, and nothing was.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The host needed an alarm that works when the host does not — which rules out anything that has to send a message at the moment of failure.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The answer is a dead‑man&amp;rsquo;s switch on a timer. Every fifteen minutes with jitter, a small script measures available memory and free disk and pings an external service only if both are above their thresholds. Silence is the alert. A machine that has run out of memory, lost its network or stopped booting produces exactly the same signal as one that is unhealthy, which is the correct behaviour and the reason this shape was chosen over an agent that reports a status. The measurement is available memory, not free memory, and that distinction turned into the most instructive part of the work: the script had been reading the right column all along while six variable names around it said &amp;ldquo;free&amp;rdquo;. On a healthy Linux box free memory is near zero because the kernel uses idle memory for cache, so a reader checking those names against a ten per cent threshold would see twelve megabytes free on a 464 MB machine, conclude the check was broken, and fix it with a one‑character change that converts a working alarm into one that breaches permanently and gets muted inside a week.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The host now has an alarm whose failure mode is to fire, and the naming that would have destroyed it has been corrected. The switch&amp;rsquo;s real limitation is stated in its own documentation: it proves the box is healthy, not that the site is serving, and those are different questions.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Made check mode tell the truth across the whole platform after finding six probes deciding on a value the host never gave, because Ansible&#39;s command module reports success under --check while skipping the command entirely.</title>
    <id>https://platform.engineer.company/portfolio/made-ansible-check-mode-tell-the-truth-116/</id>
    <link href="https://platform.engineer.company/portfolio/made-ansible-check-mode-tell-the-truth-116/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <summary>A dry run now either measures something or says it did not, and neither of those is the third option it used to have.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A dry run against production is supposed to be the safe way to find out what a change will do. In September 2026 a dry run failed on an assertion that was simply wrong about the host, and advised the operator to set a flag that would have relaxed a security sandbox. The dry run had not read the host. It had read a value the host never gave and drawn a conclusion from it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Every probe whose result feeds a decision had to be made honest under check mode, and the ones that could not be had to say so out loud instead of staying quiet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The cause is a property of the tool that is documented and easy to forget: the command module does not execute under check mode, and what it registers is not an empty result — it is a success with empty output. Any conditional reading that register therefore decides on a value that was never measured, and it decides in whichever direction its own logic happens to point. A sweep of every registered probe found six of them, each lying differently: one reported that the supervisor accepts every unit directive without having asked the supervisor, another reported nothing to do on a host with the firewall switched off. Each was given one of two shapes. A probe that reads pre‑existing state the run has not touched is marked to run even under check mode. A probe that cannot run is skipped, and a message names what was specifically not verified — because silence in a run log reads exactly like a pass.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; A dry run now either measures something or says it did not, and neither of those is the third option it used to have. The general rule went into the development guide in the same change: check mode must not lie, and a probe that cannot see is required to announce its blindness rather than infer a verdict from it.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Added a preflight play that runs the same code as the converge against operator‑local secrets in about a second, after a half‑applied production run died on its ninth task with the swap settings already written to the live host.</title>
    <id>https://platform.engineer.company/portfolio/added-a-preflight-play-for-secrets-117/</id>
    <link href="https://platform.engineer.company/portfolio/added-a-preflight-play-for-secrets-117/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <summary>A secret that does not resolve now costs a two-second refusal on a laptop instead of a partly-applied change to a live server.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Operational secrets had just been split so that each host carries its own backup repository, passphrase and alert switch. The repository code was correct. The operator&amp;rsquo;s encrypted vault still held the previous single‑host value, and nothing could see the mismatch, because the vault is deliberately local to the operator&amp;rsquo;s machine and invisible to the repository&amp;rsquo;s own quality gate.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; That class of failure needed somewhere to fail cheaply, because it had just failed expensively.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The first converge after the change connected to the live host, ran eight tasks and refused on the ninth — correctly, but from inside a run that had already written swap settings to production. A half‑applied converge is a worse answer than a refusal, so a preflight play was written: it reaches no host at all, runs locally, gathers no facts, and executes the same two task files the real converge uses against the operator&amp;rsquo;s vault. It answers in about a second, and provisioning runs it first. The load‑bearing decision is that it is the same code rather than a second implementation of the same rule, because a check that restates a rule in another language eventually disagrees with it and disagrees silently. Writing it surfaced a trap it nearly created: facts set during a play outlive that play, so chaining the preflight and the converge into one invocation would have handed the real role a passphrase the preflight had already resolved, and passed the check on a vault that was still wrong. That was reproduced before it was guarded, in both task files.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; A secret that does not resolve now costs a two‑second refusal on a laptop instead of a partly‑applied change to a live server. The preflight is deliberately not tagged to always run and is deliberately not serialised, and both of those are recorded as decisions rather than defaults.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Reconciled a 20‑record DNS zone declaratively against the Cloudflare API with separate audit and BIND‑export entry points, and turned the CDN proxy back off on privacy grounds after building it.</title>
    <id>https://platform.engineer.company/portfolio/reconciled-a-dns-zone-declaratively-118/</id>
    <link href="https://platform.engineer.company/portfolio/reconciled-a-dns-zone-declaratively-118/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="APIs &amp; Integration" scheme="https://platform.engineer.company/categories/" />
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Networking &amp; VPN" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="Networking &amp; VPN Setup" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>The zone is versioned, comparable and exportable, and the one decision that went against the obvious default is written down with its reasoning so that nobody…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The company&amp;rsquo;s DNS carried about twenty records across a web presence, a git subdomain, two personal redirects, mail routing through a hosted mailbox provider, a transactional sending domain and the authentication records for both. All of it lived in a provider&amp;rsquo;s web console, which means the current state was whatever the last person to click had left behind.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The zone had to become a declaration in the repository, with a way to compare that declaration against what the provider is actually serving.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The zone is written as data — live records, application records, transport‑policy records and a separate list of records pending removal, which is the honest way to record a deletion that has not happened yet. One play reconciles it against the provider&amp;rsquo;s API. Two more entry points sit behind explicit opt‑in tags: an audit that reports the difference without changing anything, and an export that writes the zone out in the standard zone‑file format so it can be read by something that is not this repository. The most interesting decision was a reversal. Proxying the two web faces through the provider&amp;rsquo;s content network was built, worked, and was then turned back off — because it costs the one sentence the company&amp;rsquo;s privacy page is about. With a proxy in front, another company handles every visitor&amp;rsquo;s address and every URL they request, before we do, under their policy rather than ours. For a business whose distinguishing claim is that nobody is watching, that is a worse trade than the attacks it defends against.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The zone is versioned, comparable and exportable, and the one decision that went against the obvious default is written down with its reasoning so that nobody re‑litigates it by accident. The audit path is the part that gets used most, because knowing the difference is more often what is wanted than closing it.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Cut systemd sandbox exposure across every unit this platform installs — a dead‑man&#39;s‑switch service from 9.6 UNSAFE to 1.5, an internet‑facing git forge from 8.3 EXPOSED to 1.5 — and added a converge‑time parser check after finding a misspelled directive silently ignored in three unit templates.</title>
    <id>https://platform.engineer.company/portfolio/cut-systemd-sandbox-exposure-across-every-unit-119/</id>
    <link href="https://platform.engineer.company/portfolio/cut-systemd-sandbox-exposure-across-every-unit-119/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Containers (Docker/Kubernetes)" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Containerization &amp; Orchestration" scheme="https://platform.engineer.company/services/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>Every unit runs with the privileges it needs and not the ones it does not, the numbers are measured rather than asserted, and the class of defect where a typo…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Thirteen unit files were installed by this repository and run on the production host with the privileges the supervisor gives by default, which is most of them. A hardening score put the dead‑man&amp;rsquo;s‑switch service at 9.6 and called it unsafe; the internet‑facing git forge scored 8.3 and exposed. Both numbers were accurate and neither had prompted anything, because a score with no threshold attached is a number people learn to skip.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Every unit needed a sandbox proportional to what it actually does, and the sandboxes needed a check, because the failure mode of a wrong sandbox is that the unit starts and then breaks somewhere the parser cannot see.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Privilege restrictions went into every unit template — a privilege ceiling fixed at the unit&amp;rsquo;s own, a system‑call filter, restricted address families, and memory that is writable or executable but never both. The measured results: the dead‑man&amp;rsquo;s switch went from 9.6 to 1.5, the forge from 8.3 to 1.5, and both backup units from 9.6 to 2.3 and 2.5. Writing them turned up something better than the scores. One directive had been misspelled in three unit templates for as long as those roles had existed — a plausible‑looking name that does not exist, which the supervisor answers by logging that it does not recognise the key and starting the unit anyway. Grepping for a directive proves it was written; only the parser proves it took effect. So a verification role now runs every unit through the supervisor&amp;rsquo;s own verifier during the converge, and is included by every role that installs a unit. What that still cannot see is stated plainly in the same documents: every directive capable of breaking these units breaks them at runtime, not at parse time, and a score cannot tell whether a script still reaches its last line.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Every unit runs with the privileges it needs and not the ones it does not, the numbers are measured rather than asserted, and the class of defect where a typo becomes a silently absent control now fails a run. The limits of the measurement are recorded next to it, which is the part that keeps the next reader from over‑trusting a green band.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Built seven read‑only reporting roles that render a live host to Markdown — facts, access, git, metrics, traffic, security and provider inventory — under a rule that no number is printed the run did not measure.</title>
    <id>https://platform.engineer.company/portfolio/built-seven-read-only-host-reporting-roles-120/</id>
    <link href="https://platform.engineer.company/portfolio/built-seven-read-only-host-reporting-roles-120/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Monitoring &amp; Observability" scheme="https://platform.engineer.company/categories/" />
    <category term="Stakeholder &amp; Reporting" scheme="https://platform.engineer.company/categories/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Documentation" scheme="https://platform.engineer.company/services/" />
    <summary>The estate can be described from the repository on demand, and the reports have found real things: the two dead security controls, an undeclared listening…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The host had no dashboard and was not getting one, because a metrics stack does not fit on 464 MB and would not have been worth its cost if it did. That left an honest gap: there was no way to answer questions like who has access, how much has this repository grown, what does the traffic look like, or is the hardening actually enforced.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Those questions needed answers that could be produced on demand, cost the host nothing while nobody was asking, and could never change the thing they were describing.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Seven read‑only roles, each rendering a live host into Markdown in the repository. A facts snapshot covering operating system, hardware, storage, network, services, packages, listening sockets and processor utilisation computed from two samples of the kernel&amp;rsquo;s own counter. An access report covering accounts, sudo scope, key fingerprints, forge users and database roles. A git report per repository. A metrics report over the day&amp;rsquo;s collected samples. A traffic report built from the web server&amp;rsquo;s privacy‑masked log. A provider inventory across four provider surfaces — DNS, two cloud APIs and a dedicated‑server API. And a security report that answers whether hardening is enforced rather than configured, printing the firewall rules in match order and the live ban rule set. The governing rule across all seven is that no number is printed that the run did not measure — a report that fills a gap with a plausible figure is worse than one that leaves it blank, because only the plausible one gets believed.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The estate can be described from the repository on demand, and the reports have found real things: the two dead security controls, an undeclared listening port, and the observation that the traffic archive is only as old as the last time somebody remembered to harvest it. That last one is written up as a limitation with a specific cost recorded — sixteen days of one site&amp;rsquo;s history that rotated away between harvests and do not exist anywhere.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Deployed the company&#39;s own git forge on Soft Serve, private by default with no web panel and its SSH port bound to loopback behind a jump host, and made the landing page in front of it a build artefact of the main site rather than a hand‑kept copy.</title>
    <id>https://platform.engineer.company/portfolio/deployed-the-companys-own-git-forge-121/</id>
    <link href="https://platform.engineer.company/portfolio/deployed-the-companys-own-git-forge-121/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="System Administration" scheme="https://platform.engineer.company/categories/" />
    <category term="Web Development" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <category term="Website Development &amp; CMS" scheme="https://platform.engineer.company/services/" />
    <summary>The company hosts its own code on its own hardware, and the page in front of it inherits every check the main site passes rather than drifting away from it in…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The company&amp;rsquo;s source code lived on a third‑party hosting service, which is a reasonable place for it and a poor fit for a business whose argument to clients is that it does not hand their data to intermediaries. Running a forge instead means running a forge: authentication, access control, storage, backups, and a public face for it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; A canonical git server had to be stood up on the existing host, with the smallest possible attack surface and no web administration panel, and a landing page in front of it that does not rot.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The forge is a single binary supervised by the operating system, installed from its vendor&amp;rsquo;s package repository, deliberately chosen for being SSH‑first with no administrative web interface — the less interface, the less to defend. It is private by default: anonymous access is refused, keyless access is refused, and every declared repository is marked private rather than relying on obscurity. Its SSH listener binds only to the loopback interface on port 23231 and is reached from outside through a jump host, so the firewall&amp;rsquo;s declared surface does not grow. A protocol multiplexer that would put HTTPS and git SSH on one public port by inspecting the first bytes of a connection is written and ready behind a master switch, and that switch is off: multi‑user git over the public port is not needed yet, and a listener nobody uses is surface. The landing page in front of it was the more interesting problem. It had been a hand‑maintained copy of the main site&amp;rsquo;s design in its own repository, and every single difference ever found between the two turned out to be an accident rather than a decision: a type scale rendering the wordmark about nine per cent too large, a font declaration that collapsed two weights to one on any machine with the family installed, ornaments hidden below a certain width so they were absent on every phone, a weight used with no font shipped for it, and no main landmark or top‑level heading on any page. Five for five, and not one visible in a screenshot. The copy was deleted; the landing page is now built by the main site&amp;rsquo;s own templates and delivered as an artefact.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The company hosts its own code on its own hardware, and the page in front of it inherits every check the main site passes rather than drifting away from it in ways only a measurement can see. Divergence is still available and now has to be written down.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Deployed a container plane on Podman and Quadlet under systemd rather than Docker, because Docker publishes container ports above the host firewall&#39;s own rules — and gave deploys an unprivileged user with one fixed command instead of root.</title>
    <id>https://platform.engineer.company/portfolio/deployed-a-container-plane-on-podman-and-quadlet-122/</id>
    <link href="https://platform.engineer.company/portfolio/deployed-a-container-plane-on-podman-and-quadlet-122/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Containers (Docker/Kubernetes)" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud Infrastructure &amp; Migration" scheme="https://platform.engineer.company/services/" />
    <category term="Containerization &amp; Orchestration" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <summary>Containers run under the supervisor that was already trusted, behind the firewall that was already declared, and a routine release needs no privileged access.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The platform needed somewhere to run application containers. The obvious choice was the industry default, and the obvious choice was wrong for this host in a specific way: it rewrites the kernel&amp;rsquo;s packet‑filter rules and publishes container ports above the firewall rules the hardening role installs, so a container quietly becomes reachable from the internet regardless of what the firewall was told.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; A container plane had to be chosen that does not bypass the firewall, does not add a second supervisor beside the one already trusted, and does not require a person to be root to ship a release.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The plane is a daemonless container engine driving units generated by the operating system&amp;rsquo;s own supervisor. There is no second process manager: containers are services, they start the way services start, and they are described in the same declarative form as everything else. The containers use host networking with no published ports at all, which removes the firewall‑bypass question rather than mitigating it. Units run at the system level rather than rootless, and that is recorded as a trade — it keeps the automation simple and normal, at the cost of the stricter isolation rootless would give, and the note says which way to move if container escape ever matters more than automation simplicity. Deployment was separated from provisioning: root sets up the deployment path once, and thereafter an unprivileged user redeploys by running one fixed script through a scoped rule that permits that command and no arguments. Build the image, restart the service. No root shell, no arbitrary commands.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Containers run under the supervisor that was already trusted, behind the firewall that was already declared, and a routine release needs no privileged access. The choice against the default is written down with its reason, which matters more than the choice — the next person will be told to use the default by every article they read.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Automated the provisioning of a second server on a second cloud provider, creating the firewall before the machine so it is born behind one, with both providers&#39; firewalls written directly against their REST APIs to avoid a third‑party collection.</title>
    <id>https://platform.engineer.company/portfolio/provisioned-a-second-server-from-code-123/</id>
    <link href="https://platform.engineer.company/portfolio/provisioned-a-second-server-from-code-123/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="APIs &amp; Integration" scheme="https://platform.engineer.company/categories/" />
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Cloud Infrastructure &amp; Migration" scheme="https://platform.engineer.company/services/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="Networking &amp; VPN Setup" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <summary>A second host can be created, or re-adopted, from the repository, behind a firewall that already exists, at a cost the file states.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A second machine was needed for an application tier, at a different provider from the first, and the first machine&amp;rsquo;s own history was the argument for how to do it: it had been created by hand, and its firewall had been added afterwards, which leaves a window where a fresh host with a default password policy is reachable from the internet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The machine had to be created from the repository, and it had to be born behind its firewall rather than acquiring one shortly afterwards.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Ordering carried the design. The firewall play runs before the server play, so the rule set exists before there is anything for it to protect; on the other provider, tagging runs before the cloud firewall because a firewall that targets tags needs the tags to exist first. Both providers&amp;rsquo; firewalls are written directly against their REST APIs through a generic HTTP task rather than through a vendor collection, which removes a dependency and its version drift at the cost of writing the request shapes by hand. The role that creates the machine adopts an existing one rather than duplicating it if it is already there, so re‑running is safe. It is also documented, in its own file, as the one role in the repository that spends money — the instance type, the region, the specification and the monthly cost in euros are all written down, because a play that bills someone should say so where they will read it. That play is also the one that cannot be rehearsed the usual way: the generic HTTP task declares no check‑mode support, so a dry run skips every task in it. The rehearsal is done against the firewall play instead, which is free and reversible.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; A second host can be created, or re‑adopted, from the repository, behind a firewall that already exists, at a cost the file states. The one thing dry‑run cannot cover is named in the same file rather than left as a surprise.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Wrote a scope rule into the repository after a restructure carried another company&#39;s inventory, firewall allowances and prose into it — and kept the quarantined residue under the secret scanner rather than excluding it.</title>
    <id>https://platform.engineer.company/portfolio/wrote-a-scope-rule-after-a-credential-leak-124/</id>
    <link href="https://platform.engineer.company/portfolio/wrote-a-scope-rule-after-a-credential-leak-124/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Governance" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Governance &amp; Quality" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Documentation" scheme="https://platform.engineer.company/services/" />
    <summary>The scope boundary is a written rule with a stated test, the residue is visible rather than buried, and the specific shape of credential that got through now…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Work done for a different company rode along through a repository restructure and stayed. What came with it was not abstract: a scratch log holding live plaintext credentials, which sat in the tree past every guard for most of the repository&amp;rsquo;s history; a stale inventory naming that company&amp;rsquo;s host; and a firewall task file opening ports to sixteen of its client networks. None of it ran. That is exactly why it survived — nothing that runs nowhere is ever reviewed again.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The boundary had to become a rule with a test attached, rather than an intention, and the residue had to be dealt with in a way that did not simply hide it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The rule is now the opening section of the repository&amp;rsquo;s instruction set: this repository manages one company&amp;rsquo;s infrastructure and only that, and another party&amp;rsquo;s host, inventory, firewall allowance, DNS zone or credential does not belong in it — not even disabled, commented out, or parked in a file no playbook imports. The practical test is written next to it: would this company still be responsible for this if the relationship ended. The residue was quarantined into a clearly‑named directory rather than deleted, so the history stays legible, and the quarantine is deliberately partial — the two structural linters skip it, and the secret scanner, the vault guard and the emoji check deliberately still read it, because those are the three that would catch the thing that got in. The leak itself produced a linter rule: a custom pattern that flags a credential passed as a command‑line flag, which is the shape the leaked one had and which the standard rule set did not match.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The scope boundary is a written rule with a stated test, the residue is visible rather than buried, and the specific shape of credential that got through now fails a commit. The lesson recorded alongside it is the general one: the dangerous artefact is not the one that runs, it is the one that does not, because that is the one nobody reads again.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Split the four per‑host operational secrets after establishing that two hosts sharing one dead‑man&#39;s switch alert less than two switches, not more, and that a shared backup passphrase makes two hosts one repository.</title>
    <id>https://platform.engineer.company/portfolio/split-every-operational-secret-per-host-125/</id>
    <link href="https://platform.engineer.company/portfolio/split-every-operational-secret-per-host-125/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Solution Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="Backup &amp; Disaster Recovery" scheme="https://platform.engineer.company/services/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <summary>Secrets are per host by construction, and the two failure modes that would have followed from sharing them are written down where the next person edits the…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The platform was built for one host and was about to have two. Several operational secrets had been written as single values on that assumption: one backup repository, one passphrase, one alert switch. Extending them to a second host by sharing them is the path of least resistance and it is wrong in two separate ways, both of which fail quietly.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; Each secret had to become a map keyed by host, and the reason had to be written down, because the shared version looks correct and costs nothing until the day it matters.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Two arguments settled it, and both are recorded next to the configuration. A dead‑man&amp;rsquo;s switch shared by two hosts alerts less than two switches, not more: either host still pinging keeps the check green while the other one is dead, so adding a host to a shared switch actively reduces the coverage of the one that was already there. And a backup repository string is only a location — the passphrase is the whole of the encryption, so two hosts sharing a passphrase are not two repositories with a common secret, they are one repository with two directories in it. Each value became a map keyed by inventory hostname, resolved per host by a shared task file that both the converge and the preflight run. The existing host was then named in all four maps with its repository and both switches left empty, which is the truthful state and keeps the two open initiatives honest about owing the operator half of the work rather than the code.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Secrets are per host by construction, and the two failure modes that would have followed from sharing them are written down where the next person edits the file. The empty entries are the part worth keeping: they say the wiring exists and the value does not, which is a different and more useful statement than a missing key.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Built a commit gate of 22 one‑line linters plus five that earn a paragraph, with no warning tier and no inline suppressions permitted, covering HTML, CSS, JavaScript, Python, YAML, Markdown, shell, links, spelling, secrets and typography.</title>
    <id>https://platform.engineer.company/portfolio/built-a-22-linter-commit-gate-127/</id>
    <link href="https://platform.engineer.company/portfolio/built-a-22-linter-commit-gate-127/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Frontend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Product Strategy &amp; Requirements" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Documentation" scheme="https://platform.engineer.company/services/" />
    <summary>Mechanical objections are made by a machine before a commit exists, and the gate is the only reviewer this project has.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A contributing guide is a set of suggestions. Everyone agrees with it, and then it is Friday, the change is small, and the guide loses. On a one‑person project that is worse rather than better, because there is no reviewer at all — the only thing between a bad change and production is the person who wrote it, at the moment they are least inclined to argue with themselves.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The standards had to be executable, so that breaking one fails a commit rather than waiting to be noticed.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; What grew is a gate of 22 linters with no warning tier: every diagnostic is an error, and the site generator itself runs with warnings promoted to failures so even a deprecation stops the build. The obvious ones are there — HTML validation, CSS, JavaScript, Python, YAML, Markdown, shell, spelling, secrets, dead links. The interesting ones are the project‑specific checks that no off‑the‑shelf tool has an opinion about: that both colour themes paint every layered surface with the same number of layers, that no photograph is displayed wider than half its source pixels, that the deployed tree contains no private path or hostname, that the prose obeys the tone rules in all three languages, that a page has a Markdown twin and a valid alternate‑protocol representation. Inline suppressions are prohibited outright — no ignore comment, no disable directive, no bypassing the hook, and no renaming a file to dodge a matcher. The rule that keeps that honest is that a pre‑existing failure is not an excuse: a check that surfaces a defect nobody introduced gets fixed in the same pass.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Mechanical objections are made by a machine before a commit exists, and the gate is the only reviewer this project has. The cost is stated rather than hidden: committing is slow, and a badly written guard is genuinely infuriating to work around, which is why the guards themselves were later brought under a formatter and a linter of their own.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Cut the site&#39;s browser‑driven quality gate from 1,636 seconds to 615 by scheduling its checks longest‑first through a worker pool bounded to four lanes, after measuring that alphabetical order cost 320 seconds against 224.</title>
    <id>https://platform.engineer.company/portfolio/cut-the-visual-quality-gate-to-ten-minutes-128/</id>
    <link href="https://platform.engineer.company/portfolio/cut-the-visual-quality-gate-to-ten-minutes-128/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Frontend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Performance Tuning" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Frontend Development" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Leadership &amp; Consulting" scheme="https://platform.engineer.company/services/" />
    <summary>The gate went from 1,636 seconds to 615, while the checks got broader rather than thinner — the serial cost went up and the wall clock came down.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Eleven of the site&amp;rsquo;s checks drive a headless browser: layout at every window shape the design draws, type scale, translated‑text expansion, contrast, accessibility rules, forced colours, mascot sizing, motion, print across six paper combinations, console errors and visual regression. Run one at a time they took 1,636 seconds, a little over twenty‑seven minutes. A gate that takes twenty‑seven minutes is a gate that gets skipped, and a skipped check is indistinguishable from a passing one.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The wall clock had to come down far enough that running them was the default rather than a decision, without weakening any of them.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The work was measurement first. Each check was timed individually on a twelve‑core machine: layout at 405 seconds, type at 301, translation at 282, contrast at 189, accessibility at 178, and so on down to seventeen. Two findings shaped the answer. Running all of them at once was slower than running four at a time — 265 seconds against 224 — because each check is itself a browser doing parallel work, and oversubscribing the machine costs more than the concurrency wins. And ordering by longest processing time first beat alphabetical order by nearly a third, 224 seconds against 320, which is the classic scheduling result and shows up here because the checks vary by a factor of twenty in cost. So the runner is a bounded worker pool, sized from the core count with a floor of two and a ceiling of four, fed longest‑first. Alongside it the checks were widened rather than narrowed: they now share one viewport table of twenty‑two window shapes, derived from every media query the stylesheet actually contains, which took the layout check alone from 95 seconds to 405.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The gate went from 1,636 seconds to 615, while the checks got broader rather than thinner — the serial cost went up and the wall clock came down. The measurement is the part worth keeping: two reasonable‑sounding choices, running everything at once and running things in the order they were written, were each measurably worse than the alternative.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Mirrored the entire site as 777 Gemini documents and 777 Gopher documents off the same deployed tree, at zero bytes of change to the HTML.</title>
    <id>https://platform.engineer.company/portfolio/mirrored-the-site-to-gemini-and-gopher-137/</id>
    <link href="https://platform.engineer.company/portfolio/mirrored-the-site-to-gemini-and-gopher-137/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Frontend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Internationalization" scheme="https://platform.engineer.company/categories/" />
    <category term="Web Development" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Internationalization &amp; Localization" scheme="https://platform.engineer.company/services/" />
    <category term="Website Development &amp; CMS" scheme="https://platform.engineer.company/services/" />
    <summary>The site is readable over four protocols from one build, at 777 documents each and zero HTML change, and the alternate representations cost about twelve per…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The site is static, has no tracking and no runtime backend, and its argument is that a document does not need a megabyte of JavaScript to be read. That argument is easy to make and hard to demonstrate. Two small internet protocols demonstrate it directly, because neither of them can carry a script at all.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The whole site had to be published over Gemini and Gopher from the same content, without a second content tree and without changing the HTML.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Both are output formats of the same build rather than a separate pipeline. The site generator was given custom media types and output formats, and every page, section and taxonomy term gained two more representations alongside its HTML and its Markdown twin. The result is 777 Gemini documents and 777 Gopher menus produced from the same source, deployed to the same tree, and served by two small daemons on the same host. Two properties made it worth doing rather than a curiosity. Both formats are marked as non‑alternative representations, so nothing about the HTML changed — not one byte, and that was measured rather than assumed. And the Gopher format has no way to put a link inside a sentence, since a menu line is tab‑separated fields, so the prose is hard‑wrapped at sixty‑eight columns during the build; that constraint sharpened the writing in a way the HTML never demanded. A Tor onion mirror sits alongside them, and it is the only public face the platform could add without opening a firewall port, because the daemon dials out and nothing dials in.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The site is readable over four protocols from one build, at 777 documents each and zero HTML change, and the alternate representations cost about twelve per cent of the HTML&amp;rsquo;s own weight on disk. Only one of the four is measured for traffic, and that is stated in the platform&amp;rsquo;s own statistics document rather than being quietly ignored.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Fixed a sitemap where 172 of 176 URLs shared one modification timestamp, by taking the date from git history after establishing that the export rewrites every file on every run.</title>
    <id>https://platform.engineer.company/portfolio/fixed-a-sitemap-with-one-shared-timestamp-140/</id>
    <link href="https://platform.engineer.company/portfolio/fixed-a-sitemap-with-one-shared-timestamp-140/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Brand &amp; Marketing" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Web Development" scheme="https://platform.engineer.company/categories/" />
    <category term="Brand, Marketing &amp; SEO" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Website Development &amp; CMS" scheme="https://platform.engineer.company/services/" />
    <summary>A re-sync after a month of content edits now touches eight files of 186 instead of all of them, and the sitemap says something true.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The site&amp;rsquo;s sitemap told search engines that 172 of its 176 pages had last changed at the same instant. That is not a subtle inaccuracy — a modification date is a promise to a crawler that a page&amp;rsquo;s content changed, and a site making that promise 172 times simultaneously is either telling the truth about a full rewrite or telling nobody anything useful.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The dates had to describe the content rather than the file, without inventing precision the repository does not have.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The cause was that the date came from the file&amp;rsquo;s modification time and the content export rewrites every file on every run, so a single sync stamped the whole corpus. The fix moves the source to the version history, with a fallback chain that tries an explicit field first, then the commit history, then the file. The trap in that fix is worth recording: the literal field name has to appear in the list or the generator never reads it, so a configuration that looks like it prefers an authored date but omits the name silently ignores every authored date. Two other date decisions came out of the same work. The database now carries when each record was written and last revised, kept deliberately separate from when the work happened — those are years apart and conflating them would date a page written this year to a decade ago. And rows in that file are optional and nothing is derived, because the repository&amp;rsquo;s own history begins after the content did: a missing date leaves the field empty rather than recording a migration, on the principle that a precise wrong number is worse than an absent one, since only the wrong one gets believed.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; A re‑sync after a month of content edits now touches eight files of 186 instead of all of them, and the sitemap says something true. The general rule went into the metadata document alongside it, because the same trap applies to every field that has a fallback chain.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Brought 10,242 lines of quality‑gate JavaScript under a formatter and a linter after establishing it was the largest body of code in the repository and the only one nothing read, fixing 13 findings and suppressing none.</title>
    <id>https://platform.engineer.company/portfolio/brought-the-quality-gate-code-under-a-linter-143/</id>
    <link href="https://platform.engineer.company/portfolio/brought-the-quality-gate-code-under-a-linter-143/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Frontend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Frontend Development" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Leadership &amp; Consulting" scheme="https://platform.engineer.company/services/" />
    <summary>The largest and most load-bearing code in the repository is now formatted, linted and type-checked, with thirteen findings fixed and zero suppressions.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The site&amp;rsquo;s quality gate is thirty‑two scripts totalling 10,242 lines of JavaScript. It was, by a wide margin, the largest body of code in the repository, and it was the only body of code nothing read — no formatter, no linter, no type checking. The programs enforcing every rule in the project were the only programs subject to none of them.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The checkers had to be held to the standard they exist to enforce, and the formatter had to be fitted to them rather than the other way around.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The formatter came first, and the indentation width was the interesting decision. The repository&amp;rsquo;s default is four spaces; at four spaces the formatter would have rewritten 2,173 lines of the largest checker. An override to two spaces for those files reduced that to 38 lines of genuine drift. The principle recorded with it is that the formatter is fitted to the code, not the code to the formatter — reformatting two thousand lines to satisfy a preference destroys the ability to read the history of the file. Then the linter, which produced thirteen real findings, all fixed and none suppressed. The Python checkers got the same treatment through a type checker configured at a middle strictness with thirty individual strict‑tier rules enabled on top, chosen by measurement: at that setting the tree is silent, and of the thirty candidates twenty‑nine were already silent and one fired — and that one was fixed rather than exempted. The type checker found two real defects the linter had passed clean, both about a value&amp;rsquo;s shape rather than its syntax.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The largest and most load‑bearing code in the repository is now formatted, linted and type‑checked, with thirteen findings fixed and zero suppressions. The reason it matters more than the line count suggests is stated in the plan: a defect in the site&amp;rsquo;s stylesheet shows up as a page that looks wrong, and a defect in a checker shows up as a check that passes when it should not.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Held the generator to 981 test cases at a 92% branch‑coverage floor with warnings treated as failures, and asserted idempotence by running the whole build pipeline twice from an empty file and requiring the second pass to change nothing.</title>
    <id>https://platform.engineer.company/portfolio/held-the-generator-to-964-tests-and-a-coverage-floor-145/</id>
    <link href="https://platform.engineer.company/portfolio/held-the-generator-to-964-tests-and-a-coverage-floor-145/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Databases" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend &amp; API Development" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Leadership &amp; Consulting" scheme="https://platform.engineer.company/services/" />
    <summary>The pipeline can be re-run against a live database without fear, which is what makes incremental content work possible at all.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; A generator that assembles a database from scratch has a particular kind of bug: it works the first time and corrupts the second. Steps that insert without checking, steps that depend on the order of a previous step&amp;rsquo;s output, steps that are safe alone and not together. None of that shows up in a test that starts from nothing and runs once.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The build had to be proved repeatable rather than merely working, and the test suite had to be large enough and strict enough that a regression could not pass through it quietly.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The idempotence test is the blunt one and the most useful: build the entire database from an empty file, snapshot it, run the whole nineteen‑step pipeline again over the result, and require the second pass to change nothing. Row counts, contents and identifiers all have to match. Around it sit 383 test functions &amp;ndash; 981 cases once the parameterised ones expand &amp;ndash; across forty‑five files and 7,944 lines, covering the pipeline, the renderers, the content loaders, the targeting logic and the checkers. Branch coverage carries a floor of ninety‑two percent enforced in the build rather than reported in a summary, and the suite currently measures about 95 percent, so the floor has headroom without being decorative. Warnings are configured as failures, which is the setting that matters most in practice — a deprecation notice that prints for two years is a deprecation notice nobody reads, and the run that turns it into a red test is the run that gets it fixed.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The pipeline can be re‑run against a live database without fear, which is what makes incremental content work possible at all. The floor is a floor, not a target, and it is worth saying that ninety‑two percent branch coverage still leaves branches nothing has ever taken — the number bounds the risk, it does not remove it, and two of the defects found later in the project were in code the coverage report showed as covered.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Selected every rule the Python linter has as an error, working through 1,815 findings to reach zero, with each of the few exemptions carrying a written reason and two of them backed by a checker instead of a comment.</title>
    <id>https://platform.engineer.company/portfolio/enabled-every-python-linter-rule-as-an-error-147/</id>
    <link href="https://platform.engineer.company/portfolio/enabled-every-python-linter-rule-as-an-error-147/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend &amp; API Development" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Leadership &amp; Consulting" scheme="https://platform.engineer.company/services/" />
    <summary>The linter runs at full strength with zero findings, and every deviation is documented at the line where it is taken.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Most projects pick a comfortable subset of their linter&amp;rsquo;s rules, and the subset is chosen by whichever rules were quiet on the day it was configured. That makes the configuration a record of the code&amp;rsquo;s existing habits rather than a standard the code is held to, and every rule left off is a class of defect nobody will ever be told about.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The default had to be inverted — every rule the tool implements enabled as an error — and the resulting backlog worked to zero rather than negotiated down by turning rules back off.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; Selecting the complete rule set produced 1,815 findings on first run. They were worked through by category rather than by file, because the categories tell you something: unused arguments and shadowed builtins are noise, but the security category, the mutable‑default category and the exception‑handling category each pointed at real behaviour. Genuine incompatibilities exist — a formatter and a linter can disagree about the same line, and a few rules contradict the project&amp;rsquo;s own deliberate choices — and each of the small number of exemptions carries a written reason at the point of exemption saying what the rule wanted and why this code does otherwise. Two of them go further and are backed by a check rather than a comment, so the exemption cannot quietly widen: the rule is off, and a test asserts the specific property the rule would have enforced. Type checking runs in strict mode alongside it, which is a separate and harder standard, and it is the one that caught defects the linter could not see because they are about what a value is rather than how it is written.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The linter runs at full strength with zero findings, and every deviation is documented at the line where it is taken. The cost is real and worth naming: the strictest setting produces findings that are genuinely not worth acting on, and someone has to make that judgement 1,815 times rather than once.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Wrote tests for the checkers themselves after establishing that a checker fed only clean input will one day report clean because it read nothing — planting a misspelling to confirm the spell‑check finds it, and taking an id range from the database rather than from a number in the test.</title>
    <id>https://platform.engineer.company/portfolio/wrote-tests-for-the-checkers-themselves-149/</id>
    <link href="https://platform.engineer.company/portfolio/wrote-tests-for-the-checkers-themselves-149/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Governance" scheme="https://platform.engineer.company/categories/" />
    <category term="Databases" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Governance &amp; Quality" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Leadership &amp; Consulting" scheme="https://platform.engineer.company/services/" />
    <summary>Every checker in the project now has a test that proves it fails on bad input, and the range assertions read from the source of truth.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The project runs a set of custom checkers over its own content — a spell check, an identifier‑range check, a voice check, a figure‑consistency check. Each of them had run green for months. A checker that has only ever seen clean input and only ever reported clean is indistinguishable from a checker that reads nothing at all, and there was no test in the suite that could tell the two apart.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The checkers had to be made to prove they can fail, and the fixtures they check against had to stop being hand‑maintained copies of the thing they describe.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The pattern applied throughout is to plant the defect the checker exists to find and require the checker to find it. The spell check is fed a deliberately misspelled word and the test fails if the run comes back clean. The voice check is fed prose in the first person and must reject it. The buzzword check is fed a banned word. Each of these is a small test and each one closed a real blind spot, because two of the checkers turned out to be reading a narrower set of files than their documentation claimed and had been silently skipping content. The second change is about where a test gets its expectations: the identifier‑range check previously compared against a number written in the test file, which meant every content addition required editing a test, and an editor who updated the number without looking had disabled the check. It now derives the range from the database, so the check describes the data rather than a stale memory of it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Every checker in the project now has a test that proves it fails on bad input, and the range assertions read from the source of truth. The uncomfortable part is what this exposed: a green check had been meaningless in at least two places for an unknown length of time, and there is no way to find out retroactively what passed through.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Found the commit hooks and the quality gate running different checks while a document promised they were the same, by comparing the two lists in a test — the five that only ever ran by hand were the ones reading the CV prose.</title>
    <id>https://platform.engineer.company/portfolio/found-the-commit-hooks-and-the-gate-disagreeing-150/</id>
    <link href="https://platform.engineer.company/portfolio/found-the-commit-hooks-and-the-gate-disagreeing-150/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Documentation" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Leadership &amp; Consulting" scheme="https://platform.engineer.company/services/" />
    <summary>The hook and the gate provably run the same checks, and the prose checks now run on every commit.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The project had a commit hook that runs checks before a commit is accepted, and a full quality gate run on demand. A document stated that the hook runs the gate, so nothing could reach history without passing everything. Both lists were maintained by hand, in two different files, and nothing compared them.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The claim had to be turned into an assertion, which meant enumerating both sets programmatically and failing when they diverge.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The test reads the hook configuration and the gate&amp;rsquo;s task definitions, resolves each to the set of checks it actually invokes, and compares. They did not match. Five checks existed only in the gate and never ran on commit, and the five were not random — they were the ones that read the CV prose itself: the voice check that keeps reviews impersonal, the buzzword check, the figure‑consistency check across languages, the notation check, and the spell check over content. In other words, every check protecting code ran automatically and every check protecting the writing ran only when someone remembered. Given that the writing is the entire product, the exposure was inverted from where anyone would have guessed. The fix was to bring the five into the hook, which required making two of them fast enough to survive a pre‑commit budget, and then to keep the comparison test in place so the two lists cannot drift apart again. The document that had been describing an intention now describes something enforced.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The hook and the gate provably run the same checks, and the prose checks now run on every commit. The trade‑off is the commit hook&amp;rsquo;s runtime, which grew and will keep growing as content grows, and there is a point at which a slow hook gets bypassed — so this fix has a shelf life measured in how long the checks stay fast.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Rehearsed the forge‑side CI hook and found two defects unreachable by reading the file: a fallback that put an unresolvable argument on the hook&#39;s input, and git&#39;s own environment variable following the gate into the checkout and turning 19 tests red.</title>
    <id>https://platform.engineer.company/portfolio/rehearsed-the-forge-side-ci-hook-151/</id>
    <link href="https://platform.engineer.company/portfolio/rehearsed-the-forge-side-ci-hook-151/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Infrastructure" scheme="https://platform.engineer.company/categories/" />
    <category term="Linux &amp; Servers" scheme="https://platform.engineer.company/categories/" />
    <category term="Python" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Infrastructure as Code" scheme="https://platform.engineer.company/services/" />
    <category term="System Administration" scheme="https://platform.engineer.company/services/" />
    <summary>The hook works on both paths and both defects were found before any real push met them. The limit is that a rehearsal is still a simulation: it proves the hook…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The self‑hosted git forge accepts pushes and can run a hook on the server side to reject work that does not pass the gate. A server‑side hook is the one piece of automation that cannot be tested by running it locally: it executes in a bare repository, with no working tree, under an environment the forge sets, reading the pushed references from its standard input. Reading the script and concluding it is correct is a guess.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The hook had to be rehearsed against a real bare repository and a real push before being trusted, rather than deployed and discovered.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The rehearsal creates a bare repository, installs the hook, clones it, commits, pushes, and asserts on both the accept and the reject path. It found two defects, neither of which was visible in the file. The first was a fallback in the argument handling: when the hook could not determine a reference it substituted a placeholder that was not a resolvable object, and because the value arrives on the hook&amp;rsquo;s standard input rather than as a parameter, the failure surfaced as an unrelated error much further down. The second is the one worth remembering. Git exports an environment variable naming the repository directory when it invokes a hook, and that variable is inherited by everything the hook runs. The gate checks out the pushed revision and runs the test suite inside it, and the test suite inherited the pointer to the bare repository — so nineteen tests that touch git resolved against the wrong repository and went red, on code that was correct. The environment has to be cleared at the boundary, and that boundary is invisible unless the thing is actually run.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The hook works on both paths and both defects were found before any real push met them. The limit is that a rehearsal is still a simulation: it proves the hook survives one push shape, and the forge in production sees pushes this rehearsal does not construct, including forced updates and branch deletions.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Stopped an application filling memory at 41 MB a second — a recorded 111 GB of compressed pages on a 36 GB machine — by bounding every event stream, subscribing by event type and putting a rate budget on logging, taking 610,996 log lines down to 1,411.</title>
    <id>https://platform.engineer.company/portfolio/stopped-an-application-filling-memory-at-41mb-a-second-155/</id>
    <link href="https://platform.engineer.company/portfolio/stopped-an-application-filling-memory-at-41mb-a-second-155/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Frontend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Monitoring &amp; Observability" scheme="https://platform.engineer.company/categories/" />
    <category term="Performance Tuning" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Solution Architecture" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Frontend Development" scheme="https://platform.engineer.company/services/" />
    <category term="Platform &amp; Solution Architecture" scheme="https://platform.engineer.company/services/" />
    <category term="Site Reliability &amp; Monitoring" scheme="https://platform.engineer.company/services/" />
    <summary>Memory stays flat under sustained load and the same session that produced 610,996 log lines produces 1,411.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The application filled memory until the operating system killed it. The recorded incident reached 111 GB of compressed pages on a 36 GB machine, climbing at roughly 41 MB a second, and the log file for a single short session held 610,996 lines. A machine in that state is not slow, it is unusable — the kill arrives after the swap has already made everything else on the desktop stop responding.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The growth had to be found rather than guessed at, and every unbounded path had to be given a limit, because one bounded queue next to three unbounded ones is not a fix.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; There were three multiplying causes and the multiplication is why it was so fast. The event stream from the core was consumed without any bound, so events arrived faster than the interface could apply them and the backlog was retained rather than dropped. Every subscriber received every event and filtered afterwards, so the cost of one event was multiplied by the number of listeners, and each listener&amp;rsquo;s filtering allocated. And logging was unbudgeted, so each event produced log lines — which is the compounding term, because the volume of logging was proportional to the volume of the thing going wrong. The fix addressed all three: bounded buffers with an explicit policy for what happens when they fill, subscription by event type so a listener is only woken for events it wants, and a rate budget on logging that collapses repeats rather than writing each one. A regression test drives a high event rate and asserts the memory ceiling holds, so the bound is a property of the build rather than a comment.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Memory stays flat under sustained load and the same session that produced 610,996 log lines produces 1,411. The honest note is that the rate budget on logging discards information: when something goes wrong quickly now, the record of it is deliberately incomplete, and that is a trade made knowingly against the alternative of a machine that stops.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Wrote a parser that reads the real 7,308‑line C header and verifies every call site, every enum constant and that every pointer‑owning class is final, after a hand‑written placeholder header let calls to three removed functions compile, link and crash.</title>
    <id>https://platform.engineer.company/portfolio/wrote-a-parser-that-verifies-every-ffi-call-site-157/</id>
    <link href="https://platform.engineer.company/portfolio/wrote-a-parser-that-verifies-every-ffi-call-site-157/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="APIs &amp; Integration" scheme="https://platform.engineer.company/categories/" />
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend &amp; API Development" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Documentation" scheme="https://platform.engineer.company/services/" />
    <summary>The class of defect that produced the original crash cannot recur, because a stale reference is now a build failure rather than a runtime one.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Early in the project the C interface was represented by a hand‑written header describing the functions the application expected. That header compiled, the application linked, and calls to three functions that no longer existed in the core reached the point of being called and crashed. The compiler and the linker had both been satisfied by a description of the library rather than the library, and the gap only appeared at runtime.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The real header — 7,308 lines and 268 declarations — had to become the authority, and every use of it in the Swift code had to be verified against it automatically rather than by review.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The check is a parser that reads the actual upstream header and builds the set of functions, enum constants and types it declares, then reads the Swift source and resolves every call site and every constant reference against that set. A call to a function the header does not declare fails the build. A reference to an enum constant that has been renamed fails the build. The current count is 132 of the 268 declarations referenced, and knowing which 136 are unused is itself useful, because it says exactly how much of the core the client has not reached. The parser also enforces a rule the compiler cannot: every Swift class that owns a pointer into the core must be final. A non‑final pointer‑owning class can be subclassed, and a subclass that overrides deinitialisation or adds its own lifetime changes when the pointer is freed — a use‑after‑free with no unsafe keyword anywhere near it. The rule is checked by name across the whole tree.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The class of defect that produced the original crash cannot recur, because a stale reference is now a build failure rather than a runtime one. The limitation is that the parser understands the header&amp;rsquo;s declarations and not its semantics: it proves a function exists with a matching name, and a function whose meaning or ownership rule changed upstream while keeping its signature passes without comment.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Took the test suite from six tests over a sixty‑second limit to 135 passing in 8.9 seconds by profiling the main thread and removing the two calls it sat inside for 3,989 samples out of 4,017.</title>
    <id>https://platform.engineer.company/portfolio/took-the-test-suite-under-nine-seconds-158/</id>
    <link href="https://platform.engineer.company/portfolio/took-the-test-suite-under-nine-seconds-158/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Performance Tuning" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Leadership &amp; Consulting" scheme="https://platform.engineer.company/services/" />
    <summary>The suite went from six tests over sixty seconds -- 74 seconds of wall clock -- to 135 tests passing in 8.9, which puts it inside the window where it runs on…</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The test suite had a sixty‑second time limit and six tests were over it. A test suite that takes over a minute stops being run before every change, and a suite that is not run before every change is a report on the past. The instinct in this situation is to raise the limit, and raising the limit is how a suite gets to ten minutes.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The time had to be found rather than budgeted for, which meant profiling the suite instead of reasoning about which tests looked expensive.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The profile was taken on the main thread while the suite ran, and the result contradicted the guess. The main thread sat inside two calls for 3,989 samples out of 4,017 &amp;ndash; so the slow tests were not the ones doing the most work, and almost every test passed through the same two places. The first was a fixed wait used to let asynchronous work settle before asserting — a sleep, effectively, paid by every test that touched the event path whether or not the work had already finished. It was replaced by waiting on the actual condition with a timeout, so a test that is ready in five milliseconds takes five milliseconds and only a genuinely stuck test pays the full wait. The second was per‑test setup that rebuilt an expensive fixture each time, where the fixture was read‑only and could be built once for the suite. Neither was in a test anyone would have nominated as slow; both were in the shared path, which is why the whole suite was uniformly slow rather than a few tests being outliers.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The suite went from six tests over sixty seconds &amp;ndash; 74 seconds of wall clock &amp;ndash; to 135 tests passing in 8.9, which puts it inside the window where it runs on every save. The caveat is that the shared read‑only fixture is now a coupling point — a test that mutates it will produce a failure in a different test, and the suite&amp;rsquo;s speed depends on a discipline the compiler does not enforce.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Reached the half of the messaging core the application had never used — backup transfer, disappearing messages, message editing and resending, verified invitations, proxies and encryption policy — driving every test against the real library with no mocks.</title>
    <id>https://platform.engineer.company/portfolio/reached-the-unused-half-of-the-messaging-core-161/</id>
    <link href="https://platform.engineer.company/portfolio/reached-the-unused-half-of-the-messaging-core-161/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="APIs &amp; Integration" scheme="https://platform.engineer.company/categories/" />
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend Engineering" scheme="https://platform.engineer.company/categories/" />
    <category term="Reliability &amp; Backups" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Testing &amp; QA" scheme="https://platform.engineer.company/categories/" />
    <category term="Backend &amp; API Development" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <summary>The previously unreached half of the core is driven by tests against the real library, and the wrapper carries the highest floor in the project.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; The client used roughly half of what the messaging core offers. The unused half was not obscure — backup transfer between devices, disappearing messages, message editing and resending, verified invitation links, proxy configuration and the encryption policy for a chat. Each is a feature a user would expect and each was an untested region of the C interface, which is the more dangerous fact, because an untested region of a C interface is where the ownership mistakes live.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The unreached capability had to be driven and covered, and the tests had to run against the real library rather than a stand‑in.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The rule adopted was no mocks for the core. A mock of a C interface encodes the developer&amp;rsquo;s belief about what the library does, and every defect worth finding here is a place where that belief is wrong — so a passing mock‑based test is evidence about the mock. Instead the tests create real accounts in temporary directories, drive the real library, and assert on what it actually returns, with each suite cleaning up its own state. That is what made the coverage meaningful: exercising backup transfer meant handling a real transfer&amp;rsquo;s state machine and its failure paths, and exercising verified invitations meant constructing the real link format and having the library parse it. Coverage floors were set per layer rather than as one number, at eighty‑four percent for the core wrapper, seventy‑five for utilities and sixty‑five for models, on the reasoning that the layer touching raw pointers should be held highest and a model that is mostly stored properties should not be padded with tests to hit an average.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The previously unreached half of the core is driven by tests against the real library, and the wrapper carries the highest floor in the project. The cost is speed and determinism: real‑library tests are slower than mocks and they can fail for environmental reasons, which is the price of them being able to fail for real ones.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Audited 644 Rust crates for licence compatibility on every build, and proved the check fires by rewriting one crate&#39;s licence and by moving the pinned core revision without regenerating.</title>
    <id>https://platform.engineer.company/portfolio/audited-644-rust-crates-for-licence-compatibility-163/</id>
    <link href="https://platform.engineer.company/portfolio/audited-644-rust-crates-for-licence-compatibility-163/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Governance" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Security" scheme="https://platform.engineer.company/categories/" />
    <category term="Data Governance &amp; Quality" scheme="https://platform.engineer.company/services/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Security &amp; Access Management" scheme="https://platform.engineer.company/services/" />
    <summary>The distribution position is checked on every build, and the check is known to work because it was made to fail rather than because it has never spoken.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Linking a Rust core into a shipped application means shipping everything that core depends on. The dependency graph is 644 crates. Each carries a licence, some carry more than one, and a single copyleft crate arriving three levels down through a routine version bump changes what the application as a whole may be distributed under — silently, in a lock file nobody reads line by line.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; The licence position had to be verified on every build rather than reviewed once, with an explicit allow list, so that a change in the graph is a build failure and not a discovery made later by someone else.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The audit resolves the full transitive graph and checks each crate&amp;rsquo;s licence expression against a list of terms the project accepts, evaluating the boolean expressions properly — a crate offering a choice of two licences is acceptable if either is on the list, and a crate requiring both is only acceptable if both are. Anything unmatched fails the build rather than warning, and adding a term to the allow list is a deliberate edit with a reason. A check that has never failed is indistinguishable from one that cannot fail, so it was made to fail on purpose, twice. Once by rewriting a crate&amp;rsquo;s licence expression to something the list does not accept, which is the shape of a crate changing its terms upstream between versions &amp;ndash; the case no human review catches, because the crate itself is not new. Once by moving the pinned core revision without regenerating the audit, which is the shape of a core bump quietly bringing a new dependency with it. Both provocations failed the build as intended, and the check was left in place rather than widened.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; The distribution position is checked on every build, and the check is known to work because it was made to fail rather than because it has never spoken. Before it existed, the bundle, the licence file and the project&amp;rsquo;s own README all made a claim about 644 crates that nothing had verified. The limit is precise and should not be overstated: the check reads the declared licence metadata, and metadata can be wrong or incomplete. It proves nothing about a crate that misdeclares itself, and it is not legal advice.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Held four repositories to one history standard — conventional, emoji‑free, no attribution trailers, enforced by a commit‑message hook — alongside 46 instruction documents that govern how the work is done.</title>
    <id>https://platform.engineer.company/portfolio/held-five-repositories-to-one-history-standard-165/</id>
    <link href="https://platform.engineer.company/portfolio/held-five-repositories-to-one-history-standard-165/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-09-13T01:45:50+02:00</published>
    <category term="Agile &amp; Scrum" scheme="https://platform.engineer.company/categories/" />
    <category term="Automation &amp; CI/CD" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps" scheme="https://platform.engineer.company/categories/" />
    <category term="Documentation" scheme="https://platform.engineer.company/categories/" />
    <category term="Project Management" scheme="https://platform.engineer.company/categories/" />
    <category term="Technical Leadership" scheme="https://platform.engineer.company/categories/" />
    <category term="DevOps &amp; CI/CD Automation" scheme="https://platform.engineer.company/services/" />
    <category term="Project Management (Agile)" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Documentation" scheme="https://platform.engineer.company/services/" />
    <category term="Technical Leadership &amp; Consulting" scheme="https://platform.engineer.company/services/" />
    <summary>Five repositories share one history format and one instruction structure, both enforced by hooks rather than by discipline.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Situation.&lt;/strong&gt; Five repositories built over eighteen months by one person is the situation where process is easiest to skip, because there is nobody to coordinate with and the cost of an unreadable history is paid entirely by a future self who has not complained yet. It is also the situation where an inconsistent history is most likely, since each repository can drift into its own habits with nothing pulling them together.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Task.&lt;/strong&gt; One standard for history and one standard for instructions had to apply across every repository the work is authored in, and it had to be enforced mechanically rather than remembered.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Action.&lt;/strong&gt; The commit standard is a conventional prefix naming the kind of change and a scope, a subject under a fixed length, no emojis, and no attribution trailers of any sort — the last of these because a trailer crediting a tool is not a fact about the change, and history is for facts about changes. A commit‑message hook rejects anything that does not conform, in every repository that carries work, so the standard is a property of the repository rather than of whoever is committing. The distribution on the largest repository shows what the work actually was: 156 feature commits, 133 fixes, 128 documentation, 81 chores, 26 refactors, 20 style, 5 performance and 3 test. Documentation is close enough to fixes to be worth noticing, and that is a consequence of the second half of this — 46 instruction documents across the four, each covering one domain, each written as rules rather than description, all reachable from a single entry document per repository so there is one place to start. A documentation linter enforces per‑file size budgets and index membership, so the set stays navigable rather than growing into an archive.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Result.&lt;/strong&gt; Five repositories share one history format and one instruction structure, both enforced by hooks rather than by discipline. What this does not do is make the history good: the format is checked and the content is not, so a conforming subject line that describes nothing passes exactly as well as one that explains the change.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Opening a dApp inside Solana mobile wallets</title>
    <id>https://platform.engineer.company/notes/solana-mobile-wallet-deeplinks/</id>
    <link href="https://platform.engineer.company/notes/solana-mobile-wallet-deeplinks/" rel="alternate" type="text/html" />
    <updated>2026-09-13T01:45:50+02:00</updated>
    <published>2026-08-10T00:00:00Z</published>
    <summary>Why Phantom, Solflare and Backpack browse deep links fail on mobile, and the exact formats, trigger rules and fixes that make them work.</summary>
    <content type="html">&lt;p&gt;A React dApp built on &lt;code&gt;@solana/wallet-adapter-react&lt;/code&gt; connects desktop wallets&#xA;without trouble, but on a phone the same flow falls apart: the wallet has to&#xA;open the dApp inside its own in-app browser, and the deep links that should&#xA;make that happen quietly do not. Backpack lands on a &amp;ldquo;download the app&amp;rdquo; page;&#xA;Solflare opens the app but never the site; every variant seems to fail. We took&#xA;the problem apart, and it turned out to be four separate problems wearing one&#xA;symptom.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-four-problems&#34;&gt;The four problems&lt;/h2&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;The Backpack link was malformed.&lt;/strong&gt; The only documented format is&#xA;&lt;code&gt;https://backpack.app/ul/v1/browse/&amp;lt;url&amp;gt;?ref=&amp;lt;ref&amp;gt;&lt;/code&gt; — a universal link with&#xA;the target URL in the path and a required &lt;code&gt;ref&lt;/code&gt;. A custom-scheme guess like&#xA;&lt;code&gt;backpack://ul/v1/browse?url=...&lt;/code&gt; matches no route the app registers, so the&#xA;user ends on the wallet&amp;rsquo;s install page.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Solflare needs its universal link too:&lt;/strong&gt;&#xA;&lt;code&gt;https://solflare.com/ul/v1/browse/&amp;lt;url&amp;gt;?ref=&amp;lt;ref&amp;gt;&lt;/code&gt;, not the bare&#xA;&lt;code&gt;solflare://&lt;/code&gt; scheme. A bare scheme can launch the app without routing it —&#xA;which is exactly &amp;ldquo;the app opens, but the site tab has to be opened by hand&amp;rdquo;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Both parameters must be encoded.&lt;/strong&gt; &lt;code&gt;url&lt;/code&gt; is the full absolute dApp address&#xA;and &lt;code&gt;ref&lt;/code&gt; is the requesting origin, each passed through &lt;code&gt;encodeURIComponent&lt;/code&gt;.&#xA;An unencoded &lt;code&gt;?&lt;/code&gt; or &lt;code&gt;&amp;amp;&lt;/code&gt; in the target corrupts the parse, and the wallet&#xA;opens on its home screen instead of the browser tab.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;The trigger matters as much as the link.&lt;/strong&gt; Universal links only switch apps&#xA;on a navigation the operating system trusts — and they deliberately do&#xA;nothing when pasted into the address bar, which is also how a perfectly&#xA;correct link &amp;ldquo;fails&amp;rdquo; during testing.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;the-documented-formats&#34;&gt;The documented formats&lt;/h2&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Phantom: &lt;code&gt;https://phantom.app/ul/browse/&amp;lt;url&amp;gt;?ref=&amp;lt;ref&amp;gt;&lt;/code&gt; — no &lt;code&gt;/v1&lt;/code&gt; in this&#xA;one.&lt;/li&gt;&#xA;&lt;li&gt;Solflare: &lt;code&gt;https://solflare.com/ul/v1/browse/&amp;lt;url&amp;gt;?ref=&amp;lt;ref&amp;gt;&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Backpack: &lt;code&gt;https://backpack.app/ul/v1/browse/&amp;lt;url&amp;gt;?ref=&amp;lt;ref&amp;gt;&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;One pattern serves all three:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;const WALLET_BROWSE = {&#xA;  phantom: (url, ref) =&amp;gt;&#xA;    `https://phantom.app/ul/browse/${url}?ref=${ref}`,&#xA;  solflare: (url, ref) =&amp;gt;&#xA;    `https://solflare.com/ul/v1/browse/${url}?ref=${ref}`,&#xA;  backpack: (url, ref) =&amp;gt;&#xA;    `https://backpack.app/ul/v1/browse/${url}?ref=${ref}`,&#xA;};&#xA;&#xA;function walletBrowseLink(&#xA;  walletName,&#xA;  targetUrl = window.location.href,&#xA;) {&#xA;  const build = WALLET_BROWSE[walletName.toLowerCase()];&#xA;  if (!build) return null;&#xA;  return build(&#xA;    encodeURIComponent(targetUrl),&#xA;    encodeURIComponent(window.location.origin),&#xA;  );&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;triggering-the-link-so-ios-and-android-accept-it&#34;&gt;Triggering the link so iOS and Android accept it&lt;/h2&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Render a real anchor, precomputed.&lt;/strong&gt; A plain&#xA;&lt;code&gt;&amp;lt;a href={walletBrowseLink(&#39;phantom&#39;)}&amp;gt;&lt;/code&gt; is the most reliable trigger on both&#xA;platforms.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;If it must be programmatic&lt;/strong&gt;, assign &lt;code&gt;window.location.href&lt;/code&gt; synchronously&#xA;inside the tap handler — no &lt;code&gt;await&lt;/code&gt;, no &lt;code&gt;fetch&lt;/code&gt;, no &lt;code&gt;setTimeout&lt;/code&gt; first. After&#xA;asynchronous work the gesture context is gone, and iOS falls back to the&#xA;wallet&amp;rsquo;s website. Never &lt;code&gt;window.open&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Never test by pasting into the address bar.&lt;/strong&gt; Universal links deliberately&#xA;do not fire there; test with a tapped link or a QR code scanned by the&#xA;camera.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Mind the messenger webviews.&lt;/strong&gt; Opened inside Telegram&amp;rsquo;s or Instagram&amp;rsquo;s&#xA;in-app browser, universal links are frequently swallowed and the wallet&amp;rsquo;s&#xA;plain website loads instead. User-agent detection is heuristic at best, so&#xA;also give users a visible escape hatch: &amp;ldquo;open in Safari or Chrome, then&#xA;connect&amp;rdquo;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;the-bigger-fix-on-android&#34;&gt;The bigger fix on Android&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Hand-rolled deep links are the iOS story. On Android, Solana Mobile&amp;rsquo;s Mobile&#xA;Wallet Adapter lets a dApp running in the mobile browser connect straight to&#xA;the installed wallet app, with no in-app-browser detour at all. Recent versions&#xA;of &lt;code&gt;@solana/wallet-adapter-react&lt;/code&gt; register the mobile adapter automatically, so&#xA;upgrading the wallet-adapter packages can fix Android by itself. The target&#xA;architecture: Mobile Wallet Adapter on Android, browse universal links on iOS,&#xA;where Apple allows no equivalent.&lt;/p&gt;&#xA;&lt;h2 id=&#34;verifying-on-a-device&#34;&gt;Verifying on a device&lt;/h2&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Real device, wallet installed, link opened from the system browser — not&#xA;from a messenger.&lt;/li&gt;&#xA;&lt;li&gt;Tap a rendered link or scan a QR code; never paste into the address bar.&lt;/li&gt;&#xA;&lt;li&gt;Confirm the wallet opens and the dApp loads in its in-app browser tab — the&#xA;second half is the part that fails.&lt;/li&gt;&#xA;&lt;li&gt;Repeat without the wallet installed: the universal link should degrade to&#xA;the wallet&amp;rsquo;s website. That page appearing while the app is installed means&#xA;the link or the trigger is still wrong.&lt;/li&gt;&#xA;&lt;li&gt;Then test the messenger path, and add the &amp;ldquo;open in browser&amp;rdquo; hint if it&#xA;fails there.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;sources&#34;&gt;Sources&lt;/h2&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.phantom.com/phantom-deeplinks/deeplinks-ios-and-android&#34;&gt;Phantom: deep links on iOS and Android&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.solflare.com/solflare/technical/deeplinks/other-methods/browse&#34;&gt;Solflare: the Browse deep link&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.backpack.app/deeplinks/other-methods/browse&#34;&gt;Backpack: the Browse deep link&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.solanamobile.com/mobile-wallet-adapter/mobile-apps&#34;&gt;Solana Mobile: Mobile Wallet Adapter&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</content>
  </entry>
</feed>
