ESP32-S3 Bench Guide
ESP32‑S3 N16R8 벤치 가이드: 실시간 핀아웃, 강의, 시뮬레이터 및 벤치 로그
투자 위험을 교실에서 시뮬레이션, 학생들이 스마트폰으로 안전·위험 자산에 재산을 배분하고 프로젝터에 시장이 결산
A classroom simulation of investment risk, for finance and economics courses. Students divide their wealth between a safe and a risky asset from their phones, the market resolves on the projector, and
교육TypeScript · PLpgSQLGitHub @Water6446온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Finance simulation built for in class learning with students
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A live, in-class simulation where a professor hosts a session and students join
from their phones/laptops to split their wealth between a safe and a
risky asset each round. Built on Next.js (App Router) + TypeScript,
Supabase (Postgres / Auth / Realtime), Tailwind, Recharts, and
qrcode.react. Replaces a manual spreadsheet.
Security is a first-class requirement. The threat model is a curious CS
student with browser dev tools and the public anon key. See
Security model and the hardening checklist.README 전문 보기 ↗A live, in-class simulation where a professor hosts a session and students join
from their phones/laptops to split their wealth between a safe and a
risky asset each round. Built on Next.js (App Router) + TypeScript,
Supabase (Postgres / Auth / Realtime), Tailwind, Recharts, and
qrcode.react. Replaces a manual spreadsheet.
Security is a first-class requirement. The threat model is a curious CS student with browser dev tools and the public anon key. See Security model and the hardening checklist.
Three games share one engine — lobby, rounds, lock/reveal, leaderboard, present mode and CSV export. Hosts have accounts (a dashboard of past and live sessions); students join anonymously with a code or QR and may optionally keep their results in an account.
| Doc | What's in it |
|---|---|
| DESIGN.md | The "Academy Arcade" design system every screen follows |
| MECHANICS.md | How every game number works (luck, Sharpe, returns, ρ, fees, the index fund) |
| docs/DEPLOYMENT.md | Supabase CLI workflow, dashboard setup, the launch checklist |
| docs/ACCOUNTS.md | How accounts work, the security rules behind them, hosting limits |
| CLAUDE.md | Working notes for AI-assisted changes (read before editing) |
| Basic | Portfolio | Manager | |
|---|---|---|---|
| Risky side | one risky bet | N risky assets | 5 fund managers + an index fund |
| Outcome | good / bad | good / bad per asset | continuous normal returns |
| Round = | a round | a round | a year (25 by default) |
| Extra | — | correlation ρ | fees, leverage to 2×, a secret alpha |
The manager game teaches active vs. passive: skill is real but tiny and statistically invisible over a career, fees compound against you regardless, and a 0.05% index fund is always on the menu as the passive alternative. Its maths, the fee order of operations and the secrecy model are in MECHANICS.md § Manager game.
$100).25).safe = current − risky.p = 0.6) or Bad.new = safe + risky·(1.1|0.9)new = safe + risky·(2|0)market_mode = auto|manual,
market_scope = shared|independent (manual implies shared).Worked examples (all verified by tests, in both TS and SQL):
| mode | wealth | risky | outcome | result |
|---|---|---|---|---|
| moderate | 100 | 50 | good | 105 |
| moderate | 100 | 50 | bad | 95 |
| extreme | 100 | 50 | good | 150 |
| extreme | 100 | 50 | bad | 50 |
app/ Next.js routes: / (marketing), /host, /join, /play,
/login, /account, /auth, /privacy, /terms
components/ UI — ui.tsx primitives, icons.tsx, and one folder per
surface (host/, student/, account/, auth/, marketing/)
lib/game/ Pure, unit-tested game maths — the TypeScript mirror of
the SQL (types, math, portfolio, manager, results, format)
lib/auth/ Who may host, sign-in validation, open-redirect guard
supabase/migrations/ SQL migrations, applied in order (`npm run db:push`)
0001–0005 Schema, RLS + grants + Realtime, host RPCs + round loop,
delete_session, submit_allocation
0006–0013 Market odds, bots, the portfolio game, correlation
0008 TEMPORARY testing bypass: guests may host (see CLAUDE.md)
0014–0015 The manager game (session_secrets holds the true alpha:
RLS on, NO policies, NO grants — deny-all)
0016–0025 The account layer (see docs/ACCOUNTS.md)
0026 The manager game's index fund
0027–0030 Security fixes: throttle counts up front, player names +
host moderation, hidden odds in session_secrets,
helper grants + size limits
scripts/
db-selftest.mjs `npm run test:db` — applies every migration to a
throwaway in-process Postgres and runs both suites below
db_selftest.sql The game: security model + wealth math + manager secrecy
accounts_selftest.sql The account layer
_supabase_mock.sql Local stand-in for Supabase's auth surface (test only)
security-check.ts `npm run security-check` — the same denials, live
Copy .env.example to .env.local and fill in. The comments there explain
each one.
| var | exposure | purpose |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL | public | Supabase project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY | public | publishable key (safe; protected by RLS) |
NEXT_PUBLIC_SITE_URL | public | canonical URL for join link/QR, auth redirects, metadata; Production only (https://www.sharpesim.com) |
NEXT_PUBLIC_ALLOW_ANON_HOST | public | the testing bypass; on until launch |
NEXT_PUBLIC_EMAIL_DELIVERY | public | show email-dependent flows; off until custom SMTP |
USERNAME_LOOKUP_SECRET | server only | enables username sign-in; unset = email only |
SUPABASE_SERVICE_ROLE_KEY | server only | not used by the app; only the live security check |
The service_role key is never shipped to the client and is not needed to run the app — every privileged action is a host-only RPC.
npm run db:push).npm install
npm run dev # Next.js dev server on http://localhost:3000
npm run test # game-maths unit tests (Vitest)
npm run test:db # the database self-tests (no Docker, no cloud)
npm run test:db builds a throwaway Postgres in-process (PGlite), applies a
tiny mock of Supabase's auth.uid() / role surface plus every migration,
and runs two suites as attacker identities — aborting on any failure. Run one
with npm run test:db -- game or -- accounts. Among what they prove:
current_wealth, write
any allocation directly, or put more than their wealth at risk (the submit
RPC clamps it);sessions.config leaks no alpha, beta or
tracking_error; a student cannot read session_secrets or call
get_manager_truth before the game finishes; the leverage cap is enforced
server-side; the index fund stays out of the skill shuffle and tracks the
market exactly, less its fee;profiles, quotas and the player
cap hold, guest purges sever rather than delete results, username lookup
fails closed, the login throttle locks.While the testing bypass is live the game suite also prints a NOTE: that a
guest can host — a reminder, not a failure.
NEXT_PUBLIC_* variables above (and USERNAME_LOOKUP_SECRET if you
want username sign-in) as Vercel env vars. Do not set the service_role
key in Vercel.student-game-5.vercel.app both redirect there). Set it as the Supabase
Auth → URL Configuration Site URL, with https://www.sharpesim.com/** in
the redirect URLs, so Google and email sign-in return to your app.The full pre-class launch checklist — including closing the testing bypass — dashboard steps, smoke test and rollback plan live in docs/DEPLOYMENT.md.
anon/authenticated roles, so every direct query is subject to policy.resolve_round, a SECURITY DEFINER
function that asserts the caller is the session's host, refuses unless the
round is locked, and is the only writer of players.current_wealth.submit_allocation (and its
portfolio/manager siblings): SECURITY DEFINER RPCs that tie the row to
auth.uid(), accept only while the round is open, validate the amounts
(the basic game clamps 0 ≤ risky ≤ wealth; the manager game rejects anything
past the leverage cap) and derive safe server-side. Students hold no direct
insert/update grant on allocations at all (players: display_name only).0008 plus
NEXT_PUBLIC_ALLOW_ANON_HOST; both are reverted at launch
(docs/DEPLOYMENT.md Part C.1).0024) —
Supabase grants every new function to anon directly, so this is enforced
explicitly and asserted by the self-test.get_my_rank() (returns rank + total, never the list).session_secrets, readable
only through get_manager_truth() (the host any time, students once the game
finishes).supabase_realtime publication (done by 0002_rls.sql).npm run test:db passes, and npm run security-check against the live
project.