generated from ttipo/project-base
docs(rules): 9단계 부품 — 붙잡힌 메일 막기 · envelope 직접 · 외부 이미지 중계 · 차단 · 설정, 확장 때 옮길 키 · 동시 수 · 설정 기억
CI (Flutter) / Flutter (analyze · test) (pull_request) Successful in 20m7s
CI / Backend (lint · type-check · test · e2e · build) (pull_request) Failing after 7m9s
CI / Frontend (lint · type-check · test · build) (pull_request) Successful in 11m51s
CI / Infra (compose · Dockerfile · nginx) (pull_request) Successful in 22s
CI / 에러 코드 SSOT 동기화 검사 (pull_request) Successful in 10m36s
CI (Flutter) / Flutter (analyze · test) (push) Has been cancelled
CI / Backend (lint · type-check · test · e2e · build) (push) Has been cancelled
CI / Frontend (lint · type-check · test · build) (push) Has been cancelled
CI / Infra (compose · Dockerfile · nginx) (push) Has been cancelled
CI / 에러 코드 SSOT 동기화 검사 (push) Has been cancelled
CI (Flutter) / Flutter (analyze · test) (pull_request) Successful in 20m7s
CI / Backend (lint · type-check · test · e2e · build) (pull_request) Failing after 7m9s
CI / Frontend (lint · type-check · test · build) (pull_request) Successful in 11m51s
CI / Infra (compose · Dockerfile · nginx) (pull_request) Successful in 22s
CI / 에러 코드 SSOT 동기화 검사 (pull_request) Successful in 10m36s
CI (Flutter) / Flutter (analyze · test) (push) Has been cancelled
CI / Backend (lint · type-check · test · e2e · build) (push) Has been cancelled
CI / Frontend (lint · type-check · test · build) (push) Has been cancelled
CI / Infra (compose · Dockerfile · nginx) (push) Has been cancelled
CI / 에러 코드 SSOT 동기화 검사 (push) Has been cancelled
nestjs: 보내기 취소 · 예약 발송 · 외부 이미지 중계 · 차단과 설정 행, 체크리스트에 "붙잡힌 메일을 옮기거나 지우는 새 경로는 readHeldEmails 로 먼저 막는다"와 "발송 제출은 envelope 을 직접 준다"(주지 않으면 엔진이 받지 않는 주소를 말없이 뺀다), 인스턴스를 늘릴 때 옮길 것에 이미지 표의 암호 키 · 이미지 동시 수 · 설정 60초 기억. vue3: 9단계 행 셋(보내기 취소 · 예약, 외부 이미지 · 인쇄, 차단 · 설정)과 밀도 예외의 쓰임(새 토큰 없음). docker: 외부 이미지 중계 때문에 백엔드가 바깥 80 · 443 으로 나가야 하는 것, 도커 망 대역은 사설로, 같은 외부 프록시 뒤에 "내부 주소면 허용" 사이트를 두지 않는 것, 그 경로만의 요청 수 한도(IP 마다 1분 600회 — 뉴스레터 한 통에 이미지가 수십 개). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit was merged in pull request #3.
This commit is contained in:
@@ -124,6 +124,12 @@ sudo docker compose --env-file .env.production logs -f backend
|
||||
`X-Forwarded-For` 를 꾸며 IP 를 바꿀 수 있다. 외부 프록시 IP 는 frontend 가 보는 주소(proxy 네트워크 안)이며 고정해 둔다(`ipv4_address` 등).
|
||||
- **요청 수 한도 `THROTTLE_LIMIT`** (운영 확인 항목 — 기본 1분 100회, `THROTTLE_TTL_MS`): 백엔드는 **경로마다 · 클라이언트 IP 마다** 센다 — 사무실이 NAT 하나로 나가면 모든 직원이 경로마다 한 칸을 나눠 쓴다.
|
||||
"직원 수 × 한 사람의 평소 분당 요청(가장 많이 부르는 경로 기준 — 예: 주소록 목록 `GET /api/contacts`)"보다 넉넉히 정한다. 넘으면 그 경로가 429 `REQ_001` 이다.
|
||||
외부 이미지 중계 `GET /api/mail-images/{token}`(9단계)만은 라우트에서 IP 마다 1분 600회로 따로 정했다(뉴스레터 한 통에 이미지가 수십 개).
|
||||
- **백엔드의 바깥 연결**(운영 확인 항목, 9단계): 외부 이미지 중계는 backend 컨테이너가 바깥 80 · 443 으로 나가 이미지를 받아 온다 — 호스트 방화벽 · 사내 프록시가 막으면
|
||||
이미지 자리가 비어 보인다(다른 기능은 영향 없음). 사설 · 내부 주소로는 백엔드가 스스로 나가지 않는다(SSRF 막기 — 계약 2절 "외부 이미지 보기").
|
||||
그 막기는 사설 대역에 기댄다 — `APP_NETWORK_SUBNET` · `EDGE_NETWORK_SUBNET` 은 사설 대역으로 둔다(mail setup 은 앱 네트워크만 검사한다).
|
||||
서버 자신의 공인 주소로 풀리는 이름은 막지 않는다(공인 주소라서) — 그 요청은 호스트의 80 · 443 에 닿으므로, 같은 외부 프록시 뒤에 "내부 주소면 허용"하는 다른 사이트를 두지 않는다
|
||||
(메일 엔진의 443 은 setup 이 403 으로 막고, 중계는 응답이 그림일 때만 돌려준다 — 2026-10-29 리뷰).
|
||||
- **본문 한도는 `MAIL_ATTACHMENT_MAX_SIZE_MB` + 1MB 이상**, 읽기 시간 제한은 150s 이상. 작으면 백엔드에 닿기 전에 413 이 나고
|
||||
사용자에게는 `FILE_002` 로 보인다 (프론트 nginx 는 자동으로 맞지만 외부 프록시는 직접 맞춘다).
|
||||
- **실시간 알림 `/api/mail-events` 를 흘려보낸다** (운영 확인 항목, 계약 2절 "실시간 알림"):
|
||||
|
||||
Reference in New Issue
Block a user