FalconArena - це вебплатформа для проведення командних турнірів з програмування. Вона об'єднує весь цикл турніру в одному продукті: створення турніру, реєстрацію команд, запуск раундів, подання сабмітів, оцінювання, таблицю лідерів, архів, сертифікати, комунікацію та адміністративний контроль.
Продакшн-адреса: https://falconarena.live/
Мовні версії:
- Українська:
README.md - English:
README.en.md
FalconArena побудовано як продуктову платформу для турнірів, де всі ключові сценарії зібрані в одному середовищі:
- створення турнірів і керування статусами;
- реєстрація команд і ведення учасників;
- раунди із завданнями, дедлайнами та матеріалами;
- подання сабмітів через GitHub, demo і live demo;
- призначення журі на рівні турніру, розподіл оцінювання по раундах і формування таблиці лідерів;
- архів завершених турнірів і сертифікати;
- оголошення, особисті діалоги з керуванням повідомленнями та системні сповіщення;
- публічна сторінка
Про насз описом платформи, банером, рольовими блоками, CTA, контактами і відгуками користувачів; - сучасний інтерфейс зі світлою, синьою та темною темою.
ADMINтаORGANIZERпрацюють з турнірами, раундами, користувачами, інтеграціями та операційними налаштуваннями.TEAMреєструє команду, стежить за активним раундом і подає рішення.JURYотримує призначені роботи, виставляє оцінки та працює з підсумковими результатами.
- рольова модель
ADMIN,ORGANIZER,TEAM,JURY - вхід через email/password, Google OAuth або GitHub OAuth
- публічна сторінка турніру
- раунди з описом, вимогами, дедлайнами та додатковими матеріалами
- сабміти з GitHub, demo, live demo і коротким описом
- блокування сабмітів після дедлайну
- керований пул журі для кожного турніру
- розподіл сабмітів між журі, призначеними саме до вибраного турніру
- оцінювання по категоріях
- таблиця лідерів, архів і експорт результатів
- оголошення для ролей
- особисті діалоги з можливістю видаляти окремі повідомлення або весь діалог
- системні сповіщення
- індикатори непрочитаних повідомлень
- email-сповіщення через
consoleабоresend - фонова обробка подій турніру та доставлення повідомлень
- підтримка світлої, синьої й темної теми зі збереженням вибору в браузері
- єдиний
app shellдля всіх ролей - тихі loading-state без зайвого текстового шуму
- адаптивні робочі екрани для desktop і mobile
- профіль користувача з аватаром, мовою та часовим поясом
- керування користувачами, ролями, блокуванням доступу і CSV-експортом
- призначення журі на конкретний турнір у Dashboard
- компактний інформаційний блок адміністратора із чеклистом запуску
- розклад турніру
- профіль користувача з налаштуваннями
- сторінка
Про насз керованим описом платформи, банером, контактними каналами і відгуками - сертифікати участі та переможця
- експорт у Google Sheets через webhook
- сторінка
Інтеграції / Налаштування системи - керування контентом сторінки
Про насчерезІнтеграції: hero-текст, банер, опис робочого процесу, рольові блоки, CTA, контакти і модерація відгуків - моніторинг, стрічка активності, автоматичні перевірки та технічна документація
- Frontend: React + TypeScript + Vite
- Backend: NestJS + TypeScript
- Database: PostgreSQL + Prisma
- Cache / queue-ready layer: Redis
- Infrastructure: Docker Compose + Caddy
- CI/CD: GitHub Actions
apps/
frontend/
backend/
docs/
infra/
docker-compose/
.github/
workflows/
/- landing / вхід у застосунок/app/login- вхід/app/register- реєстрація/app/about- сторінка про платформу, команду продукту, контактні канали і відгуки користувачів/app/presentation- публічна сторінка з відеопрезентацією FalconArena/app/tournaments- список турнірів/app/tournaments/:id- публічна сторінка турніру/app/teams- список команд з фільтром за турніром/app/team- кабінет команди/app/jury- кабінет журі/app/admin- admin dashboard/app/users- admin-only керування користувачами, ролями, блокуванням і скиданням пароля/app/leaderboard- leaderboard/app/archive- архів завершених турнірів/app/messages- оголошення, сповіщення, діалоги/app/profile- профіль і налаштування/app/integrations- admin-only інтеграції та системні налаштування/app/monitoring- admin-only моніторинг системи, сигнали та технічні звіти/app/certificates- printable certificate preview
TEAM- реєструється
- створює/реєструє команду
- бачить активний турнір і раунд
- подає сабміт
- читає оголошення, сповіщення, діалоги
JURY- бачить призначені роботи
- оцінює сабміти
- читає повідомлення і розклад
ADMIN- створює турніри
- змінює статуси
- створює раунди
- розподіляє оцінювання
- створює користувачів
- керує оголошеннями, архівом, сертифікатами
ORGANIZER- має доступ до більшості організаційних дій без повного admin scope
TEAM: створює акаунт через/app/register, відкриває турніри, реєструє команду і подає сабміт.ADMIN: створює турнір, переводить його вRegistration, запускає раунд і за потреби додаєJURYтаORGANIZER.JURY: працює у власному кабінеті, відкриває призначені роботи та виставляє оцінки.ADMIN: призначає журі до турніру, розподіляє оцінювання між цим пулом журі, закриває сабміти або завершує оцінювання, перевіряєLeaderboard,Archiveі сертифікати.- Будь-яка роль: використовує
Повідомленнядля оголошень, системних сповіщень та особистих діалогів. - Авторизований користувач: може залишити відгук на сторінці
Про нас;ADMINперевіряє його вІнтеграціяхперед публікацією.
- Встановіть залежності:
npm install- Запустіть локальний bootstrap:
npm run bootstrap:localЩо робить bootstrap:
- перевіряє
Node.js >= 20 - створює
infra/docker-compose/.envз.env.example, якщо файл ще не існує - автоматично генерує Prisma Client для backend
- Запустіть локальне оточення:
docker compose -f infra/docker-compose/docker-compose.yml --env-file infra/docker-compose/.env up -d --build- Відкрийте:
http://localhost- frontend через Caddyhttp://localhost/health- backend health через proxy
Базові:
POSTGRES_DBPOSTGRES_USERPOSTGRES_PASSWORDJWT_SECRETVITE_API_URLAPP_DOMAINPRISMA_SYNC_MODE
Для email-нотифікацій:
EMAIL_NOTIFICATIONS_ENABLEDEMAIL_PROVIDER-consoleабоresendEMAIL_FROMEMAIL_REPLY_TORESEND_API_KEY
Для Google Sheets:
GOOGLE_SHEETS_WEBHOOK_URLGOOGLE_SHEETS_WEBHOOK_SECRETGOOGLE_SHEETS_DEFAULT_SHEET_NAME
Для OAuth-входу:
GOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRETGOOGLE_CALLBACK_URLGITHUB_CLIENT_IDGITHUB_CLIENT_SECRETGITHUB_CALLBACK_URLFRONTEND_OAUTH_SUCCESS_URLFRONTEND_OAUTH_FAILURE_URL
У GitHub Actions secrets для GitHub OAuth client id використовується назва GH_OAUTH_CLIENT_ID, тому що префікс GITHUB_ зарезервований GitHub.
Для storage strategy:
STORAGE_PROVIDER-localабоs3STORAGE_LOCAL_DIRSTORAGE_LOCAL_PUBLIC_PREFIXSTORAGE_S3_ENDPOINTSTORAGE_S3_REGIONSTORAGE_S3_BUCKETSTORAGE_S3_ACCESS_KEY_IDSTORAGE_S3_SECRET_ACCESS_KEYSTORAGE_S3_PUBLIC_BASE_URLSTORAGE_S3_KEY_PREFIXSTORAGE_S3_FORCE_PATH_STYLE
Примітка: ці env-параметри працюють як fallback. Основні налаштування Google Sheets, email delivery, notification rules і tournament defaults також можна зберігати через /app/integrations у базі даних.
Seed admin:
SEED_ADMIN_EMAIL=admin@falconarena.live SEED_ADMIN_PASSWORD=change_me npm run prisma:seed -w @falconarena/backendКорисні команди Prisma:
npm run prisma:generate -w @falconarena/backendnpm run prisma:migrate:deploy -w @falconarena/backendnpm run prisma:migrate:dev -w @falconarena/backendnpm run prisma:migrate:resolve:init -w @falconarena/backend
Production deploy використовує PRISMA_SYNC_MODE=migrate за замовчуванням і застосовує tracked Prisma migrations під час старту backend container.
Примітка: після npm install Prisma Client також генерується автоматично через root postinstall.
POST /auth/registerPOST /auth/loginPOST /auth/admin/usersGET /auth/googleGET /auth/google/callbackGET /auth/githubGET /auth/github/callbackGET /auth/meGET /auth/admin/ping
GET /admin/usersGET /admin/users/export.csvPATCH /admin/users/:userIdPATCH /admin/users/:userId/passwordGET /profile/settingsPATCH /profile/settings
GET /dashboard/admin/metricsGET /dashboard/jury/metricsGET /dashboard/team/metricsGET /activity/mineGET /activity/admin
GET /tournamentsGET /tournaments/:idPOST /tournamentsPATCH /tournaments/:id/statusPATCH /tournaments/:id/status/overrideGET /tournaments/:id/announcementsGET /tournaments/:id/juryPATCH /tournaments/:id/juryGET /tournaments/:tournamentId/leaderboardGET /tournaments/:tournamentId/leaderboard/export.csvPOST /tournaments/:tournamentId/leaderboard/export.google-sheets
GET /teamsPOST /tournaments/:tournamentId/teams/registerGET /tournaments/:tournamentId/teamsGET /tournaments/:tournamentId/teams/me
POST /tournaments/:tournamentId/roundsGET /tournaments/:tournamentId/roundsGET /tournaments/:tournamentId/rounds/activePATCH /tournaments/:tournamentId/rounds/:roundId/statusPATCH /tournaments/:tournamentId/rounds/:roundId/status/overridePOST /rounds/:roundId/finish-evaluation
POST /rounds/:roundId/submissionsGET /rounds/:roundId/submissions/meGET /rounds/:roundId/submissions
POST /rounds/:roundId/assignments/distributeGET /rounds/:roundId/assignmentsGET /rounds/:roundId/assignments/mePOST /rounds/:roundId/assignments/:assignmentId/evaluation
GET /announcementsPOST /announcementsPATCH /announcements/:idPATCH /announcements/read-stateGET /messages/dialogsPOST /messages/dialogsGET /messages/dialogs/:idPOST /messages/dialogs/:idDELETE /messages/dialogs/:idDELETE /messages/dialogs/:id/messages/:messageIdGET /notificationsPATCH /notifications/read-state
GET /admin/system-integrations/google-sheetsPATCH /admin/system-integrations/google-sheetsPOST /admin/system-integrations/google-sheets/testGET /admin/system-integrations/emailPATCH /admin/system-integrations/emailPOST /admin/system-integrations/email/testGET /admin/system-integrations/notification-rulesPATCH /admin/system-integrations/notification-rulesGET /admin/system-integrations/platform-contentPATCH /admin/system-integrations/platform-contentPOST /admin/system-integrations/platform-content/bannerGET /admin/system-integrations/platform-reviewsPATCH /admin/system-integrations/platform-reviews/:reviewIdGET /admin/system-integrations/tournament-defaultsPATCH /admin/system-integrations/tournament-defaultsGET /platform/aboutGET /platform/about/reviewsPOST /platform/about/reviewsGET /platform/defaults
GET /healthGET /admin/healthGET /admin/error-reports
GET /tournaments/:tournamentId/archiveGET /tournaments/:tournamentId/schedulePOST /tournaments/:tournamentId/schedulePATCH /tournaments/:tournamentId/schedule/:eventIdDELETE /tournaments/:tournamentId/schedule/:eventIdGET /tournaments/:tournamentId/certificate-templatePATCH /tournaments/:tournamentId/certificate-templateGET /tournaments/:tournamentId/certificates/teams/:teamId
Backend:
BASE_URL=http://localhost:4000 ADMIN_EMAIL=admin@falconarena.live ADMIN_PASSWORD=change_me npm run smoke:mvp -w @falconarena/backendBASE_URL=http://localhost:4000 ADMIN_EMAIL=admin@falconarena.live ADMIN_PASSWORD=change_me npm run test:e2e:admin-team-jury-leaderboard -w @falconarena/backendBASE_URL=http://localhost:4000 ADMIN_EMAIL=admin@falconarena.live ADMIN_PASSWORD=change_me npm run test:e2e:archive-certificate-export -w @falconarena/backendBASE_URL=http://localhost:4000 ADMIN_EMAIL=admin@falconarena.live ADMIN_PASSWORD=change_me npm run test:e2e:finish-evaluation -w @falconarena/backendBASE_URL=http://localhost:4000 ADMIN_EMAIL=admin@falconarena.live ADMIN_PASSWORD=change_me npm run test:e2e:profile-avatar -w @falconarena/backend
Типові перевірки:
npm run lint -w @falconarena/frontendnpm run lint -w @falconarena/backendnpm test -w @falconarena/frontendnpm test -w @falconarena/backend
- Pull Request у
main: lint + test + build - Merge у
main: GitHub Actions запускає deploy - Продакшн працює через Docker Compose і Caddy
- PostgreSQL і Redis доступні тільки у внутрішній Docker мережі
- Backend uploads/storage підтримує:
localprovider через окремий persistent Docker volumes3provider для S3-compatible storage (R2 / MinIO / S3)
Основні GitHub secrets для deploy:
SSH_HOSTSSH_USERSSH_PRIVATE_KEYSSH_PORTDEPLOY_PATHGH_PULL_USERNAMEGH_PULL_TOKENPOSTGRES_DBPOSTGRES_USERPOSTGRES_PASSWORDJWT_SECRETVITE_API_URL- email secrets за потреби
docs/implementation-plan.uk.md- підсумок реалізації та поточного продуктового стануdocs/deploy-quickstart.uk.md- деплойdocs/ops-runbook.uk.md- розгортання, rollback, backup і логиdocs/backup-restore-drill.uk.md- репетиція backup / restore БД та uploadsdocs/release-checklist.uk.md- короткий чекліст перед merge / deploydocs/admin-runbook.uk.md- щоденний сценарій роботи для ADMINdocs/support-troubleshooting.uk.md- типові проблеми і їх розбірdocs/mvp-smoke-api.uk.md- API smoke-сценарій базового турнірного flowdocs/ui-smoke-runbook.uk.md- UI smoke-сценарійdocs/project-decisions.uk.md- архітектурні рішенняdocs/acceptance-checklist.uk.md- чекліст відповідностіdocs/product-overview.uk.md- короткий продуктовий огляд платформиdocs/defense-demo-script.uk.md- рекомендований сценарій презентації платформи
Поточна реалізація зроблена у прагматичному форматі через webhook:
- Створіть Google Apps Script або інший сумісний endpoint, який приймає
POSTJSON. - Або додайте
GOOGLE_SHEETS_*у env як bootstrap/fallback, або відкрийте/app/integrationsпідADMINі збережіть webhook у базі даних. - У
ЛідербордіабоАрхівінатиснітьЕкспортувати в Google Sheets.
Backend надсилає:
- metadata турніру
- scoring model
- headers
- rows
- rowObjects
- generatedAt
- exportedBy
Базові server-side команди:
cd /opt/falconarena-deploy
sh infra/scripts/backup-all.sh
sh infra/scripts/verify-backup.sh <timestamp>Окремо також доступні:
sh infra/scripts/backup-db.shsh infra/scripts/backup-storage.shsh infra/scripts/restore-db.sh backups/<backup-file>.sqlsh infra/scripts/restore-storage.sh backups/<storage-archive>.tar.gz