Category: Uncategorized

  • Pre-Flight

    Pre-Flight

    What I Asked For

    A checklist is the easiest software in the world to build. A list of lines, a box next to each one, done. The problem Pre-Flight is actually trying to solve is the part a checklist can’t do on its own: letting the person who isn’t there know that the back door really got locked. Pilots run checklists because memory fails under routine, and a shop closing up at 9 PM is all routine. So the tension is between two people. The owner wants proof. The employee wants to lock up and go home. Every extra step for the second person makes the first person’s proof less likely to exist.

    That settled the biggest decision early. Employees don’t get accounts. Each person gets a private link, and the link is their login. There’s no app to install, no password to forget, and no sign-up screen standing between a closing shift and the alarm panel. If someone leaves, the owner deactivates them or resets the link, and the old one stops working. A whole team can be loaded from a spreadsheet in one import.

    The checklist itself has two kinds of strictness. A list can be sequential, meaning items unlock one at a time, and that rule is enforced by the server rather than just the screen. Tap ahead on a stale page and the answer comes back “Finish the earlier items first.” Individual items can also be marked critical, and those don’t respond to a tap at all. You press and hold for one full second while a bar fills across the row, and if you let go early nothing happens. “Arm the alarm” should not be something you can check off with a thumb brushing the glass on the way out. Every check-off is timestamped, so the owner doesn’t just learn that the list was finished. They learn that the front door was locked at 9:07 and the alarm was armed at 9:08.

    Assignments repeat on chosen weekdays or happen once, with a due time in the company’s own timezone. Each occurrence becomes a run, and the run takes a copy of the checklist’s items at that moment. That wasn’t cosmetic. If an owner rewords an item next month, last month’s record still says exactly what the employee was asked to confirm. There’s also a small rule that matters more than it looks: if you set up a 9 PM closing list at 11 PM, tonight’s run isn’t created, because the first thing a new user should see is not an overdue alert for something that was impossible to finish.

    Alerts go both directions. The owner gets an email the moment a run is completed, with how long it took and whether it was late. A background check every five minutes looks for anything past due and unfinished, and says whether it was started and abandoned or never opened at all. Each late run alerts exactly once.

    The first version had one owner per company and treated everyone else as a link. It was wrong within the hour. A manager who was added to the team and then signed up got dropped onto a “create your company” screen, as if they’d wandered in off the street. The fix was to match signed-in people to team entries by verified email, which makes an invite simply the act of adding someone with their address. One person can now belong to several companies with a switcher between them, and roles split three ways: owners run settings, managers run the team and lists, and members just get their checklists.

    The stats page stays deliberately small. Over 30 days it shows each person’s and each checklist’s on-time rate, missed runs, typical duration, and a streak of consecutive on-time finishes. “Typical” is the median, because one night where someone left the list open for three hours shouldn’t make the closing routine look like a three-hour job.

    What It Is

    Pre-Flight is Next.js 16 and React 19 in TypeScript, about 3,600 lines, with Clerk for sign-in, Neon Postgres through Drizzle, Resend for email, and a Vercel cron for the five-minute check. It went from an empty scaffold to a working product in an afternoon, and the multi-company rework landed eighteen minutes after that.

    The hardest problem was time, specifically the gap between “9 PM” and a moment in time. The due time is wall-clock time in the company’s timezone, but the database and the server think in UTC, and daylight saving means the offset between them changes twice a year. The conversion takes a guess, measures the timezone’s offset at that guess, corrects, and measures again, so a due time that lands near a clock change still resolves to the right instant. It does this with the browser’s built-in date formatting rather than a date library. Runs are also checked for both today and yesterday, so a list due late at night doesn’t vanish when the server’s calendar has already rolled over.

    The second problem was making sure things happen once. Runs are created by the cron, but also whenever an owner opens the dashboard or an employee opens their link, so a list shows up immediately instead of waiting up to five minutes. That means several requests can try to create the same run at the same time. The database only allows one run per assignment per day, so the losers quietly step aside. Completion works the same way: when two taps finish a list at nearly the same moment, only one of them gets to mark it complete and send the email. Overdue runs are marked as alerted before the email goes out, so a slow send can’t produce a second alert five minutes later.

    There’s also a demo company for screenshots, Ridgeline Moto Works, a motorcycle shop with six people, five checklists, and 30 days of history generated from a fixed random seed so it looks identical every time it’s reset. Today’s due times are placed relative to the moment you open it, so the dashboard always shows one list done, one done late, one overdue, one in progress, and one not started yet. Every demo address ends in example.com, and the email sender refuses to send there, so the fictional shop can’t email a real person.

    Storm Runner and Wheelie Club were games, where the worst outcome is a lost run. This one’s worst outcome is an unlocked door and an owner who assumed otherwise. The point isn’t the checklist. It’s the timestamp at 9:08.

  • Stack Ledger- Systems Manager

    Stack Ledger- Systems Manager

    What I Asked For

    Anyone who runs a small business website ends up running a stack without ever deciding to. There’s WordPress, the host under it, the DNS in front of it, a CRM, a payment processor, a sync plugin that moves members between two of those, a Zapier account holding the whole thing together, and a dozen paid plugins, each renewing on its own date. Each piece has its own login page and its own renewal email, and each needs some chore done every few months that nobody remembers until something breaks. Stack Ledger is one page that answers three questions about all of it: what do I have, what does it cost, and what needs doing.

    The design problem is that a stack is not a list. Things connect to other things, and some things live inside other things. So every item is one of five kinds. A system is a platform you run on. Hosting is where it lives. A connector moves data between systems. An app is a tool you use on the side. A plugin is a paid add-on that lives inside a system. Connections are stored on one side and shown from both, so linking WP Fusion to HubSpot means HubSpot’s card also says it’s linked to WP Fusion. Nobody has to keep both sides in sync by hand.

    Plugins were the awkward case. Twenty paid WordPress plugins as twenty cards would bury everything else on the page, so plugins fold into a collapsible list inside their parent’s card, with a count, a yearly total, and a flag for how many renew soon. A plugin whose parent gets deleted gets a card of its own rather than disappearing. Connectors are the exception that proves the rule: WP Fusion is technically a WordPress plugin, but it’s also the thing syncing your members to your CRM, so it keeps its own card and shows up in the plugin list too. Anything marked as retiring gets struck through, which is a quiet way of saying “don’t renew this.”

    Upkeep is modeled as recurring tasks, not reminders. Each task has a title, a frequency in days, and the date you last did it. The due date is computed from that, so there’s nothing to reschedule: you press Mark done and it tells you when it’s next due. A task you’ve never logged shows as “not logged” instead of pretending to be overdue. Anything due within 14 days turns amber, and anything at or past due turns red.

    All of that feeds a single section at the top called Needs attention. It pulls tasks due in the next 14 days, renewals in the next 30, SSL certificates with three weeks or less left, sites that are down, and WordPress installs behind the latest release, then sorts everything into one list by how soon it bites. That list is the product. The cards below it are the reference manual.

    The site checks are the part that does work while you’re not looking. Give any item a URL to monitor and once a day the server checks whether it’s up, how long it took to respond, when its SSL certificate expires, and which version of WordPress it’s running, compared against the latest version from WordPress.org. It keeps the last 30 results per site, so a slow day or a single outage shows up as a blip in a history rather than an alarm you already missed.

    What it doesn’t do matters as much. There are no accounts, no logins, and no cloud. It listens only on your own computer, and the README says plainly not to expose it to a network without adding a login first. There’s no sync between machines either. You pick one computer as the main one, and moving data is a deliberate export and restore, because two copies quietly merging is how ledgers end up wrong.

    What It Is

    Stack Ledger is a Node server with zero dependencies and a single HTML page, about 1,200 lines in total: roughly 300 for the server, 830 for the page, and a short demo data file. It needs Node 18 or newer and nothing else, so there’s no install step, no build step, and nothing to update. It runs at localhost on port 4321, and a small script registers it as a Mac login item that restarts itself if it stops. That second part isn’t optional in spirit, because the daily site check only happens while the server is running.

    Most of the engineering went into not losing data. The ledger is a JSON file, and every write goes to a temporary file first and is then renamed into place, so a crash mid-save can never leave half a file behind. Writes run one at a time, in order. Every change triggers a snapshot, but snapshots wait three seconds for things to settle, so editing five fields in a row produces one snapshot labeled with what changed rather than five. The newest 50 are kept. On top of that, a dated copy goes to your Documents folder once a day, outside the app folder entirely. Restoring anything, from a snapshot or a file, takes a snapshot first, which means a restore can itself be undone.

    The page checks every 15 seconds whether anything has changed and redraws if it has, but it skips the check while the tab is hidden or while you’re halfway through editing something. The server also refuses any write that didn’t come from its own page, which is the minimum a local app owes you when every other tab in your browser can see localhost.

    There are four themes: light, dark, and two terminal skins, green and amber, which drop the color coding and put a prompt in front of every label. There’s also a demo page that serves the same interface filled with a fictional studio’s stack. Its dates are generated relative to today, so it always shows a realistic mix of overdue, due-soon, and healthy states, and it never reads or writes the real ledger. That made the screenshots possible without publishing anyone’s actual renewal dates.

    It is not a clever piece of software, and it isn’t trying to be. It’s the spreadsheet everyone means to keep, except this one checks your sites every morning.