Board access guard, tag page real impl, rankings PHP-parity, freespin, more admin

Board access (mirrors gnuboard bo_read/write/comment_level):
- legacy-board.ts: getBoardMeta now returns readLevel/writeLevel/commentLevel/useSecret/useCert
- checkBoardAccess(meta, userLevel, action) helper used on:
  /[boardSlug] (read), /[boardSlug]/[wrId] (read), /[boardSlug]/write (write)
- Insufficient level → friendly lock screen with "필요 Lv.X" + login redirect for anon

Tag indexing (real):
- /tag/[tag]: pulls from inspection2.g5_eyoom_tag_write (cached subject/hit/datetime)
- ILIKE wr_tag, paginated 20 per page, total count in header
- highlights matched tag; lists other tags on each post

Rankings PHP-parity (lib/member.rank.lib.php):
- NOT IN ('admin','admin2','admin3','admin4','roy')
- mb_point > 0 AND mb_level < 11
- LEFT JOIN g5_eyoom_member.level (이윰 레벨)
- ORDER BY mb_point DESC
- Both sidebar getMemberRankings and home TopWinners switched
- Visible result: 보내드림 1.66M / 코뚜롱 1.48M / 스티브박 1.40M (admin* hidden)

Freespin (game engine):
- inspection2.app_freespin (mb_id, slug, remaining)
- Scatter ≥3 grants 5-10 free spins
- Next spin uses bet=0; remaining-- recorded transactionally
- placeBetAndSpin returns freeSpinsRemaining

Admin write:
- /admin/plugin/recaptcha (saved into public.app_settings)
- /admin/roulette (g5_roulette_list rename/delete + reward list)
- /admin/lottery/winners (lottery_history, paginated 50)

Verify: 50 iter × 16 = 800/800 PASS

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
chpark
2026-04-28 21:05:20 +09:00
parent 782029d31f
commit 505398ec9f
11 changed files with 521 additions and 42 deletions
+2 -2
View File
@@ -84,9 +84,9 @@ async function iteration(i) {
const r = await fetchOk(REACT + '/');
return r.status === 200 || r.status === 308;
});
await check('[REACT] GET /free (board 200)', async () => {
await check('[REACT] GET /free (board 200/307/308 — read-level guard OK)', async () => {
const r = await fetchOk(REACT + '/free');
return r.status === 200 || r.status === 308;
return r.status === 200 || r.status === 307 || r.status === 308;
});
await check('[REACT] POST /api/auth/login as testlogin', async () => {
const r = await fetchOk(REACT + '/api/auth/login', {