ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
학생들을 위한 6대 연간 공모전 및 이벤트 접수 포털. 간편하게 학년, 반, 번호로 가입 후 키링 공모전, 안전사고 예방 컷툰, 디지털 필사 등 다양한 대회에 응모해보세요.
Translation pending
EducationJavaScript · CSSGitHub @moodoocodingOnlineOwner 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.
🎨 SORO | 학생 연간 이벤트 공모전 포털 (Students Annual Contest Portal) 상상력을 현실로! SORO는 학생들을 위해 매달 새롭게 열리는 6대 연간 창의 공모전 및 이벤트 접수 포털입니다. 복잡한 프레임워크나 빌드 과정 없이 HTML5, Vanilla JavaScript, CSS3 로만 만들어졌고, 백엔드는 Firebase(인증·Firestore·Storage)를 씁니다. 처음에는 Google Sheets + Apps Script 로 만들었지만, 한 학급이 동시에 접속하면 로그인에 1분 넘게 걸리는 문제가 있었습니다. Apps Script 가 소유자 계정에서 요청을 하나씩 처리하기 때문이며, 코드 최적화로는 넘을 수 없는 한계였습니다(실측: 25명 동시 접속 시 최악 64초). 2026년 8월 Firebase 로 옮겼습니다.Read the full README ↗
상상력을 현실로!
SORO는 학생들을 위해 매달 새롭게 열리는 6대 연간 창의 공모전 및 이벤트 접수 포털입니다.
복잡한 프레임워크나 빌드 과정 없이 HTML5, Vanilla JavaScript, CSS3 로만 만들어졌고, 백엔드는 Firebase(인증·Firestore·Storage)를 씁니다.처음에는 Google Sheets + Apps Script 로 만들었지만, 한 학급이 동시에 접속하면 로그인에 1분 넘게 걸리는 문제가 있었습니다. Apps Script 가 소유자 계정에서 요청을 하나씩 처리하기 때문이며, 코드 최적화로는 넘을 수 없는 한계였습니다(실측: 25명 동시 접속 시 최악 64초). 2026년 8월 Firebase 로 옮겼습니다.
Radial Gradient Hover)이 적용되어 있습니다.각 공모전의 접수 상태는 관리자가 직접 열고 닫습니다. 날짜로 자동 개폐하지 않는 것은 의도된 운영 방식입니다 — 자동으로 열리고 닫히면 실제 운영에서 여러 문제가 있었습니다.
| 공모전 | ID | 내용 |
|---|---|---|
| 키링 공모전 🎨 | keyring | 아크릴 키링 도안 이미지 |
| 안전 사고 예방 컷툰 📖 | cuttoon | 4컷 만화 원고 |
| 온라인 도서관 📚 | library | 책 제목·저자와 독서 엽서(캘리그라피) |
| 디지털 필사 ✍️ | transcription | 손글씨 이미지 또는 직접 타이핑 |
| 픽셀아트 👾 | pixelart | 도트 그래픽 (내장 에디터 제공) |
| 소로 사운드 앨범 🎵 | sound_album | 음원 업로드 |
| Zep quiz 🕹️ | zepquiz_1~_6 | 회차제. 잠금이 아니라 "접수 중인 회차" 하나로 관리합니다 |
젭퀴즈만 구조가 다릅니다. 다른 공모전은 contest_lock_<ID> 로 열고 닫지만, 젭퀴즈는 zepquiz_active_round 에 적힌 회차 하나만 접수를 받습니다. 전부 닫으려면 존재하지 않는 회차인 0 을 지정합니다(관리자 화면의 🔒 젭퀴즈 잠금 버튼).
?backend=sheets 를 붙이면 예전 Apps Script 백엔드로 그 탭에서만 전환됩니다. 이전 직후 문제가 생겼을 때를 대비해 남겨 둔 길이며, 평소에 쓸 일은 없습니다.migration/firestore.rules)이 직접 막습니다.| 구분 | 기술 스택 | 설명 |
|---|---|---|
| Frontend | HTML5, Vanilla JavaScript (ES6+) | 빌드/컴파일 과정 없이 브라우저에서 직접 초고속 실행되는 경량 구조 |
| Styling | Pure Vanilla CSS3 | CSS 변수(Custom Properties), Flexbox/Grid 레이아웃, 모던 트랜지션 |
| 인증 | Firebase Authentication | 학생 계정. 이메일은 학년/반/번호/이름을 해시한 @soro.local 주소를 씁니다 |
| 데이터베이스 | Cloud Firestore | 계정 프로필, 제출물, 감상 반응, 공모전 설정 |
| 파일 저장소 | Firebase Storage | 학생 작품 이미지·음원. 문서에는 주소만 저장합니다 |
| 초기화 API | Vercel Functions + Firebase Admin SDK | 학생이 직접 요청하면 즉시 비밀번호 초기화 |
| Hosting | Vercel Ready | 정적 라우팅 및 리소스 브라우저 캐싱 구조 설계 최적화 |
soro/
├── index.html # 레이아웃, 모달·드로어 마크업, Firebase 모듈 로더
├── style.css # 노이즈 텍스처, 테마, 드로어 모션
├── app.js # 화면 로직 + 공모전 데이터셋
│ # ※ 파일 뒷부분에 Apps Script 백엔드 코드가
│ # 주석으로 들어 있습니다. 고친 뒤에는 반드시
│ # script.google.com 에 붙여넣고 재배포해야
│ # 실제로 반영됩니다.
├── firebase-backend.js # Firestore·Auth·Storage 를 다루는 백엔드 (ES 모듈)
├── api/reset-password.mjs # 학생용 비밀번호 초기화 HTTP 진입점
├── server/ # Firebase 관리자 인증·초기화 처리 (서버 전용)
├── tests/ # 실제 학생 계정을 건드리지 않는 자동 검사
├── package.json # Firebase Admin SDK 의존성과 검사 명령
├── migration/ # Sheets → Firebase 이전 도구와 보안 규칙
│ ├── firestore.rules # 데이터 접근 규칙 (권한의 실제 방어선)
│ ├── storage.rules # 작품 파일 접근 규칙
│ ├── DESIGN.md # 이전 설계와 판단 근거
│ └── *.mjs # 내보내기·변환·적재·검증 스크립트
├── 작업내역.md # 모든 변경 기록. 무엇을 왜 고쳤는지 남겨 둡니다
├── vercel.json # 정적 파일 캐시·경로 설정
└── README.md # 이 문서
현재 기본 Firebase 모드의 비밀번호 초기화에서는 이 코드를 사용하지 않습니다. 아래 내용은 ?backend=sheets로 이전 시스템을 사용하는 경우에만 해당합니다.
app.js 파일 뒤쪽에 주석으로 들어 있는 Apps Script 코드는 문서용 사본입니다. 여기를 고치고 배포해도 실제 서버 동작은 그대로입니다. 반드시 구글 시트 → 확장 프로그램 → Apps Script 에 붙여넣고, 배포 → 배포 관리 → 편집(연필) → 새 버전 → 배포 를 해야 반영됩니다.
⚠️ "새 배포" 가 아니라 기존 배포의 "새 버전" 이어야 합니다. 새 배포를 만들면 주소가 바뀌어 사이트가 백엔드를 찾지 못합니다.
users/{uid} 문서의 admin 이 true(boolean) 여야 관리자로 인정됩니다. 학번을 비교하던 예전 방식은 브라우저에서 조작할 수 있어 바꿨습니다.
보안 규칙이 "본인이 자기 문서에 admin 을 붙이는 것" 을 막습니다. 학생이 스스로 관리자가 되는 걸 막는 장치인데, 선생님에게도 똑같이 적용됩니다. 그래서 처음 한 번은 Firebase 콘솔에서 직접 넣어야 합니다(Firestore → users → 해당 문서 → 필드 추가 → admin / boolean / true). 넣은 뒤 로그아웃 후 다시 로그인해야 반영됩니다 — 관리자 토큰은 로그인할 때 발급됩니다.
data에 저장됩니다관리자 화면에서 설정한 사은품 지급 상태와 심사 후보 별표는 Firestore submissions/{submissionId} 문서의 data.prizeStatus / data.isStarred에 영구 저장됩니다. 2026년 9월 4일 이전 코드가 문서 최상위에 잘못 저장한 prizeStatus / isStarred도 호환 읽기로 복원됩니다. 해당 항목을 다시 누르면 올바른 data 안으로 저장되고 잘못된 최상위 필드는 자동으로 제거됩니다.
학생이 학년/반/번호/이름을 입력하면 Vercel의 /api/reset-password가 Firebase에서 계정을 찾아 즉시 임시 비밀번호를 발급합니다. 그 비밀번호로 로그인하면 새 비밀번호를 직접 정합니다. 선생님은 학생별 요청을 승인하거나 처리할 필요가 없습니다.
_passwordResetLimits에 트랜잭션으로 기록하고, 초기화 이력은 기존 passwordResets에 남깁니다. Firestore의 기존 기본 차단 규칙을 그대로 사용합니다.학적 정보만으로 초기화하는 운영 방식은 유지됩니다. 이 정보를 아는 사람도 요청할 수 있으므로, 무작위 임시 비밀번호가 별도의 본인 인증을 대신하지는 않습니다.
soro-migration-test의 서비스 계정 JSON 키를 준비합니다. 해당 계정에는 Firebase Authentication 사용자 변경과 Firestore 읽기·쓰기 권한이 필요합니다.FIREBASE_SERVICE_ACCOUNT_JSON이라는 Secret에 JSON 전체를 넣습니다. 운영은 Production에 설정합니다. 운영 키를 시험용 다른 프로젝트에 넣지 않습니다.서비스 계정 키는 브라우저 파일·GitHub·채팅에 붙이지 않습니다. .env.example에는 변수 이름만 있으며 .env*와 서비스 계정 파일은 Git에서 제외했습니다. 키를 바꾸면 Vercel 재배포가 필요합니다.
로컬 검사는 Node.js 24에서 npm ci 후 npm test로 실행합니다. 실제 계정 초기화는 하지 않습니다. Python/Live Server 같은 정적 서버는 /api를 실행할 수 없으므로 API 동작 확인에는 Vercel 배포나 vercel dev가 필요합니다.
그림과 음원은 Firebase Storage 에 올리고, Firestore 문서에는 주소만 저장합니다. 경로는 submissions/<공모전ID>/<학생uid>/<항목>.<확장자> 로 고정되어 있어 다시 제출하면 같은 자리를 덮어씁니다.
이전 초기에는 이 단계가 빠져 base64 를 문서에 통째로 넣었고, 엽서 한 장(0.89~1.13MB)이 Firestore 문서 한도(1MiB)를 넘어 저장이 통째로 실패했습니다. 게다가 오류 문구가 "현재 접수 기간이 아닌 공모전입니다" 로 나와 학생은 원인을 알 수 없었습니다. 지금은 실패 원인을 구분해 알리고, 파일 업로드가 실패하면 저장을 진행하지 않습니다.
asset/backgrounds/)온라인 도서관의 엽서 배경입니다. 학생이 테마를 고르면 그 안에서 무작위로 한 장이 뽑히고, 그릴 때마다 색감이 다르게 입혀집니다.
새 배경을 추가할 때: 4:3 가로, 1200×900 이상. 엽서 캔버스가 800×600이라 세로 사진을 넣으면 가운데만 잘려 보입니다.
파일을 넣은 뒤 app.js 의 CALLIGRAPHY_THEMES_IMAGES 목록에 경로를 추가해야 실제로 쓰입니다.
⚠️ 파일 이름의 앞부분은 테마를 뜻하지 않습니다. 테마가 잘못 붙어 있던 사진들을 맞는 테마로 옮겼기 때문에, 예를 들어
forest목록에sky_1.jpg(잎사귀 사진)가 들어 있습니다. 이름을 바꾸면 변경 기록을 따라가기 어려워져 그대로 두었습니다.
⚠️ 목록에 없는 파일도 폴더에는 남아 있습니다. 중복이거나 테마와 무관한 사진(게임 컨트롤러, 서류가방 든 사람 등)을 목록에서만 뺐습니다. 지우지 않은 것은 나중에 판단이 바뀔 수 있어서입니다.
배경 종류: 2026년 9월 기준 하늘·숲·바다·공간·종이/추상 테마별로 30장씩, 총 150장입니다. 같은 사진이 뽑혀도 결과가 서로 달라 보이도록 그릴 때마다 색조·채도·밝기를 조금씩 바꾸고, 여섯 가지 색감 중 하나를 덧입히고, 절반은 좌우를 뒤집고, 가장자리 어둡기를 무작위로 줍니다.
index.html 의 ?v= 값을 올려야 브라우저가 새 파일을 받습니다. 관리자 화면을 열어 둔 채 배포하면 옛 코드가 계속 돌므로, 강력 새로고침(윈도우 Ctrl+Shift+R, 맥 Cmd+Shift+R)이 필요합니다.
이 저장소를 로컬 컴퓨터로 복제(Clone)하거나 다운로드한 후, 브라우저에서 직접 실행할 수 있습니다.
# 1. 저장소 클론
git clone <repository-url>
# 2. 프로젝트 폴더 진입
cd soro
# 3. 로컬 서버 실행 (또는 index.html 더블클릭)
# VS Code를 사용하신다면 'Live Server' 확장 프로그램 실행을 권장합니다.
본 프로젝트는 vercel.json 파일이 사전 최적화되어 있으므로 별도의 빌드 커맨드 설정 없이 즉시 배포할 수 있습니다.
.vercel.app 고유 주소가 생성됩니다!