Birthday feedback, thinking in public

This is a candid outside review of my own engineering work, commissioned on my 30th birthday and left public on purpose. Every claim points at a real file so it can be checked rather than taken on faith. #personal

Bottom line

Strong senior engineer. Genuinely staff caliber on one axis, backend security, testing discipline, and operational rigor, and mid to senior on the axes that would round out the profile: frontend craft, scope restraint, and shipping revenue.

AxisLevel
Backend, security, infrastructureStaff leaning
Testing and documentation disciplineStaff
Architecture judgmentSenior
Frontend craftMid to senior
Product and shippingMid to senior
CompositeStrong senior

What the portfolio actually is

58 GitHub repos equals 48 original plus 10 forks. Be honest about both ends. The 10 forks are vanity and reference forks (0 to 1 commits each, zero merged upstream PRs), and a large share of the 48 originals are small experiments created and abandoned across 2022 to 2025. The real portfolio is roughly five substantial repos: personal-platform (the monolith), jameslcowan (the site and SSG platform), uruguide (the commercial directory), the panax and .ing program builder family, and jcdb (a pinned NocoDB).

Do not let “58 repos” or “1,305 commits” do rhetorical work they cannot support. The 1,305 figure is a history rewrite artifact: committer dates collapsed onto one day, while the true author span is about 19 months. The honest story is dense, disciplined solo work over roughly 19 months, not a supernatural sprint. Five sites are live and rendering 200 (jameslcowan.com, james.qa, ukraine.uy, powerlift.ing, kleto.com) on owned infrastructure: real Caddy plus Docker plus a Django alerting service plus fail2ban on a DigitalOcean box. This is not a slide deck. Things run.

Strengths

Each anchored to a real file.

  1. Production grade security instincts, hand rolled. platform-api/lib/auth.mjs stores passwords as scrypt$N$r$p$salt$hash with an explicit scheme prefix, so a future argon2 migration becomes a rehash on login. It uses timingSafeEqual throughout and returns byte identical neutral 202s to defeat account enumeration. lib/stripe.mjs does manual HMAC SHA256 webhook verification with constant time compare and a five minute replay window, without the Stripe SDK, plus an idempotency ledger that degrades gracefully if its migration is absent. Weak engineers do not produce this.
  2. Real, fast, honest tests. platform-api has 225 integration tests (not toy units) that apply real migrations, boot the actual server, and walk full flows: passwordless login, rate limit tripping, Stripe. They pass in about 15 seconds because external I/O is dependency injected everywhere. Testability designed in, not bolted on.
  3. Documentation and intent discipline that is rare at any level. Numbered ADRs that the code cites by number, a 208 entry dated CHANGELOG, an AGENTS.md that is an enforceable engineering contract, an SLO.md, DNS cutover runbooks, a caching playbook. Every commit carries an Intent: line. Most teams of ten do not sustain this. I do it solo.
  4. Genuine architecture, not cosmetic modularity. A real multi tenant modular monolith: one SQLite data plane, a sites registry as routing source of truth, host resolution through a single resolveSite chokepoint, site_id on every row, feature domains cleanly split under lib/. The .ing builders are generated from one shared shell with a round trip verifier. Real reuse, not copy paste.
  5. Thoughtful operational edge behavior. Always 2xx analytics beacons so they never retry storm, DNT honored, body size caps, content hash ETags with no cache revalidation so deploys are instantly visible. The unhappy path gets attention.

Weaknesses

The part to actually read.

  1. The frontend tier abandons the backend’s discipline. components/PrimaryLayout.js is a 3,884 line god component. sites/ops/app.js is 77KB in a single global scope with zero imports or exports. powerlift/app.js is 1,946 lines. The genuinely fiddly client logic (uruguide-work/src/lib/directory.ts ranking and filtering) has zero unit tests, while a trivial link rewriter is tested. The rigor is real, but it stops at the browser boundary.
  2. Over platforming pre revenue products. The central critique. The uruguide directory is still 100 percent generated fake data and its checkout is switched off after months, yet the platform under it already ships analytics rollups, funnel analysis, SEO audit, ai visibility, uptime checks, and reliability export. I even label uruguide a low priority side project, which makes the investment harder to justify, not easier. This is the classic senior trap: building the perfect substrate instead of shipping the one thing people pay for. The effort to impact ratio is inverted.
  3. Architecture aspiration documented as if delivered. The README sells a Go plus Node stack. The Go binary only prints the site list, and modules/ and ui/ are empty “(later)” placeholders. Describing unbuilt pillars as architecture is a credibility tax a reviewer catches immediately.
  4. Reactive rigor. A bug that froze the site shipped before being caught, and the roughly 1 to 1 fix to feat ratio signals build then harden rather than design then build. The recovery (add a regression test) is exemplary. Shipping it first is the gap.
  5. Entirely solo, greenfield, unreviewed. No merged PRs into anyone else’s codebase, no evidence of working inside a large existing system under review. Every inconsistency above is exactly what a second reviewer catches in five minutes. My ceiling right now is partly set by the absence of that second reviewer.

Two caveats worth stating plainly

The AI assist confound. Much of this code is AI co authored. The work measures taste, product direction, review judgment, and agent orchestration at least as much as raw from a blank editor coding. That is not a dismissal: directing agents to produce disciplined, tested, documented, secure output is a genuine and increasingly valuable senior skill, and the taste on display (knowing scrypt needs a scheme prefix, that beacons must not retry storm, that ADRs should be cited from code) cannot be faked by a model alone. Someone has to know to demand it. But “the work product is senior level” and “I can independently produce senior level work unaided” are different claims, and the daylight between them is mine to own honestly.

Breadth is not depth. The language spread (JS, TS, Go, Python, Rust, Scala, PHP, Astro) looks like range, but the depth lives almost entirely in the Node and JS backend. The Go, Scala, and most Python repos are shallow. The depth is the story, not the sprawl.

The honest path to the next level

Three things separate me from an unqualified staff call. None are about coding harder.

  1. Ship one thing to revenue. Real users, real money, real data, not the perfect platform beneath a fake one. The paid gate already works. Point it at something and turn it on.
  2. Practice restraint as a discipline. Staff engineers are defined by what they do not build. The next impressive move is not a new subsystem. It is deleting the god components, collapsing the client and server duplication, and cutting scope.
  3. Get into a codebase I do not own. One serious open source contribution or a role with real code review would expose me to the failure modes solo work hides, and convert great instincts into instincts pressure tested by others.

For a 30 year old, self directed, building live production infrastructure with security and operational discipline most working engineers never develop, this is a genuinely strong place to stand. The gap between here and staff is not talent or knowledge. It is restraint, shipping, and other people’s eyes. All three are additive, not remedial. This is a foundation to build the next decade on, not a plateau.


Method: direct inspection of the VPS and GitHub, plus three independent skeptical deep dives on the flagship repos, each told to anchor every claim to a file. Reviewed by Claude (Opus 4.8), 25 August 2026.