c61f10560f
- Express.js 기반 관리자 페이지 (사이트/크롤링/AdSense/도메인 관리) - PostgreSQL 16 + Docker Compose (Traefik 연동) - 크롤러: axios + cheerio 기반 HTML 파싱 - 스케줄러: node-cron 기반 자동 크롤링 - 공개 사이트: slug/도메인 기반 DB에서 렌더링 HTML 서빙 - 도메인: admin.startover.co.kr Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
28 lines
1.2 KiB
Plaintext
28 lines
1.2 KiB
Plaintext
<%- include('layout', { page: 'logs', pageTitle: '크롤링 로그', body: `
|
|
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h2>최근 로그</h2>
|
|
<button class="btn btn-outline btn-sm" onclick="loadLogs()">새로고침</button>
|
|
</div>
|
|
<table>
|
|
<thead><tr><th style="width:160px">시간</th><th style="width:120px">사이트</th><th style="width:120px">액션</th><th>메시지</th></tr></thead>
|
|
<tbody id="logs-tbody"></tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<script>
|
|
async function loadLogs() {
|
|
const logs = await api('GET', '/api/logs?limit=100');
|
|
document.getElementById('logs-tbody').innerHTML = logs.map(l => {
|
|
const actionClass = l.action.includes('error') ? 'danger' : l.action.includes('success') ? 'success' : 'info';
|
|
return '<tr><td class="text-muted">' + new Date(l.created_at).toLocaleString('ko-KR') + '</td>' +
|
|
'<td>' + (l.site_name || '-') + '</td>' +
|
|
'<td><span class="badge badge-' + actionClass + '">' + l.action + '</span></td>' +
|
|
'<td style="word-break:break-all">' + (l.message || '') + '</td></tr>';
|
|
}).join('') || '<tr><td colspan="4" class="text-muted" style="text-align:center;padding:2rem">로그가 없습니다</td></tr>';
|
|
}
|
|
loadLogs();
|
|
</script>
|
|
` }) %>
|