Questify

2.11.0

Released

Features

  • Added a Year Themes hub at /themes that lists the quests tagged to the current theme, shows their shared progress, keeps previous years as a readable archive, and lets the theme be created or edited in place; the dashboard now prompts for a theme when none exists instead of rendering nothing, and its banner opens the hub. (#518)

  • Replaced the Year Theme dropdown on the quest form with an on/off switch for the year's theme, added a “Create a quest for this theme” action that opens the New Quest page with it already on, and gave the AI Coach a “Suggest a quest for my theme” interview that is grounded in the theme's own wording. (#518)

  • Saving a Year Theme from the profile now hands the user to the dashboard, where the theme they just wrote is on screen; saving from the hub stays put and returns to the top of the page. (#518)

  • Added a public “Start a Jam” flow for signed-in users, including actionable browse and empty states, explicit public-visibility/countdown guidance, and a live-window join flow that always creates one dedicated Quest. (#517)

  • Added “Copy to my quests” controls to public quest cards and details so people can start from a shared quest without changing the original. (#516)

  • Opened Challenges to logged-out visitors: /challenges now shows the current daily and weekly picks, their constraints and their task lists to anyone, with a sign-in link that returns to the page, while the start form and personal history stay behind the login. (#522)

  • Added public entry points from the landing page into Public Quests, Quest Packs, Challenges and Quest Jams, plus a pricing link that appears only where billing is enabled. (#522)

  • Listed the Quest Packs, Challenges and Quest Jams pages in the sitemap, added pricing to it only where billing is enabled, and gave every public surface a meta description and a canonical URL, so the newly linked pages are indexable and no crawler is handed a route that 404s. (#522)

  • Signed-in visitors who open the marketing landing page at / are now sent to their dashboard instead of a page whose every call to action asks them to create the account they already have; logged-out visitors and crawlers still get the landing page unchanged. (#523)

  • Replaced the landing hero's static UI card with a looping demo of the core Questify loop: two tasks complete in turn, their milestones fill, the progress bar reaches full, and an achievement pops. The loop is drawn in CSS rather than shipped as a video or GIF, so it adds nothing to the page weight, stays sharp at every viewport, and cannot drift out of date against the real UI; visitors who ask their system for reduced motion get the previous static card. (#506)

Fixes

  • Stopped a failed Year Theme read from rendering an editable “Set your theme” form: the theme hub and the profile card now show an error and withhold the form, so a transient read failure can no longer be answered by overwriting an existing theme, and the dashboard leaves its theme slot empty rather than claiming the account has no theme. (#518)

  • Kept Supabase Auth's admin user listing and local fixture seeding working after the public quest catalog migration by giving its credentialless system owner the empty token state and timestamps GoTrue requires. (#505)

Security

  • Limited the public Challenge catalogue read to named columns, so the anonymous /challenges surface returns only what it renders and does not inherit whatever columns a later migration adds to the challenge tables. (#522)

  • Registered the Year Themes hub as a protected route, so signed-out visitors are bounced to login with a return path and users with onboarding still pending are routed to the wizard rather than reaching the surface directly. (#518)

  • Validated the Year Theme form's post-save destination as an internal path, so a redirect target arriving in the form body cannot send a signed-in user off-site; the AI Coach's theme grounding is read from the caller's own stored theme rather than from the request body. (#518)

  • Enforced user-created Jam authentication, creator identity, public-text limits, fixed time windows, a concurrency-safe limit of three open Jams, live-only entry, and durable immutable entry-to-Quest links inside Postgres; linked Quests cannot be permanently deleted and direct table inserts remain unavailable to ordinary users. (#517)

  • Restricted public-quest copying to authenticated callers and currently public, non-deleted sources; internal database failures stay server-side and personal task state never crosses the ownership boundary. (#516)

Technical changes· 13 entries for database, tooling, CI, tests and docs

Database

  • Added immutable creator attribution and an authenticated database function for user-started public Quest Jams, with server-derived 48-hour, 7-day, and 30-day windows. Local resets now include three rolling example Jams. (#517)

  • Added an authenticated, atomic public-quest clone that copies public quest and task wording into a caller-owned private draft while resetting progress, assignees, locations, investigations, and owner-specific links. (#516)

CI/CD

  • Extended the Lighthouse pull request audit to /pricing, /quest-packs, /challenges and /quest-jams, enabling billing in that build so the pricing page exists to be measured, and added the same three newly linked pages to the production audit. (#522)

  • The coverage comment posts a readable summary again. file-coverage-mode: all rendered a row for each of the 243 files vitest reports and a link for each of the ~1,840 uncovered line ranges — about 240,000 characters against the 65,536 GitHub allows in a comment body — so every pull request received the action's "report too large to inline" stub instead of a report. The comment now carries the totals plus the files the pull request touched, which is the action's own default; the whole-repo table was never in the comment and is still written to the workflow summary. (#523)

Tests

  • Pinned account deletion against the new RESTRICT on a Quest Jam entry's dedicated Quest. quests.owner_id and quest_jam_entries.user_id both cascade from auth.users and the quests cascade is queued first, so the delete only survives because RESTRICT is checked as the triggering statement's after-trigger queue drains; deferring or re-declaring the constraint would break Supabase Admin deletion and the end-to-end deleteTestUser() helper with no other symptom. (#527)

  • Added Vitest coverage for the landing hero demo's static base frame, its decorative role, and the two failures that would otherwise be silent in the browser: an animation utility the Tailwind preset does not define, and an animated element missing its reduced-motion opt-out. (#506)

  • Pinned both Lighthouse workflows to one shared audit route list, and pinned the billing flag the pull request build needs for /pricing to exist, so the two cannot drift apart or be silently narrowed. (#522)

  • Added Vitest coverage for the public challenge query skipping every user-scoped read, the challenge card's signed-out and signed-in calls to action, the Challenges page distinguishing a failed read from an empty pool, the landing page's public links and flag-gated pricing link, and the sitemap's public-only contents; Playwright covers the signed-out Challenges page and the landing-page routes into it. (#522)

  • Added Vitest coverage for the Year Theme current/archived split, the tagged-quest query filter, the dashboard prompt, and the shared theme progress bar, plus Playwright coverage for hub route protection, the themeless dashboard prompt, and creating a theme from the hub. (#518)

  • Added Vitest coverage for the Year Themes hub's protected-path registration and for listYearThemes rejecting when its quest-count query fails after the theme row has been read — the failure mode the theme pages' error states exist for. (#518)

  • Added Vitest coverage for the Year Theme toggle's submitted value and archived-theme binding, the post-save redirect and its off-site rejections, the coach's theme entry point, and the theme-grounded prompt being built from the stored row rather than the request body; Playwright covers the theme deep link and the profile redirect. (#518)

  • Added pgTAP, Vitest, and Playwright coverage for user-created Jam authorization, public discovery, immutable ownership and entry links, live-only entry, duration and quota enforcement, rolling examples, form behavior, and sign-in routing. (#517)

  • Added pgTAP, Vitest, and Playwright coverage for clone authorization, privacy resets, validation and failure handling, and the signed-in copy flow. (#516)