ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
Next.js 16 app serving two things at www.pgd-velikomlacevo.si:
1. Gasilski kviz (public) – practice quizzes and literature for pionirji, mladinci and pripravniki.
2. Inventar (/inventar, private) – equipment lending records, replacing the paper textbook.
The quiz works with no environment variables. /inventar needs AUTH_SECRET,
AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET, ALLOWED_EMAILS and DATABASE_URL.
drizzle-kit and tsx do not read .env.local the way Next.js does, so
drizzle.config.ts and db/seed.ts load it explicitly - the db:* scripts work with no
extra setup.檢視完整 README ↗Next.js 16 app serving two things at www.pgd-velikomlacevo.si:
/inventar, private) – equipment lending records, replacing the paper textbook.npm install
cp .env.example .env.local # or: vercel env pull .env.local
npm run dev # http://localhost:3000
The quiz works with no environment variables. /inventar needs AUTH_SECRET,
AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET, ALLOWED_EMAILS and DATABASE_URL.
npm run db:migrate # apply migrations (uses DATABASE_URL_UNPOOLED)
npm run db:seed # insert the starting equipment; idempotent
npm test # 104 unit tests
npm run typecheck
drizzle-kit and tsx do not read .env.local the way Next.js does, so
drizzle.config.ts and db/seed.ts load it explicitly - the db:* scripts work with no
extra setup.
Neon project aged-river-74703807 has two branches. A branch is a copy-on-write clone,
not a second database kept in sync by hand: dev started as a copy of main and stores
only what has changed since.
| Branch | Endpoint | Used by |
|---|---|---|
main | ep-cool-leaf-… | Vercel Production only. The brigade's data. |
dev | ep-mute-unit-… | Local .env.local, Vercel Preview + Development |
Nothing you run locally - npm run dev, db:migrate, db:seed, npm test - can reach
production. db:seed prints the endpoint it is about to write to before writing.
tests/db-integration.test.ts creates and deletes rows, so it reads TEST_DATABASE_URL
and never DATABASE_URL; leave it unset and the suite skips instead of writing to
whatever DATABASE_URL happens to be. It creates its own [TEST]-prefixed equipment
rather than depending on seed data, so renaming equipment in the UI cannot break it.
To refresh dev with current production data, delete and recreate the branch:
npx neon branches delete dev --project-id aged-river-74703807
npx neon branches create --project-id aged-river-74703807 --name dev --parent main
The problem it solves is double-promising: the brigade has 2 fridges, and more than
once both were promised to different people for the same date. That is a future
conflict, so every lend-out is a date-range reservation (from–to, both days
inclusive) rather than a current in/out flag.
Availability is total − peak concurrent usage, not total − sum of overlapping loans. Summing is too conservative and would refuse valid requests: with 30 tables,
one loan holding 20 on Sep 1–3 and another holding 20 on Sep 5–7, a request for 10 tables
across Sep 1–7 is genuinely satisfiable — every day has at least 10 free — but the sum is
40 > 30. The engine lives in lib/inventory/availability.ts; it is pure and unit tested,
including that exact case.
Writes are serialised. Checking availability and then inserting is a lost-update: two
powerusers can both pass the check and both insert, recreating the bug in software. The
invariant ("no item is over-committed on any day") is an aggregate over a date range, so
it cannot be a UNIQUE, CHECK, or EXCLUDE constraint. Instead every booking write
runs in one interactive transaction that starts with pg_advisory_xact_lock
(lib/inventory/mutations.ts). Lifecycle transitions use compare-and-swap instead, so a
double-click performs exactly one transition.
Two database drivers, on purpose. Reads use neon-http (stateless, nothing to leak).
Writes use neon-serverless with a per-request WebSocket Pool that is always closed,
because the HTTP driver cannot do interactive transactions and a module-scope WebSocket
pool leaks connections in serverless.
Dates are 'YYYY-MM-DD' strings compared lexicographically, and "today" comes from
the Ljubljana wall clock (lib/dates.ts). Vercel functions run in UTC, so
new Date().toISOString().slice(0,10) would make the evening "Zamuja" list a day stale.
Authorization is requireActor() inside every Server Action, not proxy.ts. Server
Actions are addressable POST endpoints; middleware is routing. The allowlist fails closed:
an empty ALLOWED_EMAILS admits nobody.
app/ routes; app/inventar/** is auth-gated
[kategorija]/kviz/ one dynamic route replacing three duplicate quiz views
components/ quiz/, literatura/, inventar/
lib/quiz/ questions.ts is pure; data.server.ts holds the JSON imports
lib/inventory/ availability.ts + transitions.ts are pure; queries/mutations are server-only
db/ schema, client (reads), tx (writes), seed
data/*.json question banks - stays out of public/, it contains the answers
public/images|literatura assets served by the CDN
tests/ Vitest, node environment, pure modules only
lib/quiz/data.server.ts and the inventory query/mutation modules use
import 'server-only', which turns an accidental client import into a build error. That
throws outside an RSC environment, which is why the pure logic sits in separate files that
tests can import.
correctAnswer to the browser. That is inherent to a self-check quiz
with no backend grading, and was true of the previous version too.data/prva_pomoc.json has one question ("Kako se imenuje preveza na sliki?") whose two
wrong answers are the same string, so it renders with 2 options instead of 3. The
generator de-duplicates; adding a second distinct distractor would restore 3 options.vescine, oznake and prva_pomoc have no pripravnik-tagged questions, so the
pripravniki quiz reads its pools as ['pripravnik', 'mladinec']
(lib/quiz/config.ts). Tagging those questions for pripravnik in the data would make
the union unnecessary.