Skip to content
Role
Founder – product · design · full-stack · operations
Team
Solo
Period
2026.06 – 2026.07
Tools
Next.js, TypeScript, Supabase, Python, Tailwind, Figma

Startup grants × an anonymous builder community

Commit

Summary

A daily pipeline that collects and cleans government startup grants, with an anonymous builder community on top – so finding a grant, testing an idea and logging the work happen in one mobile-first app. Designed and built by a designer, alone, with AI pair-programming.

28 days
From plan to launch

264 commits (Jun 16 – Jul 13, 2026)

11,757
Grants collected

As of Sep 6, 2026

₩0
Monthly infrastructure cost

No paid external APIs

Role – product · design · frontend · backend · data pipeline · operations (solo)

1 / 6
Commit in use (0:51) – the live service recorded on a phone: the feed, the grant index, category filters, sorting by deadline, a grant page with its AI summary, and search.

Overview

Commit treats a grant announcement as a post written by the agency's account. The grant list and the community feed share one skeleton, and an agency's page is drawn with the same component as a person's profile. Finding a grant, getting an idea tested anonymously and recording the work continue along one timeline.

Live: commit.ai.kr

Problem

Even finding grants is hard.

  • Scattered sources – 1,722 different ways of writing agency names in the production database.
  • Messy originals – duplicated agency names, broken "?" characters, and prefixes like "(re-posted)(extended)".
  • No amounts – the grant API has no funding amount; it lives only in a separate programme API.
  • Wrong order – most lists sort by posting date, when what matters is the deadline.
  • Nothing after finding – half-formed ideas are hard to post in a real-name community.

Research

K-Startup, Bizinfo, contest sites, startup media, Disquiet, Indie Hackers and Product Hunt, and Notion went into one comparison table. The conclusion wasn't "nobody does this" but "nobody connects it": there are places that collect grants, places that write startup news and places to share building in public – none that links the three.

Looking at the data itself mattered too: the founding-period and age fields often listed "every possible range", so tagging them as-is put every tag on every grant.

Key decisions

  1. 01Treat a grant as a post by the agency's account

    Then there's no reason to build grant search and the community separately – people and agencies post, get followed and get saved by the same rules.

    The grant list and the feed share one component skeleton; agency pages reuse the profile header, and follow, bookmark and report work the same way.

  2. 02Pivot from community-first to grants-first

    People arriving from search were looking for grants. A community needs people to exist; grants only need a crawler.

    Mentors, a demand-validation gate, build scores and ad slots were removed. The home is public without login, which is only asked for at actions like posting – which also fixed search indexing.

  3. 03Accuracy over coverage

    One wrong amount costs more trust than many right ones earn.

    Amounts show only where the match is certain – 2,595 of 11,757 grants (22.1%). Logos likewise: a favicon service returned blank icons as “success”, so only 116 hand-checked agency logos are used.

  4. 04Guarantee anonymity in the schema, not in a promise

    An anonymous community is only trustworthy if even the operator can't expose who wrote what.

    Row-level security on every table from day one; posts are read only through a public view without author identifiers; personal columns are locked with column-level grants. Posts reported by several users hide automatically.

Design

"Toss's information hierarchy + Threads' timeline." Blue means action, green means alive, and no arbitrary values.

  • Tokens – a 7-step type scale (11 / 12 / 13 / 15 / 17 / 20 / 24), buttons at 36 / 44 / 48, radii 8 / 12 / 16 / full, 15 colour tokens × light and dark, one typeface (Pretendard) at −0.02em.
  • Action colour and link colour split – after changing the accent blue, blue links inside body text became hard to read, so the button colour and the in-text link colour were separated.
  • Three responsive layouts – under 768px / 768px+ / 1280px+, with a 640px centre column and a 360px right rail. Mobile tap targets grew from 36px to 44px.

Build

The collection pipeline

A Python crawler collects grants daily and cleans them in seven steps. Titles pass through five regex stages, applied retroactively to past data too. Notifications are deduplicated by a unique key, every run writes a heartbeat, and an alert fires if nothing has been collected for 36 hours. It runs on GitHub Actions at no extra cost.

Database and search

Supabase (PostgreSQL): 24 tables and 12 views and RPCs. Search is built in three layers: typo-tolerant trigram search → pgvector semantic search (with the built-in gte-small embedding model) → autocomplete and personal weighting. If an RPC fails, client-side results take over.

The limits are written down too: there are no LLM calls – grant summaries and eligibility checks are rule-based. With a paid external API, cost alone would have kept search out of the product.

Scale and lessons learned

In 28 days, 938 files changed (+27,927 / −6,233 lines); the code is 118 files and 10,536 lines with 47 components. Thirteen mistakes were logged – a feed limit that showed only four days of posts, dates off between UTC and Korean time, an ad script loaded only as a preload so ownership verification failed.

Ship · results

11,757
Grants collected
250
Open right now
22.1%
Grants with a verified amount

Where a person steps in

  • By itself – a Python crawler gathers notices daily through seven steps and records a heartbeat on every run. It says so when nothing has arrived for 36 hours.
  • By hand – on money, accuracy beat coverage. Where the rules are not sure, the figure stays empty and the reader is sent to the original (22.1%).
  • Never handed over – no model is called at runtime. Removing the place where it can be wrong costs less than correcting wrong answers.

Reflection

  • Row-level security controls which rows; which columns is a job for grants. Learned while making anonymity a property of the schema.
  • When an external dependency dies, the screen should live. Search, logos and amount matching all had their failure states designed first.
  • Next – from 10 users to 100. And the debt: zero tests, a remote database that migrations alone can't reproduce, and a single grant source (K-Startup).