Add NAS native Go Company X sync docs

This commit is contained in:
heejae 2026-03-13 18:48:51 +09:00
parent 5f6cbccdc2
commit 3b20c0ef5f
2 changed files with 242 additions and 0 deletions

View File

@ -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 -> 내부 저장소` 동기화의 기본 실행 단위를 재현하고, 이후 운영 자동화의 기준 구현을 만드는 것이다.

View File

@ -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 주기`, `전체 트리 적용`, `운영 로그 포맷 확정` 같은 운영 자동화 기준 고정이다.