feat(B01): 시스템 로그에 대상·접속 정보 기록 + 1년 보관 정리 (2026-09-06 사용자 확정)
- 기록을 `common_util_audit.record_audit()` 한 곳으로 모음 — 여섯 자리에 흩어져 있던 raw INSERT 제거 - 대상 식별자 칸 신설(`017_audit_log_detail.sql`, 적용 완료) — 기존 `resource_id` 는 INT 라 프로젝트 UUID 를 못 담아 늘 NULL 이었음. 프로젝트 생성·수정·삭제·회사 생성이 대상을 남김 - 접속 주소·브라우저 기록 — 라우터가 요청을 넘겨 주고, 프록시 뒤에서는 X-Forwarded-For 우선 - 보관 기간 `AUDIT_LOG_RETENTION_DAYS` 기본 365일, 임시 보관함 정리 루프에 얹어 함께 정리 - 화면: 시스템 로그 표에 대상·접속 주소 열 추가(대상은 UUID 앞 8자만) 자체검증 — 프로젝트 생성·하드삭제를 실화면에서 돌려 두 줄 모두 `프로젝트 e1040640… · 127.0.0.1 · 2026-09-06 09:54/09:55` 로 남는 것 확인. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,14 +8,16 @@
|
||||
|
||||
import logging
|
||||
import shutil
|
||||
from typing import Any
|
||||
|
||||
from common_util.common_util_audit import record_audit
|
||||
from common_util.common_util_storage import resolve_project_root_for_delete
|
||||
from config.config_db import get_db_pool
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def hard_delete_project(project_id: str, actor_id: int) -> bool:
|
||||
async def hard_delete_project(project_id: str, actor_id: int, request: Any | None = None) -> bool:
|
||||
"""프로젝트를 DB와 영구저장소에서 완전히 지운다. 되돌릴 수 없다.
|
||||
|
||||
자식 테이블은 나열하지 않는다 — `projects.id`를 참조하는 테이블이 전부
|
||||
@@ -60,10 +62,13 @@ async def hard_delete_project(project_id: str, actor_id: int) -> bool:
|
||||
await connection.rollback()
|
||||
return False
|
||||
# 감사 기록은 프로젝트가 사라진 뒤에도 남는다. resource_id는 FK가 없어 고아가 되지 않는다.
|
||||
await cursor.execute(
|
||||
"""INSERT INTO system_audit_logs (user_id, action, resource_type, resource_id)
|
||||
VALUES (%s, 'PROJECT_HARD_DELETE', 'project', NULL)""",
|
||||
(actor_id,),
|
||||
await record_audit(
|
||||
cursor,
|
||||
actor_id=actor_id,
|
||||
action="PROJECT_HARD_DELETE",
|
||||
resource_type="project",
|
||||
resource_ref=project_id,
|
||||
request=request,
|
||||
)
|
||||
await connection.commit()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user