diff --git a/src/app.js b/src/app.js index 0bec917..5639e9b 100644 --- a/src/app.js +++ b/src/app.js @@ -97,44 +97,42 @@ app.get('/logout', (req, res) => { // ===== 루트 → 관리자로 리다이렉트 ===== app.get('/', (req, res) => res.redirect('/admin')); +// 서버사이드 데이터를 script 태그로 만드는 헬퍼 +function initScript(data) { + return ''; +} + // ===== 관리자 페이지 (데이터 서버사이드 렌더링) ===== app.get('/admin', adminAuth, async (req, res) => { try { const sites = await db.query(`SELECT s.*, (SELECT COUNT(*) FROM crawl_results WHERE site_id = s.id) AS crawl_count FROM sites s ORDER BY s.id`); const adsense = await db.query('SELECT * FROM adsense_configs ORDER BY id'); const logs = await db.query(`SELECT l.*, s.name AS site_name FROM crawl_logs l LEFT JOIN sites s ON s.id = l.site_id ORDER BY l.created_at DESC LIMIT 10`); - res.render('admin/dashboard', { - initialData: JSON.stringify({ sites: sites.rows, adsense: adsense.rows, logs: logs.rows }) - }); - } catch (e) { res.render('admin/dashboard', { initialData: '{}' }); } + res.render('admin/dashboard', { ssrData: initScript({ sites: sites.rows, adsense: adsense.rows, logs: logs.rows }) }); + } catch (e) { res.render('admin/dashboard', { ssrData: initScript({}) }); } }); app.get('/admin/sites', adminAuth, async (req, res) => { try { const sites = await db.query(`SELECT s.*, ac.name AS adsense_name, (SELECT COUNT(*) FROM crawl_results WHERE site_id = s.id) AS crawl_count FROM sites s LEFT JOIN adsense_configs ac ON ac.id = s.adsense_config_id ORDER BY s.id`); const adsense = await db.query('SELECT * FROM adsense_configs ORDER BY id'); - res.render('admin/sites', { - initialData: JSON.stringify({ sites: sites.rows, adsense: adsense.rows }) - }); - } catch (e) { res.render('admin/sites', { initialData: '{}' }); } + res.render('admin/sites', { ssrData: initScript({ sites: sites.rows, adsense: adsense.rows }) }); + } catch (e) { res.render('admin/sites', { ssrData: initScript({}) }); } }); app.get('/admin/sites/:id', adminAuth, async (req, res) => { try { const site = await db.query('SELECT * FROM sites WHERE id = $1', [req.params.id]); const results = await db.query(`SELECT id, site_id, status, error_message, crawled_at, jsonb_array_length(COALESCE(parsed_data->'items','[]'::jsonb)) AS item_count FROM crawl_results WHERE site_id = $1 ORDER BY crawled_at DESC LIMIT 20`, [req.params.id]); - res.render('admin/site-detail', { - siteId: req.params.id, - initialData: JSON.stringify({ site: site.rows[0] || {}, results: results.rows }) - }); - } catch (e) { res.render('admin/site-detail', { siteId: req.params.id, initialData: '{}' }); } + res.render('admin/site-detail', { siteId: req.params.id, ssrData: initScript({ site: site.rows[0] || {}, results: results.rows }) }); + } catch (e) { res.render('admin/site-detail', { siteId: req.params.id, ssrData: initScript({}) }); } }); app.get('/admin/adsense', adminAuth, async (req, res) => { try { const adsense = await db.query('SELECT * FROM adsense_configs ORDER BY id'); - res.render('admin/adsense', { initialData: JSON.stringify(adsense.rows) }); - } catch (e) { res.render('admin/adsense', { initialData: '[]' }); } + res.render('admin/adsense', { ssrData: initScript(adsense.rows) }); + } catch (e) { res.render('admin/adsense', { ssrData: initScript([]) }); } }); app.get('/admin/domains', adminAuth, async (req, res) => { @@ -142,15 +140,15 @@ app.get('/admin/domains', adminAuth, async (req, res) => { const domains = await db.query(`SELECT d.*, s.name AS site_name FROM domain_mappings d LEFT JOIN sites s ON s.id = d.site_id ORDER BY d.id`); const sites = await db.query('SELECT id, name FROM sites ORDER BY id'); const adsense = await db.query('SELECT id, name FROM adsense_configs ORDER BY id'); - res.render('admin/domains', { initialData: JSON.stringify({ domains: domains.rows, sites: sites.rows, adsense: adsense.rows }) }); - } catch (e) { res.render('admin/domains', { initialData: '{}' }); } + res.render('admin/domains', { ssrData: initScript({ domains: domains.rows, sites: sites.rows, adsense: adsense.rows }) }); + } catch (e) { res.render('admin/domains', { ssrData: initScript({}) }); } }); app.get('/admin/logs', adminAuth, async (req, res) => { try { const logs = await db.query(`SELECT l.*, s.name AS site_name FROM crawl_logs l LEFT JOIN sites s ON s.id = l.site_id ORDER BY l.created_at DESC LIMIT 100`); - res.render('admin/logs', { initialData: JSON.stringify(logs.rows) }); - } catch (e) { res.render('admin/logs', { initialData: '[]' }); } + res.render('admin/logs', { ssrData: initScript(logs.rows) }); + } catch (e) { res.render('admin/logs', { ssrData: initScript([]) }); } }); // ===== API ===== diff --git a/views/admin/layout.ejs b/views/admin/layout.ejs index 38fa345..ea7533c 100644 --- a/views/admin/layout.ejs +++ b/views/admin/layout.ejs @@ -119,7 +119,7 @@ tr:hover td{background:rgba(255,255,255,.02)}
- +<%- typeof ssrData !== 'undefined' ? ssrData : '' %>