The anchor was the candidate PR website — planned, built, and deployed on Next.js Edge Runtime and running at choiwoongju.com. It carried the candidate introduction, the pledges, and the election information in a single editorial flow. The fuller story of what the campaign office was actually like lives in this magazine — see Magazine, "The Election."
Before writing the front-end, I established a visual design language of my own. I studied the 2018 and 2020 Alexandria Ocasio-Cortez campaigns — the work of the Tandem studio in New York — through the archived campaign site and the published design analysis, and distilled the principles rather than the surface: break the rote party-color cliché, let typography carry the message instead of the photograph, and treat motion as a way to make a static poster feel like a movement. From there I built an original system — a navy-and-red palette chosen against the default party colors, Pretendard for a single typographic voice, a right-to-left marquee of activity photos as the web translation of "amplify the movement," and drop-cap and highlight-underline accents — applied consistently across the site, print, and share images.
The campaign's concept — a brighter future for Gwanak-gu — I turned into a picture. I built an isometric cityscape of the district with HUD-style callouts laid over it, each pledge pinned to the neighborhood it belongs to — Samseong-dong, Daehak-dong, the Dorimcheon stream, the Gwanaksan walking trails — under a headline that types itself in. The map lets a voter see a promise for their own neighborhood at a glance instead of reading it as a list.
I consulted on the imagery itself, too. For the portrait I recommended a frame with the candidate's gaze toward the upper right — forward, upward, aspirational. And beyond the polished professional shots, I pushed for photographs of real work — legislative activity at the National Assembly, academic work, and meeting residents — so the site would read him not only as a professional politician but as another citizen standing among the voters.
A chatbot answers questions about the candidate. It streams Claude Sonnet over SSE, and its safety is built as two distinct stages: a pre-response prompt-injection gate that catches encoding-based bypasses and role-hijacking patterns, and a post-response election-law filter that screens for the eight categories of expressions Korean election law forbids — direct vote solicitation, predicting the result, inferring poll numbers, and the rest.
For discovery, structured data (JSON-LD), a sitemap, and robots cover search-engine optimization, while an llms.txt route implements generative-AI search (GEO) at the code level. The new domain reached the first page on both Google and Naver, earned Naver's sitelinks rich result, and search became the largest identified acquisition channel — 88% of identified inbound during election week. On the AI side, a July 2026 field measurement put identity queries to four engines — Google AI Overviews, Claude, Gemini, and Perplexity — and all four answered the councilor's current standing accurately, three of them citing the official site directly as a source.
To plan the canvassing route using data, I built a canvassing-location analyzer driven by time-of-day foot traffic. Six public-data feeds — population present by time of day, subway, bus, and others — are scored on a PostGIS 100-meter grid that weights population and transit hubs by hour, then drawn as location scores on Kakao Maps. It first ran on Supabase and Vercel; when capacity, query memory, and timeouts became the ceiling, I moved it wholesale to GCP — refactored into a NestJS hexagonal server on Cloud SQL in Seoul — and verified the move with a pg_dump-to-pg_restore lossless cutover and a full row-count reconciliation across seventeen tables, bit-perfect on the scores.
The mailing side ran on a Python pipeline that derived the two thousand households targeted for printed campaign mail out of a raw set of 7,798, cross-verified across four channels — the Real Estate Board, the building-registry HUB, the road-name address service, and Kakao Local — before auto-generating the post office's bulk-mailing form.
I automated the statutory accounting forms. I built a pipeline that opens the Korean HWPX format directly as a zip of XML, cloning and populating table rows, and reconciled the political-funds income-and-expense ledger one-to-one against the bank statement. After the election, the campaign-cost reimbursement filing was processed the same way.
After the inauguration I turned the campaign site into an official council-activity site covering news, council work, pledges and the councilor’s profile. I also operate a constituent-complaint system: a Gmail collector and an Android app capturing SMS, RCS and MMS feed an authenticated admin back office on the same deployment, with no new infrastructure.
The second phase connected that public site to an editorial system. I built a pipeline that collects official Gwanak District Council records, fixes the source version, generates an article draft with Claude, then runs a separate Claude fact-check and evidence, media and accessibility checks before automatic publication. The CMS manages articles, structured bodies, sources, images, video and featured placement, with edition approval, archiving, restoration and rollback. The web, search and chatbot all use the same approved publication edition, so content can change without a code redeploy.
Developer peer feedback exposed an image-delivery bottleneck: the home page was sending full-size CMS JPEGs. I reproduced it and added responsive WebP derivatives while preserving the originals and checking publication rights and access permissions. In Chrome measurements on September 19, 2026, home-page image transfer fell from 40.74 to 0.390 MB at 1440px and from 40.66 to 0.198 MB at 390px — reductions of 99.0% and 99.5%.
On September 28, 2026, I extended SEO, generative-engine optimization (GEO) and answer-engine optimization (AEO) for the council-activity site. I aligned author and publisher identities, original-source attribution, publication and modification dates, activity dates and representative images across the page and structured data. Repeating six questions three times produced 18 Google searches and 72 answers from ChatGPT, Gemini, Perplexity and Claude, letting me examine identity errors, omitted roles and source substitutions in the actual responses.


