Portfolio
Web applications, native Apple apps, distributed systems, and developer tools I've built.
Web Apps
Side projects that turned into real SaaS products.

AccessHawk
Web ApplicationCombined Playwright browser automation with AI integration through OpenRouter to build a full scanning pipeline. Designed the job queue architecture for scheduled scans, implemented tiered subscription billing with Polar.sh, and applied deep WCAG knowledge to make the output actually useful.
- Nuxt 4
- TypeScript
- MongoDB
- Redis
- BullMQ
- Playwright
- Polar.sh
- OpenRouter
- Doppler
- Railway

SereneReader
Web ApplicationBuilt a real-time RSS platform from scratch with background job processing via BullMQ, Server-Sent Events for live updates, and a custom theming engine. Localized into 13 languages with complete message coverage, per-locale plural rules, and locale-specific date and currency formatting. Recently launched native iOS, iPad, macOS, and Apple Watch apps that keep feeds, folders, read state, and Focus Mode in sync with the web app.
- Nuxt 4
- TypeScript
- i18n (13 locales)
- Swift
- SwiftUI
- MongoDB
- Redis
- BullMQ
- Polar.sh
- Resend
- Doppler
- Railway

MyPetDay
Web ApplicationLed the full architecture as Solution Architect and Lead Developer. Set up the infrastructure on Railway, hardened the security layer, optimized MongoDB queries for performance, and integrated AWS S3 for media storage. Focused on building a clean, mobile-first experience.
- Nuxt 4
- TypeScript
- MongoDB
- Polar.sh
- AWS S3
- Tailwind CSS
- Doppler
- Railway

SPConnector
Web ApplicationEngineered a multi-tenant system with real-time WebSocket communication, intelligent print routing logic, and AES-256-GCM encryption for customer data. Integrated the Shippo and PrintNode APIs and built a load-balanced queue to handle thousands of daily orders reliably.
- Vue.js
- Express.js
- MongoDB
- Redis
- Polar.sh
- Resend
- Tailwind CSS
- Doppler
- Railway
Apple Apps
Native apps for Apple platforms, built in Swift and SwiftUI.
SereneReader
- iPhone
- iPad
- Mac
- Apple Watch
The native client for the SereneReader platform: one Swift 6 codebase covering iPhone, iPad, Mac, and Apple Watch. Mutations write to a local SwiftData store first and replay from a queue when connectivity returns, so starring and marking read work offline, while a long-lived Server-Sent Events connection reconciles state with the web app in real time. Focus Mode, the five hand-tuned themes, and full keyboard navigation on iPad and Mac came across with it.
- Swift 6
- SwiftUI
- SwiftData
- watchOS
- WKWebView
- Server-Sent Events
- Keychain
- OPML
Pulse: Widgets for GA4
- iPhone
- iPad
- Mac
- Apple Watch
Glanceable Google Analytics for people running more than one site. Live visitor counts land on the home screen, the lock screen, the Apple Watch, and the Mac menu bar, each stamped with an honest "as of" time so a stale number never reads as a live one. Built as a single multiplatform Swift 6 target under strict concurrency, with hand-rolled OAuth 2.0 PKCE, Keychain-stored tokens, and a SwiftData cache shared across targets through an App Group. Zero third-party dependencies.
- Swift 6
- SwiftUI
- SwiftData
- WidgetKit
- watchOS
- StoreKit 2
- OAuth PKCE
- GA4 Data API
- Xcode Cloud
SiteGrade: Security Check
- iPhone
- iPad
- Mac
A security report card for any website. Enter or share a URL and SiteGrade grades what the site actually serves browsers, A to F: security headers, the TLS certificate chain and expiry, DNS and email-auth records, HTTPS redirect behavior, and mixed content, with every finding explained in plain English. All checks are passive and read-only. The scan engine sits directly on Network.framework and dnssd, with hand-written DNS wire parsing and DER certificate decoding, in one Swift 6 codebase under strict concurrency for iPhone, iPad, and Mac. Zero third-party dependencies.
- Swift 6
- SwiftUI
- SwiftData
- Network.framework
- dnssd
- WKWebView
- StoreKit 2
- Share Extension
- Xcode Cloud
Open Source
Tools I built for myself and decided to share.
A11yHawk
The open-source, self-hostable accessibility scan engine behind AccessHawk. Loads a page in a real browser, runs Lighthouse audits, and optionally has an LLM of your choice analyze the full page against WCAG criteria. No accounts, no telemetry.
- Free Lighthouse-only scans in seconds, no API key
- BYOK AI analysis against every WCAG criterion
- JSON, markdown, and self-contained HTML reports
- Annotated screenshots with issues boxed on the page
- CLI with CI gating, HTTP server mode, Docker image
- TypeScript
- Node.js
- Playwright
- Lighthouse
- OpenRouter
- Docker
Claude Code Plugins
Plugins I wrote for Claude Code. Security audits, performance checks, accessibility testing, ADO integration. I use these daily.
- Security audits: Hours of review in minutes
- Performance audits: Bottleneck and N+1 detection
- Accessibility audits: Catches issues tools miss
- Azure DevOps: Work items and time logging
- Git and phase planning automation
- TypeScript
- Node.js
- MCP
- Claude AI
- Azure DevOps API
- Git
- OWASP
UmamiDash
Real-time analytics dashboard for self-hosted Umami instances. Built it to monitor website traffic across multiple sites without switching between Umami tabs.
- Real-time visitor and pageview monitoring
- Multi-site dashboard in a single view
- Clean UI with shadcn-vue components
- Connects to any self-hosted Umami instance
- Vue 3
- shadcn-vue
- Express
- TypeScript
- Umami API
UmamiHA
Home Assistant integration for self-hosted Umami analytics. Built it to surface website traffic data directly in my HA dashboards without checking Umami separately.
- Real-time active visitors sensor
- Pageviews, visits, and bounce rate tracking
- Multi-site support with per-website sensors
- HACS compatible for easy installation
- Configurable update intervals
- Python
- Home Assistant
- HACS
- Umami API
PulseRT
macOS menu bar app that shows real-time GA4 visitor counts. I wanted to see traffic without opening a browser tab.
- Real-time visitor counts in menu bar
- Native Swift/SwiftUI, no Electron
- Configurable refresh: 5-60 second intervals
- Secure local credential storage
- Last updated timestamp visibility
- Swift
- SwiftUI
- macOS
- GA4 API
- Google Cloud
ReplyQueue
Chrome extension that finds social posts related to your content as you scroll, then suggests replies. Built it to make content promotion less tedious.
- Passive discovery: extracts posts as you scroll
- AI-powered contextual reply suggestions
- Keyword and semantic content matching
- Adjustable relevance thresholds (10-90%)
- Local-first: all data stays on device
- Vue 3
- TypeScript
- Tailwind CSS
- Chrome Manifest V3
- RSS
GA Mac Dashboard
Native macOS app for monitoring multiple Google Analytics real-time dashboards in a customizable grid. Built it to track all my sites at once without juggling browser tabs.
- Multiple GA4 dashboards in one window
- Customizable grid layout with configurable rows and columns
- Shared sessions across views, login once
- Fullscreen mode for distraction-free monitoring
- Persistent URLs between sessions
- Swift 6.0
- SwiftUI
- GA4
- WebKit
GA Win Dashboard
Windows port of GA Mac Dashboard for monitoring multiple Google Analytics dashboards in a customizable grid. Portable single-exe distribution, no install required.
- Multiple GA4 dashboards in one window
- Customizable grid layout with configurable rows and columns
- Shared sessions across views, login once
- Fullscreen mode for distraction-free monitoring
- Portable .exe, no install required
- Electron
- TypeScript
- electron-vite
- GA4
- CSS Grid
Technical Blog
What I'm working on and what I've figured out.
I Open-Sourced the Engine Behind AccessHawk. Meet A11yHawk.
A11yHawk is the open-source, self-hostable accessibility scan engine that powers AccessHawk. Real browser capture, Lighthouse audits, and bring-your-own-key AI analysis against every WCAG criterion. Build your own accessibility tooling without the per-scan SaaS bill.
Your Claude Prompts Are an Audit Gap. LiteLLM Closes It.
A staff engineer's case for putting LiteLLM in front of Claude to close the audit gap: PII filtering, secret detection, virtual keys per user, and a real log of every prompt. Config examples and an honest take on the tradeoffs.
84 Malicious TanStack Versions Hit npm. My Portfolio Pulled Zero.
On May 11, 2026, the Mini Shai-Hulud worm published 84 malicious versions across 42 TanStack packages in a six-minute window. My portfolio runs on TanStack Start. None of the bad versions ever touched it. Here is why, and what every project running npm should be doing right now.
That Accessibility Widget Isn't Protecting You. It's a Lawsuit Waiting to Happen.
Accessibility overlays like AudioEye and accessiBe promise WCAG compliance with a single line of JavaScript. The FTC, the courts, and the disability community all disagree. I dig into why overlays fail, what legal exposure they actually create, and what it takes to build accessibility into your source code.
Railway Is My Go-To Infrastructure. Here's Why I Recommend It to Enterprise Clients
I run several production projects on Railway, from SaaS platforms with background workers to simple marketing sites. After years on AWS and Azure, Railway cut my go-to-live time from days to minutes. Config-as-code, built-in databases, non-serverless deployments by default, and a platform that ships meaningful features weekly.
Why I Chose Nuxt Over Next.js for AccessHawk
I built AccessHawk with Nuxt instead of Next.js. Vue's reactivity model and auto-imports made me faster, and I didn't have to give up TypeScript or testing to get there.
