Jeongtae Kim / 김정태
Resume

Freelance product development

Campaign Operations & Client Collaboration Platform

A SaaS consolidating scattered agency work into one workflow per campaign. Built solo from requirements to release.

Context and problem

  • Quoting → content review → placement reporting → schedule and work log, each in a different tool. The same information re-entered, and advertisers ringing to ask where things stood.
  • How far to let the advertiser in was the central problem. They need to review deliverables and comment; internal quotes and colleague notes stay private.
  • Fully separate screens drift apart; merged screens leak. The design sits between the two.
  • Built solo, so the reasoning and the outcome of each decision are in the release notes and commit history.

Role, period, and scope

Role
Freelance product development engagement
Period
2026.03–2026.05
Scope
Sole responsibility from requirements through design and implementation
Attribution
Requirements, design, frontend and backend implementation, and release were all mine.
Technologies
React · TypeScript · FastAPI · PostgreSQL · Playwright

System map

  1. Internal back office

    The operating surface where campaigns, quotes, review, placement reports, schedules, and work logs are handled in one place.

  2. Client-facing surface

    A restricted surface where clients see the work and leave feedback. Internal information never reaches it.

  3. Connecting flow

    The summary and state transitions that keep both surfaces reading the same underlying state.

  4. Permission layer

    Access rules defined per page and re-applied in bulk whenever the definition changes.

Decisions that mattered

Put feedback onto the work itself

Individual work

Problem
Video and image feedback travelled through chat and email, so people described positions in sentences and it was never clear which version they meant.
Judgment
Remove the step where someone has to describe a position in words.
Action
Video comments anchor to a playback timestamp; image comments anchor to coordinates through drawing markup. Both are bound to the version they were left on.
Verification
I replayed feedback from review meetings through these screens and checked whether any case still required describing a location in words.

Separate internal review links from client share links

Individual work

Problem
Reusing one link for two purposes meant an address intended for a client could open an internal review screen at any moment.
Judgment
Splitting the addresses is safer than splitting permissions with conditionals inside one screen.
Action
Internal review links and client share links are issued on separate routes, and share links carry their own expiry and access scope.
Verification
I walked every screen a share link could reach and compared it against the list each link type is allowed to open.

Split disclosure rules between client view and review mode

Individual work

Problem
Clients and the internal team look at the same data, but not at the same fields. Scatter that condition across screens and the rules drift apart quickly.
Judgment
Disclosure rules belong to the mode and are managed in one place, not repeated per screen.
Action
Client view and review mode became explicit modes, and what each mode may read is declared in one place.
Verification
I opened the same campaign in both modes, compared the fields screen by screen, and checked that no internal field survived into client mode.

Per-page permissions with bulk re-application

Individual work

Problem
Editing permissions screen by screen every time a role appeared meant a newly added page would eventually be missed in silence.
Judgment
Declare permissions per page, and make a changed definition reapply across the board.
Action
I defined permissions per page and built a procedure that re-applies a changed definition to existing users and roles in bulk.
Verification
I switched between roles, exported the list of reachable pages, and compared it against the permission definition.

Redraw the backend and frontend boundaries

Individual work

Problem
As features accumulated it stopped being obvious which file owned which part of the work, and a change in one place broke a screen that looked unrelated.
Judgment
If the business domains show up in the code structure, the blast radius of a change becomes predictable.
Action
I split the backend along business domains and pulled shared code behind its own boundary, then regrouped the frontend into feature and shared units.
Verification
After the restructure I opened every screen route to confirm the data and the rendering were unchanged, then re-ran the type check.
  • Restructured the backend into nine domains and more than fifty frontend files into feature and shared boundaries

A summary API that joins scattered state

Individual work

Problem
Finding out how far a campaign had progressed meant opening the quote, the review, and the placement report separately.
Judgment
Assembling status per screen produces different answers per screen, so it is defined once on the server.
Action
I built a summary endpoint that returns campaign, quote, review, and placement state together, and pointed every screen at that one response.
Verification
I created campaigns at different stages and compared the summary against each detail screen for disagreement.

Reporting cards that preserve what happened after publication

Individual work

Problem
Once a placement went live, checking the result depended on somebody remembering, and no trace was left of when anything had been collected.
Judgment
Fix the collection points in advance and record the state at each one.
Action
Per-platform publication badges and the scheduled collection points are laid out as cards on the placement report screen.
Verification
I checked that the state at each collection point matched the actual publication result and that missing platforms were shown rather than skipped.
  • Collection status at D+0, D+1, D+7, and D+14

A work log and a monthly calendar dashboard

Individual work

Problem
Schedules lived in a calendar while the record of what was done lived in personal notes. With no way to see both, there was nothing to look back on.
Judgment
Putting the schedule and the work log on one screen makes it an operating record without extra effort.
Action
I built a work-log module and surfaced it in a monthly calendar dashboard alongside campaign dates.
Verification
I loaded a full month of data and checked date boundaries, recurring entries, and how empty days render.

Replace stacked modals with a side panel

Individual work

Problem
Opening a detail during review stacked a modal on top of a modal, so people had to decide with the context behind them hidden.
Judgment
For work that has to keep its context, a modal covering the screen is the wrong shape.
Action
The stacked modals moved into a right-hand panel, so the main content stays visible while a detail is inspected and closed.
Verification
I opened and closed the panel with the keyboard alone to confirm focus returns to its origin, and checked that the main content is not obscured on narrow screens.

Stabilise database connections in a serverless environment

Individual work

Problem
Connections dropped without warning in the serverless environment, and migration state differed between environments.
Judgment
Rather than working around connection errors that would not reproduce, find the cause first.
Action
I set connection lifetime and retry behaviour to match the environment and unified migration application onto a single path.
Verification
I called repeatedly both right after deployment and after idle periods to see whether connection errors reproduced, and compared migration state across environments.

Unify how every calendar renders

Individual work

Problem
Calendars were spread across screens with slightly different holiday and emphasis rules, so the same date could look different depending on where you saw it.
Judgment
Pull the display rules into shared logic instead of copying them into each calendar.
Action
I lifted holiday resolution and emphasis rendering into shared logic and pointed every scattered calendar at it.
Verification
Using a month containing both public holidays and weekends, I opened all the calendar screens side by side and compared their rendering.
  • Unified holiday rendering across six calendars and bold-text rendering across eight

Implementation evidence

Recaptured with synthetic data. Client, campaign and account identifiers and the original metadata are removed.

Measurable outcomes

A full product delivered solo in about seven weeks
The product reached release even though design and implementation both sat with one person.
Shipped from version 1.0.0 through 1.6.0
Scope grew while the product stayed in a working state, rather than landing in one large drop.
Thirteen release notes documenting every change
The client could see what changed and when without having to ask.
Authored 629 of the repository’s 636 commits
The change history shows that most of the work came from my own hands.
Loaded and checked 65 routes after the restructure
After the restructure I opened the screens one by one to confirm nothing had shifted.
Zero TypeScript compiler errors at verification time
Verification finished with the type check passing rather than pending.
Folded 62 pieces of meeting feedback into the product
Requests raised in meetings ended up in the product instead of in a backlog nobody read.

Reflection

  • Working solo means fast decisions and no reviewer. Recording the reasoning in release notes and change history covered the gap.
  • Next time I would consolidate permission and disclosure rules earlier. Doing it after the screens multiplied took the longest.