Same problems, different stacks
| anekdotnik | sudoky | pozdravok | |
|---|---|---|---|
| What | Jokes site (~43k) | Sudoku game | Greetings catalog (~12k) |
| Stack | Next 16 + Postgres | Vanilla JS | Next 15 + Drizzle |
| Host | Vercel | Cloudflare Pages+Worker+D1 | Vercel / Node |
| Analytics | Yandex Metrica + 1st-party | Umami | Metrica (off) |
| Data | DB-primary | D1 edge | static-first, DB-optional |
| Live? | Yes (monetization-blocked) | Yes | Not launched |
Project evolution audit
Each project independently re-derived SEO, analytics, share, favorites and a design system — and each hit variants of the same bugs. None of those lessons reached the next project except by memory.
anekdotnik 189 commits
Arc: create-next-app → "jokes only" → Postgres-as-truth in 2 days → engagement before SEO → 6-week dormancy → analytics + LLM tagging → 20k external import → honest P&L → ranker.
- Discovered: sitemap-index, two-part thin-page rule, silent-degrade analytics, enum-pinned resumable tagging, "pageviews are the revenue unit"
- Mistake: the 60-topic taxonomy (biggest SEO effort) returns ~0 traffic
sudoky 21 commits
Arc: full offline game in 2 same-day commits → 4-month gap → i18n → almost the entire product (Worker+D1, Umami, streaks, duel) in one Aug-13 burst.
- Discovered: Worker+D1 daily-challenge backend, CORS/offline-graceful API, Umami wrapper discipline
- Mistake: live wrong-canonical domain + fabricated rating (see Live Findings)
pozdravok 18 commits
Arc: design-first with ad slots day one → static-first/DB-optional architecture → scraped 12k greetings → popularity-weighted SEO → still unlaunched (example.ru).
- Discovered: static-first/DB-optional layer, AI-discoverability (llms.txt, GEO), CLS-safe ad slot, canvas share-image
- Mistake: committed 12k scraped texts against its own rule; data-in-code OOM
Coverage across the lifecycle
Every recurring capability, by project. The ★★★ rows are reinvented in all three and are the first consolidation targets; ★ rows are genuinely project-specific and should stay that way.
| Capability | anek | sudoky | pozdr | Priority |
|---|---|---|---|---|
| SEO foundation | ● | ◐ | ● | ★★★ |
| Analytics + event taxonomy | ● | ● | ◐ | ★★★ |
| Share button | ● | ◐ | ● | ★★★ |
| Favorites (localStorage) | ● | ◐ | ● | ★★★ |
| Programmatic long-tail pages | ● | ○ | ● | ★★ |
| AI-discoverability (llms.txt, GEO) | ○ | ○ | ● | ★★ |
| Share-as-image (canvas/OG) | ● | ○ | ● | ★★ |
| Data-access repository layer | ● | ○ | ● | ★★ |
| Admin CRUD + auth | ● | ○ | ● | ★★ |
| LLM content pipeline | ● | ○ | ◐ | ★★ |
| Deployment | ● | ● | ◐ | ★★ |
| DB-on-serverless hardening | ● | — | ○ | ★★ |
| Monetization (RSYA/ads) | ○ | ◐ | ◐ | ★★ |
| Voting / rating | ● | ○ | ○ | ★ |
| Progression / streaks | ○ | ● | ○ | ★ |
| i18n | ○ | ● | ○ | ★ |
High-value capability records
Each with its universal-core vs configurable split. Install/validate procedures come in Phase 2, only for capabilities we actually extract.
SEO Foundation Kit ★★★
Core: canonical/OG/robots/JSON-LD emitters, sitemap-index pattern, param stripping, the two-part thin-page rule (noindex AND sitemap-exclude). Config: site URL, title templates, thresholds, JSON-LD types. All three reimplement it — top extraction target.
Analytics + Taxonomy ★★★
Core: a silent-degrade queue-and-flush wrapper, allowlisted event enum, sendBeacon, IP rate-limit before DB work, length-normalized dwell. Config: provider (Umami vs Metrica — market-driven) + event vocabulary.
Engagement Kit ★★★
Core: share targets + Web Share API (with the iOS synchronous-blob fix), localStorage store with SSR guards + cross-tab sync. In all three, near-zero project-specific.
LLM Content Pipeline ★★
Core: structured-output enum pinning, resumable idempotent runs, sync-vs-batch, prompt caching, the replace-vs-merge hazard, dry-run-before-spend. Config: taxonomy, prompt, model.
Share-as-Image ★★
Core: fitFont auto-size, taint-free canvas, R2/S3 SigV4 upload, branding composited (models garble text), per-item error isolation. Config: templates, model.
DB-on-Serverless Hardening ★★
Core: bounded pool (the recurring outage), Lightsail SSL, admin-vs-app roles, public-endpoint pre-parse throttle. Nearly all universal for Vercel + managed Postgres.
Consolidation targets
Where the projects diverge — decide what to unify and what to keep configurable.
| Problem | anekdotnik | sudoky | pozdravok | Verdict |
|---|---|---|---|---|
| Analytics | Metrica + 1st-party | Umami | Metrica (off) | Provider configurable; share wrapper+taxonomy |
| Host/compute | Vercel + PG | CF Pages+Worker+D1 | Vercel + Drizzle | Two families; don't force one |
| Content storage | DB-primary | D1 | static, DB-optional | Static-first is more portable — but runtime file, not source module |
| Identity | cookie voter_key | anon device-id | localStorage | One small "no-accounts" identity util |
| Structured data | per-page JSON-LD | fabricated rating ⚠️ | full generators + llms.txt | Consolidate on pozdravok's; never fabricate ratings |
Proposed skills & bootstrap
Thin skills over one per-project site.config, not a framework. Every skill must pass the test: will it save time, reduce mistakes, or improve quality on the next project?
seo-core P0
Emit head + sitemap-index + robots + JSON-LD from config; validate (canonical == domain, sitemap resolves, no fabricated data). All 3 reimplement it; 2 have live bugs it prevents.
analytics-core P1
Provider-configurable wrapper (Umami | Metrica) + standard event taxonomy + "SPA next must fire a pageview." Reconciles 3 divergent implementations.
engagement-kit P1
Share + favorites, with the iOS synchronous-blob fix baked in. Built 3× with the same recurring bugs.
db-serverless P1
Pool bounds + roles + pre-DB rate-limit + migration checklist. The most-repeated outage; Vercel+PG family only.
llm-content-pipeline P2
Enum-pinned resumable classify/generate. Only one mature instance — extract when a 2nd need appears.
NOT skills
Scrapers (legal risk), Sudoku engine, duel server, swipe deck, voting/streaks internals. Genuinely project-specific.
new-project <name> --stack next|static --host vercel|cloudflare --market ru|intl
→ 1 site.config → 2 select capabilities → 3 configure from config
→ 4 validate each → 5 deploy-readiness report
Hard-won lessons every future project inherits
The highest-value output: rules paid for in real outages and dead features.
- Measure before scaling. anekdotnik's biggest SEO effort (60-topic taxonomy) returns ~0 traffic while 3 curated pages carry 28%. Don't build a matrix on assumed demand.
- Pageviews are the revenue unit — a reading loop that produces no navigation is invisible. Sank both infinite scroll and untracked swipe. Any SPA "next" must fire a virtual pageview.
- Scaffolded ≠ done. All three shipped inert monetization/analytics for months (Metrica ID empty, ads off, example.ru). Count it done only when it's live and firing.
- Data-in-code doesn't scale. pozdravok's 224k-line content module OOMs the build and rendered 52 MB pages. Large content → runtime file / DB; paginate before loading 10k items.
- Content sourcing is a legal + monetization risk. pozdravok committed ~12k scraped third-party texts against its own rules (RSYA ban risk). Any shared scraper = owned/licensed sources only, never auto-commit.
- CSV metrics lie. A Metrika CSV was ~3× understated vs the live UI → a bogus growth claim. Compare like-for-like from the live report.
- Footguns:
ON DELETE CASCADE, regex-only screening, and colliding migration numbers across branches all bit anekdotnik. Bake into the DB skill's checklist. - Build for demand, not ahead of it. sudoky's fully-built duel server sits dark; monetization mocks never shipped. Capital tied up before validation.
Real issues found on live / near-live sites
Incidental but valuable: the history pass surfaced concrete, fixable problems.
Live sudoky.net — SEO regression
canonical, OG, sitemap.xml, robots.txt, and JSON-LD all point at a stale fikratius.github.io/Sudoku/ instead of sudoky.net (left at Aug-13 go-live). Plus a fabricated aggregateRating 4.8/1250 and manifest/OG referencing PNGs that aren't in the repo. → a contained fix brief.
Pre-launch pozdravok — legal / RSYA risk
~11,854 scraped third-party greetings are committed & served against the repo's own stated rule, labeled CC-BY though not owned. An RSYA "non-unique content" ban risk and copyright exposure — best resolved before launch. → operator decision.
Pre-launch pozdravok — hygiene
Still on placeholder example.ru; build needs a 6 GB heap workaround (the data-in-code OOM). Launch-blocking.
How I'll handle these
They're Howard's repos. I'll package the sudoky SEO fix as a ready brief on your go, and bring the pozdravok scraping question to you as a decision (it's a content/legal call, not a code bug).
Prioritized implementation plan
P0 = build now (repeated, high-value, low ambiguity) · P1 = build next (needs standardization) · P2 = investigate (insufficient evidence). Not everything becomes a skill.
P0 build now
- guardrails.md checklist — the 8 lessons; near-zero cost, highest ROI
- seo-core skill — all 3 reimplement it; 2 have live bugs
- Fix sudoky.net SEO regression — live, contained
P1 build next
- analytics-core — reconcile Umami vs Metrica
- engagement-kit — share + favorites + iOS fix
- db-serverless module + checklist
- Decision: pozdravok scraped content
P2 investigate
- llm-content-pipeline (1 mature instance)
- deploy-core (two families)
- monetization-slot (nothing earns yet)
- bootstrap CLI · versioning · practice-discovery
Where it should live
- New repo
website-capabilitiesfor the registry + docs. - Claude Code skills for executables as they graduate.
- Botswain stays orchestration; no product code.
Sequencing rationale
Prove the extract-and-validate loop on seo-core first: if it saves time on the next SEO setup and its validator catches the wrong-canonical class of bug, that earns the P1 extractions. P2 waits for a real second consumer — the discipline that keeps this a compounding library, not a framework nobody asked for.