The AI Lab on this site has four interactive apps, a serverless backend with model routing and rate limiting, a Playwright suite across three browser engines, a media pipeline that generates social cards from the rendered pages, and a deploy path from commit to production. I built all of it, and I maintain all of it.
I'm not saying that to brag. I'm saying it because "can ship an AI feature end to end" is a specific skill profile, and the best way to explain it is to walk the loop.
Backend
Firebase Functions, Node 20, one function per endpoint. The chat function validates the request at the edge, resolves a server-side prompt key, checks the model against a cost allowlist, walks a fallback chain with a circuit breaker, and applies a per-visitor rate limit backed by Firestore. Every AI Lab app talks to the same function with its own prompt keys, so hardening it once hardened all of them.
The part that separates "it works" from "it ships" is the failure handling. Provider error bodies stay in the logs. Retryable and permanent errors are classified differently at the server and at the client, on purpose. Secrets are Firebase Secrets, and the function refuses to run in production if the IP-hashing salt isn't bound. None of that is visible to a visitor, and all of it is why the chat has stayed up through provider outages and model retirements.
Frontend
Vanilla JavaScript, no framework, no build step. That was a deliberate choice for a portfolio: the source a reviewer reads is the source the browser runs. The design system is modern CSS, oklch color, clamp() typography, container queries, a light and dark theme applied before first paint, prismatic gradients defined in exactly one file. Accessibility is a requirement: skip links, ARIA patterns for the tier selector and navigation, visible focus rings, reduced-motion handling in the shared animation layer.
The four apps share modules for configuration, storage, error handling, and transcript rendering, which is where a solo engineer saves the most time. Promptpad, Problem Solver, and Agent Agenda each have their own state model and prompt contracts, and each one inherited the chat's request contract instead of reinventing it.
Testing
Fifty-seven spec files. Desktop Chrome, Desktop Firefox, Mobile Safari. A canary of eighteen sentinel tests runs first. A batched runner splits the rest into groups so browsers don't exhaust the machine. Axe-core scans on twelve pages. Contrast ratios computed in-browser. Pixel-position checks on the navigation across page types. Mocked API responses for the chat so the suite is deterministic. Visual baselines at several viewports.
The suite is the reason I can change a shared module and know within minutes what it touched. It's also the thing I trust least on faith, which is why the runner got audited and fixed after I found it reporting killed batches as passing.
Media and content
The blog renders Markdown client-side, and a script screenshots each rendered article to produce Open Graph, card, and thumbnail images in both themes, recorded in a manifest with signatures so nothing regenerates unnecessarily. Another script produces the sitemap and llms.txt from one page manifest. Another turns artist-supplied hero PNGs into fifteen responsive variants each. None of this is glamorous. All of it is the difference between a blog and a pile of files.
Deploy
Firebase Hosting for the static site with strict security headers. Firebase deploy for functions. A predeploy gate that probes each production model with a tiny request. A production smoke script that checks status codes and headers after the deploy. Two git repositories, one public for the site and one private for the infrastructure, with the public one mounted as a directory of the private one.
Where assistants change the math
The honest answer is that this scope wasn't reachable for one person on evenings and weekends a few years ago. What changed isn't that assistants write the code. It's that they carry context between sessions when the rules are written down, they execute plans I've approved while I'm doing something else, and they run the verification loop without getting bored of it.
The role that's left for me is the one I'd want anyway: decide what to build, set the constraints, review the plan, review the diff, own the outcome. When that role is done well, one person can hold the whole surface. When it isn't, no number of assistants helps.
What "senior" means here
Owning the entire delivery surface changes what senior means. It isn't knowing the deepest thing about one layer. It's knowing enough about every layer to make the tradeoffs between them, and being the person accountable when the tradeoff was wrong. The portfolio is the proof I can offer for that: not a list of technologies, but shipped work you can use, with the source open and the tests visible.