System Status

Orchestrator: {{ (status.status || 'unknown').toUpperCase() }} Interval: {{ status.interval }}s
BrowserMgr active {{ status.browser_metrics.active_sessions }}/{{ status.browser_metrics.max_concurrency }} runs {{ formatNumber(status.browser_metrics.runs_total || 0) }} ok {{ formatNumber(status.browser_metrics.success_total || 0) }} err {{ formatNumber(status.browser_metrics.errors_total || 0) }} retry {{ formatNumber(status.browser_metrics.retries_total || 0) }} q.avg {{ status.browser_metrics.queue_wait_avg_ms || 0 }}ms
Total Fixtures
{{ formatNumber(stats.fixtures || 0) }}
Across {{ Object.keys(stats.by_source || {}).length }} sources
Total Markets
{{ formatNumber(stats.markets || 0) }}
Total Odds Tracked
{{ formatNumber(stats.odds || 0) }}

Crawler Operations

Sharpbook Makers
{{ plugin.alias.substring(0,2) }}

{{ plugin.alias }}

{{ plugin.last_success ? new Date(plugin.last_success).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}) : 'Never' }}
SHARP ⭐ MAIN {{ plugin.state }} {{ getCooldownLabel(plugin) }} {{ getStaleLabel(plugin) }}

{{ plugin.message }}

{{ formatHealth(plugin) }}
{{ formatNumber(stats.by_source?.[plugin.alias] || 0) }} DB
Softbook Sites
{{ group.label }}
{{ group.plugins.length }} sites
{{ plugin.alias.substring(0,2) }}

{{ plugin.alias }}

{{ plugin.last_success ? new Date(plugin.last_success).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}) : 'Never' }}
{{ plugin.state }} {{ getCooldownLabel(plugin) }} {{ getStaleLabel(plugin) }}

{{ plugin.message }}

{{ formatHealth(plugin) }}
{{ formatNumber(stats.by_source?.[plugin.alias] || 0) }} DB

Recent Fixtures

Total: {{ formatNumber(totalFixtures) }}
Page {{ currentPage }}
Source Sport/League Match (Home vs Away) Start Time Updated
No data available.
{{ f.source_alias }} {{ getKickoffBadgeLabel(f) }}
{{ f.sport_name }}
{{ f.league_name }}
{{ f.home_team }}
VS
{{ f.away_team }}
{{ formatDate(f.start_time) }}
{{ getKickoffDetailLabel(f) }}
{{ formatDate(f.updated_at) }}

Site Analyzer & Plugin Generator

{{ analyzeError }}

{{ analyzeResult.success ? 'Analysis Complete' : 'Analysis Unconfirmed' }}

Decision: {{ analyzeResult.result.decision }}
Site Type: {{ analyzeResult.result.matched_template || analyzeResult.result.site_type || 'unknown' }}
API Base: {{ analyzeResult.result.api_base || '-' }}
Confidence: {{ Math.round((analyzeResult.result.confidence || 0) * 100) }}%
Reason: {{ analyzeResult.result.unknown_reason }}
Credential Debug
Backend received username: {{ analyzeResult.request_debug?.username_present ? `yes (${analyzeResult.request_debug?.username_length || 0})` : 'no' }}
Backend received password: {{ analyzeResult.request_debug?.password_present ? `yes (${analyzeResult.request_debug?.password_length || 0})` : 'no' }}
Auth probe attempted: {{ analyzeResult.result.debug?.auth_probe_attempted ? 'yes' : 'no' }}
Plugin Generated: {{ analyzeResult.plugin_path }}
Evidence
- {{ item }}
Top Candidates
{{ candidate.site_type }} {{ Math.round((candidate.confidence || 0) * 100) }}%
{{ candidate.api_base }}
{{ candidate.evidence[0] }}
Auth Probe Debug
{{ probe.site_type }} {{ probe.success ? 'success' : 'failed' }}
{{ probe.api_base }}
{{ item }}

{{ analyzeResult.message }}

Next steps: Add {{ analyzeAlias || analyzeResult.result.site_type }} to enabled_sites in your config.yaml and restart the orchestrator.

{{ analyzeRegisterMessage }}

Site Registry

{{ siteRegistryError }}
Loading registry...
No sites saved in registry yet.
Alias Type Visible State Profiles Source Action
{{ item.alias }} {{ item.site_type || '-' }} {{ item.enabled ? 'VISIBLE' : 'HIDDEN' }} {{ item.runtime?.state || 'UNKNOWN' }} {{ item.auth_profile_count || 0 }} (+{{ item.fallback_count }} fb) {{ item.source_kind || 'config' }}

Surebet Scanner

Mode
VS
{{ arbError }}

No arbitrage opportunities found for {{ arbSiteA }} vs {{ arbSiteB }}.

No overlapping fixtures found between {{ arbSiteA }} and {{ arbSiteB }}.

Match Market Site A Site B Profit% Stake A Stake B Expected
Start Time Sport & League Site A Match Name ({{ arbSiteA }}) Site B Match Name ({{ arbSiteB }}) Match Confidence Action
{{ formatDate(match.start_time) }}
{{ match.sport }}
{{ match.league_name }}
{{ match.home_team }} VS {{ match.away_team }} {{ match.home_team }} VS {{ match.away_team }} {{ (match.similarity_score * 100).toFixed(0) }}%
{{ filteredArbs.length }} opportunities found ({{ arbResults.filter(a => a.profit_pct > 0).length }} positive) Bankroll: ₩{{ formatNumber(arbBankroll) }}
{{ matchedFixtures.length }} overlapping fixtures detected AI Match Active ID Match Active
{{ selectedArb.market_type }} {{ formatPeriodLabel(selectedArb.period, selectedArb) }} Line: {{ selectedArb.line }} {{ selectedArb.profit_pct > 0 ? '+' : '' }}{{ selectedArb.profit_pct.toFixed(2) }}% {{ getKickoffBadgeLabel(selectedArb) }}
{{ selectedArb.home_team }} VS {{ selectedArb.away_team }}
{{ formatDate(selectedArb.start_time) }} {{ getKickoffDetailLabel(selectedArb) }} {{ selectedArb.league || selectedArb.league_name }}
{{ entry.site }} {{ entry.label }} {{ getFreshnessDetailLabel({ observed_at: entry.observed_at }) }}
{{ side.alias }}
{{ side.fixture_id }}
{{ market.name }} {{ specialConditionLabel(market.special_condition) }} {{ market.type }}
{{ selectedFixture.source_alias }} {{ selectedFixture.sport_name }} {{ getKickoffBadgeLabel(selectedFixture) }}
{{ selectedFixture.home_team }} VS {{ selectedFixture.away_team }}
{{ formatDate(selectedFixture.start_time) }} {{ getKickoffDetailLabel(selectedFixture) }} {{ selectedFixture.league_name }}

{{ modalError }}

No markets available for this fixture.

{{ market.name }} {{ specialConditionLabel(market.special_condition) }} {{ market.type }}
{{ odd.name }} {{ odd.line > 0 ? '+' : '' }}{{ odd.line }}
{{ odd.price.toFixed(2) }}

Odds History

{{ chartLabel }}

Loading history...

{{ chartError }}

History Points
{{ formatDate(point.fetched_at) }} {{ Number(point.price).toFixed(2) }}

DOM Verify

브라우저로 사이트 실제 DOM 배당 수집 → DB 배당 조회 → 비교

브라우저 현황 메인 크롤러  {{ browserStatus.main.active }}/{{ browserStatus.main.max }} (크롤링 중) (대기) DOM 브라우저  {{ browserStatus.dom.active }}/{{ browserStatus.dom.max }} (수집 중) (대기)

대상 사이트

Step 1 — 실제 DOM 배당 수집

브라우저로 사이트에 로그인해 배당이 렌더링된 HTML을 캡처합니다.

수집 완료
{{ domVerifySnapshotResult.file ? domVerifySnapshotResult.file.split('/').pop() : '' }}
{{ Math.round((domVerifySnapshotResult.size_bytes||0) / 1024) }} KB · {{ domVerifySnapshotResult.captured_at ? domVerifySnapshotResult.captured_at.replace('T',' ').slice(0,19) : '' }}
배당 {{ domVerifySnapshotResult.dom_total_odds }}개 파싱됨

Step 2 — DB 배당 조회 & 비교

DB 최신 배당을 가져와 수집된 DOM 배당과 비교합니다.

{{ domVerifyError }}
DB 배당 샘플: {{ domDbOddsResult.rows ? domDbOddsResult.rows.length : 0 }}건 수집 시각: {{ domDbOddsResult.fetched_at ? domDbOddsResult.fetched_at.replace('T',' ').slice(0,19) : '' }}
경기 마켓 선택지 DB 배당 업데이트
{{ r.match_label }} {{ r.market_name }} {{ r.selection }} {{ r.price.toFixed(2) }} {{ r.updated_at ? r.updated_at.slice(0,16) : '' }}
DOM 총 배당: {{ domVerifyResult.dom_total_odds }} 일치: {{ domVerifyResult.summary.match }} 불일치: {{ domVerifyResult.summary.mismatch }} DOM 없음: {{ domVerifyResult.summary.not_in_dom }}
경기 마켓 선택지 DB DOM 상태
{{ c.match_label }} {{ c.market }} {{ c.selection }} {{ c.api_price.toFixed(2) }} {{ c.dom_price !== null ? c.dom_price.toFixed(2) : '—' }} {{ c.status==='match' ? '✓ 일치' : c.status==='mismatch' ? '✗ 불일치' : '? 미발견' }}

메인 루프 작동 중

현재 다른 크롤링 작업이 브라우저를 사용 중입니다.
잠시 후 다시 시도해 주세요.