Diagrams — how YB100 is built

Editorial diagrams of the yb100 v3.1 stack. One accent per diagram; 4-grid SVG, 1px hairlines, theme-aware tokens. Generated via /abc-diagrams.

01Architecture — 3-tier read priority

#architecture

Every public page calls getAllItems(); it cascades through three stores so the site never returns a blank.

BrowserGET /list/filmNext.js · force-dynamic/list/[categoryId]/page.tsxgetAllItems()src/lib/content.tsTier 1 — AuthoritativeSupabase · public.yb100_itemsanon-key · RLS where status = 'published'600 rows · 6 × 100cmsPublic()fallback (empty or PGRST205)Tier 2 — Legacy primaryMongoDB · AIDB.YB100MONGO_URI · receives writes via mongo-mirror.ts~597 docs · source="yb100"getMongoDb()fallback (Mongo unreachable / empty)Tier 3 — Hardcoded fallbackLISTS_STATICsrc/lib/data.ts · 600 placeholder itemsalways availablebuild-time bundled

Supabase yb100_items is authoritative; Mongo FLEET.items and the LISTS_STATIC bundle are progressive fallbacks. content.ts is force-dynamic — no module cache means admin edits show up on the next request.

02Auth flow — middleware gate

#auth

/admin and /api/admin are private. Everything else (including unknown 404 paths) is public by design.

Browsermiddleware.tsSupabase auth/adminGET /admin/pagescookie: yb100-dev-bypass? · sb-token?isPrivate?/admin · /api/adminsupabase.auth.getSession()user.email | nullALLOWED_EMAILS checkmat@matsiems.com → render307 → /login?next=/admin/pagesother email → signOut() · ?error=unauthorized

Middleware probes the cookie + Supabase session, signs out wrong-email accounts, and lets mat@matsiems.com through. PRIVATE_PREFIXES is the allowlist; flip in src/lib/supabase/middleware.ts.

03CMS publish flow — admin edit to live page

#publish

One PATCH + one PUT, three downstream writes, zero waiting on a Vercel function recycle.

PageEditorAPI routeSupabasemongo-mirrorrevalidatePublic /PATCH/api/admin/pages/homeupsertPage()yb100_pages upsert by slugPageRowPUT ?action=publishstatus='published', published_at=now()version + log rowmirrorUpsert()YB100_pages collectionbust(slug)revalidatePath("/")cache flushednext visitor sees fresh copyno Vercel function recycle needed

upsertPage hits Supabase, mirrors to Mongo, then revalidatePath() flushes the Vercel cache for the public route. The next visitor sees the new copy on their first request.

04Data model — Supabase tables + Mongo FLEET mirror

#data-model

Pages and items are the authoritative writes; versions and the publish log are append-only audit.

yb100_pagesslug (PK)titlebody_mddata jsonbstatus (draft/published)published_atcreated_at · updated_atyb100_page_versionsid (uuid)slug → yb100_pageskind (save / publish)body_md · datacreated_by · created_atyb100_itemsid (PK · "cat:rank")category_id · rankt · y · d · cr numeric(3,1)country · noteimage (S3 key)data jsonbstatus (published / draft / archived)UNIQUE (category_id, rank)yb100_publish_logid (uuid)kind (page · item)ref (slug or item id)version_id (nullable)published_bystatus (ok · failed)published_atAIDB.YB100 (Mongo mirror)source: "yb100"categoryId · rank · t · y · d · c · r · imageupdatedAt · mirrored from yb100_items1:n versionswrites log rowpublish eventmirrorUpsert()

yb100_items mirrors to Mongo FLEET.items (app='yb100') so the public site keeps rendering when Supabase is in degraded mode. Schema lives in supabase/migrations/0001_cms.sql.

05Admin surface — four consoles + dashboard

#admin

/admin is the cockpit; each console owns one upstream system.

/adminOverview · stats · recent editsPages/admin/pageslist · NewPageForm/admin/pages/[slug]PageEditor · md previewVersionHistory · view live ↗Items/admin/itemspaginated · category filter+ NewItemForm/admin/items/[id]ItemEditor · delete · statusMongo console/admin/mongohealth · suggestions/admin/mongo/[db]/[coll]JSON filter · CRUDinsert form · per-row editS3 console/admin/s3health · folders · suggestionsRe-index → _index.json/admin/s3/[...key]preview · metadata · deleteCross-cuttingAuth gate · /api/auth/logout · publish log · revalidatePath · suggestions surfaces · health probe

Pages and Items write to Supabase + Mongo. Mongo and S3 are read/write browsers for the underlying stores. The dashboard pulls stats from yb100_pages, yb100_items, and yb100_publish_log.

06View system — six renderers + URL state

#view-system

?view= chooses one of six renderers; ViewToggle is the only thing that touches the URL.

URL state?view=tilessurvives reloadViewToggleresolveView() → ViewIdTweaksProviderlocalStorage · /list/[cat] onlyannotate(lists)Record<CategoryId, Item[]> → AnnotatedItem[]SectionsViewdefaultgroupedTilesView8-col griddenseBoxesView4-col chunky+ rating chipListViewcompact rows+ rating barTableViewdata gridsortableScrollerViewhorizontalper-categoryGridMode/list/[cat] · podiumListMode/list/[cat] · podium rowMagazineMode/list/[cat] · spotlight + 4Mounted on:/ · /lists · /list/[categoryId]SectionsView is the default for / and /lists; GridMode is the default for /list/[cat] (uses TweaksProvider for persistence).

Home and /lists default to Sections; /list/[cat] owns the rich GridMode + ListMode + MagazineMode renderers and stores selection in TweaksProvider (localStorage). Every renderer takes the same AnnotatedItem[] shape.

07Image pipeline — Runware to next/image

#image-pipeline

Four stages, one bucket, one signed-URL boundary at the admin edge.

1 · GenerateRunware / Nano-Banananpm run cover:genPNG → JPG (sharp)scripts/generate-covers.tsS3 com27/yb100/<cat>/<rank>.jpg · eu-west-22 · IndexAdmin · Re-indexPOST /api/admin/s3/indexlistAll() ContinuationToken loopsrc/lib/s3-admin.tsyb100/_index.jsonin-bucket snapshot3 · ReferenceAIDB.YB100.imageyb100/<cat>/<NNN>.jpgSupabase yb100_items.imageS3 key (mirror)/api/admin/s3/suggestionsorphans · broken · gaps4 · ServeCover.tsxnext/image fillsizes hintVercel image proxyavif/webp · resizeedge-cacheBrowser600 covers · lazydevice-sized webp

Generation runs outside the app (Runware via cover:gen). The /admin/s3 console keeps an in-bucket _index.json snapshot. Reference rows live in AIDB.YB100 and yb100_items; the suggestions endpoint diffs them against the bucket. Cover.tsx serves through Vercel's image proxy (avif/webp/resize).

08SEO surface — robots, sitemap, metadata, JSON-LD

#seo

Three crawl surfaces, two metadata layers, two JSON-LD blocks.

Googlebot/robots.txt → /sitemap.xml/robots.txtAllow / · Disallow /admin//sitemap.xml609 URLs · dynamiclayout.tsx · metadataBasetitle template · og defaultsgenerateMetadata()/list · /item · per-route OGJSON-LD structured data/list/[cat] · ItemList (100 ListItem)name · description · itemListElement[].position/name/url/image/item/[cat]/[rank] · BreadcrumbListHome → Lists → Top 100 X → ItemOG / Twitter share/item/<cat>/<rank> → og:image = S3 cover, twitter:card=summary_large_imageog:url, og:type="article", alternates.canonical · per-pageLighthouse targetSEO ≥ 95

Sitemap is dynamic — every push picks up new items via getAllItems(). generateMetadata() per route reads the CMS for OG title/description. /list/[cat] emits ItemList JSON-LD; /item/[cat]/[rank] emits BreadcrumbList.

09Deploy pipeline — commit to edge

#deploy

Push to main fires both GitHub Actions (gate) and Vercel (deploy) in parallel.

LocalEdit · npm run dev:13002 · force-dynamicnpm run lint + buildtsc · eslint . · next buildgit push origin mainflexappdev/yb100GitHub Actions (.github/workflows/ci.yml)build jobnpm ci · lint · build · with secretse2e jobplaywright install + test:e2eartifact uploadon failure onlyparallel — also fires on push:Vercelwebhook · npm ciprj_fFA3ppMSauYRH5xQtItIkGwQI6g0next build · env injectedproduction scope · 16 varsdeploy promotedyb100-khaki.vercel.appEdge6 security headers · CSP · image proxy (avif/webp/resize) · ISR via revalidatePath() from admin writes

Local: lint + build smoke. GitHub: build + e2e jobs with secrets. Vercel: webhook → build with production-scope envs → promote to www.yourbest100.com. The edge layer adds 6 security headers + CSP + image transforms + revalidatePath-driven ISR.

v3.1 · 4-grid · 1px hairlines · one accent per diagram · theme tokens from src/app/tokens.css
01
Lv 1 · Browser0 pts
0 / 100 to Lv 2+1 / 200px scrolled
Theme
Display
Density