
In-House Systems — Website, Internal Tools, and an Automation Suite
Starting as the in-house systems person at a performance-marketing agency, I built real, production-running systems in code — from a company website renewal to internal tools to a marketing-automation suite.
- PHP/MariaDB
- TypeScript
- React
- Playwright
- Cloudflare
Problem
Mid-sized marketing agencies often have no “development team” at all. The website sits frozen exactly as an outside vendor delivered it, and reporting, disclosure management, lead review, and budget checks all run by hand. I joined as the in-house systems person and took it on myself to turn this repetition into code.
What I built
Company website renewal. I rebuilt the legacy static pages into a structure with an admin CMS, API, database, and KO/EN i18n. I found and removed a security flaw (plaintext credentials hardcoded in the source), and standardized CSRF protection, escaping, and server-side validation. I introduced a “verify on staging first, then ship to production” rule and shipped repeated deploys with no production incidents.
Internal operations tools. I converted administrative work into web tools, including a seating-arrangement management tool (415 commits). Serverless (free-tier) deployment keeps maintenance cost at $0.
Marketing-automation suite — 11 packages. Ad-performance report automation (auto-detects 3 formats → dashboard → generates XLSX/PPT), a regulatory-approval-number registry (blocks the pipeline on expiry), a lead-quality checker (validates 28 columns, detects duplicates, aggregates CPA), a budget-pacing monitor, API connectors for 5 ad platforms (with real HMAC/OAuth2/JWT auth implementations), and a notification bridge. Three principles run through all of it:
- fail-closed — if there’s an expiry, an error, or a duplicate, the pipeline dies with a non-zero exit. The system catches what a person misses.
- no personal-data egress — personal-data columns are reduced to counts immediately on parsing, and tests enforce that the raw values never appear on screen or in any report.
- honest labeling — a metric that can’t be computed is marked “not computable,” never disguised as zero.
Results
- All 11 packages build and test green — 452 automated tests (measured), TypeScript strict.
- A single weekly report: 60–90 minutes by hand → under 5 minutes of upload + export (estimated, assumptions documented).
- A read-only crawler found real defects in live reference scans — like a leftover legacy analytics tag — the kind manual review had been missing.
Limitations and failure modes
- Company assets (code and data) belong to the company. What I can share here is limited to scope, methodology, and measured figures — no real data or account screens are disclosed.
- The ad-platform API connectors have auth and parsing implemented and tested, but since I’m still waiting to receive real API keys, verification against real-world response-schema differences remains open (documented).
- The time saved is an estimate — change the assumptions and the number changes too. That’s why the assumptions are always written down alongside it.
What I learned
When you build systems for “an organization with no developers,” the thing that matters most isn’t polish — it’s handoff-ability. A system with documentation, tests, and gates keeps running even without me, and that’s the condition under which an organization can trust a system.