feat(sponsors): curated sponsor ad zones, tracking, and funding model#705
Conversation
Fund the project with curated campus-relevant sponsors (no ad networks, no third-party scripts, no cookies): - Zone A: status bar "Supported by" badge (gold sponsor) - Zone B: dismissable side panel banner (gold+silver, daily rotation) - Zone C: prerendered /sponsors showcase page - Zone D: sponsor strip above SiteFooter on static pages - First-party impression/click beacons via /api/sponsor-event into new sponsor_impressions table (0038); session-deduped, bot-filtered, degrades gracefully when the table is missing - Sponsor config in public/sponsors.json; images self-hosted and SW-precached; /sponsors added to workbox denylist so returning PWA users don't get the map shell - Funding model (40/30/30 split, tier pricing) and ad policy docs; GitHub FUNDING.yml; privacy/terms sponsored-content sections
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_f2892958-9a3f-4a24-b3cd-303d6872aabf) |
staging HEAD fails the verify job's biome check on these two files; mechanical fixes only (import wrapping, bracket-to-dot access).
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_eb2a1f6a-8b99-48e1-8f8d-dc39fd180c40) |
|
CI status: verify, migrations, CodeQL, bundle all green on 48f058d. The gated e2e / e2e job failed on the first commit with |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_310f4bfd-385d-435b-ba52-d7310b776cd7) |
- Fictional demo sponsor (active, gold) with generated logo/banner art so every zone can be eyeballed on preview; deactivate before prod release - Side panel drawer is row flex: banner rendered as a side column; wrap so the full-width banner lands below the entity content - Banner art already carries name/tagline: keep text for screen readers only, avoiding visual duplication - Fix swallowed spaces around inline links on /sponsors (Astro trims text-node whitespace at element boundaries across newlines)
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_a3929817-7059-4ac3-8ee8-75184f7456d7) |
|
f1d7b5b adds Kape Kalabaw, a fictional demo sponsor (active, gold tier, generated art) so all four zones can be eyeballed on the preview deploy: status bar badge, side panel banner, /sponsors hero card, footer strip on legal/changelog pages.
Also in this commit: side panel drawer flex-wrap fix (banner was rendering as a side column next to entity content), banner text now screen-reader-only when banner art is present, and whitespace fixes around inline links on /sponsors. |
Gold/Silver sponsors with a real place entity get their existing map pin highlighted: static gold ring, always-visible "Sponsored" label, max 3 at once with gold priority. Anchored via sponsors.json placeName -> places.name so pins can never point at fabricated locations; clicking opens the normal place detail panel. map_pin impression/click beacons reuse the session-deduped tracker. Ad policy amended: pins are the one map-surface exception, everything else on the canvas stays ad-free.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_0a944782-b9dc-4222-9ab4-1ca4275e1672) |
/donate page (preset + custom amounts, optional message) posts to /api/donate, which creates a PayMongo Checkout Session (QR Ph, PHP 10-50k, kape.stimmie.dev pattern) and redirects to the hosted checkout; no payment data touches the server. PAYMONGO_SECRET_KEY is an optional astro:env secret so the route degrades to 503 when unset. /donate added to SW precache + navigate denylist, footer/README/FUNDING links, and the funding-model doc.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_3ae4fca9-b5f1-4738-8048-779f2af587a5) |
…butions" Editor-published edits now append a ledger row (source: editor_published) alongside proposal approvals, and signed-in editors can see their own contribution history via GET /api/contributions/mine and a new section in Account Settings. Leaderboard queries now filter to active, credit-opted-in contributors.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_3576b965-c389-4bb0-9e53-3eb9915bbd74) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_cb8c4f41-1ffd-41c0-b21e-fc5f93f0f66a) |
# Conflicts: # .github/FUNDING.yml # README.md # src/lib/amis/normalize-class.ts # src/pages/donate.astro
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_ea5b158b-d137-4d21-b8fa-346bc11edb66) |
|
🎉 This PR is included in version 2.3.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Who are you?
Summary
Adds the curated sponsor ad system funding the project: four ad zones (status bar badge, dismissable side panel banner,
/sponsorsshowcase page, static-page strip), first-party impression/click tracking (/api/sponsor-event→ newsponsor_impressionstable, migration0038), sponsor config inpublic/sponsors.json(sample sponsor ships inactive, so no ads render until a real sponsor is activated), plus funding-model and ad-policy docs, GitHubFUNDING.yml, and sponsored-content sections on Privacy/Terms.No ad networks, no third-party scripts, no cookies: images are self-hosted and SW-precached; impressions are
sessionStorage-deduped and bot-filtered server-side; every placement is labeled "Sponsored"./sponsorsis added to the workboxnavigateFallbackDenylist(same trap as/planner) so returning PWA users don't get the map shell.Developer checklist
bun run test(362 pass; newsrc/lib/sponsors.test.ts)bun run lint(Biome, clean)run/e2elabel set (newe2e/smoke/sponsors-page.spec.ts)QA Summary (code changes)
Automated:
bun run test— 362 passbun run test:components— 130 pass (newSponsorBanner.component.test.ts: render, inactive-config empty state, dismiss persistence)POST /api/sponsor-eventtests inintegration/http/public.integration.test.ts(valid beacon, missing fields → 400, bot UA dropped)e2e/smoke/sponsors-page.spec.ts— 6/6 pass locally (desktop + mobile)DATABASE_URL)If auth, routing, or schema changed:
0038_sponsor_impressions.sqlapplied and verified (sponsor_impressionsexists). Note:schema_migrationsledger was freshly baselined during this session and already records 0038, so the release workflow will not re-run it — the table is live. Route degrades gracefully (200, no insert) if the table is ever missing.If map chrome, editor, or side panel changed:
Manual browser check with a real activated sponsor on staging preview is the remaining gap (sample sponsor is inactive by design, so staging shows no ads — flip
active: trueinpublic/sponsors.jsonon a preview to eyeball placements).Notes for reviewers
sponsor_impressionsis server-only — deliberately not added to PGliteSYNCED_TABLES, so nopglite-schemaregen needed.sponsor_impressions./sponsors, footer strip) evaluate the active window at build time; a sponsor whose start date passes after the latest deploy appears on the next build (documented indocs/ad-policy.md).Note
Medium Risk
Touches payments (PayMongo secret), new DB migration for sponsor analytics, and visible map/side-panel UI; sponsor route degrades if migration is missing but donations require correct env configuration.
Overview
Introduces a curated sponsor system driven by
public/sponsors.json(sample sponsor ships inactive): status-bar Gold badge, dismissable side-panel banner on entity detail views, static-page strip,/sponsorsshowcase, and up to three sponsored map pins on realplacesentities with session-deduped impressions/clicks viaPOST /api/sponsor-eventinto newsponsor_impressions(migration0038). PWA precache/denylist covers/sponsorsand/donate./donateis rebuilt aroundPOST /api/donate(PayMongo QR Ph checkout, optionalPAYMONGO_SECRET_KEY); GCash details are removed from campus config. Funding/ad-policy docs, README sponsors section,FUNDING.yml, and Privacy/Terms sponsor copy ship with the change.Contributor ledger gains
editor_publishedrows when editors publish directly (sessionPublishingActor),GET /api/contributions/mine, Account settings “My contributions”, and leaderboard filtering to active users who opted into public credits.Minor: AMIS normalize bracket cleanup, planner E2E selector fixes, transit integration cleanup.
Reviewed by Cursor Bugbot for commit 1b821cc. Bugbot is set up for automated code reviews on this repo. Configure here.