frindlymap/CLAUDE.md

7.2 KiB
Raw Blame History

Friendly Map — Claude 작업 지침 (인수인계)

이 파일은 이전 대화(claude.ai 프로젝트 "Frindly Map")에서 정한 것을 새 세션에 넘기는 문서다. 세션을 시작하면 먼저 이 파일, README.md, tool/check_modules.py 를 읽고, 작업 전에 아래 원칙을 한 번 읊고 시작한다.

사용자와 일하는 규칙 (1순위, 어기지 말 것)

  • 모든 답변은 한글. 고친 파일은 일부 발췌가 아니라 처음부터 끝까지 완본으로 보여 준다.
  • "목업"이라는 말은 쓰지 않는다 ("화면 설계"라고 한다).
  • 나는 솔루션 개발자다: 구조가 기능보다 먼저다. 화면과 내부를 분리한다.
  • 모듈화 필수. 모듈은 다른 모듈을 고치지 않고 빼고 끼울 수 있어야 한다. tool/check_modules.py 가 의존 방향을 검사한다(새 모듈은 ALLOW 표에 등록).
  • 소스 파일은 300~400줄, 최대 700줄.
  • 모듈별로 시험한다(tool/test_module.sh <모듈>). 시험이 끝난 모듈은 다시 만들지 않고 그 위에 쌓는다.
  • 한 번에 한 플랫폼. 지금은 안드로이드만. 다른 플랫폼은 사용자가 지정할 때 platform_<이름> 모듈만 새로 붙인다.
  • 단계마다 되묻지 말고 합리적으로 정해 진행하고, 결정한 내용은 결과에 적는다. 멈춰 서서 "대기"하지 않는다. (단, 되돌릴 수 없는 파괴적 작업은 먼저 묻는다.)

제품

Android 다크모드 인맥 앱(Flutter/Dart). 옛 "Family MAP" + 카카오톡식 대화. 목적별 명함(개인/회사/학교/그룹·여행/가족) 교환, "어디서 봤지?" 유추, 가계도, 연결 고리, 검색, 자동 연동 추천, 내 정보 숨기기, 가족 모임(촌수·통화 요약·생일/기일 알림).

이미 정한 기술 결정 (바꾸지 말 것)

  • 모든 데이터는 기기에 암호화 저장(안드로이드 SQLCipher). 전화번호는 식별자일 뿐 키 재료가 아니다.
  • 모든 기기가 서버 겸 클라이언트(P2P). 외부 DB(server/)는 암호화된 임시 우편함 + 기준 시각 제공뿐.
  • 12단어 복구 코드, Shamir 조각 기본 5/3(설정으로 조절), 사람 식별은 전화번호 1순위·이름 2순위.
  • 대화는 영구 보관, 1MB/기기 사용률 80% 초과 시 별도 저장(조절 가능). 시각은 1/100초, 충돌 시 먼저 쓴 변경이 앞선다. 고친 명함은 "다시 보내기"에서만 보낸다. 그룹 대화 키는 돌리지 않는다.
  • 가족 모임 데이터(가계도, 생일, 기일, 통화 주제)는 기기 안에만 저장하고 어디로도 보내지 않는다. 전화번호 없는 친척은 local:<id> 번호의 기기 안 전용 사람이다.

구조

  • lib/modules/<이름>/<이름>.dart 가 모듈의 공개 입구(예외: platform_ui.dart, storage_sqlite.dart). 다른 모듈은 입구 파일만 import.
  • 모듈: core, platform, platform_android, storage, keys, sharing, sync, transport, discovery, inference, layout, visibility, kinship, events, groups, work, app, ui.
  • 조립은 모듈 밖: lib/main.dart, lib/composition/android_bootstrap.dart.
  • 안드로이드 전용 플러그인은 platform_android 에서만 import (PLATFORM_ONLY 목록).
  • 화면은 AppScope.of(context).app(FriendlyApp)의 서비스만 쓴다.

상태 (2026-10-26 기준)

  • 맥 podman Flutter(stable) 컨테이너에서 flutter analyze 문제 없음, flutter test 307개 통과(widget_test.dart 포함), 서버(Python) 18개 통과, check_modules.py 통과.
  • 2026-10-26 추가: groups 모듈(그룹 정의·비밀번호 잠금), 주소록 가져오기(flutter_contacts), 설정의 "그룹 · 주소록". 관계망 로드맵 1단계(그룹 계층: 학교 › 초등~대학원, 가족 › 친가·외가·처가·시가·촌수 모름, 회사 › 회사 › 팀) 끝. 2단계(채팅·사람 화면의 "관계 정하기": RelateService, 촌수 맞춰 친가·외가·처가, 촌수 모름 모음, 연결 고리) 끝. 3단계(work 모듈, WorkService: 팀 대화방, 📌 업무 맡기기·정리, 🚨 긴급 호출 즉시 알림) 끝. 4단계(CareerService: 받은 회사 명함 비교로 이직 알림, 확인하면 이전 회사 그룹에 이전 구성원으로 흐리게·새 회사 그룹으로 이동, 지우기·무시) 끝. 로드맵 1~4단계 완료.
  • flutter build apk --debug 성공(app-debug.apk 약 190MB). 컨테이너마다 SDK 34·35, CMake 를 다시 내려받아 15분 넘게 걸린다. 빌드할 때는 시험을 같이 돌리지 않는다(podman 머신 8GB 에서 Gradle 데몬이 메모리 부족으로 꺼진 적 있음).
  • 빌드 경고(아직 빌드를 막지는 않음): nsd_android, flutter_contacts 가 Kotlin Gradle Plugin 을 직접 적용한다. 앞으로 Flutter 판에서 빌드가 실패할 수 있으니, 지원 판이 나오면 nsd 버전을 올린다. geolocator_android 는 deprecated API 를 쓴다는 Note 만 나온다.
  • 확인 안 된 곳: 실제 기기에서 화면 실행과 플러그인 동작(geolocator, call_log, url_launcher, flutter_local_notifications, timezone, sqflite_sqlcipher, nsd, mobile_scanner, sensors_plus, flutter_secure_storage).
  • pubspec.lock 은 이 컨테이너(Flutter stable)에서 풀린 판을 기준으로 올린다(2026-10-26 flutter_contacts 추가 때부터).
  • 빌드 캐시: -v fm-gradle:/root/.gradle -v fm-pub:/root/.pub-cache 를 붙이면 두 번째 빌드부터 빨라진다.
  • 알려진 한계: 윤달 생일 미지원(기일만 지원), 음력 변환 1951~2049년, 통화 기록 읽기(READ_CALL_LOG)는 Play 스토어 제한, WebRTC·앱 잠금·복구 단어 재확인 알림·공유 이미지/PDF 저장·우편함 요청 서명은 미구현. 문자 인증은 서버에 --sms-webhook 연결이 필요.

빌드·시험 방법 (Mac Pro 2013, podman)

Flutter 는 직접 설치하지 않고 컨테이너로 쓴다 (프로젝트는 홈 폴더 안에 있어야 podman machine 이 공유한다):

podman machine start
podman run --rm -it -v "$PWD":/app -w /app ghcr.io/cirruslabs/flutter:stable bash
flutter create --platforms=android --org com.friendlymap --project-name friendly_map .
python3 tool/android_patch.py          # 권한·수신기·desugaring·minSdk 패치 (여러 번 돌려도 같은 결과)
flutter pub get && flutter analyze && flutter test
flutter build apk --debug              # build/app/outputs/flutter-apk/app-debug.apk
  • build/, .dart_tool/ 는 만들어지는 폴더라 저장소에 올리지 않는다(.gitignore). android/ 는 Gitea 에는 올라가 있다.
  • 서버 시험: cd server && python3 -m unittest test_mailbox test_verify.
  • 모듈 경계 검사: python3 tool/check_modules.py.
  • 저장소: http://192.168.88.15:3180/diadmin/frindlymap (Gitea, remote origin). 고친 뒤 커밋해서 Gitea 에 푸시한다.
  • GitLab 에는 올리지 않는다. 단, 하루 한 번 메이저 업그레이드 때만 GitLab 에 올린다(원격은 아직 등록되지 않음).

작업 방식

  • 고치면 해당 모듈 시험을 다시 돌리고, 마지막에 전체 시험과 check_modules.py 를 돌린다.
  • 새 기능은 (1) 순수 모듈 또는 서비스 + 시험 → (2) 화면 순서로, 기존 시험이 끝난 모듈은 고치지 않는다.
  • 끝낼 때 한글로: 무엇이 바뀌었나, 무엇을 돌려 확인했나, 확인 못 한 것은 무엇인가.