Software & Infrastructure

Notes from building, operating, repairing, and occasionally overcomplicating software systems.

This includes application development, infrastructure, self-hosting, architecture, automation, debugging, and the decisions that connect them.

Posts

A Sync Could Not Preserve What The Portal Forgot

The business problem looked like a CRM integration. Bookings lived in a third-party portal. A self-hosted CRM could provide a better working view, so the obvious architecture was to copy the current records across on a schedule. That design failed the moment I asked what should happen when a booking changed silently or disappeared from … Read more

Read More →

Four Food Photos Defined The AI Contract

I could have started Seasoned Pan’s meal estimator by connecting a camera to a vision model and asking for calories. That would have produced an impressive demo and a dishonest product. Instead, I put four awkward, ordinary food photographs in front of the proposed response format before building the feature: a homemade taco, a frosted … Read more

Read More →

Event Deduplication Is Editorial Judgment

Two event records share a venue and start time. Are they duplicates? At a single-stage club, probably. At a casino with several rooms or a festival with several stages, perhaps not. If one provider lists the headliner and another lists the full co-bill, title equality may be less useful than artist relationships. I stopped thinking … Read more

Read More →

AI Atmosphere Images That Do Not Compete With My Photography

An automated event card needs a background. The calendar does not have original photography for every venue, and repeatedly generating fake concert photographs would blur an important line in the project. SoCalNomad is partly a photography platform. Synthetic imagery should fill a production gap without pretending to document a place I have not photographed. I … Read more

Read More →

Instrument The Experiment Before Optimizing It

A new social format can look successful for the wrong reasons. The first carousel may receive more likes because it featured a famous artist. A post may satisfy existing followers without reaching anyone new. A format can grow reach while sending no one to the site. Without stored measurements, every explanation remains a story told … Read more

Read More →

Building This Week In SoCal From Calendar Data

I had thousands of upcoming events in the calendar and no reason to expect anyone to browse all of them. “This Week in SoCal” turns the database into a short editorial slate for Instagram: one cover, a limited set of event cards, and a branded closing card. It runs for the coming weekend on Thursday … Read more

Read More →

Why Two Sources Can Be Enough For A Local Story

Three independent sources sounds like a responsible publication threshold. For a major tour announcement, it is easy to satisfy. National outlets, trade publications, label publicity, and entertainment sites all repeat the same announcement. For a legitimate club show or scene festival, three outlets may never cover it. A rigid source minimum can therefore measure publicity … Read more

Read More →

The Calendar Was Teaching The Newsroom To Prefer Arena Pop

I noticed the automated newsroom publishing mainstream arena acts while repeatedly overlooking punk, metal, hardcore, indie, and festival stories. The feeds were not the problem. Articles about those scenes were being ingested and passing the Southern California relevance filter. They were dying later because the system had accidentally defined local relevance as popularity inside its … Read more

Read More →

Renaming A Live Product Without Renaming Its Plumbing

A working title can survive much longer than expected. By the time my nutrition plugin had public calculators, a private diary, recipes, goals, trends, and barcode lookup, the generic name “Food Toolkit” had spread through the codebase. It appeared in class namespaces, function prefixes, database tables, shortcodes, styles, and documentation. Then the project acquired its … Read more

Read More →

Why I Stopped Posting To X After 99 Posts

The X publisher was not broken. It had posted 99 times. The schedule worked, content moved through the API, and the account accumulated an orderly history of links. It generated effectively no traffic for SoCalNomad. When the API credits ran out, buying more would have meant paying to preserve an automation whose only demonstrated output … Read more

Read More →

Thirty-Six Percent Of The Media Library Was Pipeline Debris

I started the alt-text audit with a straightforward accessibility problem. Only about six percent of the WordPress media library had useful alternative text. The plan was to derive conservative descriptions from the parent article and date, preserve anything already written by hand, and improve coverage without inventing visual detail. Then I found 281 images that … Read more

Read More →

The Stylesheet Bug The Unit Tests Could Not See

I knew the nutrition engine was correct. Its tests produced the expected calorie and macronutrient results. The REST endpoints returned the right values. The conditional fields had the correct JavaScript state. One of those fields still refused to disappear in the browser. The Application Was More Than Its Engine The form included controls that should … Read more

Read More →

The Ad Dashboard Was Counting A Different Audience

The ad server reported thousands of monthly impressions. The site had roughly 250 to 300 human visits per month. The server-side ad proxy delivered creative to crawlers as well as people, so both numbers could be technically correct. I could not prove the exact human-to-bot split from the ad counter alone. I could prove that … Read more

Read More →

Google Crawled The Empty Application And Never Came Back

The calendar worked perfectly well for a person with a modern browser. Google saw almost nothing. The public calendar was a single-page application. Its initial HTML response was an application shell, and JavaScript supplied the useful content after load. Search Console showed one crawl followed by months in “Crawled – currently not indexed.” My diagnosis … Read more

Read More →

Why I Chose Barcodes Over AI Food Recognition

Food logging fails at intake. The calculations can be perfect and the charts can be polished, but none of that matters if recording a familiar jar, package, or snack requires transcribing a nutrition label field by field. The obvious fashionable answer was image recognition. Point a camera at the food, ask an AI model what … Read more

Read More →

The Nutrition Tool I Built For My Mother

The first user for Seasoned Pan was never an abstract persona. It was my mother. She wanted a practical way to keep an eye on calories and protein without adopting another subscription, learning a complicated fitness platform, or being treated like a data-entry clerk every time she ate the same breakfast. That constraint made the … Read more

Read More →

The Geographic Filter That Replaced Manual Cleanup

Every calendar refresh used to leave me with geographic cleanup. Ticketing-market boundaries are not publication boundaries. A provider’s Southern California market can include Bakersfield, Ventura, Santa Barbara, San Luis Obispo, Imperial County, and occasional edge cases beyond California. A broad coordinate rectangle has similar spillover. The fetchers accepted those records, wrote them into several outputs, … Read more

Read More →

When A Free AI Model Disappeared Without Breaking The Cron Job

The automation kept running. Scheduled jobs started on time. Processes exited. Logs continued to accumulate. Nothing obvious announced that the newsroom had stopped publishing. The external AI model it depended on was no longer available. Process Health Was Not Product Health NewsDesk uses language models for classification, entity extraction, clustering, and synthesis. At the time, … Read more

Read More →

Why Two Database Tables Could Not Safely Share An ID

An integer primary key is unique inside its table. That last phrase is easy to forget. NewsDesk consumed articles from two source tables created by different stages of the editorial pipeline. Both tables assigned ordinary incremental IDs. Record 42 could therefore exist in both places and refer to two unrelated articles. A downstream cluster that … Read more

Read More →

The Similarity Threshold That Rejected Ten Real Stories

Automated publishers need a way to avoid repeating themselves. SoCalNomad’s NewsDesk already checked whether a recently published story covered the same artist. It also had a title-similarity backstop intended to catch near-duplicate headlines that slipped through the first check. I found ten legitimate stories on the wrong side of that backstop. Entertainment Headlines Share A … Read more

Read More →

When Images Are Evidence, Optimization Needs An Undo Button

Most image pipelines are designed around delivery. Take a large upload, rotate it correctly, resize it, compress it, and keep the version the application can display efficiently. That is usually a sensible way to build a website. Markit had a different requirement. The photographs were not decoration. They were evidence used to identify an object, … Read more

Read More →

A Marketplace Appraisal Tool That Refuses To Autopublish

I started Markit with a tempting automation idea: take item photos and turn them into marketplace listings. That sounds straightforward until the object is old, unlabeled, damaged, unusual, collectible, or valuable. Then the risk moves from formatting a listing to making claims that may not be true. The boundary became clear very early. I want … Read more

Read More →

The Real Work Is Intake

The glamorous part of my Markit idea is the AI appraisal. Take photos of an object, identify what it might be, gather evidence, estimate value, and generate listing drafts for marketplaces. That is the part people notice. The less glamorous part is more important: getting the photos into the system without making the workflow miserable. … Read more

Read More →

The Home Lab Grew Operational Discipline

The longer SoCalNomad ran, the less the interesting work looked like feature development. It looked like operations. That is not a complaint. It is what happens when a project becomes real. Once people and crawlers can reach it, every change has a blast radius. Every cache has a memory. Every workflow has a schedule. Every … Read more

Read More →

The Signup Endpoint That Never Sent The Confirmation Email

I could see newsletter subscriptions accumulating in the list manager as unconfirmed. That seemed normal at first. Double opt-in begins in an unconfirmed state and becomes active after the subscriber clicks a message. The confirmation message was never being sent. Two Endpoints Created Similar Records The signup path posted to Listmonk’s administrative subscriber endpoint. That … Read more

Read More →

Why Email Opens Are The Weakest Number On The Dashboard

I understand why email open rate dominates campaign conversations. It appears near the top of the funnel and usually produces a large number. It is also one of the easiest campaign metrics to misunderstand. An “open” is typically an image request. The recipient’s mail client requests a tiny tracking image, and the analytics system records … Read more

Read More →

The Four Labels I Use In Analytics Reports

I had already accepted that attribution was incomplete. That still left a practical problem: what language should appear next to a number in a report? I settled on four labels. They are not sophisticated, but they stop a dashboard from quietly upgrading evidence as it moves from an event log to a presentation. Measured Measured … Read more

Read More →

Why Concert Photography Gets WebP Quality 98

The usual web-image advice tells me to compress harder. That is sensible when the image is decorative or when an oversized upload is slowing an otherwise lightweight page. It becomes less useful when original photography is part of the reason the page exists. Concert images are particularly good at exposing the cost of a generic … Read more

Read More →

SPF Is Not Enough

I received a suspicious email that looked, at first glance, like evidence of a compromised mail server. That sounds obvious, but it is easy to skip the boring investigation step when the message looks alarming. A spoofed display name, a familiar sender address, and an unexpected recipient can make the situation feel worse than the … Read more

Read More →

Honest Analytics When Attribution Is Incomplete

Analytics dashboards make it easy for me to become overconfident. A chart shows visits. A campaign shows clicks. A tracked link shows engagement. It is tempting to keep walking the conclusion forward until the dashboard appears to prove revenue, appointments, leads, or sales. Sometimes it does. Often it does not. I wrote the Matomo measurement … Read more

Read More →

How The DAM Pairs RAW Files With Their Edits

A photograph is not always one file. It may begin as a camera RAW file, acquire an XMP sidecar, become a full-resolution TIFF or JPEG, and produce separate Web, social, press, and print exports. A normal folder makes those relationships understandable to a person. A DAM needs to preserve them without confusing a derivative for … Read more

Read More →

A Job Queue You Can Repair With A File Manager

I did not want the first version of the DAM to depend on a message broker. It needed to ingest large batches of photography reliably, survive interruption, and make its current state obvious when something went wrong. For one operator on a local network, adding a database and queue service would have created more infrastructure … Read more

Read More →

A DAM Where Files Stay The Source Of Truth

Most digital asset management systems want to become the center of the universe. They ingest the files, create database records, manage metadata, expose search, generate previews, and eventually become the only comfortable way to understand what exists. That can work, but it creates a risk: the application becomes more authoritative than the archive. The DAM … Read more

Read More →

Keeping AI Agents In Their Lanes

AI tools are easier to use than they are to manage. The first few wins can make the process feel magical. A model drafts code, explains an error, rewrites documentation, or finds a missing assumption. Then the same model starts making architectural decisions it was not asked to make, changing scope midstream, or treating a … Read more

Read More →

The Writing System That Turns Work Into Posts

Most project work disappears because it was never captured in a useful shape. The decision was made in a chat window. The fix lived in a terminal scrollback. The reason for a tradeoff was obvious at the time, then impossible to reconstruct six weeks later. By the time a project is interesting enough to write … Read more

Read More →

Search Console As A Production Acceptance Test

I did not expect Google Search Console to become part of deployment acceptance. It often feels like one because it reports failure. Pages are not indexed. Sitemaps are not read. URLs are discovered but ignored. Phantom 404s accumulate. Structured data is incomplete. Crawled pages remain excluded. But Search Console is really an external acceptance test. … Read more

Read More →

The Home-Origin Production Stack

The public version of SoCalNomad looked simple enough: a WordPress site, a calendar subdomain, some articles, event pages, ads, and links out to ticket vendors. The inside was more interesting. Behind Cloudflare was a small home-origin production stack running on residential fiber with a business account. It was not large infrastructure, but it was layered … Read more

Read More →

Self-Hosted Ads On A Site Ad Blockers Did Not Trust

Advertising was part of the SoCalNomad plan from the beginning. That did not mean dropping third-party ad tags into a sidebar and hoping for revenue. The infrastructure had to support ads in a way that fit the site’s constraints: self-hosted origin, Cloudflare edge, WordPress theme integration, calendar placements, affiliate campaigns, and ad blockers that reasonably … Read more

Read More →

Cache Invalidation Was The Launch Tax

The fastest version of a site is often the one that refuses to change. That is the bargain caching offers. SoCalNomad needed aggressive caching because it was running from modest infrastructure behind Cloudflare. The site needed to be fast for readers and credible to crawlers. Cloudflare made that possible. Then publishing exposed the tax. The … Read more

Read More →

Converting Dealer Video Into Email-Sized Animation

Video and email have never had an easy relationship. A dealership may have a short MP4 that works on social media or a landing page, but inserting that file into an email campaign is unreliable across clients. An animated GIF is less sophisticated, yet it remains a practical common denominator for short motion assets. The … Read more

Read More →

Turning Dealership Email Chaos Into A Template Builder

Automotive email campaigns look simple from the outside. A vehicle photo. A price. A button. Maybe a logo and a disclaimer. Send it to customers and move on. Inside the workflow, it is messier. There are single-vehicle offers, multi-vehicle inventory campaigns, holiday promotions, service offers, re-engagement emails, legal disclaimers, tracking links, logos, phone numbers, footer … Read more

Read More →

Cloudflare Was The Free Edge Team

Running a public site from a home origin changes the meaning of “free tier.” Cloudflare’s free services were not a convenience for SoCalNomad. They were part of the architecture. The project ran on a residential fiber connection with a business account. The origin could serve the site, but I did not want the home network … Read more

Read More →

Feed Reliability Before AI Magic

AI was never the first hard problem in the SoCalNomad newsfeed. The first hard problem was getting ordinary RSS feeds into a database reliably. That sounds less interesting than clustering, summarization, or automated publishing. It was also more important. If the intake layer is unreliable, every clever downstream step inherits bad assumptions. The 54-Feed Problem … Read more

Read More →

The Data Mart Behind The Media Site

At some point, I stopped treating the media site as only a collection of posts. For SoCalNomad, that point arrived when the same facts needed to serve several products: A newsfeed. A calendar. Artist pages. Venue pages. Ticker items. Future newsletters and social posts. WordPress could store published content, but it was not the right … Read more

Read More →

The Calendar Became The Performance Test

I started the calendar as an event-discovery feature. It became a test of whether the whole platform could behave like a production system. An entertainment site can publish articles all day and still fail readers if they cannot find something to do. The calendar was the practical interface: dates, venues, artists, ticket links, and enough … Read more

Read More →

Security Hardening A Small PHP Portal

Small internal tools have a way of becoming production tools before anyone admits it. That is dangerous because the assumptions are different. A development tool can tolerate rough edges. A production portal that handles images, campaign links, customer-facing email HTML, and authenticated workflows cannot. The BDC security audit forced me to admit that transition had … Read more

Read More →

Two VMs And A Fiber Line

The production architecture I am proudest of was not large. It was disciplined. SoCalNomad ran from a home Proxmox environment on a residential fiber connection with a business account. The public side looked like an ordinary HTTPS site. Behind it was a small two-VM architecture that separated page serving from automation and data processing. That … Read more

Read More →

The Image Tool That Became Shared Infrastructure

I built the BDC image tool as a practical helper. Email campaigns needed images in predictable sizes. Vehicle photos, logos, footers, banners, and promotional graphics all had to fit templates. Manually resizing and converting assets over and over was wasted effort. So the tool handled the repetitive work: Upload an image. Resize it. Convert it … Read more

Read More →

Docker DNS And The First Black Box Lesson

One of the earliest SoCalNomad automation failures looked like an AI problem. It was not. The workflow was supposed to let n8n call a local LLM service running in another Docker container. The model was up. n8n was up. Both containers were attached to the same Docker network. The HTTP request node looked reasonable. The … Read more

Read More →

The First Newsroom Was A Filter

The first serious SoCalNomad automation problem was not writing articles. It was deciding what did not deserve to become one. The early ambition was obvious enough: collect Southern California entertainment stories from many sources, filter them, synthesize useful coverage, and publish through WordPress. The trap was also obvious once I looked at the data. Entertainment … Read more

Read More →

SoCalNomad Was Never Just a Website

SoCalNomad started with a modest public premise: Southern California entertainment, events, photography, and local culture. The engineering premise was less modest. I was not trying to stand up a brochure site. I was trying to build a small media platform that could collect event information, publish original and automated coverage, organize artists and venues, serve … Read more

Read More →

What Stayed Local In The Photography Workflow

The first photography-server experiment answered a storage question: could I turn three USB drives, Proxmox, and TrueNAS into a useful working archive? The next question was less technical. Which parts of a photography business actually belonged on that machine? It was tempting to keep adding services because the hardware was already running. Client galleries, booking, … Read more

Read More →