Automation-focused engineer who builds tools and systems that solve real problems. Over 20 years of enterprise IT experience spanning infrastructure, scripting, and systems architecture — now combined with full-stack product development. Known for translating user needs into working solutions, debugging complex systems across the stack, and automating manual processes out of existence.
Looking for senior roles bridging infrastructure, platform, and applied AI — remote preferred.
Currently: enrolled in MIT's Applied AI and Data Science Program (expected completion September 2026), studying for CISSP, Anthropic AI certifications, and IaC tooling.
Python, Flask, JavaScript, React, HTML/CSS, REST API design, SQL, PostgreSQL, Redis
PowerShell, Python, PowerCLI, Bash, process automation, scheduled task orchestration
Stripe payments & billing, Twilio SMS, MailGun / SendGrid email, Git, CI/CD workflows
Windows Server, VMware vSphere, Azure, Active Directory, Exchange Online, DNS/DHCP
ServiceNow, Device42, SCCM, Claude Code, ChatGPT Codex, GitHub Copilot, Fusion 360, 3D printing (resin & FDM), ESP32 / Raspberry Pi
Building with the Claude API (Anthropic), Claude Code in Action (Anthropic), Risk Management (Packt), CISSP (in progress)
More than two decades of building and debugging systems before AI tooling existed shaped how I use it now. The same instincts that catch subtle bugs in unfamiliar codebases — recognizing when an answer is too clean, when a fix doesn't address the root cause, when a confident explanation is wrong — apply directly to the suggestions these tools produce. AI is the most useful collaborator I've ever worked with on routine code. It is also confidently wrong often enough to require a senior engineer at the wheel.
Tools I use day-to-day. Claude Code in the terminal for repository-aware work, Claude.ai for design conversations and architectural sounding-board sessions, GitHub Copilot for inline completion in the IDE, and ChatGPT Codex for cross-checking and second opinions. Different tools, different sweet spots — relying on any one of them in isolation leaves capability on the table.
What I trust them with. Boilerplate scaffolding — CRUD endpoints, test setup, glue scripts that aren't load-bearing. First-pass debugging — rubber-ducking errors, narrowing down where a bug probably lives, generating hypotheses faster than I can alone. Refactoring and code review — catching consistency issues, dead branches, and the obvious smells a fresh pair of eyes would spot. In all three cases the work is recoverable: if the AI is wrong, I notice quickly and the cost is low.
What I don't trust them with. Architecture and design decisions, where being subtly wrong compounds over months. Anything touching production data, auth, or infrastructure changes — places where confident-wrong is catastrophic and the fix is hard to walk back. Domain-specific business logic that requires understanding edge cases or regulatory context the model has no way to know. And I will never merge code I haven't read end-to-end, even if it works — AI fluency hides brittle assumptions, and "it ran" isn't the same as "I understand it."
The synthesis. The judgment is mine; the velocity is theirs. AI has not replaced the senior engineering work — reading the system, understanding the constraints, making the trade-offs. It has compressed everything around that work. Used well, that's a multiplier. Used poorly, it accelerates the production of code no one really understands, including the person who wrote it.
"To err is human; to really foul things up requires a computer." Now hand that computer to someone who's outsourced their judgment to an AI. Watch out.
Automation and systems engineering for a global manufacturing organization with 1,000+ Windows Servers across a VMware/Azure hybrid environment spanning 15+ VMware clusters. Designed and built an end-to-end SOX audit reporting pipeline — PowerShell collection, Power Automate Desktop orchestration, and Python (Pandas, openpyxl) for assembly, validation, and image-embedded report generation — that collapsed a two-week manual workflow of per-server scans, hand-formatted Excel sheets, and pasted screenshots from ADUC and password managers into a 1-2 hour automated run. Built dozens of additional PowerShell, PowerCLI, and Python tools to streamline server provisioning, compliance validation, and infrastructure management. Authored SCCM SQL reporting queries to replace manual data collection, designed Device42 auto-discovery assessments, and led incident management and L2/L3 escalations for critical infrastructure.
Network infrastructure mapping and documentation using Python and SQL, building tooling to audit and visualize the environment. Developed automation in PowerShell, Python, and VB to reduce manual administration overhead. Participated in a website platform migration in a Linux environment and assisted with an enterprise security rollout — identifying a privilege escalation vulnerability during testing.
Worked across multiple manufacturing environments spanning plant operations and business systems. Designed network topology changes for production floors, bridged automation and business teams to translate operational needs into infrastructure solutions, and administered virtualized environments and Citrix. On the business side, developed VB.NET applications and Crystal Reports to automate reporting workflows and managed ERP system integrations.
Seven years of on-call ownership for server and network infrastructure at a multi-branch banking operation under FDIC/OCC regulatory oversight. Managed core banking systems, domain infrastructure, and backup architecture across production and DR sites. Developed automation scripts for routine compliance checks and system health monitoring. Designed and tested disaster recovery and business continuity plans covering critical transaction processing, wire transfer, and customer-facing banking platforms.
Massachusetts Institute of Technology — Professional Education Applied AI and Data Science Program (AAIDSP) — In progress, expected completion September 2026.
Additional Coursework — Iowa State University, Northeast Iowa Community College, Moraine Park Technical College. Coursework in information technology and general studies.
QR-based pet identification SaaS, designed and built end-to-end as a solo project — full-stack development, ops, and a custom manufacturing pipeline.
Stack. React single-page app on the frontend, Flask API on the backend, PostgreSQL for core data. Stripe for subscription billing, Twilio for SMS notifications when a tag is scanned, MailGun for transactional email. Multi-role access controls separate pet owners, shelter staff, and site admins, each with their own UI surface and permissions model.
Digital-to-physical pipeline. The architecturally interesting piece is the manufacturing path: customer order data flows from the database through a code-generated STL pipeline that produces print-ready 3D models, which then go to resin printers for on-demand tag production. It collapses what would normally be a hand-off between a SaaS and a fulfillment vendor into a single owned pipeline.
Shelter partner system. Shelters have their own self-service onboarding flow, an approval workflow gated on admin review, and a batch-fulfillment path for tag orders. The partner side is its own surface area, distinct from the direct-to-consumer flow.
Pet-Trax sells QR-printed plastic tags. By the time the second go-to-market channel was live, the codebase carried two separate identity systems for what was physically the same object — and the e-commerce path didn't even have a Tag entity at all. Pet.uuid was the tag identity. Adding partner shelters introduced a third identity model. When a fourth channel came up on the roadmap, the math stopped working: every feature on the next slate — audit log, admin overrides, pre-minted inventory, replacement flow — required building the same thing three times.
The push. A friend tested the promo flow. He claimed one of his two tags fine. The second came back "tag not found" — the database row was gone, even though the STL file from batch creation proved it had once existed. The denormalized claim counter still read 2/2 because nothing had decremented it. He registered a new pet, got a fresh ID that didn't match the QR in his hand, and the records were now permanently inconsistent. There was no audit log to reconstruct what had happened. That single incident exposed three symptoms of the same disease — hard-deletes on objects that physically still existed in the world, no append-only history, and counters drifting silently from reality — but the real answer to "why migrate now" was the accumulating pressure underneath.
The new shape. A single tag table owns physical identity for every QR ever printed. Every channel — direct, promo, partner — writes the same Tag row, distinguished by a source_type field. A status column drives a state machine (unclaimed → active → suspended → replaced) enforced through a transition_to(...) method that won't accept invalid transitions and writes an event to an append-only tag_events log in the same call. The denormalized claim counter is gone, replaced by a COUNT(*) against the new table. Hard delete is gone — a row representing something in the physical world outlives the object.
The migration. One Alembic migration, inline backfill, no dual-write. Justified because the user base was small and I controlled every call site. The discipline that made it safe: keep the old columns populated alongside the new during the entire code cutover, drop them only in a final irreversible step once the new path was stable. Code shipped in independently deployable PRs — models, creation paths, scan paths, API responses, deletion paths, admin tools — in that order. The hardest piece wasn't the data migration; it was the rename across the API and frontend. Dozens of endpoints, dozens of React components, route params and query keys and prop names, every miss a runtime bug in a different code path.
What I'd tell someone facing the same call. Identity belongs in its own table from the start, even when there's only one channel — the cost on day one is one extra join, the cost of retrofitting it across three channels is months. Hard delete on physical objects is malpractice; soft-delete with a voided status and accept that the unclaimed pool grows. An append-only audit log is two extra lines per write on day one and weeks of instrumentation later. Don't dual-write if you don't have to. And plan column renames before you plan the new schema — Alembic untangling in a venv on a prod database at midnight is exactly as fun as it sounds.
Ongoing tinkering with ESP32 and Raspberry Pi microcontrollers, Fusion 360 CAD modeling, and both FDM and resin 3D printing. On the AI/ML side, hands-on work with ComfyUI, Florence2, and LoRA training with PyTorch — less about following tutorials and more about breaking things until they make sense. Projects range from small one-off gadgets to more involved builds where the hardware and software sides have to talk to each other. It's the same problem-solving muscle as the day job, just with fewer tickets and more solder.
Live infrastructure telemetry dashboard for my VPS. Collectors poll system, security (fail2ban), and web-server metrics on a timer, store time-series data in SQLite with two-tier retention, and serve it through a read-only Flask API to a React frontend — world maps of attacker geography, attack heatmaps, and request/latency charts.
A check-in/check-out system for work-study students that uses rotating HMAC-SHA256 QR codes to make scan forgery impractical. A browser-based device simulator (or eventually an ESP32 with an e-ink display) emits a fresh 13-character base32 code every 10 seconds; the FastAPI backend validates the code cryptographically, rejects replays, and infers check-in vs. check-out direction per business location — so a student working at two campuses gets independent in/out state at each. The frontend is a React SPA with a native-camera QR scanner that drives the full scan-to-confirmation flow in one tap.
The threat model that shaped everything. Work-study programs typically rely on honor-system clock-in sheets or unattended kiosks — neither is hard to fake. The constraint here was that a student's phone is the scanner, not the validator, so the QR code on the physical device has to be the unforgeable element. That means the code has to be time-bound, cryptographically tied to the device's shared secret, and single-use. All the interesting design decisions follow from those three requirements.
Rotating code algorithm. Each device has a shared secret provisioned at registration. The rotating code is HMAC-SHA256(secret, floor(unix_time / 10))[0:8] encoded in uppercase base32 — not base64. The base64 choice would be wrong here: QR alphanumeric mode only allows [A-Z][0-9] plus a handful of symbols, so base64's +, /, and lowercase letters would force the QR encoder to fall back to binary mode, roughly doubling code size and risking readability on cheap displays. Base32 stays entirely within the alphanumeric alphabet. The 8-byte truncation gives 64 bits of entropy per window, which is more than sufficient against brute-force over a 10-second window.
Clock-skew tolerance vs. replay defense — these are in tension. Accepting only the current window would reject legitimate scans from students whose phone clocks are a few seconds off. The server therefore accepts the current window and the two adjacent ones (±1), giving roughly a 30-second acceptance band. That 30-second window is where a replay attack could live: capture a valid code, replay it within the window. The defense is the code_used column on the event table — before accepting any scan, the server checks whether (device_id, code) already appears in event. This works because the HMAC output is deterministic per window: the same device will emit the same code for the full 10-second window, so every code is redeemable exactly once regardless of when within that window it's first used.
Per-business direction inference. The naïve implementation would track in/out state globally per student, which breaks immediately for anyone working at two locations: a check-out at campus A would make the next check-in at campus B look like a check-out. The fix is to scope direction to the intersection of (student_id, business_id). Every event record stores business_id denormalized from the device's location — a deliberate tradeoff of a small write-time redundancy for fast, join-free reads when inferring direction. The query is just "most recent event where student_id = ? and business_id = ?"; if the last direction was in, this is an out, otherwise in.
QR scanner component choice. The obvious library for in-browser QR scanning is html5-qrcode, but it breaks under React 18 strict mode because strict mode double-mounts components during development, and html5-qrcode doesn't cleanly handle being initialized twice on the same DOM node — you get a runtime error and a stuck camera stream. The alternative is getUserMedia directly on a <video> element plus jsQR running frame-by-frame on a canvas. It's about 65 lines of code, it survives strict mode's double-mount, and camera teardown is a single stream.getTracks().forEach(t => t.stop()) call on unmount. No wrapper library needed.
Hardware simulator as a spec compliance check. The browser-based device simulator (hardware_sim/index.html) reimplements the same rotating-code algorithm in pure JavaScript using the Web Crypto API's SubtleCrypto.sign('HMAC', ...). It has no dependency on the backend code, so any mismatch between the two implementations surfaces immediately as a scan rejection. Running the simulator alongside the backend and making a successful scan end-to-end is a de-facto integration test of the cryptographic protocol.