feat: integrate Serilog and Telegram notifications
TaxBaik CI/CD / build-and-deploy (push) Successful in 51s

- Add Serilog for structured logging (Console + File)
- Implement TelegramNotificationService for admin alerts
- Log successful/failed login attempts with Telegram notifications
- Add application startup/shutdown logging
- Log important events to Telegram Chat ID: -5585148480
- Configuration: Telegram:BotToken and Telegram:ChatId in appsettings

Features:
- Automatic daily log rotation
- Structured logging with timestamps
- Environment-aware alerts
- Error and info level Telegram messages

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-06-28 16:19:38 +09:00
parent e797da6140
commit 2bde490e9e
15 changed files with 517 additions and 8 deletions
+57
View File
@@ -0,0 +1,57 @@
import { chromium } from '@playwright/test';
const browser = await chromium.launch();
const page = await browser.newPage();
try {
// 1. 로그인
console.log('🔓 로그인 중...');
await page.goto('http://178.104.200.7/taxbaik/admin/login', { waitUntil: 'networkidle' });
await page.fill('input[placeholder="사용자명"]', 'test_admin');
await page.fill('input[placeholder="비밀번호"]', 'TestAdmin@123456');
await page.click('button:has-text("로그인")');
await page.waitForURL(/\/taxbaik\/admin\/dashboard$/, { timeout: 10000 });
console.log('✅ 로그인 성공');
// 2. Settings 페이지로 이동
console.log('\n📍 Settings 페이지로 이동...');
await page.goto('http://178.104.200.7/taxbaik/admin/settings', { waitUntil: 'domcontentloaded' });
// 3. 다양한 대기 전략 시도
console.log('⏳ 페이지 로드 대기 중...');
for (let i = 1; i <= 5; i++) {
await page.waitForTimeout(1000);
const title = await page.locator('h4:has-text("설정")').count();
const body = await page.locator('body').evaluate(el => el.innerHTML.length);
const mudComponents = await page.locator('[class*="mud-"]').count();
console.log(`시도 ${i}: body=${body}bytes, mud=${mudComponents}, title=${title}`);
if (mudComponents > 10 && body > 5000) {
console.log('✅ 페이지 렌더링 감지됨!');
break;
}
}
// 4. 최종 상태 확인
console.log('\n📊 최종 상태:');
const hasContent = await page.locator('body').evaluate(el => el.innerText.length > 100);
const hasComponents = await page.locator('[class*="mud-"]').count();
console.log(`- 텍스트 콘텐츠: ${hasContent ? '있음' : '없음'}`);
console.log(`- MudBlazor 컴포넌트: ${hasComponents}`);
if (!hasContent) {
console.log('\n❌ Settings 페이지 렌더링 실패');
console.log('HTML 스니펫:');
const html = await page.content();
const bodyMatch = html.match(/<body[^>]*>([\s\S]{0,500})/);
if (bodyMatch) console.log(bodyMatch[1]);
}
} catch (error) {
console.error('❌ 에러:', error.message);
}
await browser.close();