MyGo 云音乐
用 Go 与 MyGo 写成的第三方网易云音乐桌面客户端。原生界面,没有 WebView;边下边播,无损与 Hi-Res,逐字歌词与「律动」,刘海播放器。
Translation pending
See everyone you can vote for — what they say, what they've done, and what's been verified. No ZIP needed.
MediaTypeScript · HTMLGitHub @JasonJosephITOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
Live at knowyour.vote.
The voter-facing web app of the Civic Awareness Project (CAP): a nonpartisan
civic tool that lets a Florida voter enter a ZIP code and see every candidate
in their races side by side — What They Say, What They've Done, and
Fact-Check cleanly separated, every claim traceable to a source.
The app is a presentation layer only. The CAP pipeline (Profiler / Record /
Fact-Checker / Orchestrator + deterministic Balance Audit) writes
neutrality-audited data to Supabase; this app reads what has passed the
audit and been published, and never authors, edits, or reorders a claim.Read the full README ↗Live at knowyour.vote.
The voter-facing web app of the Civic Awareness Project (CAP): a nonpartisan voter guide for Florida's November 3, 2026 general election. A voter sees everyone on their ballot, with no ZIP needed for the statewide races and amendments, and can add a district or county for the rest. For each race with a published brief, every candidate gets the same issues, fixed by office, and under each issue what the candidate says, quoted word for word from their own campaign site, with a link to the page it came from. Where a candidate's site says nothing on an issue, the brief says "No stated position found".
What ships this cycle is stated positions only. Records ("What They've
Done") and fact-checks are not part of the 2026 general: every published
profile has verifiable_fact_count = 0 and fact_checks_performed = 0
(docs/general-election/launch-handoff-2026-10-04.md §1). The schema keeps
room for them; nothing fills them this cycle.
The app is a presentation layer only. The briefs are built offline, never in
a request. The candidate-site ingest and the brief-rows writer produce them
(docs/general-election/brief-runs/), the CAP pipeline's deterministic
Balance Audit checks them, and a human publishes them. This app reads what
has passed the audit and been published, and never authors, edits, or
reorders a claim.
Next.js 16 (App Router) · React · TypeScript · Tailwind CSS v4 · Supabase (Postgres + RLS) · Resend (opt-in email reminders) · Vercel (hosting and cron) · Plausible (cookieless analytics, off until configured) · Sentry (PII-scrubbed, off until configured) · Google Ads tag (loads only after a visitor accepts the cookie banner).
npm install
cp .env.example .env.local # fill in the values
npm run dev # http://localhost:3000
.env.example is the canonical list of names; it never
holds a value. Locally the values go in .env.local (gitignored — .gitignore
matches .env*). For the deployed app they live in Vercel → Settings →
Environment Variables and nowhere else. A secret that reaches a git history or
a chat transcript is burned: rotate it, don't delete it.
The NAME must match exactly. The code reads each variable by its exact name, and a near miss is the same as no variable at all: nothing warns, the feature just stays off.
There is one deliberate exception. Vercel production stores the Supabase
service-role key as SUPABASE and the Resend API key as RESEND (the
founder's names, confirmed 2026-10-05). Until #109 deployed on 2026-10-05,
nothing read them, so the signup, both crons, the deadline banner and the
calendar file all failed. src/lib/server-keys.ts now reads
SUPABASE_SERVICE_ROLE_KEY and RESEND_API_KEY, falling back to SUPABASE
and RESEND when the canonical name is unset or empty, and every read of
either key in the deployed app (src/) goes through it. Local scripts under
scripts/ still read only SUPABASE_SERVICE_ROLE_KEY, so .env.local
needs that name. JEV holds the TypeSafe key, which Vercel doesn't need
(TYPESAFE_API_KEY below). Every other variable must use the exact name.
After adding or renaming a variable, compare its name against the list below
character for character, then redeploy (Vercel applies env changes only to
new deployments). The production env checklist and an end-to-end test are in
docs/general-election/reminders-e2e-runbook.md.
Also unset in production on 2026-10-04, under any name:
NEXT_PUBLIC_PLAUSIBLE_DOMAIN, SENTRY_DSN, NEXT_PUBLIC_SENTRY_DSN,
PELIAS_BASE_URL and ADMIN_EMAILS. So knowyour.vote runs no analytics,
sends no error reports and offers no address suggestions, and the admin
console is closed. Since 2026-10-14 street addresses go through Google
(GOOGLE_MAPS_API_KEY, below).
NEXT_PUBLIC_ is a one-way door — Next.js inlines those values into the
browser bundle at build time. Everything else is server-only and must never
gain that prefix. src/lib/supabase/service.ts and src/lib/geocode.ts import
server-only, so pulling them into a client component is a build error rather
than a leak.
NEXT_PUBLIC_SUPABASE_URL — the Supabase project this app reads.NEXT_PUBLIC_SUPABASE_ANON_KEY — the key behind every public read. Public
by design: RLS, not secrecy, is the boundary (0002_rls.sql).Nothing else is needed to run npm run dev. Every other variable turns one
feature on, and each feature says so plainly when its key is absent — a
missing key degrades a surface, it never fakes one.
SUPABASE_SERVICE_ROLE_KEY (or SUPABASE, production's name) — the two
app-owned write paths (voting-info signups and the news cron's news_item
upserts), the reminder cron, and every read of the verified election dates
in election_event: the deadline banner on / and the calendar file
/api/calendar/general_2026.ics. Bypasses RLS, so it is server-only in the
strongest sense. Unset under both names → POST /api/voting-info returns 503 with nothing sent or stored, both crons
return 503 (the news feed keeps yesterday's items), the calendar file
returns 503, and the deadline banner renders nothing.GOOGLE_MAPS_API_KEY — street addresses (since 2026-10-14). Places API
(New) suggests addresses as the voter types, and the Geocoding API matches
one typed without picking (src/lib/geocode.ts); a typed match counts only
when the voter's own words agree with it (src/lib/address-text.ts). Only
the resulting point goes to the Census Bureau, which answers its census
block (src/lib/census-block.ts). Enable both APIs on the key and restrict
it to them. Unset → no address field, only the district picker, and both
/api/address/* routes answer 503.ADDRESS_LOOKUP_OFF — the off switch for street addresses. Any value → no
address field even with a key, both /api/address/* routes answer 503, and
/privacy says nothing typed leaves the site. Redeploy after changing
either: /privacy is prerendered.RESEND_API_KEY (or RESEND, production's name) + EMAIL_FROM — opt-in
transactional email: the voting-info reply and the deadline reminders. Both
are required; one alone counts as unconfigured. Unset → the voting-info
POST and the reminder cron both return 503 without sending or storing
anything.CRON_SECRET — authenticates both cron routes. Vercel Cron invokes with
GET + Authorization: Bearer …; the manual contract is POST +
x-cron-secret. Compared in constant time (secretEquals), never ===.
Unset → fail-closed: every cron request gets 401, Vercel's included.ADMIN_EMAILS — the admin console's entire authorization surface: a
comma-separated, case-folded allowlist of Supabase Auth emails. Unset →
sign-in is closed and /admin/login says "Admin sign-in isn't configured
yet." rather than pretending otherwise.TYPESAFE_API_KEY — the news issue characterizer
(scripts/news-characterize.ts) and the candidate-site ingest, both local
scripts. No route, cron or page reads it, so Vercel does not need it. Unset
→ the run refuses to start, loudly, because a silent skip looks exactly
like "no issues found".NOTIFICATIONS_PAUSED — pauses outbound reminder sends without a code
change. Any non-empty value pauses, including the string false; to
resume, remove the variable. On Vercel an env change reaches only new
deployments, so redeploy after setting or removing it.SHOW_CANDIDATE_CONTACT — renders the campaign-contact block, and only
when set to exactly true. Held until the first real R2 refresher run has
been reviewed.NEXT_PUBLIC_SITE_URL — canonical origin for sitemap.xml, robots.txt,
the OG metadata base, and the admin magic-link fallback. Falls back to
https://knowyour.vote, the production domain, so an unset value is only
wrong on a preview deployment.NEXT_PUBLIC_PLAUSIBLE_DOMAIN — loads the cookieless analytics script.
Unset → no script at all. Unset in production as of 2026-10-04, so no
analytics run on knowyour.vote today, although /privacy describes
Plausible as in use.NEXT_PUBLIC_SENTRY_DSN — browser error reporting, loaded lazily after
hydration so the SDK stays out of the initial bundle. Unset → never loaded.SENTRY_DSN — server error reporting, started by src/instrumentation.ts.
Unset → the server SDK never loads. The hook used to sit at the repo root,
where next build never registered it because the app has a src/
folder, so before 2026-10-05 no server error was ever reported.Both SDKs send scrubbed error reports and nothing else: no tracing, session
counts or client reports (src/lib/sentry-options.ts). A report keeps the
error, the route, the method and the user agent; cookies, credentials, query
strings, ZIPs, emails and IPs are removed (src/lib/sentry-scrub.ts).
node scripts/verify-sentry-scrub.ts tests the scrubber, and
node scripts/verify-sentry-server.ts runs the real server SDK against a
local stand-in and checks what leaves. /privacy describes error reports
only while a DSN is set.
The Google Ads tag has no variable. Its ID is a constant in
src/components/features/SitePrompts.tsx, and it loads only after a visitor
presses Accept on the cookie banner; Decline means it never loads. Keeping
it is recommended, pending founder confirmation; docs/scope-changes.md
(2026-10-04) records the choice and what removing it would touch.
The admin Site page pulls deploy health and recent errors. Each panel names the exact variable it is missing instead of going blank, so "not wired" and "wired but quiet" stay tellable apart.
VERCEL_API_TOKEN + VERCEL_PROJECT_ID — the Deployments panel; add
VERCEL_TEAM_ID when the project sits in a team.SENTRY_AUTH_TOKEN + SENTRY_ORG + SENTRY_PROJECT — the Errors panel.
SENTRY_URL only for self-hosted Sentry (defaults to https://sentry.io).The tail of .env.example — SUPABASE_DB_URL, CAP_READONLY_DB_URL,
ANTHROPIC_API_KEY, FEC_API_KEY, TWILIO_*, CAP_* — belongs to the CAP
pipeline, which runs locally under Civic Awareness (Know Your Vote)/.
Vercel never needs them. CAP_AGENT_ID, CAP_LOG_SINK, and
CAP_DISPATCH_TOKEN are set by the launcher per process, never by hand.
ANTHROPIC_API_KEY sits there, not with the web app's keys, on purpose. The
web app stopped reading it when the Find My Candidates quiz was removed on
2026-09-25 (docs/general-election/quiz-clipped-2026-09-25.md); checked on
2026-10-04, nothing under src/ or scripts/ reads it. Its one remaining
reader is the CAP agent runtime (runtime/cap_runtime/session.py, which also
accepts ANTHROPIC_AUTH_TOKEN), the parked "Session C" way of building
briefs. It is not set in Vercel and does not need to be.
Scripts that need keys load .env.local themselves — most with
process.loadEnvFile, the news characterizers through
scripts/env-local.ts, which also falls back to the main checkout's file
when run from a .claude/worktrees/… worktree and prints to stderr which
file it used. The migration and Sentry-scrub checks under
Database need no keys at all.
supabase/migrations/ holds, in order:
0000_pipeline_read_models.sql — the pipeline-owned read models per
CAP_Schema_v1.md (created from here only because the shared project was
empty at app-build time; the pipeline owns these tables).0001_app_tables.sql — the four app-owned tables (zip_district,
race_publication, news_item, voting_info_subscription).0002_rls.sql — Row-Level Security: anon reads published races only and
can never touch voting_info_subscription.Verify migrations + RLS invariants locally (embedded Postgres, no cloud):
node scripts/verify-migrations.mjs
node scripts/verify-sentry-scrub.ts
The live database holds no demo data. The nine demo-* races — clearly
fictional fixtures (every person and program invented, sources pointing at
example.org) that let the app be built and verified before the CAP pipeline
produced anything real — were dropped from the live project on 2026-09-21 by
the drop_demo_races migration. They were draft and never voter-visible,
but their office names (Governor of Florida, U.S. House — District 10) did
not announce themselves as fake, and they were one publication flip away from
reading as real content.
The seed scripts remain in scripts/ (build-demo-seed.mjs,
demo-seed*.sql, demo-teardown.sql) for the local verification harness
only — node scripts/verify-demo-seed.mjs replays them into embedded
Postgres. Never run them against the live project, and never seed a real
race from them: their content is invented, and a real race's positions come
from the candidate's own material with a citation per claim.
State as of 2026-10-04. What is left before Election Day, and who acts on
each item, is in docs/general-election/launch-handoff-2026-10-04.md.
.env.local / Vercel env: SUPABASE_SERVICE_ROLE_KEY (enables
voting-info storage, both crons and the election dates), CRON_SECRET
(without it both cron routes 401, Vercel's own invocation included),
RESEND_API_KEY + EMAIL_FROM (enables the email), ADMIN_EMAILS (opens
admin sign-in), and optionally NEXT_PUBLIC_SITE_URL,
NEXT_PUBLIC_PLAUSIBLE_DOMAIN / NEXT_PUBLIC_SENTRY_DSN + SENTRY_DSN.
See Environment variables for what each one
degrades to when it's absent. Production on 2026-10-05: the two public
Supabase variables, NEXT_PUBLIC_SITE_URL, CRON_SECRET and EMAIL_FROM
are set under these names, and the service-role and Resend keys as
SUPABASE and RESEND, which the app reads since #109 (the exception
above). ADMIN_EMAILS, Plausible and Sentry are unset. The signup and
the crons have not been seen working yet;
docs/general-election/reminders-e2e-runbook.md step 4 (by 2026-10-20)
tests the signup and reminders end to end.knowyour.vote and the production *.vercel.app URLs are
public; preview deployments still require a Vercel login.supabase/migrations/0033_listed_publication.sql live, after
the code that renders the listed tier has deployed. On its own it makes
nothing visible: it widens what listed could show and seeds a draft
race_publication row for every general-election race, so the door has
something to flip. Done 2026-09-23.scripts/list-ballot-2026.sql by hand. It flips every draft general
race to listed through set_race_publication (one admin_action row per
race) and inserts listed rows for the three amendments. That puts the
roster and the ballot text in front of voters, and not one brief. The
script's header says how to reverse it. Done: no general race is still
draft.The order of 3 and 4, and why, is in
docs/general-election/listed-tier-2026-09-23.md.
Every claim shown is audited pipeline output, held to the same rules for
every candidate in the race. A race's brief — profiles, issues, positions, claims and
their sources — is publicly reachable only when every candidate Profile has
balance_check_passed = true and race_publication.status = 'published'; a ballot measure's arguments only when both sides are present,
balanced, and measure_publication.status = 'published'. Enforced in RLS and
the read queries, not just the UI.
Before that there is one lower tier, listed, and it carries no claims. At
listed a voter can see the roster and nothing else: the race, the names
printed on the ballot (race.candidate_ids, ballot tier only), party as
filed, the official site where it was verified by reading the page, verified
social handles, whether the seat was already decided, and an amendment's
verbatim ballot text. That is public record from the Division of Elections
and the county Supervisors of Elections, not our writing. Migration 0033
enforces the split in RLS: it widens only the roster policies (race,
candidate, race_publication, candidate_social_account,
ballot_measure, measure_publication), and leaves every brief-table policy
(profile, issue, position, claim, claim_source, measure_resource)
reading 'published' exactly as 0002 and 0011 wrote them — so a listed
race cannot leak an unaudited claim, whatever rows sit beneath it.
Candidate order is a fixed neutral rule. Party chips are never color-coded.
See docs/ for the PRD, vision, roadmap, and design system.
docs/general-election/brief-runs/apply-2026-10-04.mdlistedlisted