A ground-up rebuild of Online Taxman's website — a tax and financial services firm that handles US taxes for expats, entrepreneurs, and internationally-operating businesses. After years of maintaining their WordPress site, we replaced it with a modern, statically-rendered site that loads fast, keeps WordPress purely as a content back end, and guides visitors through detailed consultation forms that route straight into the firm's internal workflow. I was lead developer — owning architecture, data flows, integrations, and all the interactive and backend work — alongside my design partner Laurel, a designer and frontend developer who owned the design and the design system.
Online Taxman
A ground-up rebuild of a tax services firm's website on Astro and Svelte, replacing WordPress with a fast, statically-rendered architecture. I led development, owning the monorepo, integrations, and complex consultation forms alongside my design partner Laurel. Lead volume jumped roughly 10-15x.

Online Taxman
Live
Introduction

The Challenge
Online Taxman needed to move beyond WordPress after years of performance and flexibility constraints. Their lead volume was low, and they believed a significantly more modern and focused site was essential to scale a growing tax and financial services practice serving US expats and international entrepreneurs. The site also faced a serious operational problem: bots were spamming contact forms and booking fake consultations, wasting accountants' time.
The Outcome
Lead volume increased roughly 10–15x (excluding spam), delivering the growth the business needed.
Tech Stack
Frontend
- Astro
- Svelte
- SCSS
- Zag.js
- TanStack Form
- Partytown
- Usercentrics
- Pagefind
- reCAPTCHA
- CSS
- Font Awesome
- Svelte 5
Language
- TypeScript
- GraphQL
- JavaScript
- Zod
Backend
- WordPress
- Turso
- Cloudflare Turnstile
- OpenAI
- Bouncer
CMS
- Notion
Database
- libSQL
- SQLite
DevOps
- pnpm
- Netlify
- Zapier
- Husky
- lint-staged
- Knip
- dependency-cruiser
- GitHub Actions
- Rollup
Tooling
- ESLint
- Stylelint
- Calendly
- Google Tag Manager
- Vitest
- Prettier
- Claude
- Cursor
- GitHub Copilot
- Astro 7 as the core framework, using a static-first islands architecture so most pages ship no client-side JavaScript at all. Interactive pieces are Svelte 5 islands, hydrated only where they earn their weight.
- TypeScript in strict mode across the whole codebase (no
anyallowed by convention), with SCSS Modules for component-scoped styling on top of a shared design-token layer. - A pnpm workspace monorepo I architected up front: two deployable sites (
sites/onlinetaxmanand the second brand, Global Expat Advisors) plus@repo/sharedfor cross-site components and utilities, and dedicated packages for design tokens, ESLint, Stylelint, and TypeScript config presets. - WordPress retained as a headless CMS, consumed over GraphQL through custom Astro content loaders — roughly 150 blog posts and a few dozen pages migrated without asking the content team to change how they work.
- Zag.js headless state machines power accessible accordions, dialogs, comboboxes, selects, and multi-step flows; TanStack Form handles form state in the Svelte islands.
- Netlify hosting with edge functions and serverless functions for form endpoints, plus Turso (libSQL) for submission logging, rate-limit state, and ban history.
- Integrations across Zapier webhooks (CRM routing), Calendly (consultation booking), Notion (pre-call questionnaire sync), Google Tag Manager with Partytown, and Usercentrics for consent.
- Pagefind for fully static, index-at-build-time site search, wrapped in a shared search core both sites consume.
- Quality tooling: Vitest, ESLint, Stylelint, Prettier, Husky + lint-staged, Knip, dependency-cruiser, and GitHub Actions CI.

Key Implementation Details
Monorepo architected before it existed — The second brand, Global Expat Advisors, is what drove the workspace split, and we planned for it from the beginning rather than refactoring into it later.
- The Online Taxman build was deliberately structured as the "build out the shared framework" phase, so extraction into
@repo/sharedwas step one of building GEA rather than a cleanup pass. - Strict import-direction rules keep the layering honest: sites may import from
@repo/sharedand@repo/design-tokens, shared may import tokens, and tokens import nothing — enforced by a style-boundary checker and a custom token-reference script that rejects undefined custom properties. - Laurel's design system lives inside that structure as a three-layer token contract: neutral tokens in
@repo/design-tokens, site-owned--theme-*overrides per brand, and site-private palette constants that shared components are forbidden from touching.
Layered anti-spam defense for a real operational problem — Bots weren't just filling the inbox; they were booking fake consultations and burning real accountant hours.
- Rate limiting backed by Turso, with tunable thresholds, ban history, and manual IP access rules.
- A captcha provider abstraction that supports both Cloudflare Turnstile and reCAPTCHA (a two-pronged v3/v2 flow), with hostname fail-open handling so legitimate users never get stuck.
- Bouncer email validation as a third layer, catching disposable and invalid addresses before a submission ever reaches the CRM.
- The combination has almost entirely solved the problem — spam moderated substantially without adding friction for real prospects.
Complex conditional consultation forms — The multi-step intake flows are the site's revenue path, and they carry a lot of machinery.
- Conditional branching across steps with Zag.js step machines, partial-save so a half-finished form survives a refresh or a return visit, and resubmission guards.
- A Zapier retry/replay system so a failed webhook delivery is recoverable rather than a silently lost lead.
- Attribution tracking and GTM dataLayer events wired through the funnel, plus dynamic confirmation pages and Calendly booking confirmation.
- A dedicated
test:consultationcommand runs as part of the production build, so the highest-risk path is verified on every deploy.
PageData mirroring convention — Each site's src/data/pages directory mirrors src/pages exactly, giving a single source of truth for routing metadata, SEO, schema.org output, sitemap control, and redirects. Page copy and section composition live in data files rather than inline in routes, which keeps routes thin and makes cross-site reuse of section shells practical.
Performance work as a first-class task — Redirect-chain flattening, category-archive build path optimization, build throttle-queue fixes, bundle analysis via a per-site bundle-analyze script, and Partytown offloading for third-party tags.
Documented, enforceable conventions and CI — The repo carries a substantial rules and skills library (.agents/rules, .agents/skills) covering forms, content loaders, PageData, rate limiting, schema.org, and WordPress GraphQL.
- CI detects affected workspaces and runs only the relevant quality gates and test suites, keeping pull request feedback fast in a growing monorepo.
- A separate GitHub Actions workflow runs an OpenAI-backed PR review that loads path-scoped instruction files and a component inventory, then scores changes against a threshold before merge.
What I Contributed
- Architected a pnpm workspace monorepo from the ground up to support two brands with shared UI components, design tokens, and strict import-direction rules enforced by custom boundary checkers.
- Built all interactive features and backend functionality, including complex multi-step consultation forms with conditional branching, partial-save, Zapier retry/replay workflows, and resubmission guards.
- Designed and implemented a layered anti-spam system combining rate limiting backed by Turso, dual captcha providers (Turnstile and reCAPTCHA v2/v3), and Bouncer email validation to stop bots from wasting operational capacity.
- Owned all third-party integrations and data flows: WordPress GraphQL content loading, Zapier webhook routing, Calendly booking, Notion sync, and Turso-based logging and rate-limit state.
Outcome
-
PageSpeed Insights scores improved from ~60 to ~90 on mobile and ~80 to ~85 on desktop in real-world production (with third-party tags).
-
Spam moderated substantially after the layered anti-spam defenses went live, nearly eliminating the operational cost of fake consultation bookings.
-
The monorepo foundation paid for itself immediately when the second brand, Global Expat Advisors, was built on the same shared component library and form backend.
The rebuild moved PageSpeed from roughly 60 to 90 on mobile and 80 to 85 on desktop in the real world — and around 96 mobile / 100 desktop measured without the client's third-party analytics tags. More importantly, lead volume is up roughly 10–15x excluding spam, which is the number that actually mattered to the business. The shared monorepo foundation then paid for itself immediately: the second brand, Global Expat Advisors, was built on top of the same component library, tokens, and form backend rather than starting from scratch.