From 3b20c0ef5f38f5feaa491e1ae9283ac5e1607d1f Mon Sep 17 00:00:00 2001 From: heejae <0914eagle@gmail.com> Date: Fri, 13 Mar 2026 18:48:51 +0900 Subject: [PATCH] Add NAS native Go Company X sync docs --- ...0313_nas_본체_go_companyx_sync_계획.md | 168 ++++++++++++++++++ ...o_companyx_sync_구현_및_대표검증.md | 74 ++++++++ 2 files changed, 242 insertions(+) create mode 100644 journey/plans/260313_nas_본체_go_companyx_sync_계획.md create mode 100644 journey/worklog/260313_nas_본체_go_companyx_sync_구현_및_대표검증.md diff --git a/journey/plans/260313_nas_본체_go_companyx_sync_계획.md b/journey/plans/260313_nas_본체_go_companyx_sync_계획.md new file mode 100644 index 0000000..6d925ca --- /dev/null +++ b/journey/plans/260313_nas_본체_go_companyx_sync_계획.md @@ -0,0 +1,168 @@ +--- +tags: [infra, nas, companyx, sync, go, plans] +--- + +# 260313 NAS 본체 Go Company X Sync 계획 + +**상태**: 완료 (2026-03-13 Go CLI 빌드, 테스트, 대표 폴더 dry-run/실동기화 검증 완료) + +## 상위 원칙 +- [Infra Project Identity](../../00_Philosophy/00_IDENTITY/Infra_Project_Identity.md) +- [Core Infrastructure Principles](../../00_Philosophy/01_PRINCIPLES/Core_Infrastructure_Principles.md) +- [Operational Guardrails](../../00_Philosophy/02_GUARDRAILS/Operational_Guardrails.md) +- 공통 작성 원칙: [0_VALUE Writing Principles](https://github.com/happybell80/0_VALUE/blob/main/02_Governance/writing-principles.md) + +## 관련 문서 +- [외부 NAS -> 내부 NAS 컴퍼니엑스 파일 동기화 아이디어](../ideas/260307_external_nas_companyx_sync_아이디어.md) +- [외부 NAS -> 내부 NAS 컴퍼니엑스 실시간 동기화 아이디어](../ideas/260312_external_nas_companyx_실시간동기화_아이디어.md) +- [외부 NAS -> 내부 NAS 컴퍼니엑스 동기화 리서치](../research/260307_external_nas_companyx_sync_research.md) +- [외부 NAS -> 내부 NAS 컴퍼니엑스 실시간동기화 리서치](../research/260312_external_nas_companyx_실시간동기화_리서치.md) +- [NAS 본체 Go Company X Sync 구현 및 대표 검증](../worklog/260313_nas_본체_go_companyx_sync_구현_및_대표검증.md) + +## 문제 정의 + +- 이미 닫힌 문제는 `외부 NAS -> 내부 저장소` 기본 동기화 구조가 성립하는가이다. +- 이번에 푸는 문제는 `NAS 본체에서 이 구조를 Go 코드로 재현 가능하게 실행하고, 이후 운영 기준을 그 구현 위에 올릴 수 있는가`다. +- 즉 새 코드는 `외부 NAS 직접 사용 제거`, `내부 저장소 단일 기준 유지`, `NAS 본체 직접 실행`, `재개 가능한 동기화`를 실제 실행 단위로 고정해야 한다. + +## 이번 계획에서 고정하는 범위 + +- 실행 주체는 NAS 본체다. +- 구현 언어는 Go로 고정한다. +- 초기 실행 형태는 `1회 실행 CLI`로 고정한다. +- 대상 원본 루트는 외부 NAS `/6.Company X`다. +- 대상 내부 저장 루트는 NAS 본체의 Company X 저장 경로다. +- 외부 접근 방식은 DSM File Station API pull로 유지한다. +- 기본 증분 기준은 `수정시각 + 파일 크기`로 유지한다. +- 외부 삭제는 내부 저장소에 자동 전파하지 않는다. +- 실패 기록, 상태 기록, 요약 기록은 파일로 남긴다. + +## 이번 계획에서 아직 고정하지 않는 범위 + +- 최종 cron 주기 +- 상주 daemon 채택 여부 +- Search API 채택 여부 +- 인증서 정상화 방식 +- 최종 로그 포맷의 세부 필드 추가 확장 + +## 구현 목표 + +### 1. Go 실행 엔트리를 만든다 + +- `infra/scripts` 저장소에 NAS 본체에서 직접 실행할 Go 진입점을 추가한다. +- 단일 바이너리 실행을 기준으로 하고, 초기 단계는 CLI 1회 실행 모델로 둔다. +- 이후 cron에서 재사용할 수 있게 입력 인자와 종료 코드를 단순하게 유지한다. +- 초기 바이너리 이름은 `companyx-sync`로 고정한다. +- 초기 소스 루트는 `infra/scripts/go/companyx-sync`로 고정한다. + +### 2. workspace-config를 읽는 구조를 고정한다 + +- 비민감값은 `runtime.env`, 민감값은 `secrets.env`에서 읽는다. +- 코드 안에 운영 기본값과 인증값을 하드코딩하지 않는다. +- 대상 루트, 로그 루트, 상태 파일 경로도 설정에서 주입 가능한 구조로 둔다. +- 필수 키가 없으면 즉시 실패하고, 누락 키 이름을 로그에 남긴다. + +### 3. DSM API pull 기본 경로를 재현한다 + +- 로그인 +- 폴더 목록 조회 +- 파일 다운로드 +- 다운로드 후 내부 저장소 반영 +- 이 네 가지를 먼저 Go에서 재현한다. + +### 4. 증분 판정과 기록 구조를 넣는다 + +- 파일 존재 여부 +- 파일 크기 +- 수정시각 +- 이 세 가지로 기본 다운로드 여부를 판단한다. +- 실패 로그, 상태 파일, 실행 요약 파일을 남긴다. +- 로그 루트 기본값은 Company X 동기화 로그가 이미 쌓이는 경로 계열을 따른다. +- 초기 기본 경로는 `/workspace/.sync-logs`로 고정한다. +- 상태 파일 기본 경로는 `/workspace/.sync-logs/companyx_sync_state.json`로 고정한다. +- 실패 로그 기본 경로는 `/workspace/.sync-logs/companyx_sync_failures_YYYYMMDD.jsonl` 패턴으로 고정한다. +- 요약 파일 기본 경로는 `/workspace/.sync-logs/companyx_sync_summary_YYYYMMDD_HHMMSS.json` 패턴으로 고정한다. +- 삭제 후보 로그 기본 경로는 `/workspace/.sync-logs/companyx_delete_candidates_YYYYMMDD.jsonl` 패턴으로 고정한다. + +### 5. 삭제 비전파 원칙을 유지한다 + +- 외부에 없는 파일을 바로 지우지 않는다. +- 삭제 후보 로그만 남긴다. +- 자동 삭제는 이번 계획 범위에 넣지 않는다. + +### 6. 재개 가능성을 우선 확보한다 + +- 전체 트리 중 어디까지 스캔했는지 상태 파일에 남긴다. +- 마지막으로 실제 다운로드한 경로도 남긴다. +- 실패 후 다음 실행이 완전 초기화 없이 이어질 수 있게 최소 상태를 유지한다. + +## 초기 구조 결정 + +- 모듈은 하나로 시작하고, 패키지 분리는 구현 중복이 생길 때만 늘린다. +- 1차 구조는 `config`, `dsm`, `sync`, `main` 정도의 최소 패키지로 제한한다. +- Python 구현과 기능 parity를 무리하게 한 번에 맞추지 않고, `다운로드 -> 증분 -> 상태기록` 순으로 단계적으로 맞춘다. +- 첫 구현에서는 daemon, queue, webhook, Search API 최적화는 넣지 않는다. + +## 실행 순서 + +1. `infra/scripts`에 Go 진입점과 모듈 구조를 추가한다. +2. `workspace-config`를 읽는 설정 로더를 만든다. +3. DSM 로그인, 목록 조회, 다운로드를 재현한다. +4. `/6.Company X`의 대표 파일 1건 다운로드까지 먼저 맞춘다. +5. 대표 하위 폴더 1개 동기화까지 확장한다. +6. 상태 파일, 실패 로그, 요약 파일을 붙인다. +7. 전체 트리 1회 실행 가능한 수준까지 올린다. +8. 이후 cron/주기 계획은 별도 적용 문서나 worklog에서 닫는다. + +## 1차 구현 순서 고정 + +1. `--remote-root`, `--local-root`, `--log-root`, `--dry-run` 플래그를 지원하는 CLI를 만든다. +2. 설정 파일 없이도 플래그 우선, 설정 파일 fallback 순서로 해석되게 한다. +3. 대표 파일 1건 다운로드를 먼저 검증한다. +4. 대표 하위 폴더 1개 동기화를 검증한다. +5. 같은 입력 재실행 시 `skipped`가 증가하는지 확인한다. +6. 실패 강제 상황에서 실패 로그와 상태 파일이 남는지 확인한다. + +## 체크리스트 + +- Go 바이너리가 NAS 본체에서 직접 실행된다. +- 바이너리 이름과 소스 루트가 문서 기준과 일치한다. +- 외부 DSM API 로그인과 파일 다운로드가 재현된다. +- 내부 저장소 기준 경로로 파일이 실제 반영된다. +- `수정시각 + 파일 크기` 기준 증분 판정이 동작한다. +- 실패 로그가 남는다. +- 상태 파일이 남는다. +- 요약 파일이 남는다. +- 삭제는 자동 전파되지 않는다. + +## 검증 기준 + +- 대표 파일 1건 다운로드 성공 +- 대표 하위 폴더 1개 동기화 성공 +- 같은 입력 재실행 시 불필요한 재다운로드가 줄어듦 +- 실패 상황에서 실패 로그와 상태 파일이 남음 +- 실행 종료 후 요약 파일에서 `downloaded`, `skipped`, `failed`를 확인할 수 있음 + +## 완료 조건 + +- NAS 본체에서 Go 기반 동기화 CLI가 직접 돈다. +- 외부 DSM API pull, 내부 저장소 반영, 기본 증분 판정이 한 흐름으로 연결된다. +- 상태 파일, 실패 로그, 요약 파일이 실제 산출물로 확인된다. +- 구현 결과만으로 다음 단계 cron 적용 문서를 쓸 수 있을 만큼 실행 단위와 산출물이 고정된다. +- 이 주제는 더 이상 `Go로 옮길 수 있는가`가 아니라 `운영 주기와 배포 방식을 어떻게 고정할까` 문제만 남는다. + +## 2026-03-13 적용 상태 + +- Go 모듈 `infra/scripts/go/companyx-sync`를 추가했다. +- CLI 진입점 `cmd/companyx-sync`를 만들고 `workspace-config` 기반 설정 로더를 붙였다. +- `DSM API login -> list -> download -> 상태/실패/요약 기록` 흐름을 Go로 재현했다. +- `go test ./...`는 통과했다. +- 대표 사진 폴더 `/6.Company X/7. 사진/220308_X코스_5기 발표 사진` 대상 `--dry-run` 검증 결과 `downloaded=20`, `failed=0`, `files_seen=20`이었다. +- 같은 대표 폴더 실동기화 결과도 `downloaded=20`, `failed=0`, `files_seen=20`, `downloaded_bytes=6505335`였다. +- 같은 입력 재실행 결과는 `downloaded=0`, `skipped=20`, `failed=0`이었다. +- 실동기화 후 로컬 저장 경로에는 파일 `20개`가 실제 생성됐다. +- 요약 파일과 상태 파일도 실제로 생성돼, 이 계획 문서는 완료로 닫는다. + +## 한 줄 결론 + +- 목표는 NAS 본체에서 Go 코드로 `외부 NAS /6.Company X -> 내부 저장소` 동기화의 기본 실행 단위를 재현하고, 이후 운영 자동화의 기준 구현을 만드는 것이다. diff --git a/journey/worklog/260313_nas_본체_go_companyx_sync_구현_및_대표검증.md b/journey/worklog/260313_nas_본체_go_companyx_sync_구현_및_대표검증.md new file mode 100644 index 0000000..c7fc2ee --- /dev/null +++ b/journey/worklog/260313_nas_본체_go_companyx_sync_구현_및_대표검증.md @@ -0,0 +1,74 @@ +--- +tags: [infra, nas, companyx, sync, go, worklog] +--- + +# 260313 NAS 본체 Go Company X Sync 구현 및 대표 검증 + +## 상위 원칙 +- [Infra Project Identity](../../00_Philosophy/00_IDENTITY/Infra_Project_Identity.md) +- [Core Infrastructure Principles](../../00_Philosophy/01_PRINCIPLES/Core_Infrastructure_Principles.md) +- [Operational Guardrails](../../00_Philosophy/02_GUARDRAILS/Operational_Guardrails.md) +- 공통 작성 원칙: [0_VALUE Writing Principles](https://github.com/happybell80/0_VALUE/blob/main/02_Governance/writing-principles.md) + +## 관련 문서 +- [NAS 본체 Go Company X Sync 계획](../plans/260313_nas_본체_go_companyx_sync_계획.md) +- [외부 NAS -> 내부 NAS 컴퍼니엑스 동기화 리서치](../research/260307_external_nas_companyx_sync_research.md) +- [외부 NAS -> 내부 NAS 컴퍼니엑스 실시간동기화 리서치](../research/260312_external_nas_companyx_실시간동기화_리서치.md) + +## 실행 요약 + +- `infra/scripts/go/companyx-sync` 아래에 Go 모듈과 `cmd/companyx-sync` CLI를 추가했다. +- CLI는 `runtime.env`, `secrets.env`를 읽고 DSM API 로그인, 목록 조회, 다운로드, 증분 판정, 상태/실패/요약 기록을 수행하도록 구현했다. +- 증분 기준은 기존 운영 결론대로 `수정시각 + 파일 크기`를 유지했고, 삭제는 자동 전파하지 않고 후보 로그만 남기도록 맞췄다. + +## 검증 + +### 1. 단위 테스트 + +- 실행: `GOCACHE=/workspace/.cache/go-build GOMODCACHE=/workspace/.cache/gomod /workspace/admin/bin/go test ./...` +- 결과: 통과 + +### 2. 대표 폴더 dry-run + +- 실행 대상: `/6.Company X/7. 사진/220308_X코스_5기 발표 사진` +- 옵션: `--dry-run` +- 결과: + - `downloaded=20` + - `failed=0` + - `files_seen=20` + - `downloaded_bytes=6505335` + +### 3. 대표 폴더 실동기화 + +- 실행 대상: `/6.Company X/7. 사진/220308_X코스_5기 발표 사진` +- 로컬 저장 경로: `/workspace/companyx_go_sample_real_20260313` +- 결과: + - `downloaded=20` + - `failed=0` + - `files_seen=20` + - `downloaded_bytes=6505335` + - 생성 파일 수: `20개` + +### 4. 같은 입력 재실행 + +- 같은 대표 폴더와 같은 로컬 저장 경로로 다시 실행했다. +- 결과: + - `downloaded=0` + - `skipped=20` + - `failed=0` + +### 5. 산출물 + +- 상태 파일 생성: + - `/workspace/.sync-logs-go/companyx_sync_state.json` + - `/workspace/.sync-logs-go-real-20260313/companyx_sync_state.json` +- 요약 파일 생성: + - `/workspace/.sync-logs-go/companyx_sync_summary_20260313_094026.json` + - `/workspace/.sync-logs-go-real-20260313/companyx_sync_summary_20260313_094042.json` + - `/workspace/.sync-logs-go-real-20260313/companyx_sync_summary_20260313_094225.json` + +## 현재 판단 + +- NAS 본체에서 Go 기반 Company X sync CLI를 직접 실행할 수 있는 상태가 됐다. +- 기본 동기화 구조를 Go로 재현하는 문제는 닫혔다. +- 다음 문제는 `cron 주기`, `전체 트리 적용`, `운영 로그 포맷 확정` 같은 운영 자동화 기준 고정이다.