Woonzero was already an active social platform, but finding people to play with wasn't its own layer; there was no game picker when creating a post, so which game a post was even about was mostly a guess. We added a layer on top: game identities, filterable looking-for-group listings, and a group chat that opens automatically once a listing fills.
Problem
No game layer, search scattered
Solution
Game identity + filtered listing + group chat
01Problem
Finding a teammate was a matter of luck.
Someone looking for a teammate on Woonzero had to rely on ordinary posts, comments or direct messages in a feed with no game tagging; without a game picker on the post composer, finding people to play with wasn't a dedicated feature, just something people improvised in the general feed. There was no filter for role, rank or available time, so finding the right person came down to luck more than search.
General postCommentDirect message
No game taggingcan't filter · luck-based
A player found by chance
representative flow
02Constraints
Three constraints shaped the design.
K1
Game identity runs on self-reporting, today
Verifying rank through an outside service like Riot or Steam was its own body of work; rank and role were deliberately left to the player's own word, with a verification badge pushed to the roadmap. A listing owner weighs an applicant's stated rank and decides for themselves.
K2
Has to stay current in four languages at once
The community speaks four languages; listing and guide content has to stay equally current across all of them. A build-time test that catches a missing translation key keeps that discipline in place — the translation itself is still typed by hand.
K3
Listings can't turn into clutter
Unlimited open listings make the list unusable fast; every listing gets an expiry, and its state updates through a lazy transition computed on read rather than a separate timer.
03 — Approach
A listing searches for a role, not a player.
A player first links a game identity, then opens a looking-for-group listing stating the role, rank range and time they need. How you join depends on the mode the listing owner picked: some listings let you drop straight into an open slot, others require you to apply and wait for the owner to approve or reject you. A group chat opens automatically the moment the listing is created, so by the time the roster is full, everyone is already in it.
Feed ranking used to keep the most-liked posts of all time at the top; as the platform grew, that one rule turned into a real bug — old posts stayed pinned at the top forever. We also tried a Hacker News-style formula, a Wilson/Bayesian rate estimate, and a single slow-decay formula; none of them held up against years of accumulated history or the data we actually had (no dislikes, no view counts). What shipped is a time-invariant score, an affinity signal, and a small quota reserved for older posts that are explicitly tagged as archive.
04Screens
An open role has to show up immediately.
anyone free?
we're 4
anyone free tonight
we're 4, need support
what rank though
Team listing
NovaTROpen
KaanQFull
Ayça V.Open
Team listing
NovaTR · Support · DiamondOpen
KaanQ · Sniper · GoldFull
Ayça V. · Tank · DiamondOpen
Deniz O. · Sniper · SilverFull
Baran K. · Support · GoldOpen
A team-search request from chat turns into a listing tagged open or full.
Player profile
NoNovaTRSupport · Diamond
Game identities
ValorantNovaTR#EU1linked
League of LegendsNovaTRlinked
CS2steam/novatrlinked
Past teams
North WolvesNight ShiftTeam Purple
Linked game identities get added one by one, past teams sit on the same profile.
05What we learned
What we're carrying into the next project.
01We don't leave a simple rule in place once we know it will age badly ('most-liked of all time'); for feed ranking we tested several alternatives against real data before settling on a time-invariant formula.
02We don't pick a storage provider on unit price alone; at this scale, egress and integration cost mattered more than the per-GB difference.
03Keeping a separate database column per language stops scaling; embedded i18next plus a build-time test that catches missing keys turned out to be the more sustainable way to keep four languages equally current.