STRUCTURED LANGUAGE · EFFORTLESS DISCOVERY

Make finding your next read as easy as pressing play.

TagSpark is a Korean web-fiction discovery system built from a manually reviewed corpus of 229 works and 76 tags. Readers control what to include or avoid, transparent scoring ranks exact and related matches, and the next phase explores embedding-assisted similarity without replacing reviewed catalog truth.

PREFERENCE INPUTLIVE TRACE
INCLUDE
  • 아이돌
  • 구원
  • 힐링
EXCLUDE
  • 피폐
ALIAS NORMALIZATION
아이돌연예계
CURATED NEIGHBOR
구원0.60종교
PERFECT MATCH작품 01연예계 · 구원 · 힐링
RELATED작품 02EXACT 연예계 · CLUSTER 구원0.74
피폐EXCLUDED BEFORE RANKING
PREFERENCE → NORMALIZE → RANK
ROLE
Language Systems & Full-stack Developer
DURATION
Ongoing
PROJECT TYPE
Independent Product
RESPONSIBILITIES
Full-corpus review and annotation, inductive taxonomy design, alias sets, hand-curated similarity thesaurus, weighted ranking, product design, APIs, database, and deployment
TOOLS
React 18, TypeScript, Vite, Tailwind CSS, Neon Postgres, Vercel
LINKS

PRODUCT CONTEXT

The platform had no tags at all. So I built the taxonomy.

The source platform offered no usable tagging, so there was no way to curate “works that feel like this.” Recommendation was not the first problem; constructing the language data it would depend on was.

How do you build a controllable recommendation signal when the source platform provides no usable metadata to begin with?

PHASE 1 · SHIPPEDFrom-scratch dataset and an interpretable baseline
PHASE 2 · PLANNEDSemantic axes gated by human validation

PHASE 1 · 01 · DATASET FROM SCRATCH

No tags existed, so I read every work and built the dataset.

I read all 229 works, derived the taxonomy inductively from recurring patterns, defined 9 categories and 76 tags with alias sets, then hand-annotated the full catalog. The recommendation system sits on top of that language-data work.

01READ ALL 229 WORKS

Full-corpus review, not a sampled subset.

02INDUCE THE SCHEMA

Recurring patterns became categories, tags, and aliases.

03ANNOTATE EVERY WORK

1,630 reviewed work–tag assignments.

229WORKS
76TAGS
9CATEGORIES
1,630WORK–TAG ASSIGNMENTS

PHASE 1 · 02 · EXPLICIT PREFERENCE

People state their taste. TagSpark makes it comparable.

Include and exclude choices keep preference visible. Surface forms then collapse through lowercase, Unicode NFKC normalization, whitespace removal, punctuation stripping, and known aliases before the catalog is compared by canonical tag ID.

include + exclude→alias normalization→canonical tag ids
INCLUDE / EXCLUDE SELECTION01 / 03
SUGGESTED TAGSTap to include
INCLUDE2
EXCLUDE2
SEARCH → SELECT → REVERSE OR REMOVE

PHASE 1 · 03 · NORMALIZE, RELATE, SCORE

A small, inspectable model ranks the catalog.

Exact and alias matches receive the strongest evidence. Category overlap and hand-curated neighbors add weaker context before results split into perfect matches and related recommendations.

01EXACT MATCH
02ALIAS
03SAME CATEGORY
04CURATED NEIGHBOR
05WEIGHTED SCORE
SIGNALCONTRIBUTION
EXACT TAG1.0
ALIAS OVERLAP0.9
SAME CATEGORY0.35
CURATED NEIGHBOR0.6
CORE TAG+0.25
PERFECT MATCH
Every required tag ID is present.
RELATED
Grouped by exact overlap, then ordered by weighted score.
CURRENT LIMIT
Curated relationships use a fixed 0.6 contribution; no learned embedding participates in ranking.

PHASE 1 · 04 · CATALOG OPERATIONS

The baseline depends on maintained, reviewable data.

NEON CATALOG
VERCEL API
SCHEDULED REFRESH
AVAILABILITY CHECK
CATALOG
Works, canonical tags, and reviewed work–tag relations
MAINTENANCE
Daily rolling refresh for up to 20 prioritized records
SAFETY
Validation, deduplication, and unavailable-work state

PHASE 2 · THE RECOMMENDATION GOAL

Make the ranking respond to the reader—not only the query.

Phase 1 is query-based: the same include and exclude choices produce the same ranking for everyone. Phase 2 adds a persistent, explicit taste profile so eligible works can be re-ranked for each reader.

  • Start from 3–5 favorites and explicit include/exclude choices.
  • Combine reviewed tag affinity, validated axis distance, and direct feedback.
  • Keep exclusions hard and keep every personalized movement explainable.
01FREEZE BASELINE
02MOVE RELATIONS TO DB
03CALIBRATE AXES
04BUILD TASTE PROFILE
05PERSONALIZED RE-RANK
06VALIDATE + RELEASE

PHASE 2 · 01 · CALIBRATE

Estimate the cheap signal first. Review works only where it matters.

The plan separates tag-level calibration from work-level refinement. That makes the first map inexpensive to build and focuses human judgment on close, disputed, or low-confidence placements.

STEP 01 · TAG COMPARISON91 candidate tag pairs

Compare which tag contributes more to darkness or relational tension. Bradley–Terry or logistic regression turns those judgments into initial axis weights.

OUTPUT · AXIS_TAG_WEIGHT
STEP 02 · PRE-MAPPlace all 229 works

Aggregate reviewed work–tag assignments with the initial tag weights. This produces a diagnostic map, not a product result.

OUTPUT · INITIAL WORK POSITIONS
STEP 03 · WORK COMPARISONReview uncertain neighborhoods

Sample close pairs, disagreements, and sparse regions instead of comparing every work. Use those judgments to refine the axis.

OUTPUT · CALIBRATED DISTANCE

KEEP THE SIGNALS SEPARATE

TAG_SIMILARITY

Reviewed relation between tags used by the Phase 1 recommender.

NOW · FIXED 0.6
AXIS_TAG_WEIGHT

A tag’s learned contribution to a named continuous quality.

PHASE 2 · FROM TAG PAIRS
WORK COMPARISON

Human supervision that corrects uncertain work positions.

PHASE 2 · ACTIVE REVIEW
AXIS DISTANCE

An optional ranking contribution, disabled until validation passes.

RELEASE WEIGHT · STARTS AT 0

PHASE 2 · 02 · MODEL ONLY WHAT VARIES BY DEGREE

Two candidate axes. Everything else keeps its proper type.

Darkness and relational tension can vary continuously. Completion and adult content remain filters; genre and worldview remain visible categories. Phase 2 does not force the entire taxonomy into an opaque embedding.

DARKNESSEXPLORATORY HAND-WEIGHTED PLACEMENT
DARKERLIGHTER
RANGE NOT YET CALIBRATED
RELATIONAL TENSIONCANDIDATE AXIS
LOWERHIGHER
TAG COMPARISON PENDING

PHASE 2 · 03 · PERSONALIZED RE-RANKING · PLANNED

A user model changes the order—not the catalog truth.

Personalization sits after candidate eligibility. Availability, explicit exclusions, and required tags are resolved first; only then does the user profile change the order of the remaining works.

01 · COLD START3–5 favorites

Aggregate reviewed tags and validated axis positions into an initial taste profile.

02 · HARD RULESEligible works

Apply availability, include requirements, and excluded tag IDs before personalization.

03 · RE-RANKPersonalized queue

Combine the Phase 1 score with user tag affinity, validated axis proximity, and direct feedback.

04 · UPDATEExplicit feedback

“More like this” and “not for me” update the user profile without rewriting work annotations.

PERSONALIZED SCORE
PHASE 1 MATCH+USER TAG AFFINITY+VALIDATED AXIS PROXIMITY+EXPLICIT FEEDBACK

Axis proximity and feedback contributions begin at zero and enter ranking only after offline evaluation. Explicit exclusions always override the score.

PROFILE
Persist a signed anonymous taste profile that the reader can inspect, reset, or revise.
STRONG SIGNAL
Favorite, more-like-this, and not-for-me actions—not passive reading history.
BOUNDARY
Personal feedback updates user preference weights; reviewed catalog annotations remain shared truth.
EXPLANATION
Show the tags, axis direction, or feedback connection that moved each recommendation.

PHASE 2 · 04 · PRODUCT EXPERIENCE

Personalization should feel like a reading queue, not a settings panel.

Readers can begin with favorites, adjust their current mood, and refine results with “more like this” or “not for me.” The system returns a personalized queue while preserving visible include and exclude controls.

Mobile remains the primary surface. A desktop map may expose the same validated distances for exploration, but the map is a view—the personalized ranking loop is the product.

favorites+current mood+direct feedback→personalized reading queue
Mood direction → constrained results

MEDIA PLACEHOLDER · VALIDATED AXES · NOT A GENERIC EMBEDDING MAP

PHASE 2 · 05 · RELEASE CONTRACT

No personal signal reaches ranking just because it sounds useful.

Each new contribution must improve personalized retrieval, preserve Phase 1 constraints, and remain explainable. Until then, its weight stays at zero and the interpretable baseline remains the fallback.

01INDEPENDENT PAIRS
02AGREEMENT GATE
03FIT AXIS WEIGHTS
04RETRIEVAL TEST
05WEIGHT 0 → CONTROLLED RELEASE
HUMAN AGREEMENT

Cohen / Fleiss Kappa · Krippendorff Alpha

RANKING AGREEMENT

Spearman correlation · Kendall tau · pair reconstruction

RETRIEVAL + GEOMETRY

Precision@K · nDCG@K · trustworthiness · exclusion violations

TAKEAWAY + PHASE 2 ROADMAP

A recommender is only as trustworthy as the language data beneath it

The strongest contribution is the full-coverage taxonomy and annotation layer. Phase 2 extends it without presenting planned axes, personalization, or learned similarity as shipped.

01Freeze the baseline

Protect exact-match recall, exclusions, normalization, and stable ordering with regression tests before introducing a second ranking layer.

02Move relationships into data

Migrate hard-coded tag similarities into reviewable database records before adding new semantic signals.

03Calibrate tags, then works

Use 91 tag comparisons to seed each axis, generate a preliminary map, then spend work-level review only on uncertain neighborhoods.

04Release validated controls

Add axis-distance to ranking at weight zero, require measurable retrieval value, and expose only axes that pass agreement and product-clarity gates.