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:
@@ -13,6 +13,7 @@ from fastapi import (
|
||||
HTTPException,
|
||||
Path,
|
||||
Query,
|
||||
Request,
|
||||
Response,
|
||||
UploadFile,
|
||||
)
|
||||
@@ -196,10 +197,11 @@ async def user_company_search(
|
||||
|
||||
@router.post("/user/company/create")
|
||||
async def user_company_create(
|
||||
request: Request,
|
||||
payload: CreateCompanyRequest,
|
||||
session: dict[str, Any] = Depends(verify_session),
|
||||
):
|
||||
result = await create_company(int(session["user_id"]), payload.model_dump())
|
||||
result = await create_company(int(session["user_id"]), payload.model_dump(), request)
|
||||
return {"status": "success", **result}
|
||||
|
||||
|
||||
@@ -369,6 +371,7 @@ async def admin_projects(session: dict[str, Any] = Depends(require_company_admin
|
||||
@router.put("/projects/{project_id}")
|
||||
async def dashboard_update_project(
|
||||
project_id: str,
|
||||
request: Request,
|
||||
payload: UpdateProjectRequest,
|
||||
session: dict[str, Any] = Depends(verify_session),
|
||||
):
|
||||
@@ -387,7 +390,7 @@ async def dashboard_update_project(
|
||||
)
|
||||
await check_project_refs(int(project["company_id"]), data)
|
||||
member_ids = data.pop("member_user_ids", None)
|
||||
if not await update_project(project_id, data, int(session["user_id"])):
|
||||
if not await update_project(project_id, data, int(session["user_id"]), request):
|
||||
raise HTTPException(status_code=404, detail="프로젝트를 찾을 수 없습니다.")
|
||||
if member_ids is not None:
|
||||
# 만든 사람은 늘 참여자로 남는다.
|
||||
@@ -398,6 +401,7 @@ async def dashboard_update_project(
|
||||
@router.delete("/projects/{project_id}")
|
||||
async def dashboard_delete_project(
|
||||
project_id: str,
|
||||
request: Request,
|
||||
session: dict[str, Any] = Depends(verify_session),
|
||||
):
|
||||
project = await get_project(project_id)
|
||||
@@ -413,7 +417,7 @@ async def dashboard_delete_project(
|
||||
|
||||
# 개발 PC에서만 하드 삭제. 배포 기본값은 지금까지처럼 소프트 삭제다.
|
||||
delete_project = hard_delete_project if PROJECT_DELETE_HARD_ENABLED else soft_delete_project
|
||||
if not await delete_project(project_id, int(session["user_id"])):
|
||||
if not await delete_project(project_id, int(session["user_id"]), request):
|
||||
raise HTTPException(status_code=404, detail="프로젝트를 찾을 수 없습니다.")
|
||||
return {"status": "success"}
|
||||
|
||||
@@ -426,10 +430,11 @@ async def system_companies(session: dict[str, Any] = Depends(require_system_admi
|
||||
|
||||
@router.post("/admin/companies")
|
||||
async def system_create_company(
|
||||
request: Request,
|
||||
payload: CreateCompanyRequest,
|
||||
session: dict[str, Any] = Depends(require_system_admin),
|
||||
):
|
||||
result = await create_company(int(session["user_id"]), payload.model_dump())
|
||||
result = await create_company(int(session["user_id"]), payload.model_dump(), request)
|
||||
return {"status": "success", **result}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user