Easy-to-manage touch screens
무료 오픈소스 터치스크린으로 USB 설정 가이드, 드래그‑드롭 편집기, 로컬 제어를 제공하며 Home Assistant용으로 제작되었습니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Next.js + Supabase app: accounts, cloud-synced collections (video games, comics, trading cards, vinyl records, books, DVDs, VHS, CDs, consoles, Funko Pops, and LEGO sets), public profiles, follows, comments, trophies, and a community leaderboard.README 전문 보기 ↗
Next.js + Supabase app: accounts, cloud-synced collections (video games, comics, trading cards, vinyl records, books, DVDs, VHS, CDs, consoles, Funko Pops, and LEGO sets), public profiles, follows, comments, trophies, and a community leaderboard.
supabase-schema.sql (in this folder), and click Run. This creates all tables, security rules, and leaderboard views.storage-setup.sql the same way (New query → paste → Run) — this sets up the storage bucket avatar uploads need. Without this, avatar upload will fail with a "bucket not found" error.comics-migration.sql, currency-migration.sql, achievements-migration.sql, collectibles-migration.sql, region-migration.sql, copytype-migration.sql, ebayprice-migration.sql, completeness-migration.sql, fullycompleted-migration.sql, valuesnapshots-migration.sql, showcase-migration.sql, activity-migration.sql, steam-connect-migration.sql, recommend-games-migration.sql, trophy-completion-migration.sql, halfstar-ratings-migration.sql, trophy-leaderboard-migration.sql, activity-trophies-migration.sql, consoles-migration.sql, publicprice-refresh-migration.sql, funko-migration.sql, valuable-leaderboard-migration.sql, friends-leaderboard-migration.sql, friends-leaderboard-expanded-migration.sql, currency-aware-valuable-leaderboard-migration.sql, security-definer-views-migration.sql, function-search-path-migration.sql, avatar-storage-policy-migration.sql, revoke-internal-function-access-migration.sql, handle-new-user-revoke-migration.sql, revoke-anon-authenticated-function-access-migration.sql, feedback-migration.sql, newsletter-optin-migration.sql, condition-photos-migration.sql, activity-reactions-migration.sql, trophy-rarity-migration.sql, comment-rate-limit-migration.sql, price-drop-alerts-migration.sql, completeness-split-migration.sql, vhs-migration.sql, article-submission-rate-limit-migration.sql, rls-performance-migration.sql, webauthn-rate-limit-migration.sql, feedback-rate-limit-migration.sql, notification-mute-migration.sql, wishlist-public-migration.sql, wishlist-priority-migration.sql, public-lists-migration.sql, recommend-collectors-migration.sql, forsale-migration.sql, collection-types-migration.sql, email-backup-migration.sql, master-set-cache-migration.sql, activity-digest-migration.sql, wantlist-matches-migration.sql, trophy-variety-migration.sql, api-tokens-migration.sql, item-reviews-migration.sql, upcoming-releases-migration.sql, upcoming-release-aliases-migration.sql, and discogs-import-migration.sql (same New query → paste → Run process). Also run item-photos-storage-migration.sql the same way as storage-setup.sql in step 3 — without it, uploading a condition photo fails with a "bucket not found" error. Brand new projects can skip all of these — supabase-schema.sql and storage-setup.sql already include everything. (One exception: supabase-schema.sql previously didn't actually include the trophy case tables/functions — that's now fixed, but if you set your project up before this fix, you'll still need to run achievements-migration.sql once for trophies to work.).env.local.example to .env.local.ROADMAP.md for why.https://localhost (required by the form, not actually used since this app never does a browser-based Twitch login), and pick Category: Application Integration..env.local as IGDB_CLIENT_ID and IGDB_CLIENT_SECRET. Unlike the Supabase keys, these are not prefixed with NEXT_PUBLIC_ — they're used only by a server-side route (app/api/igdb-search/route.js) and are never sent to the browser, since exposing the client secret would let anyone use your Twitch app's quota..env.local as COMICVINE_API_KEY. Not prefixed with — used only by server-side routes (, , , , and ) and never sent to the browser.npm install
npm run dev
Open http://localhost:3000, sign up, and try it out.
.env.local.The site's already wired up for Google AdSense (a cookie-consent banner, the ad script, an ads.txt route, and a Privacy Policy page all exist — they just need your AdSense account's ID to switch on). Ads only start showing once you set the env var below and a visitor accepts the cookie banner.
ca-pub-XXXXXXXXXXXXXXXX. Add it to your Vercel project's Environment Variables as NEXT_PUBLIC_ADSENSE_CLIENT_ID, then redeploy (Vercel → Deployments → ⋯ → Redeploy) so it takes effect.ads.txt file at yoursite.com/ads.txt, which AdSense checks for).Worth knowing: the cookie banner defaults to not loading ads until a visitor clicks Accept, which is the honest baseline for EU/UK cookie-consent rules — it's a simple accept/decline banner, not a full certified consent platform. If this ever grows into something with real traffic/revenue, it'd be worth a proper look at compliance (and the Privacy Policy at /privacy) rather than relying on what's here.
The site already generates sitemap.xml and robots.txt automatically (home, Find Collectors, Leaderboard, and every public profile — private profiles are excluded), plus a branded image that shows up when a link gets shared on Discord/Reddit/iMessage/etc. It also carries real schema.org structured data (JSON-LD) — a SoftwareApplication block on the homepage, and FAQPage markup on each of the 4 SEO landing pages — giving Google a shot at an FAQ/app rich result for free, from content that's already written and shown either way. None of that requires any setup. What actually gets Google/Bing to crawl and index the site is submitting it to their tools directly:
https://shelflife.site as a property, verify ownership (the easiest method is usually the DNS TXT record through whoever you registered the domain with), then under Sitemaps submit https://shelflife.site/sitemap.xml.That's it — from then on, every git push redeploys automatically.
None of this is required for the site to work — without it, the Feedback page still saves every submission to the database (readable any time in Supabase's Table Editor, under feedback), it just won't also email you. Set this up when you want the email notification and the ability to send the opt-in newsletter.
.env.local (and your Vercel project's env vars) as RESEND_API_KEY. Server-only, never sent to the browser.RESEND_FROM_EMAIL — the "from" address for both the feedback notification and the newsletter, e.g. Shelf Life <[email protected]>. Has to be on a domain you verified with Resend in step 1.ADMIN_EMAIL — the email address you sign into Shelf Life with. This gates /admin/newsletter (a private, unlinked page — only visible to whoever's signed in with this exact email) and controls where feedback-submission notifications get sent by default.FEEDBACK_NOTIFY_EMAIL if you want feedback notifications to go to a different address than ADMIN_EMAIL — otherwise they fall back to ADMIN_EMAIL automatically.NEXT_PUBLIC_-prefixed anything, never commit it, and only ever use it server-side, which is exactly how lib/supabaseAdmin.js uses it here), and add it as SUPABASE_SERVICE_ROLE_KEY. It's needed because looking up opted-in collectors' actual email addresses means reading auth.users, which the normal app-wide Supabase client intentionally can't see./admin/newsletter to write and send an update to everyone who's checked "Email me when something new ships" in their Profile Settings. It's a manual send, not automatic — nothing goes out until you write it and hit Send.Lets you set "notify me if this drops below $X" on a wishlist item; a Vercel Cron job checks once a day and sends an in-app notification the first time it dips below that price. Without this set up, the field in the Add/Edit form still saves, it just never gets checked.
openssl rand -hex 32 on the command line, or any long random string — and add it as CRON_SECRET in both .env.local and your Vercel project's env vars.SUPABASE_SERVICE_ROLE_KEY is also set (see step 6 under Feedback emails above) — the daily check has no signed-in user to run as, so it needs the same service-role client the newsletter uses.vercel.json already schedules the job (/api/cron/price-drop-check, once daily) — Vercel picks this up automatically on deploy, nothing to configure in the dashboard. Needs price-drop-alerts-migration.sql on existing projects.The same CRON_SECRET and SUPABASE_SERVICE_ROLE_KEY also cover the account-deletion cron (/api/cron/process-account-deletions), the weekly currency-rate refresh (/api/cron/refresh-currency-rates), the weekly stats digest (/api/cron/weekly-stats-digest, needs ADMIN_EMAIL and Resend set up too — see step 7), the opt-in monthly data-backup email (/api/cron/email-data-backup, needs Resend too, not ADMIN_EMAIL — it emails each opted-in collector their own backup, not you), the weekly Pokémon master-set variant cache refresh (/api/cron/refresh-master-sets, no third-party key needed — TCGdex is free/open), the opt-in weekly activity digest email (/api/cron/email-activity-digest, needs Resend too, same as the monthly backup), and the weekly Upcoming Releases cache refresh (/api/cron/refresh-upcoming-releases, needs IGDB_CLIENT_ID/IGDB_CLIENT_SECRET/COMICVINE_API_KEY too — the same keys game/comic search already require) below — nothing extra to set up for any of them once this step is done.
If a cron job actually fails (a query error, a fetch failure, missing config), it now emails ADMIN_EMAIL directly rather than only logging it — Vercel's runtime log retention on the current plan is 1 hour, too short to reliably catch an overnight failure. See lib/cronAlert.js.
None of the above catches a cron that stops firing entirely — a vercel.json misconfiguration, a broken build, a Vercel Cron outage — since nothing runs to report the silence. Closing that needs a free external dead-man's-switch service (healthchecks.io or Cronitor both work, no cost):
vercel.json and are in UTC, same as Vercel Cron itself — both services default to UTC too, so paste them in as-is rather than converting to local time).
price-drop-check — 0 13 * * * (daily, 13:00 UTC)process-account-deletions — 0 14 * * * (daily, 14:00 UTC)refresh-currency-rates — 0 6 * * 1 (weekly, Monday 06:00 UTC)weekly-stats-digest — 0 13 * * 0 (weekly, Sunday 13:00 UTC)email-data-backup — 0 11 1 * * (monthly, 1st at 11:00 UTC)refresh-master-sets — 0 8 * * 1 (weekly, Monday 08:00 UTC)email-activity-digest — 0 12 * * 0 (weekly, Sunday 12:00 UTC)refresh-upcoming-releases — 0 8 * * 2 (weekly, Tuesday 08:00 UTC)https://hc-ping.com/<uuid>). Collect all 8 into one JSON object, keyed by the job names above exactly as spelled — e.g. {"price-drop-check": "https://hc-ping.com/...", "process-account-deletions": "https://hc-ping.com/...", ...} — and add that whole object as a single Vercel env var, CRON_WATCHDOG_URLS. Doesn't need the NEXT_PUBLIC_ prefix (it's server-only), so add it as a Sensitive/Secret-type var, not Config.<url>/fail on a real failure (lib/cronWatchdog.js) — if a job ever goes silent instead, the watchdog service itself emails you once the check's grace period passes, the piece nothing inside Vercel can do on its own.Safe to skip entirely — every cron already works and already emails ADMIN_EMAIL on a real failure via lib/cronAlert.js; this only adds coverage for the much rarer "didn't run at all" case.
The public gift list page (/u/[username]/wishlist) shows "Buy on eBay" / "Search Amazon" links under each item — real, working search links either way, with optional affiliate tracking on top so a purchase made through one earns a small commission.
NEXT_PUBLIC_EBAY_EPN_CAMPAIGN_ID.yoursite-20) into NEXT_PUBLIC_AMAZON_ASSOCIATE_TAG..env.local and your Vercel project's env vars, and redeploy. Leave either blank to skip tracking for that one — the links themselves still work./forgot-password, /reset-password) using Supabase's own reset-password email, self-service account deletion with a 48-hour grace period (a "Danger zone" section in Profile Settings, with a confirmation email so there's a real record of the request beyond the in-app banner), and an "Account security" section next to it with a "Sign out of all other devices" button — also fires automatically right after a password reset, so recovering a compromised password actually closes out whatever session had it./dashboard): add/edit/delete/filter/search across nine collectible types in one shelf, each with tailored fields — platforms for games, series/issue/publisher/writer/artist/grade/variant for comics, set/card number/player/grade for trading cards, artist/label/format/edition for vinyl, author/publisher/format/edition for books (director/studio for DVDs, artist/label for CDs), manufacturer/storage-variant/special-edition/region/grade for consoles, and series-line/Pop!-number/character/exclusive-to/grade/chase-variant for Funko Pops — plus shared tags, barcodes, and Search auto-fill for games (IGDB), trading cards (Pokémon TCG/Scryfall), books (Open Library), and consoles (a built-in common-systems list — no external API). An "Import CSV" button bulk-adds items from a spreadsheet at once, using a downloadable template with the right columns, and flags rows that look like something already in your collection (same title-matching rule as the single-item duplicate warning) so you can skip them instead of importing silent duplicates; "Export CSV" downloads your whole collection back out at any time, in the same column layout, as a backup. "Log in with Steam" (in Profile Settings) plus "Import from Steam" bulk-adds someone's owned PC games automatically. Consoles and Funko Pops both reuse existing fields rather than adding new columns (manufacturer/storage-variant/edition/grade, and series-line/Pop!-number/character/exclusive-to double up on the same publisher/format/edition/grade/card_set/card_number/player_name fields comics, cards, and vinyl already use) — needs consoles-migration.sql and funko-migration.sql on existing projects.achievement_defs table and can be edited/extended directly in Supabase; the awarding logic lives in the check_and_award_achievements SQL function (in supabase-schema.sql for new projects, achievements-migration.sql for existing ones).ROADMAP.md in this folder for a running list of ideas for what to build next.NEXT_PUBLIC_app/api/comic-search/route.jsapp/api/comic-detail/route.jsapp/api/comic-master-set/route.jsapp/api/comic-creator-search/route.jsapp/creator/comics/[id]/page.js.env.local as REBRICKABLE_API_KEY. Not prefixed with NEXT_PUBLIC_ — used only by a server-side route (app/api/lego-search/route.js) and never sent to the browser..env.local as EBAY_CLIENT_ID and EBAY_CLIENT_SECRET. Same as the IGDB keys, these are server-only and never sent to the browser (app/api/ebay-price/route.js).shelflife.site)..env.local (and your Vercel project's env vars) as STEAM_API_KEY. Server-only, never sent to the browser (app/api/steam-games/route.js).lib/siteUrl.js (SITE_URL), since Steam's login flow requires a fixed callback address. If you ever change domains, update that file.STEAM_API_KEY also powers "Sync achievements from Steam" on the dashboard (pulls per-game achievement completion % for Steam-imported games) — nothing extra to set up once the key above is in place..env.local (and your Vercel project's env vars) as DISCOGS_API_TOKEN. Server-only, never sent to the browser (app/api/discogs-collection/route.js).discogs.com/user/<name> in a regular browser. Whoever's collection you're importing needs their Discogs privacy setting (Settings → Privacy on discogs.com) set to Public first, or Discogs returns it as empty./dashboard/insights/u/username): view a collector's shelf, follow them, leave comments. Shows a "Collection value" stat (same purchase-price/eBay blend as the dashboard) and each item's last-checked market price right on its card. A signed-in visitor can also hit "Refresh prices" to re-check eBay for that collector's whole shelf — writes through a narrow refresh_item_market_price database function rather than opening up full edit access, so a visitor can only ever touch those three price columns, never anything else on someone else's items. Users can toggle their profile private in Profile Settings. The Collection tab opens with the same segmented-shelf hero the dashboard has (real cover art, one row per type the collector owns and has enabled, each in its own color/icon) — click a row to filter the grid below to that type, or a cover to jump straight to it (games/comics/trading cards/Funko Pops open the item directly; other types filter to that row). Needs publicprice-refresh-migration.sql on existing projects.recommend-games-migration.sql on existing projects./leaderboard): tabs for most-owned items, trending titles (last 14 days), biggest public collections, most valuable public collections, a trophy case ranking, and a Friends tab (just the public collectors you follow, with its own row of pills for the same 5 categories), each with a gold/silver/bronze podium for the top 3 (cover art or avatar sized up, colored glow per medal) — computed from public collections only. "Most valuable" converts every collector's total to USD behind the scenes to decide ranking order (a weekly cron keeps the underlying rates current — see step 8), and now shows a converted figure alongside each collector's own-currency total on the podium too — in whichever currency the viewer has picked in their own Settings, not a fixed USD, whenever it's different from the collector's own. Needs trophy-leaderboard-migration.sql, valuable-leaderboard-migration.sql, friends-leaderboard-migration.sql, friends-leaderboard-expanded-migration.sql, and currency-aware-valuable-leaderboard-migration.sql on existing projects./u/username): a PlayStation-style trophy case — bronze/silver/gold/platinum badges earned for collection milestones (first item, 10 items, 100 items, 25 completed, follower counts, etc.). Trophies are computed and awarded by a trusted database function, not by the browser, so they can't be faked. Earning one also shows up in your followers' /feed. Requires activity-trophies-migration.sql on existing projects for the feed part.halfstar-ratings-migration.sql on existing projects./dashboard/insights): breakdowns of your owned items by type, platform, and genre, value by type, spending by month, and which calendar month you tend to add the most items in — all derived from data already in your collection, no new fields to fill in. A second "Made for what you collect" section below adds type-specific panels that only show up for types you actually own: backlog health + trophy completion for games, raw-vs-graded + top card sets for trading cards, top series for comics and books, record labels + format for vinyl/CD, manufacturer for consoles, studio for DVD/VHS, character for Funko Pops. No new env vars or migration.condition-photos-migration.sql and item-photos-storage-migration.sql on existing projects./feedback, linked from the footer): a bug/issue/feature-suggestion form anyone can use, no account required. Every submission saves to the feedback table; see step 7 below to also get an email notification. Needs feedback-migration.sql on existing projects./admin/newsletter) to manually write and send an update to everyone opted in. See step 7 below for setup — needs newsletter-optin-migration.sql on existing projects./feed entry, one per person per event. Reacting to someone else's activity notifies them (via the bell). Needs activity-reactions-migration.sql on existing projects.trophy-rarity-migration.sql on existing projects./video-game-collection-tracker, /comic-collection-app, /collectible-database, /retro-game-inventory) each targeting a different real search term with genuinely different content for that audience, cross-linked from the footer and each other. Content lives in lib/landingPages.js; add a new entry there plus a matching app/<slug>/page.js to add more.comment-rate-limit-migration.sql on existing projects.components/CustomListsModal.jsx, managed from your public profile's "Manage lists") also show up as a Filters-panel dropdown now, so a list you built for profile browsing (Favorites, For sale, etc.) doubles as a saved view on the dashboard where you're actually managing the collection — previously lists were profile-display only.feedback-rate-limit-migration.sql on existing projects.app/manifest.js), with a minimal offline fallback page if you open it with no connection. Deliberately doesn't cache your actual collection data for offline browsing — that's still fetched fresh from Supabase every time, so you're never looking at stale prices or a friend's already-changed collection.price-drop-alerts-migration.sql on existing projects.vhs-migration.sql on existing projects.passkey-migration.sql and webauthn-rate-limit-migration.sql on existing projects; no new env vars (reuses SUPABASE_SERVICE_ROLE_KEY, already required for the newsletter feature)./admin/stats, private/unlinked — only visible to ADMIN_EMAIL): total users, new signups this week/month, items logged site-wide, the most active public collectors over the last 30 days, and a "Cron jobs" section showing each scheduled job's last run time and status (or "Never run yet") — pulled from data that already exists in every table involved, no new fields to fill in. Needs cron-heartbeat-migration.sql on existing projects.CRON_SECRET/SUPABASE_SERVICE_ROLE_KEY the price-drop cron already needs)./admin/stats shows on demand now also land in ADMIN_EMAIL's inbox automatically every Sunday morning, via a Vercel Cron job — turns it from something you have to remember to check into something that just shows up. See step 8 for setup.ADMIN_EMAIL if it actually fails, instead of the failure only existing in Vercel's 1-hour runtime logs. See step 8./admin/reports, only visible to ADMIN_EMAIL) and emails a notification the same way feedback does. Rate-limited server-side (5 per 5 minutes per person), same shape as comments. Needs report-migration.sql on existing projects; no new env vars./whats-new now show right on the home page for signed-out visitors too, not just behind a small footer link — the same section the logged-in home page already had.aria-live), and a fixed missing focus indicator on tag/chip input fields — first slice of a larger accessibility pass, see ROADMAP.md for what's still open.refresh-master-sets, no setup needed) now also pre-fetches every card's real variant data for Pokémon sets people have actually logged cards from, so the grid can show prints you don't own yet, not just confirm the ones you do — Magic doesn't need this, since Scryfall returns full variant data for a whole set in one request already.COMICVINE_API_KEY (see step 5) — same key comic search/auto-fill already use.notification-mute-migration.sql on existing projects./u/<username>/wishlist): a lightweight, shareable page showing just your wishlist — meant for sending to family/friends around gift-giving occasions instead of handing them the whole collection to dig through. Reachable from "More actions" on your public profile, with its own share button. A second, separate "Share my gift list even when my profile is private" toggle in Profile Settings lets you share just this page without making the rest of your collection public — needs wishlist-public-migration.sql on existing projects./notifications, linked from the bottom of the bell dropdown): the bell itself only ever shows your most recent 30 — this page shows everything still in the database, 50 at a time, with a filter row to narrow it down to just one notification type. Same per-category mute settings apply here too. No new env vars or migration.SeriesGrid pagination: any "See master set"/"See full series" grid (Pokémon, comics, or the crowdsourced fallback) now shows the first 100 entries with a "Show more" button for the rest, instead of rendering a very large set all at once./notifications to a type you've muted now says so directly, with a link straight to the Notifications tab of Settings instead of leaving you to guess why nothing's showing up./u/<username>/wishlist) so "get this one first" items land at the top. Needs wishlist-priority-migration.sql on existing projects./lists, linked from the navbar): browse every public custom list site-wide — not just the ones a particular collector made, everyone's. Click one to see its full contents on its own page. Needs public-lists-migration.sql on existing projects.recommend-collectors-migration.sql on existing projects.wantlist-matches-migration.sql on existing projects.forsale-migration.sql on existing projects./dashboard/wrapped, linked from the dashboard sidebar): a shareable, end-of-year recap card — items added, busiest month, completions, ratings, and estimated value change, built entirely from data already tracked. No new env vars or migration./dashboard/appraisal, linked from the dashboard sidebar): a print-optimized, itemized document of your owned items and their current value, grouped by type with subtotals and a grand total — use your browser's "Save as PDF" for insurance documentation. No new env vars or migration.prefers-reduced-motion support, and a new /accessibility page (linked in the footer) documenting what's covered and what's still open. No new env vars or migration./u/[username]/wishlist — real search links either way, with optional eBay Partner Network / Amazon Associates tracking on top. See step 9 for setup.npm install after pulling to drop the now-unused @zxing/browser dependency.lib/consoleList.js's built-in console list (the one search backend not backed by a live third-party API) now falls back to edit-distance fuzzy matching when a plain substring search comes up empty, so a dropped or swapped letter ("nintendo swithc", "xbox seris x") still finds the right console. Substring/prefix matches still always rank first. Games, cards, books, VHS/DVD/CD/vinyl, and comics search already go through APIs (IGDB/Scryfall/TCGdex/Open Library/iTunes/MusicBrainz/Comic Vine) with their own fuzzy matching, so they weren't touched.collection-types-migration.sql on existing projects.npm test (or npm run test:watch) now runs a real Vitest suite covering the site's pure-logic modules — title/card-number normalization and duplicate matching, currency formatting, the shelf-mosaic grouping/packing logic, and the series/master-set matching keys. Deliberately scoped to logic that needs no test environment at all (no React components, no Supabase/API calls) as a starting point, not full coverage. Needs one npm install to pull in the new vitest dev dependency; nothing else to configure.ROADMAP.md. No new env vars or migration./api/cron/email-data-backup (see step 6 for cron setup) — needs email-backup-migration.sql on existing projects./feed shows, condensed into one email instead of something you have to remember to check. Off by default, and skips itself entirely on a quiet week with nothing to report. A new cron job, /api/cron/email-activity-digest (see step 6 for cron setup) — needs activity-digest-migration.sql on existing projects.@supabase/ssr and @supabase/supabase-js bumped to the minimum patched versions above a set of known advisories, tested against the full build and test suite first.npm audit issues that only resolved on next@16. Requires Node 20.9+ (declared in package.json's engines field) — run npm install after pulling to pick up the new versions. See CHANGELOG.md for the full technical writeup./api/cron/refresh-master-sets, see step 6) pre-fetches every card's real print-variant data for Pokémon sets people have actually logged trading cards from, so the master-set grid can show a print you've never touched as a real, unowned tile — not just confirm variants you already have. Needs master-set-cache-migration.sql on existing projects./dashboard/catalogue, linked from the dashboard sidebar and from an active "Browse by system" tile): pick a platform and see every game IGDB has on file for it as its own checkable tile, greyed out except what you've already logged for that system — not just a checklist of what's already in your own collection, the real thing. Click any not-owned tile to check eBay for it (CeX if eBay has nothing), same click-through every other missing-entry grid on the site already has. Real server-side pagination and a title-search box, since a major platform's catalog can run into the thousands, and the grid uses the full page width on desktop. (Originally restricted to IGDB's "main game" category to keep DLC/bundles/ports out, but that filter turned out to be broken — see CHANGELOG.md — and was removed, so a system's occasional DLC/bundle/port entry can show up alongside the real releases now.) Uses the same IGDB_CLIENT_ID/IGDB_CLIENT_SECRET env vars game search/auto-fill already needs — no new setup. No migration needed./dashboard/labels, linked from the dashboard sidebar): pick which owned items to include and print a small QR sticker per item, sized for Avery 5160 (or compatible) address label sheets — 30 per sheet. Scanning a label opens that item's own page here, signed in on your phone — a fast way to look a boxed item back up if you actually store a physical collection. Adds a new qrcode npm dependency — run npm install after pulling. No new env vars or migration./dashboard/api-tokens, linked from the dashboard sidebar): generate a personal access token and pull your own collection as JSON — GET /api/v1/me and GET /api/v1/collection (optional ?type=/?ownership= filters), authenticated via Authorization: Bearer sl_live_... instead of a signed-in session. Free, rate-limited to 60 requests/minute per token; only a hash of each token is ever stored, so the raw value is shown once, at creation. Needs api-tokens-migration.sql on existing projects — no new env vars./collectible?type=&title=) now has a Reviews section — a star rating plus written text, one per reviewer, aggregated across everyone who's reviewed that exact item, separate from the existing personal (per-copy, private-by-default) rating field. Posting one requires actually owning the item, enforced at the database level. Same visibility rule as comments and lists elsewhere on the site — visible to anyone if your profile is public, otherwise just to you. Needs item-reviews-migration.sql on existing projects — no new env vars.zoom — works for signed-out visitors too, and matters most in the wrapped iOS app, where the system-level "Larger Text" setting doesn't reach web content. Remembered per device (localStorage), not tied to your account. No new env vars or migration./dashboard/upcoming-releases, linked from the dashboard sidebar): a calendar of upcoming releases — grouped by month — plus a running "this week"/"this month" spend total from expected prices you type in yourself (neither IGDB nor Comic Vine exposes real price data for something that hasn't released yet). Games and comics are matched differently (redesigned Sep 2026, see CHANGELOG.md): a game shows up if it's an upcoming, currently-hyped release (by IGDB's own pre-release "hype" signal, not just anything technically unreleased) in a genre or on a platform your own collection already touches — not tied to any specific franchise you own — while a comic issue still has to belong to an exact series you already own something from (Comic Vine has no clean genre-equivalent to broaden against). A weekly cron (/api/cron/refresh-upcoming-releases, see step 6) keeps a cache of real upcoming dates warm for every platform/genre/series someone here actually tracks, so the page never hits IGDB/Comic Vine live. Uses the same IGDB_CLIENT_ID/IGDB_CLIENT_SECRET/COMICVINE_API_KEY env vars game/comic search already need — no new setup. Needs upcoming-releases-migration.sql and upcoming-release-aliases-migration.sql on existing projects (the second one fixes a real bug — see CHANGELOG.md — where a cached franchise almost never matched what a title was actually stored as; the same alias table now also resolves platform/genre lookups, no further migration needed for that). The page will show nothing until the cron has actually run once — on a brand-new deploy (or right after adding this feature to an existing project), don't wait for the weekly schedule: run vercel crons run /api/cron/refresh-upcoming-releases from the project directory a few times a couple minutes apart to backfill an existing collection faster (each run picks up a fresh batch it hasn't cached yet, up to MAX_SERIES_PER_RUN).app/dashboard/layout.js + components/DashboardSidebar.jsx) that's visible on every /dashboard/* route — a sticky left column on desktop, a slide-in drawer from the left on mobile (same off-screen-transform pattern the navbar's own mobile menu already used) — grouped into My Collection, Insights & reports, Utilities, and Account, with the current page highlighted. The old "More actions" dropdown on the main dashboard toolbar is gone; Refresh all prices and Settings are now plain buttons in the toolbar instead. No new env vars or migration — layout/component/CSS only.discogs.com/user/<name> in a browser. Only Vinyl and CD formats are imported (no Cassette/digital/box sets). Re-running it, or running it against a second username, skips anything already in the collection instead of creating duplicates. Goodreads' half of this idea (book import) turned out not to be buildable — Goodreads stopped issuing new developer API keys in Dec 2020. Needs DISCOGS_API_TOKEN (see step 8 of "Configure the app" above) and discogs-import-migration.sql on existing projects.SeriesGrid uses everywhere else on the site. Public — works signed out, same as the SEO landing pages — with ownership-highlighting and click-to-price-check on missing entries once you're signed in. Four now ship: /creator/comics (writer/artist, via Comic Vine — uses the same COMICVINE_API_KEY game/comic search already needs), /creator/books (author, via Open Library — no key needed), /creator/games (developer/publisher, via IGDB — uses the same IGDB_CLIENT_ID/IGDB_CLIENT_SECRET game search already needs), and /creator/cards (illustrator, via Scryfall for Magic and TCGdex for Pokémon — both fully free and keyless). No new setup or migration for any of the four — each reuses an API this project's other search/auto-fill features already rely on, or needs none at all.card_set/card_number/player_name/publisher/grade/is_variant/variant_notes) rather than adding new columns. Unlike Funko Pops, LEGO sets get a real "Search" auto-fill button (see step 6 of "Configure the app" above) backed by Rebrickable's free, live set database — fills in Theme and Set number from an actual search instead of typing every set in by hand. Always treated as a physical item (no digital LEGO sets), same as consoles/Funko Pops/VHS. Shows up in Collection Insights' "Made for what you collect" section (a "By theme" breakdown) once you own at least one. Needs lego-migration.sql on existing projects.REBRICKABLE_API_KEY the original LEGO Search button already needs (see step 6) — no new setup, no migration.legobuilt-migration.sql on existing projects.