zioinfo-mail/itsm/static/customer.css
DESKTOP-TKLFCPR\ython e228faabf5 feat(itsm): G-1~G-12 확장 기능 + 하네스/봇/설치스크립트 구현
G-1: 메신저 Webhook Relay + _send_to_room 실제 httpx 호출 구현
G-2: POST /api/tasks/bulk SR 대량작업 엔드포인트 (최대 100건)
G-3: 라이선스 만료 알림 스케줄러 (매일 09:00 KST)
G-4: 체험판 upgrade_banner 필드 + license.py 배너 로직
G-5: core/auto_rca.py + incidents/problem auto-rca 엔드포인트
G-6: core/deploy_impact.py + vibe impact-analysis 엔드포인트
G-7: core/ticket_classifier.py + SR 생성 시 AI 분류 + ai-suggestion API
G-8: VulnPatchRecord 모델 + vuln_scan 패치추적 4개 엔드포인트
G-9: core/jira_sync.py + gateway Jira/Confluence 연동 엔드포인트
G-10: core/push_notify.py + routers/push.py + PushSubscription 모델
G-11: approvals 다중승인 (위임/서명/기한초과/마감연장)
G-12: alembic.ini + migrations/ + cicd/migrate_to_postgres.sh

하네스: guardia-orchestrator 확장기능 Phase 반영
봇명령어: /sr /status /license /bulk 슬래시 명령어 추가
설치스크립트: setup/ (Ubuntu, CentOS, RHEL, Windows) --test 옵션 포함

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:18:52 +09:00

120 lines
6.0 KiB
CSS

/* ─── GUARDiA 고객 포털 (라이트 테마) ─── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--blue: #1a73e8;
--blue-l: #e8f0fe;
--green: #1e8449;
--red: #c0392b;
--yellow: #f39c12;
--gray: #5f6368;
--light: #f8f9fa;
--border: #dadce0;
--font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
html, body { font-family: var(--font); background: var(--light); color: #202124; min-height: 100vh; }
/* header */
.portal-header { background: #fff; border-bottom: 1px solid var(--border); }
.portal-header-inner { max-width: 760px; margin: 0 auto; padding: 14px 20px; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 6px; }
.portal-logo { display: flex; align-items: center; gap: 10px; }
.logo-g { background: var(--blue); color: #fff; width: 32px; height: 32px; border-radius: 6px; display: flex; align-items: center; justify-content: center; font-weight: 900; font-size: 18px; }
.logo-text { font-size: 16px; font-weight: 700; color: #202124; }
.portal-sub { font-size: 12px; color: var(--gray); }
/* main */
.portal-main { max-width: 760px; margin: 32px auto; padding: 0 20px 60px; }
/* card */
.portal-card { background: #fff; border: 1px solid var(--border); border-radius: 12px; padding: 32px; box-shadow: 0 1px 4px rgba(0,0,0,.06); }
.result-card { text-align: center; }
.card-title { font-size: 20px; font-weight: 700; margin-bottom: 8px; }
.card-desc { font-size: 14px; color: var(--gray); margin-bottom: 24px; line-height: 1.6; }
/* form */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; }
@media (max-width: 540px) { .form-grid { grid-template-columns: 1fr; } }
.form-group { display: flex; flex-direction: column; gap: 5px; }
.form-group.full { margin-bottom: 16px; }
label { font-size: 13px; font-weight: 500; color: #3c4043; }
.req { color: var(--red); }
input[type=text], select, textarea {
padding: 9px 12px; border: 1px solid var(--border); border-radius: 6px;
font-size: 14px; font-family: var(--font); outline: none;
transition: border-color .15s;
}
input:focus, select:focus, textarea:focus { border-color: var(--blue); box-shadow: 0 0 0 2px rgba(26,115,232,.2); }
textarea { resize: vertical; }
.btn-submit {
width: 100%; padding: 12px; background: var(--blue); color: #fff;
border: none; border-radius: 8px; font-size: 15px; font-weight: 600;
cursor: pointer; transition: background .15s; display: flex; align-items: center; justify-content: center; gap: 8px;
}
.btn-submit:hover { background: #1557b0; }
/* result */
.result-icon { font-size: 48px; margin-bottom: 12px; }
.sr-id-box { background: var(--blue-l); border-radius: 8px; padding: 14px 20px; margin: 20px 0; display: inline-block; }
.sr-id-label { font-size: 12px; color: var(--blue); display: block; margin-bottom: 4px; font-weight: 600; }
.sr-id-value { font-size: 20px; font-weight: 700; color: var(--blue); font-family: "Consolas", monospace; }
/* status badge */
.status-badge-row { margin: 16px 0 12px; display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; }
.s-badge { padding: 4px 10px; border-radius: 20px; font-size: 12px; font-weight: 600; }
.s-RECEIVED { background: #f1f3f4; color: #5f6368; }
.s-PENDING_APPROVAL { background: #fef9c3; color: #92400e; }
.s-APPROVED { background: #dcfce7; color: #166534; }
.s-IN_PROGRESS { background: #dbeafe; color: #1e40af; }
.s-COMPLETED { background: #d1fae5; color: #065f46; }
.s-FAILED_ROLLBACK { background: #fee2e2; color: #991b1b; }
.s-REJECTED { background: #fee2e2; color: #991b1b; }
/* progress timeline */
.progress-title { font-size: 14px; font-weight: 600; text-align: left; margin-bottom: 12px; color: #3c4043; }
.timeline { border-left: 2px solid var(--border); padding-left: 18px; text-align: left; }
.tl-item { position: relative; margin-bottom: 14px; }
.tl-item::before { content: ""; position: absolute; left: -23px; top: 5px; width: 8px; height: 8px; border-radius: 50%; background: var(--border); border: 2px solid #fff; }
.tl-item.ok::before { background: var(--green); }
.tl-item.err::before { background: var(--red); }
.tl-action { font-size: 13px; font-weight: 600; color: #3c4043; }
.tl-detail { font-size: 12px; color: var(--gray); margin-top: 2px; }
.tl-loading { font-size: 13px; color: var(--gray); padding: 8px 0; }
/* rating */
.rating-section { margin: 24px 0; padding: 20px; background: #fffbeb; border-radius: 8px; border: 1px solid #fde68a; }
.rating-title { font-size: 15px; font-weight: 600; margin-bottom: 12px; color: #92400e; }
.stars-row { display: flex; justify-content: center; gap: 8px; margin-bottom: 12px; }
.star-btn {
font-size: 32px; background: none; border: none; cursor: pointer;
color: #d1d5db; transition: color .1s, transform .1s;
line-height: 1;
}
.star-btn:hover, .star-btn.active { color: #f59e0b; transform: scale(1.15); }
.rating-comment-input {
width: 100%; padding: 8px 12px; border: 1px solid var(--border);
border-radius: 6px; font-size: 13px; margin-bottom: 10px;
}
.btn-rate {
background: #f59e0b; color: #fff; border: none; padding: 9px 24px;
border-radius: 6px; font-size: 14px; font-weight: 600; cursor: pointer;
}
.btn-rate:disabled { opacity: .5; cursor: not-allowed; }
.rating-done { font-size: 15px; color: var(--green); font-weight: 600; margin-top: 8px; }
.btn-new {
margin-top: 20px; padding: 10px 24px; background: transparent;
border: 1px solid var(--border); border-radius: 6px; font-size: 14px;
cursor: pointer; color: var(--gray); transition: background .15s;
}
.btn-new:hover { background: var(--light); }
/* spinner */
.spinner { width: 16px; height: 16px; border: 2px solid rgba(255,255,255,.4); border-top-color: #fff; border-radius: 50%; animation: spin .7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
/* hidden */
.hidden { display: none !important; }
/* footer */
.portal-footer { text-align: center; font-size: 12px; color: var(--gray); padding: 20px; border-top: 1px solid var(--border); background: #fff; }