ESP32-S3 Bench Guide
ESP32‑S3 N16R8 벤치 가이드: 실시간 핀아웃, 강의, 시뮬레이터 및 벤치 로그
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
An anonymous question board for Cal Poly Pomona CS tutoring. Students scan a QR code, ask a question, and
answer each other — no account, no login. A second QR code at the tutoring desk handles walk-in check-ins,
so the department gets traffic numbers without a paper sign-in sheet.
It runs on free tiers and is meant to be something a tutor can forget about for a month. Keeping it free,
small, and anonymous is the point. Read Scope and Student privacy
before adding anything.README 전문 보기 ↗An anonymous question board for Cal Poly Pomona CS tutoring. Students scan a QR code, ask a question, and answer each other — no account, no login. A second QR code at the tutoring desk handles walk-in check-ins, so the department gets traffic numbers without a paper sign-in sheet.
It runs on free tiers and is meant to be something a tutor can forget about for a month. Keeping it free, small, and anonymous is the point. Read Scope and Student privacy before adding anything.
Contents: Scope · Student privacy (FERPA) · How it works · Running it locally · Contributing · Deploying · Handing it off · Maintainers
/admin for tutors and admins, and badges for teachers or others a tutor vouches
for.| Not doing | Why |
|---|---|
| Student accounts, campus sign-in (SSO), emails | Ties posts to identifiable students — see Student privacy. Also the whole flow is "scan and type". |
| Names or student IDs on check-ins | Same. Hashing names doesn't help: with a class roster they match back in seconds. |
| Replies / comment threads | A third kind of post to report, hide, edit, delete, and badge — and then people expect notifications. Answers + upvotes + "solution" cover it. |
| Notifications (email, push, SMS) | They cost money and need contact details. |
| Private messages | Unmoderatable, and a harassment channel. |
| Video uploads, rich-text editing | Storage and moderation cost; plain text plus code blocks is enough for CS questions. |
| Analytics or visitor tracking | Beyond the check-in counts, nobody has needed it, and it collects data we'd rather not have. |
| Background jobs, cron, queues | Scheduled work (password rotation, the daily summary) runs after a page view instead. |
| Anything paid | The site must never send anyone a bill. |
If tutors have asked for something twice and it fits the above, open an issue. If it doesn't fit, the answer is probably no, and that's fine.
The one hard rule: this site must never store anything that identifies a student.
That means no names, no student (Bronco) IDs, no emails or phone numbers, no campus sign-in, no class rosters, no grades, and nothing that links a check-in or a post to a specific person — not even hashed or "just for staff".
Why. FERPA (the Family Educational Rights and Privacy Act) is the U.S. law that protects students' education records: records directly related to a student and kept by the university or by someone acting for it. "Which student came to tutoring, when, and for what class" is the kind of record that can fall under it. Such records belong in systems the university has approved, with the access controls and agreements that come with them. This site runs on personal free-tier accounts (Vercel, Neon, Discord) with no data agreement with the university, so the only safe design is not to hold that information at all. Whether some particular data would count as an education record is a question for the university, not for us — this project avoids ever having to ask it.
If you think a feature needs student-identifying data, stop. Ask the tutoring coordinator and Cal Poly Pomona's IT / information security office first. The answer will almost always be to use a system the university already runs.
| Data | What's kept | Identifies a student? |
|---|---|---|
| Posts | The text, an optional nickname, an optional photo, a random browser id, a salted hash of the IP | Not by design. Students can still type personal info — the footer asks them not to, and tutors delete it (see below). |
Browser id (qa_visitor cookie) | A random id, so people can edit their own posts and vote once | No — random, not linked to anything. |
| IP addresses | Only as a salted hash, for spam limits and "delete all from this network". Raw IPs are never stored. | No. |
| Votes, reports, recovery codes | Browser id, IP hash, report reason; recovery codes as a hash only | No. |
Rate-limit log (activity) | Action type, IP hash, browser id — deleted after 2 days | No. |
| Check-ins | Year, class, reason, first visit, time, and a short "Other" text. No browser id, no IP. | No. The "Other" box is 60 characters and staff-only, but it's free text — don't add more of those. |
| Bug tickets | The note, the page path, and a browser summary like "Chrome 128 · Windows" | No. No contact info is asked for. |
| Badge holders | A badge title, a color, an admin's note, a hash of the code | Badges are for staff and teachers. Don't create one named after a student, or put a student's name in the note. |
| Discord | Copies of post and ticket text in alerts; check-in totals only | Same as posts. |
Vercel keeps its own request logs, which include IP addresses; the app doesn't add anything to them.
Before you open a pull request, answer these in its description:
If the answer to 2 is "yes" or "maybe", the change doesn't go in.
A tutor deletes the post from /admin or the post itself. Deleting removes the post, its answers, votes,
reports, and photos for good. Hiding only takes it off the page; the text stays in the database. Also
delete the matching Discord alert if one was sent.
``` fences render as code blocks, `x` as inline code.
Everything else is plain text.XXXX-XXXX-XXXX); entering it at /recover
unlocks that post on another browser or device. Only a hash of the code is stored.uploads/<uuid>.webp), so photos can move to
another store without touching posts./admin and can close, reopen, or delete them; closed
ones are deleted after 180 days./qr: a printable poster with a QR code pointing at the site./login (linked quietly from the footer), with one box for everything: the admin
password, the tutor password, or a badge code. The header then shows ADMIN, TUTOR, or the person's
badge, and staff get a Moderation button with the number of posts waiting for them. Students never need
to sign in, so there's deliberately no sign-in button in the header.ADMIN_PASSWORD makes you an admin; signing in with the
rotating password makes you a tutor. Tutors do the day-to-day moderating. Admin-only: editing the
defaults, managing badge holders, rotating the password by hand, and deleting everything from one network
(which on campus Wi-Fi can catch bystanders). Posts written while signed in as staff are labeled
ADMIN or TUTOR./admin: an emergency read-only switch, temporary setting changes that expire on
their own, the word filter, the check-in numbers, bug tickets, and a review queue with approve / hide /
delete and bulk delete.ADMIN_PASSWORD stays valid as a break-glass key. Rotation is skipped
entirely when no Discord webhook is set, so nobody gets locked out./admin does — do that when a tutor leaves. Changing ADMIN_PASSWORD in Vercel signs admins out./login. Posts made while signed in with that code carry the badge, and the
code also lets that person edit those posts from another device. Per badge holder, an admin can allow
higher posting limits or skip the review queue. Handing out a new code keeps the badge and the posts but
signs out whoever had the old one — that's the fix if a code leaks. Badges are a label, not a power: they
can't moderate anything./checkin (poster at /qr/checkin): year, class, what they need help with, and whether it's their
first time. "Other" opens a short text box. No checkout./admin: counts for today / 7 / 30 days, breakdowns by class, reason, hour, weekday,
and year, a CSV download for any date range (opens in Excel), and a way to remove a joke entry.New posts run through a profanity filter, a link cap, and a duplicate check. Campus Wi-Fi puts many people behind one IP address, so per-IP limits are loose on purpose, and per-browser limits do the real work.
| What | Limit |
|---|---|
| Posting | 6 per browser / 10 min, 40 per IP / 10 min (deleted posts still count) |
| Photos | 100 per IP / hour, 150 MB site-wide per day (protects the free 1 GB store) |
| Votes | 50 per IP per post / hour |
| Edits | 20 per browser / 10 min |
| Wrong recovery codes | 20 per IP / 15 min |
| Failed sign-ins | 5 per IP / 15 min; past 30 site-wide / 15 min, ADMIN_PASSWORD is paused (the tutor password and badge codes still work) |
| Reports | 30 per IP / 10 min |
| Bug tickets | 3 per browser / 10 min, 30 per IP / hour |
| Check-ins | 3 per browser / 3 hours (more say "already checked in"), 300 per IP / hour |
f.u.c.k and sh1t. Tutors can add words (e.g. chegg), un-block built-in words,
and test a sentence right on the admin page.Every setting has a default and an optional temporary change that reverts on its own (1, 2, 6, 12, 24 hours, or until cleared). Tutors can only change the first six settings below, for at most 24 hours; the rest, and "until cleared", are admin-only. "Clear all temporary changes" reverts everything (for a tutor, everything they could have set); STOP EVERYTHING makes the site read-only until a tutor turns it back on.
| Setting | Default |
|---|---|
| Read-only mode | Off |
| Hold new posts for approval | Off |
| Pause photo uploads | Off |
| Profanity filter (off / censor / hold for review / reject) | Censor |
| Reports before auto-hide (different networks) | 3 |
| Discord alert for every new post | On |
| New tutor password every … days | 7 (0 turns rotation off) |
| Daily check-in summary on Discord | On |
Badge holders with "higher limits" get five times the per-browser posting allowance and skip the per-network photo cap; the site-wide daily photo budget still applies to everyone.
| Role | Service |
|---|---|
| Code | GitHub |
| Hosting | Vercel Hobby (Next.js 16, React 19) |
| Database | Neon Postgres (added from Vercel's Storage tab), via postgres.js |
| Photos | Vercel Blob |
| Alerts | Discord webhooks |
Free-tier notes: Vercel's Hobby plan is for non-commercial projects, which this is. A free Neon database sleeps when nobody is using it and wakes on the next request (your data stays). Watch the Usage tab in the Vercel dashboard.
You need Node.js 20.9 or newer, Git, and a Postgres database of your own for development.
Never develop against the production database, and never use real student data as test data. Make up your test posts. If you're a maintainer with Vercel access,
vercel env pullmay hand you the productionDATABASE_URL— replace it with your own before running anything.
Get the code. Fork the repository on GitHub, then:
git clone https://github.com/<you>/bronco-overflow.git
cd bronco-overflow
npm install
Get a database. Any recent Postgres works. Pick one:
docker run --name bronco-db -e POSTGRES_PASSWORD=dev -p 5432:5432 -d postgres:17
Your connection string is then postgres://postgres:dev@localhost:5432/postgres.Configure. Copy the example file and fill in two values:
cp .env.example .env.local
DATABASE_URL — your development database from step 2.ADMIN_PASSWORD — any long value; you'll use it to sign in as admin.Leave the rest out. Without BLOB_READ_WRITE_TOKEN, photos are saved to public/uploads/. Without a
Discord webhook, alerts are skipped. If you want to test alerts, use a webhook on your own Discord
server — never the real tutors' channel.
Run it.
npm run dev
Open http://localhost:3000. Tables are created on the first request, so there's
no migration step. Sign in at /login with your ADMIN_PASSWORD to see /admin.
id that posts already useid is what's storednode_modules/next/dist/docs/ — see AGENTS.md.CREATE TABLE IF NOT EXISTS skips a database that already exists, so a new column
also needs an ALTER TABLE ... ADD COLUMN IF NOT EXISTS line at the bottom of
src/lib/db.ts. Without it the live site breaks and your local one looks fine.deleteQuestion
for the full list.server-only, next/headers, or the database can't be pulled
into a "use client" file — the build fails with a confusing Pages Router error. Shared constants and
types live in their own module (src/lib/member-types.ts,
src/lib/settings.ts) for exactly this reason."use server" files can only export async functions. Constants go somewhere else
(src/lib/report-reasons.ts exists because of this).secrets table): the session key, the IP-hash salt, and the tutor
password. Swapping in a different database signs everyone out, resets IP-based rate limits, and
invalidates badge codes. Back it up before migrating.IMAGE_BASE_URL or
else the Blob store behind BLOB_READ_WRITE_TOKEN. To move photos, copy the files with the same paths and
point one of those at the new place. If it's not Vercel Blob, IMAGE_BASE_URL also opens the
Content-Security-Policy for that host.The goal is a board that a tutor can forget about for a month and that never sends anyone a bill. Small, boring changes are the good ones.
main in your fork (fix-empty-state, add-cs1200-tag, …). One change per pull request.npm run lint
npx tsc --noEmit
npm run build
main. In the description, say:
Every push to main deploys to production, so the maintainer merges only after trying the change.
Good first issues: fix the class list in tags.ts, improve the empty states, make the admin page nicer
on a phone.
The repository is public, so don't open a public issue for a security problem or for anything exposing personal information. Contact the maintainer privately instead.
git remote add origin https://github.com/<you>/bronco-overflow.git
git push -u origin main
DATABASE_URL. Prefer Neon's pooled connection string (the host contains
-pooler); if only POSTGRES_URL exists, copy its value into DATABASE_URL.BLOB_READ_WRITE_TOKEN. If photo uploads fail, try one while signed in as staff: the error then
says why (for example a missing token or a private store).ADMIN_PASSWORD under Settings → Environment Variables: at least 16 random characters
(/admin warns if it's shorter). This is the break-glass key; day to day, tutors use the rotating
password from Discord.DISCORD_WEBHOOK_URL. Use a channel only tutors can read — the tutor
password is posted there. To split alerts across channels, see Discord channels.main deploys automatically.https://<project>.vercel.app/qr and print the poster. The poster and Discord links use the
production domain Vercel reports (your custom domain, once you add one). Anywhere other than Vercel, set
NEXT_PUBLIC_SITE_URL.| Variable | Required | What it is |
|---|---|---|
DATABASE_URL | Yes | Postgres connection string |
ADMIN_PASSWORD | Yes | The admin (break-glass) password |
BLOB_READ_WRITE_TOKEN | In production | Vercel Blob store for photos |
DISCORD_WEBHOOK_URL | Recommended | Alerts, and the rotating tutor password (no webhook, no rotation) |
DISCORD_WEBHOOK_* | No | Per-kind alert channels — see below |
NEXT_PUBLIC_SITE_URL | Off Vercel | The site's address, for posters and links |
IMAGE_BASE_URL | No | Where photos are served from, if not the Vercel Blob store |
DB_POOL_MAX | No | Database connections per server instance (default 5) |
Changing a variable needs a redeploy.
One webhook is enough: everything goes to DISCORD_WEBHOOK_URL. To send a kind of alert to its own
channel, create a webhook there and set its variable. Anything unset (or blank) falls back to the main one.
/admin shows where each kind currently goes.
| Variable | What goes there |
|---|---|
DISCORD_WEBHOOK_POSTS | New questions and answers |
DISCORD_WEBHOOK_MODERATION | Reports, auto-hides, posts waiting for review, "board paused" |
DISCORD_WEBHOOK_PASSWORD | The new tutor password — must be a tutors-only channel |
DISCORD_WEBHOOK_CHECKINS | The daily check-in summary |
DISCORD_WEBHOOK_TICKETS | Bug reports and tickets |
The list lives in src/lib/channels.ts.
When a new admin takes over. Do it in this order; nothing here needs downtime.
.vercel.app address, so printed posters keep working. You have to own the project's team
and be a member of the target one; if their account isn't offered (a Hobby account is one person), see
If a transfer isn't possible.secrets table holds the session
key, the IP-hash salt, and the tutor password, so a fresh one signs everyone out and breaks every
badge code.uploads/…), and connect it to the
project (that sets BLOB_READ_WRITE_TOKEN). Posts store only keys, so nothing in the database changes./qr to check.ADMIN_PASSWORD: they set a new, long one in Vercel and redeploy. That signs out every admin
session — including yours./admin.DISCORD_WEBHOOK_* variables, and redeploy; then
delete the old webhooks.The new admin imports the GitHub repository into their own Vercel account and adds their own Neon database and Blob store, then copies the data over:
pg_dump --no-owner --no-acl "$OLD_DATABASE_URL" | psql "$NEW_DATABASE_URL"
Use Neon's direct connection strings here (the host without -pooler). Copying the whole database keeps
the secrets table, so badge codes keep working. Then copy the photos with the same paths, set the
environment variables, and deploy. The .vercel.app address changes, so the posters need reprinting — a
custom domain avoids that, since it can be pointed at whoever runs the site.
| Role | Who |
|---|---|
| Current admin | @suisarbre |
Update this table when the site changes hands.
NEXT_PUBLIC_SITE_URLcampusTime() from
src/lib/format.ts so people see Pomona time.member-types.ts and the class map in
src/components/MemberBadge.tsx. An unknown color falls back to green.ILIKE '%…%' and "Hot" sorts in SQL over the whole table. Fine for thousands of
questions, worth revisiting around tens of thousands.NEXT_PUBLIC_* variable — those are compiled into the browser bundle.