범서고등학교 학생 커뮤니티 플랫폼
"지혜로운 눈으로 꿈을 이루고, 따뜻한 가슴으로 인류에 봉사하자"
beomseo.in은 범서고등학교 17대 학생회 정보기술부에서 기획·개발한 학생 커뮤니티 웹 플랫폼입니다.
학생들이 학교 생활에서 필요한 정보를 한곳에서 쉽게 찾고, 서로 소통할 수 있는 공간을 만들기 위해 시작되었습니다. 학교/학생회 공지와 예산 공개 게시판 확인부터 자유 게시판, 동아리 모집, 학생 청원, 설문조사, 실시간 투표, 분실물 게시판, 교내 중고거래, 수학여행 반별 미션 게시판, 그리고 학교 생활 정보 허브 안의 스포츠리그 문자중계·팀별 라인업·개인별 순위까지 — 범서고 학생이라면 누구나 참여할 수 있습니다.
개발 철학
- 첫째도 개발의 편리함, 둘째도 학생들의 편리함 🛠️
- 복잡하게 만들지 않는다. 단순하지만 완성도 있게 ✅
| 상징 | 설명 |
|---|---|
| 🎯 교훈 | 지혜로운 눈으로 꿈을 이루고 따뜻한 가슴으로 인류에 봉사하자 |
| 🎯 목표 | 지적 능력과 고운 인성이 조화로운 인간으로 성장시킨다 |
| 🌲 교목 | 곰솔나무 — 끈기와 장수, 장대함을 상징 |
| 🌺 교화 | 모란 — 부귀와 번영, 행복을 상징 |
|
|
|
|
/notices/*는 학교/학생회 공지용NoticeCenterPage와 예산 공개용BudgetBoardPage로 분기됩니다./notices/budget진입 시 백엔드GET /api/notices/budget/settings응답의 기본 연/월로 리다이렉트됩니다.- 예산 공개는
BUDGET_BOARD_START_YEAR~BUDGET_BOARD_END_YEAR범위의 활성 회계연도만 노출합니다.
| 구분 | 기술 | 비고 |
|---|---|---|
| 언어 | Python | |
| 프레임워크 | Flask 3.1 | 앱 팩토리 패턴 (메인 API) |
| FastAPI | 스포츠리그 + 수학여행 전용 비동기 서버 | |
| ASGI 서버 | Uvicorn | FastAPI 런타임 |
| ORM | Flask-SQLAlchemy / async SQLAlchemy | Flask·FastAPI 공유 DB |
| DB | MariaDB (PyMySQL / aiomysql) | |
| 캐시 | Redis + Flask-Caching | 장애 시 NullCache fallback |
| 인증 | Flask-JWT-Extended / PyJWT | Cookie + CSRF 이중 보호 |
| 비밀번호 | bcrypt | |
| 레이트리밋 | Flask-Limiter | 사용자ID/IP 기반 |
| 푸시 알림 | firebase-admin | 급식 Web Push sender 스크립트 |
| 구분 | 기술 | 비고 |
|---|---|---|
| 라이브러리 | React 19 | |
| 번들러 | Vite 7 | |
| 라우팅 | React Router DOM 7 | lazy loading |
| HTTP | Axios | withCredentials 쿠키 인증 |
| 차트 | Recharts | |
| 폼 빌더 | react-form-builder2 | 설문 빌더 |
| 아이콘 | Lucide React | |
| XSS 방어 | DOMPurify | |
| 푸시/알림 | Firebase Web Push | 설치형 PWA 급식 알림 |
| 분석 | Cloudflare Zaraz + GA4 | 민감 키 자동 필터링 |
flowchart TB
subgraph Client["🖥️ 클라이언트"]
Browser["웹 브라우저"]
end
subgraph Frontend["⚛️ 프론트엔드 (React / Vite)"]
SPA["SPA (React Router)"]
API_Layer["API Layer (Axios)"]
Security["Security (sanitize / policy)"]
Analytics["Analytics (Zaraz)"]
end
subgraph Backend["🐍 백엔드 (Flask)"]
App["App Factory"]
Auth["인증 (JWT Cookie)"]
Routes["블루프린트 ×11"]
Models["SQLAlchemy Models"]
Utils["Utils (보안/캐시/업로드)"]
end
subgraph FastAPIServer["⚡ 실시간/이벤트/급식 서버 (FastAPI)"]
FastApp["FastAPI App"]
AsyncRoutes["비동기 라우트"]
SSE["SSE 스트리밍"]
end
subgraph Infra["🗄️ 인프라"]
MariaDB[("MariaDB")]
Redis[("Redis")]
Uploads["📁 uploads/"]
end
Browser --> SPA
SPA --> API_Layer
API_Layer -->|"HTTPS + Cookie JWT + CSRF"| App
API_Layer -->|"HTTPS + Cookie JWT + CSRF"| FastApp
App --> Auth
App --> Routes
Routes --> Models
FastApp --> AsyncRoutes
AsyncRoutes --> SSE
Models --> MariaDB
AsyncRoutes --> MariaDB
Utils --> Redis
Utils --> Uploads
SSE --> Redis
SPA --> Security
SPA --> Analytics
- 프론트 앱은
ThemeProvider → NetworkStatusProvider → PwaInstallProvider → AuthProvider순서로 전역 상태를 감쌉니다. - 인증/일반 API 요청에서 transport 계열 네트워크 실패가 발생하면
app:network-request-failed이벤트를 통해OfflineGate전체 화면 오버레이가 열립니다. - PWA 설치 UI는
beforeinstallprompt가 지원되는 브라우저와 iOS Safari 수동 설치 경로를 분리해서 처리합니다. - FastAPI 서버는 스포츠리그와 수학여행 게시판뿐 아니라 급식 조회, 급식 평점, 급식 알림 구독 API도 함께 제공합니다.
- 급식 조회 요청은 MySQL에 저장된 데이터만 읽고, 실제 NEIS 호출은 동기화 스크립트에서만 수행합니다.
[일반 요청]
사용자 클릭 → React Component → Axios (withCredentials) → Flask 라우터
→ 미들웨어(JWT 검증, CSRF, Rate Limit)
→ 블루프린트 핸들러
→ SQLAlchemy ORM → MariaDB
→ JSON 응답 → React 렌더링
[FastAPI 요청]
사용자 클릭 → React Component → fastapiApi / sportsApi (withCredentials) → FastAPI 라우터
→ JWT 쿠키 검증 (PyJWT)
→ 비동기 핸들러
→ async SQLAlchemy → MariaDB
→ JSON / SSE 스트림 응답 → React 렌더링
beomseo.in/
├── 📄 README.md ← 지금 읽고 있는 이 문서
├── 📄 LICENSE ← GNU GPL-3.0
├── 📄 TODO.md ← 개발 로드맵 & 아이디어
├── 📄 .gitignore
│
├── 🐍 backend/ ← Flask API 서버
│ ├── app.py # 앱 팩토리 + 미들웨어
│ ├── config.py # 환경별 설정 (보안/캐시/레이트리밋)
│ ├── requirements.txt
│ ├── requirements_fastapi.txt # FastAPI 전용 의존성
│ ├── .env.example
│ ├── routes/ # 11개 블루프린트 (기능별 API)
│ │ ├── auth.py # 인증/회원
│ │ ├── notices.py # 공지 + 예산 공개 설정/CRUD
│ │ ├── free.py # 자유게시판
│ │ ├── value_pick.py # 인성 가치 PICK!
│ │ ├── club_recruit.py # 동아리 모집
│ │ ├── subject_changes.py # 과목변경
│ │ ├── petitions.py # 학생 청원
│ │ ├── surveys.py # 설문 교환
│ │ ├── votes.py # 실시간 투표
│ │ ├── lost_found.py # 분실물
│ │ └── gomsol_market.py # 곰솔 마켓
│ ├── fastapi_app/ # FastAPI 실시간/급식 전용 서버
│ │ ├── main.py # 앱 팩토리, CORS, 보안 헤더
│ │ ├── config.py # Pydantic Settings (동일 .env 공유)
│ │ ├── database.py # async SQLAlchemy (aiomysql)
│ │ ├── models.py # 순수 SQLAlchemy ORM 모델
│ │ ├── schemas.py # Pydantic V2 요청/응답 스키마
│ │ ├── deps.py # JWT 쿠키 인증 + 역할 검사
│ │ ├── utils.py # sanitize, SSE 포맷터
│ │ ├── routes/ # FastAPI 라우터
│ │ │ ├── sports_league.py # 문자중계/라인업 CRUD + SSE 스트림 엔드포인트
│ │ │ ├── field_trip.py # 수학여행 반 게시판/점수판/업로드 엔드포인트
│ │ │ └── meals.py # 급식 조회/평점/알림 구독 엔드포인트
│ │ └── services/ # 비동기 도메인 로직
│ │ ├── sports_league.py # 스냅샷, 이벤트 CRUD
│ │ ├── sports_league_players.py # 선수 라인업/개인기록 CRUD
│ │ ├── sports_league_realtime.py # asyncio pub/sub
│ │ ├── sports_league_seed.py # 시드 데이터
│ │ ├── field_trip.py # 수학여행 게시판/점수판/업로드 로직
│ │ ├── meals.py # 급식 동기화/조회/평점 로직
│ │ └── meal_notifications.py # 급식 알림 구독/발송 로직
│ ├── models/ # SQLAlchemy 모델
│ ├── services/ # 도메인 서비스/실시간 보조 로직
│ ├── scripts/ # 운영용 부트스트랩 스크립트
│ │ ├── bootstrap_field_trip.py # 수학여행 기본 반/비밀번호 시드
│ │ ├── sync_school_meals.py # NEIS 급식 동기화
│ │ ├── send_school_meal_notifications.py # Firebase 급식 알림 발송
│ │ └── migrate_notice_budget_board.py # 기존 notices 스키마에 예산 공개 컬럼/인덱스 추가
│ ├── utils/ # 보안·캐시·업로드 유틸
│ ├── uploads/ # 파일 업로드 저장소
│ └── docs/ # 백엔드 문서
│
└── ⚛️ frontend/ ← React SPA
├── index.html
├── package.json
├── vite.config.js
├── .env.example
├── src/
│ ├── App.jsx # 라우터 + Provider
│ ├── main.jsx # 엔트리포인트
│ ├── api/ # Axios 기반 API 모듈 + FastAPI/급식 알림 클라이언트
│ ├── components/ # 재사용 컴포넌트 (70개)
│ ├── features/ # 기능 단위 hook/data/utils 묶음
│ ├── pages/ # 페이지 컴포넌트 (45개)
│ ├── context/ # Auth/Theme/NetworkStatus/PWA 컨텍스트
│ ├── pwa/ # 설치/푸시 알림/오프라인 유틸
│ ├── security/ # URL/HTML/CSV sanitize
│ ├── analytics/ # Zaraz 이벤트 래퍼
│ ├── layout/ # AppLayout
│ ├── config/ # 환경 설정
│ ├── styles/ # 글로벌 스타일
│ └── utils/ # 유틸리티
└── docs/ # 프론트엔드 문서
| 도구 | 최소 버전 | 용도 |
|---|---|---|
| Python | 3.10+ | 백엔드 런타임 |
| Node.js | 20+ | 프론트엔드 런타임 |
| npm | 10+ | 패키지 관리 |
| MariaDB | 10.6+ | 데이터베이스 |
| Redis | 7.0+ | 캐시 & 레이트리밋 (선택사항) |
git clone https://github.com/hanjm-github/beomseo.in.git
cd beomseo.incd backend
# 가상환경 생성 & 활성화
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate
# 의존성 설치
pip install -r requirements.txt
# 환경 변수 준비
copy .env.example .env # Windows
cp .env.example .env # macOS / Linux
# .env 파일을 열어 DB 접속 정보, JWT_SECRET_KEY,
# BUDGET_BOARD_START_YEAR / BUDGET_BOARD_END_YEAR 등을 수정합니다
# 기존 notices 테이블을 이미 사용 중인 환경이라면 예산 공개 확장 스키마를 먼저 반영합니다
python scripts/migrate_notice_budget_board.py
# 서버 실행
python app.py💡 기본 개발 서버:
http://127.0.0.1:5000
cd backend
pip install -r requirements_fastapi.txt
python -m uvicorn fastapi_app.main:app --host 127.0.0.1 --port 8000 --reload💡 FastAPI 서버:
http://127.0.0.1:8000(Swagger:/docs) 스포츠리그 문자중계와 수학여행 게시판 API를 함께 제공합니다.
cd frontend
# 의존성 설치
npm install
# 환경 변수 준비
copy .env.example .env # Windows
cp .env.example .env # macOS / Linux
# 개발 서버 실행
npm run dev💡 기본 개발 서버:
http://localhost:5173
# 백엔드 헬스체크
curl http://127.0.0.1:5000/api/health
# 프론트엔드
# 브라우저에서 http://localhost:5173 접속cd frontend
npm run build # dist/ 디렉터리에 빌드 파일 생성
npm run preview # 빌드된 결과물 미리보기이 프로젝트에는 백엔드와 프론트엔드 각각의 상세 문서가 포함되어 있습니다.
| 문서 | 설명 |
|---|---|
| backend/README.md | 백엔드 종합 가이드 |
| backend/docs/backend_api.md | API 레퍼런스 |
| backend/docs/backend_architecture.md | 아키텍처 문서 |
| backend/docs/fastapi_deployment.md | FastAPI 스포츠리그/수학여행/급식 서버 배포 가이드 |
| backend/docs/school_meals.md | 급식 조회 + PWA 급식 알림 문서 |
| 문서 | 설명 |
|---|---|
| frontend/README.md | 프론트엔드 종합 가이드 |
| frontend/docs/frontend-code-map.md | 코드 맵 |
| frontend/docs/frontend-architecture.md | 아키텍처 문서 |
| frontend/docs/frontend-api-reference.md | API 참조 |
| frontend/docs/analytics-tracking.md | 분석 트래킹 스펙 |
| frontend/docs/team-checklist.md | 팀 체크리스트 |
| 문서 | 설명 |
|---|---|
| TODO.md | 개발 로드맵 & 아이디어 |
| LICENSE | GNU GPL-3.0 라이선스 |
이 프로젝트는 GNU General Public License v3.0 하에 배포됩니다.
beomseo.in
Copyright (C) 2026 범서고등학교 17대 학생회 정보기술부
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
🌲 곰솔나무처럼 끈기 있게, 모란처럼 아름답게 🌺
범서고등학교 17대 학생회 정보기술부가 만들었습니다.
