8000 GitHub - a205-banggoot/banggoot-public: [SSAFY 2학기 공통 프로젝트 - 최우수상] AR 원격 하자 검수로 임대차 분쟁을 예방하는 임대차 관리 서비스 · GitHub
[go: up one dir, main page]

Skip to content

About

[SSAFY 2학기 공통 프로젝트 - 최우수상] AR 원격 하자 검수로 임대차 분쟁을 예방하는 임대차 관리 서비스

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

방긋: AR 원격 하자 검수로 임대차 분쟁을 예방하는 임대차 관리 서비스

방긋 (Banggoot)

SSAFY 15기 A205팀 공통 프로젝트

임대차(집주인 / 세입자) 관계의 전 주기를 영상 및 사진 증거와 승인 절차로 기록하여, 하자 책임 및 원상복구 범위 같은 분쟁의 근거를 남기는 서비스입니다.

  • 세입자: 모바일 앱으로 집 연결 / 입주 검수(AR 스캔) / 하자 요청 / 월세 납부
  • 집주인: 모바일(현장) + 웹 대시보드(관리)로 집 / 하자 / 월세 / 계약 관리
  • 관리자: 웹 백오피스로 소유권 인증 / 분쟁 / 통계 관리

1. Introduction

전세/월세 계약이 끝난 뒤 가장 흔한 분쟁은 "이 하자가 입주 전부터 있었는가, 세입자 책임인가"를 증명할 자료가 없다는 것입니다.

방긋은 입주 시점 AR 스캔으로 집의 3D 도면과 하자 위치를 기록합니다. 거주 중 발생하는 하자 / 수리 / 월세 납부는 승인 절차와 함께 시간순으로 기록되어 퇴거 시 원상복구 범위를 객관적 근거로 정산할 수 있게 합니다.

  • 팀 레포: lab.ssafy.com/s15-webmobile1-sub1/S15P11A205
  • 백엔드는 신규 MSA(services/)와 성능 비교 대조군인 기존 모놀리식(legacy/banggoot)을 두었습니다.

2. Key Features

도메인 설명
회원 / 인증 소셜 로그인(카카오 / 구글), 포트원 본인인증, JWT 기반 인가
집 등록 카카오 우편번호 주소 검색, 소유권 증빙 업로드
입주 관계 초대코드 / 주소 기반 집주인-세입자 연결
계약 관리 계약서 업로드 / 계약 조건 관리
입주 검수 Unity 기반 AR 스캔으로 3D 도면 생성, 도면 위 하자 위치 핀 기록
실시간 화상 검수 WebRTC(SFU)로 집주인 / 세입자가 함께 검수하며 도면 포인터를 실시간 공유
하자 관리 사진 기반 하자 등록, 온디바이스 AI 모델로 하자 유형 자동 분류(19종)
수리 하자별 수리 요청 / 승인 흐름
월세 / 관리비 납부일 D-day, 증빙 업로드, 통계 시각화
퇴거 재스캔으로 입주 전/후 도면 비교, 원상복구 범위 산정
알림 FCM 푸시(연체 경고 / 수리 승인 등), 인앱 알림함
채팅 집주인-세입자 실시간 채팅
관리자 소유권 인증 심사, 분쟁 처리, 통계 대시보드

3. Tech Stack

분류 기술
Backend
Frontend (Web)
Frontend (Mobile)
AR
AI / ML
Real-time / Storage
Infra / CI-CD

4. Usage

각 컴포넌트의 상세 실행 방법(환경 변수, 로컬 인프라 기동 순서, 빌드 / 배포 절차 등)은 exec/ 디렉토리의 포팅 매뉴얼 을 참고하세요.

# 프론트엔드 (frontend/를 루트로 진행)
cd frontend
pnpm install
pnpm dev                     # 웹 + 모바일 동시 실행
pnpm --filter web dev        # 웹만 (http://localhost:3000)
pnpm --filter mobile start   # 모바일만 (Expo 개발 서버)

# 백엔드 MSA (services/)
cd services
./gradlew :inspection:bootRun

# 백엔드 Legacy (backend/banggoot)
cd backend/banggoot
./gradlew bootRun

# 실시간 통신 서버 (rtc-server/)
cd rtc-server
go run .

# 오브젝트 스토리지 서버 (storage-server/)
cd storage-server
go run .

5. Directory Structure

S15P11A205/
├── frontend/                 # ⭐ 프론트 모노레포 루트 (Turborepo + pnpm)
│   ├── apps/
│   │   ├── mobile/             # Expo + Expo Router + NativeWind (세입자 전체, 집주인 현장, AR)
│   │   └── web/                # Next.js App Router (집주인 대시보드 / 관리자)
│   └── packages/              # 웹 / 모바일 공유 로직 (api / schema / constants / tokens ...)
├── ar-unity/                 # ⭐ Unity AR 스캔 / 도면 생성 엔진 (모바일에 라이브러리로 임베드)
├── services/                 # ⭐ 백엔드 MSA (Gradle 멀티모듈, Spring Boot)
│   ├── common/                # 서비스 공통 라이브러리
│   ├── identity/              # 회원 / 인증
│   ├── property/              # 집 / 계약 / 입주 관계
│   ├── inspection/            # 검수 / 하자 / 도면 / 파일 / RTC 연동 / 수리
│   ├── analysis/              # 하자 이미지 분석 연동
│   ├── chat/                  # 채팅
│   ├── notification/          # 알림(FCM)
│   └── mlops/                 # 모델 서빙 / 재학습 파이프라인 연동
├── backend/banggoot/         # 신규 Legacy 빌드 트리 (services와 동일 스펙, 대조군)
├── legacy/banggoot/          # 성능 비교용 기존 모놀리식 원본 (수정 금지)
├── ai-service/               # ⭐ 하자 분류 AI 모델 (MobileNetV3, 학습, 추론 및 검증 코드)
├── rtc-server/               # ⭐ Go + Pion WebRTC 시그널링 서버 / SFU
├── storage-server/           # Go 내용 주소 오브젝트 스토리지 (재학습 이미지 보관)
├── contracts/                # 서비스 간 JSON Schema 계약
├── infra/                    # Jenkins, Kafka, 모니터링, 로컬 개발 인프라, k6 벤치마크
├── nginx/                    # 리버스 프록시 설정
├── docs/                     # 문서
└── exec/                     # 상세 실행/포팅 매뉴얼

6. Architecture

방긋 아키텍처

  • MSA vs Legacy 병행: services/는 신규 마이크로서비스이고 legacy/banggoot은 기존 모놀리식을 그대로 보존한 성능 비교 대조군입니다. 두 스택은 같은 Spring Boot/Java 버전을 쓰지만 Kafka는 MSA에만 연결되어 있습니다. infra/benchmark의 k6 시나리오로 처리량과 지연시간을 비교합니다.
  • 실시간 검수: 화상 통화와 도면 포인터 공유는 각 클라이언트가 rtc-server(Pion 기반 SFU)에만 연결되고 클라이언트끼리 직접 연결되지 않는 구조입니다.
  • AI 파이프라인: 하자 사진은 온디바이스(모바일, onnxruntime) 또는 서버(analysis/mlops)에서 MobileNetV3 모델로 분류됩니다. 재학습용 원본 이미지는 storage-server에 1년간 보관 후 만료됩니다.
  • 자세한 다이어그램과 시퀀스는 다음 문서를 참고하세요.

7. 하자 분류 모델과 MLOps

세입자가 검수 중 찍은 사진을 기기에서 분류해 하자 종류를 제안하고, 사용자가 확정한 라벨을 모아 모델을 다시 학습합니다.

7.1 모델

DACON 도배 하자 데이터셋(4,249장) 등을 정리해 학습한 MobileNetV3-Large 단일 라벨 분류기입니다.

구조 / 파라미터 mobilenetv3_large_100 · 4.226 M
입력 [1, 3, 224, 224] float32 NCHW, RGB (EXIF 회전 → 짧은 변 256 resize → 중앙 224 crop)
출력 19개 logit → softmax(logit / T), T = 2.0725 (temperature scaling)
배포 형태 ONNX 16.9 MB — ai-service/models/bangoot_mobilenet_v1/
CPU 추론 batch 1 median 29 ms (실측)

성능 — 선택 지표는 평가 support가 있는 12개 클래스의 macro F1입니다.

지표 Validation Test
macro F1 (12 클래스) 0.6843 0.7824
top-1 0.8110 0.8346
top-3 0.9449 0.9577
ECE (15 bins) 0.0638 0.0619
n 254 260

test가 validation보다 높은 것은 일반화가 더 잘 돼서가 아닙니다. 차이 0.0982 중 91%가 단 두 클래스(석고수정·들뜸) 에서 나오고, 그 클래스들의 평가 표본은 45장입니다. macro F1은 모든 클래스를 같은 무게로 평균하므로 12장이 F1을 반 점씩 흔듭니다. 두 수치를 같은 추정의 두 번의 뽑기로 보고, 낮은 쪽에 기대를 맞춥니다. 근거는 MODEL_CARD.md.

ONNX 이식 검증 — PyTorch 대비 최대 절대 logit 차이 1.87e-05, argmax 완전 일치. 전처리는 논쟁이 아니라 측정으로 정했습니다. bicubic→bilinear 교체는 확률을 0.035만 바꾸고 결정을 바꾸지 않아 플랫폼 기본 파이프라인을 쓰도록 허용했고, 중앙 crop 생략은 top-1 확률을 0.86 → 0.61로 떨어뜨려 필수로 남겼습니다(학습이 프레임 중앙 87.5%만 본 탓 — 보간 문제가 아니라 화각 문제입니다).

7.2 왜 온디바이스인가 — 서버 폴백이 없다

추론 경로에 서버가 없습니다. 번들이 없으면 제안이 없을 뿐 검수는 그대로 돌아가고, 비행기 모드에서도 제안이 뜹니다. 실행 공급자는 listSupportedBackends()가 실제로 돌려준 목록에서만 고르고(qnn → nnapi → xnnpack → cpu), 세션 생성이 실패하면 한 단계씩 물러섭니다. 컴파일된 것과 실제로 쓸 수 있는 것이 다르기 때문입니다 — onnxruntimeUseQnn을 켜면 목록에 qnn이 나오지만 해당 AAR에 libQnnHtp.so가 없어(Qualcomm 라이선스) dlopen으로 죽는 사례를 실측했습니다.

7.3 재학습 한 바퀴

flowchart TD
    A["앱: 사진 촬영"] -->|"① 기기에서 ONNX 추론"| B["제안 표시"]
    B --> C["사용자 확정/수정"]
    C --> D["inspection: 확정 저장"]
    D -->|"② Kafka"| E["mlops: 동의 확인 → 사진 fetch → sha256 대조"]
    E -->|③| F["storage-server(사진) + training_samples(라벨)"]
    F -->|"④ 100건이면 회차 개설"| G["개발 PC GPU: 파인튜닝"]
    G -->|"⑤ 측정값만 보고"| H{"mlops 승격 판정<br/>Δmacro F1 > 0.029 ?"}
    H -->|"예"| I["번들 승격"]
    H -->|"아니오"| J["REJECTED — 샘플 반환, 200·300장에서 재시도"]
    I -->|"⑥ 앱이 다음 실행에 manifest 확인"| A
L DEF5 oading

bangoot_autotrain.py가 회차를 발견해 학습까지 자동으로 잇습니다(systemd timer + --once 권장). 판정 로직은 한 줄도 가져오지 않았습니다 — 승격은 서버가 정합니다.

7.4 조용히 깨지는 것을 막는 장치들

이 파이프라인의 위험은 대부분 "성공한 것처럼 보이면서 틀리는" 종류입니다.

위험 왜 조용한가 장치
노이즈를 개선으로 오인 100장은 기존 train 약 2,800장에 3.5% 추가입니다. 그 정도 개선은 seed 노이즈(σ 0.015~0.029)에 묻힙니다 승격 가드 Δ > 0.029. 대부분의 회차가 REJECTED로 끝나는 것이 설계이며, 거부 이력이 곧 요구사항의 성능 로그입니다
모델이 자기 예측을 재학습 19클래스 → (대상 × 손상) 매핑은 되돌릴 수 없습니다. 유추해 채우면 자기 출력을 정답으로 배웁니다 사용자가 제안을 고치면 세부 클래스를 한 번 더 묻습니다. 건너뛴 샘플은 COARSE_ONLY로 적재만 하고 학습에서 제외
바뀐 사진에 옛 라벨 확정 이후 사진이 교체돼도 적재는 성공합니다 적재 시 선언 체크섬과 실제 sha256 대조, 불일치는 폐기
라벨 id 재번호 배포된 모델의 출력 id가 곧 라벨 레지스트리입니다. renumber하면 설치된 모든 번들의 의미가 바뀝니다 미지의 클래스가 보이면 사진을 한 장도 받기 전에 회차 중단
움직이는 holdout 홀드아웃이 같이 자라면 비교가 아무것도 재지 않습니다 새 샘플은 전부 train. val.csv·test.csv 불변
스크립트가 가드 우회 우회했다는 사실이 아무 데도 안 남습니다 스크립트는 측정값만 보고, 판정은 mlops

동의는 opt-in이고, 동의하지 않은 사용자의 사진은 내려받지도 않습니다 — 받아 두고 나중에 지우는 것은 동의를 받은 것이 아닙니다. 원본 보관 1년, 철회 시 즉시 삭제하고 라벨 행만 감사용으로 남깁니다. 사진은 DB에 넣지 않고 storage-server(Go, 외부 의존성 0)가 내용 주소 저장소로 받습니다 — 키가 곧 sha256이라 중복 제거·위변조 감지·불변 캐시가 따라옵니다. 게이트웨이에는 노출하지 않습니다.

📄 docs/ondevice-defect-classification.md · HOW_THE_MODEL_CLASSIFIES.md


8. AR 검수 — 왜 Unity + AR Foundation인가

AR은 네이티브에서만 동작합니다. 그래서 프론트엔드는 앱 2개 + AR 엔진 1개로 나뉩니다. 로직(머리)은 packages/에서 공유하고, 화면(몸)은 웹·모바일로 분리하며, AR 스캔만 Unity로 격리합니다.

apps/mobile (RN)  ──임베드──▶  ar-unity (Unity as a Library)
      │                              │
      │  startInspection(launchJson) │  AR Foundation ─▶ ARCore
      │                              ▼
      ◀────────  result.json  ───────┘   (도면 폴리곤 + 하자 핀 + 사진 경로)

경계는 result.json 계약 하나입니다. Kotlin 브리지(InspectionUnityModule)가 Unity Activity를 띄우고 경로를 돌려주며, Expo config plugin(withInspectionUnity)이 :unityLibrary 포함·소스 복사·Activity 선언을 자동 배선합니다.

8.1 타 플랫폼 확장 용이성 — 이것이 결정적이었다

AR Foundation은 Android의 ARCore와 iOS의 ARKit을 하나의 공통 API로 다룹니다. 앱 스크립트가 직접 부르는 것은 ARSession · ARPlaneManager · ARRaycastManager · ARAnchorManager · AROcclusionManager 같은 추상 컴포넌트이고, 벤더 SDK를 직접 호출하는 곳이 없습니다.

iOS를 추가할 때 바뀌는 것
Packages/manifest.json com.unity.xr.arkit 추가 (현재 arcore 6.5.0 + arfoundation 6.5.0 + xr.management 4.5.4)
XR Management 설정 iOS 빌드 타깃에 ARKit loader 등록
Assets/Inspection/Scripts/ 전체 변경 없음 — 평면 감지·raycast·앵커·CPU 이미지 캡처가 모두 AR Foundation API
익스포트 ExportAndroidLibrary 옆에 iOS 프레임워크 익스포트 경로 추가

즉 확장 비용이 앱 로직 재작성이 아니라 provider 패키지 교체와 빌드 배선에 갇힙니다. RN용 AR 라이브러리를 직접 쓰거나 ARCore SDK를 네이티브로 호출했다면 이 경계가 코드 전반에 번졌을 것입니다.

8.2 개발 용이성 — 씬이 아니라 코드가 진실

HUD(InspectionHud · HudMinimap)는 uGUI를 코드로 조립합니다. 씬 파일을 수동 편집하지 않으므로 변경이 git diff로 읽히고 리뷰가 됩니다. 디자인 토큰은 @banggoot/tokens에서 DesignTokens.cs로 생성돼 웹·모바일·AR이 같은 값을 씁니다. 에디터 자동화도 코드로 있습니다 — InspectionBuildExporter(배치 익스포트), AutomaticWallGeometryVerifier · AutomaticWallOccupancyVerifier(스캔 기하 검증), InspectionFontPipeline(SDF 폰트 아틀라스 재생성).

8.3 유지보수 — 트래킹 품질과 실패 처리를 우리가 통제한다

  • Depth 우선 raycast, Plane 대체. Environment Depth 지원 기기는 TrackableType.Depth를 먼저 쓰고, 미지원·실패 시 PlaneWithinPolygon으로 물러섭니다. 기기 편차를 정책으로 흡수합니다.
  • 좌표는 상대 좌표로만 저장합니다. ARCore 월드 Pose는 raycast 직후 메모리에서만 쓰고, 도메인 모델에는 Root Anchor 기준 localPosition = root.InverseTransformPoint(worldPose.position)로 변환해 넣습니다. 세션이 바뀌어도 핀 사이의 관계가 유지됩니다.
  • 프로세스가 죽어도 결과가 남습니다. RN 프로세스가 Unity 전체화면 중 종료되면 promise는 잃지만 result.json은 <documentDirectory>/inspections/<sessionId>/<roomCode>/에 남고, 화면이 마운트될 때 복구를 제안합니다.
  • 버전을 고정합니다. Unity·Gradle·AGP·Kotlin·AR Foundation·ARCore 조합을 검증한 뒤 핀으로 박습니다. 최신을 무조건 따라가지 않습니다.

⚠️ 현재 지원 범위는 ARCore(Android) 전용입니다. iOS·웹에는 AR 스캔이 없습니다. 위 표는 확장이 설계상 열려 있다는 뜻이지, 이미 검증됐다는 뜻이 아닙니다. 또한 ARCore Required + Vulkan 조합이 minSdk 29를 강제합니다 — API 26까지 내리려면 Vulkan을 빼고 OpenGLES3만 써야 합니다.

📄 ar-unity/README.md · docs/[arcore] unity build test.md


9. 멀티스테이지 빌드와 스케일링 대비

9.1 이미지 구조

저장소의 모든 이미지가 멀티스테이지입니다. 마지막까지 단일 스테이지로 남아 있던 infra/jenkins/Dockerfile도 COPY --from으로 전환했습니다 — 이전에는 apt-get으로 docker CLI를 넣느라 GPG 키링·apt 메타데이터·의존 패키지가 최종 레이어에 남았는데, 실제로 필요한 것은 실행 파일 두 개뿐입니다.

이미지 build stage runtime stage
services/ (7 서비스 공용) eclipse-temurin:25-jdk eclipse-temurin:25-jre-alpine
rtc-server, storage-server golang:1.26-alpine alpine:3.20 (static, -s -w strip, uid 10001)
frontend node:22.14-alpine node:22.14-alpine + Next standalone
infra/jenkins docker:29.7.2-cli, docker/compose-bin:v2.40.3 jenkins/jenkins:2.568.2-lts-jdk21

서비스 이미지는 7개가 아니라 1개입니다. SERVICE build arg로 어떤 모듈을 빌드할지 정합니다.

docker build --build-arg SERVICE=identity -t banggoot-identity services/

베이스 태그는 전부 고정했습니다. jenkins/jenkins:lts 같은 움직이는 태그는 다시 빌드하는 순간 조용히 올라가고, 플러그인 호환이 깨지면 원인이 우리 커밋에 없어 되짚기 어렵습니다.

9.2 빌드 캐시 — 무엇이 문제였나

배포는 서버에서 매번 docker compose up -d --build로 빌드합니다. 그런데 Dockerfile은 멀티모듈 빌드라 COPY . .로 컨텍스트 전체를 복사해야 합니다(settings.gradle이 모든 모듈을 include하므로 대상 모듈만 복사하면 "Configuring project ':X' without an existing directory" 로 죽습니다).

그래서 소스가 한 줄만 바뀌어도 COPY . .가 무효화되고, 그 뒤의 RUN ./gradlew가 통째로 다시 돕니다. 이 레이어 안에 Gradle 홈이 들어 있으므로 매 배포마다 Gradle 배포판(9.5.1)과 모든 의존성을 처음부터 다시 내려받았습니다.

BuildKit 캐시 마운트가 그 항목만 레이어 무효화 밖으로 빼냅니다.

RUN --mount=type=cache,target=/root/.gradle,sharing=locked \
    ./gradlew :${SERVICE}:bootJar --no-daemon -x test

모듈별 build.gradle을 먼저 복사하는 흔한 수법은 쓰지 않았습니다. 서비스가 하나 늘 때마다 Dockerfile을 고쳐야 하고, 고치는 걸 잊으면 그 서비스의 이미지 빌드에서야 드러납니다. 캐시 마운트는 그 함정 없이 같은 효과를 냅니다. sharing=locked는 빌드가 동시에 돌 때 Gradle 캐시가 깨지지 않게 합니다.

9.3 실측 — 재배포 빌드가 37초에서 7초로

services/identity를 Dockerfile과 같은 명령(:identity:bootJar --no-daemon -x test)으로 빌드하며, 회차마다 git archive로 pristine 소스 트리를 새로 펼쳐 COPY . .가 무효화된 상태를 재현했습니다.

회차 Gradle 홈 대응하는 Dockerfile 시간
cold-1 비어 있음 before (캐시 마운트 없음) 39 s
cold-2 비어 있음 before 35 s
warm-1 이전 회차 캐시 재사용 after (캐시 마운트 적중) 8 s
warm-2 〃 after 6 s

중앙값 37 s → 7 s · 약 81% 감소(5.3배). cold 회차마다 323 MB를 새로 내려받았고, 로그에 Downloading https://services.gradle.org/distributions/gradle-9.5.1-bin.zip이 남아 Gradle 배포판 자체가 매번 재다운로드됐다는 점이 확인됩니다. 서비스가 7개이므로 services/common 하나만 고쳐도 이 비용이 7번 발생했습니다.

측정 조건과 한계. macOS arm64 / JDK 25.0.1 / Gradle 9.5.1 / Spring Boot 4.1.0에서 Docker 밖에서 잰 값입니다. 측정 환경의 Docker 데몬이 레지스트리 메타데이터를 받지 못해(호스트 네트워크는 정상, 데몬만 차단) 이미지 빌드를 끝까지 돌릴 수 없었습니다. 그래서 캐시 마운트가 실제로 보존하는 항목 — Gradle 배포판 + 의존성 캐시 — 만 분리해 쟀습니다. 베이스 이미지 pull과 레이어 export 같은 Docker 고유 비용은 두 경우 모두에 동일하게 더해지므로, EC2에서의 절대 시간은 이보다 크고 감소 비율은 이보다 보수적으로 나타납니다. 재현: ./gradlew :identity:bootJar --no-daemon -x test를 빈 GRADLE_USER_HOME과 재사용 GRADLE_USER_HOME으로 각각 실행.

9.4 조용히 깨지는 빌드 불변식은 테스트로 잠갔다

DockerfileBuildGuardTest는 깨져도 조용한 것만 지킵니다.

  • chmod +x gradlew가 COPY . . 뒤에 오는가 — gradlew는 git에 100644로 들어 있어 COPY가 실행 비트를 도로 지웁니다. 앞에 두면 리눅스에서만 exit 126이고, Windows 개발 머신에서는 COPY가 0755로 들어가 통과하므로 EC2에서만 드러납니다.
  • .dockerignore가 .env*를 거르는가 — 빠지면 실제 시크릿이 이미지 레이어에 남습니다. 빌드는 성공하고 앱도 정상 동작합니다.
  • Jenkins 이미지에 docker · docker compose · curl이 실제로 있는가 — COPY --from 경로가 틀려도 이미지는 멀쩡히 만들어지고 다음 배포에서야 터집니다. curl은 notifyMattermost가 bare로 부르므로 없으면 모든 파이프라인의 알림이 함께 죽습니다. 그래서 빌드 시점에 RUN docker --version && docker compose version && curl --version으로 검증합니다.

9.5 향후 스케일링을 위한 대비

대비 지금 상태 스케일 아웃 시
서비스 = 배포 단위 7개 서비스가 이미지 1개 + SERVICE arg로 갈라집니다. Jenkins 잡은 banggootServicePipeline(service: 'x') 한 줄 트래픽이 몰리는 서비스만 replica를 늘립니다. 새 서비스는 모듈 + 잡 한 줄
DB 격리 인스턴스는 공유하되 스키마·롤로 격리(svc_identity 등). 마이그레이션이 롤 비밀번호를 TCP 인증으로 검증한 뒤 앱을 올립니다 롤 경계가 이미 그어져 있어 서비스별 물리 분리가 스키마 이동으로 끝납니다
비동기 경계 아웃박스 패턴 + Kafka 12토픽/12 DLQ. analysis는 HTTP 엔드포인트가 없는 Kafka 전용 워커 워커를 옆으로 늘리는 것이 곧 처리량. 소비자 없는 이벤트는 EventWiringCompletenessTest가 잡습니다
빌드 파이프라인 Skip if unchanged가 자기 디렉터리 + common + 빌드 방식을 정하는 파일(Dockerfile·compose·.dockerignore·gradlew)을 함께 봅니다 서비스가 늘어도 무관한 잡이 돌지 않습니다. watchPaths로 저장소 밖 의존(mlops ↔ ai-service/models)까지 선언
배포 직렬화 전역 lock('banggoot-deploy-global') — 단일 EC2에서 동시 빌드가 자원을 다투지 않게 호스트가 늘면 lock을 서비스 단위로 쪼갭니다. 캐시 마운트의 sharing=locked가 이미 그 상황을 견딥니다
관측 Prometheus · Grafana · Loki · Alloy · cAdvisor. 컨테이너별 CPU·메모리로 독립 스케일링을 수치로 봅니다 어느 서비스를 늘릴지 근거가 이미 쌓입니다

모놀리식(legacy/banggoot)을 성능 비교 대조군으로 남겨 쓰기 지연·읽기 처리량·장애 격리·독립 스케일링 4축을 같은 자로 잽니다. 벤치마크 수치를 거짓으로 만드는 요인(fallback 유출, 없는 id 조회, 회차 간 잔여 데이터 등)에는 각각 테스트·임계값·초기화 장치를 걸어 뒀습니다 — 📄 infra/benchmark/README.md


10. Testing

영역 방법
백엔드 MSA (services/) ./gradlew test : JUnit5 + AssertJ + Mockito 기반. Kafka가 필요한 테스트는 기본 실행에서 kafka 태그로 제외되며 브로커를 띄운 뒤 ./gradlew :common:kafkaTest로 별도 실행합니다.
백엔드 Legacy ./gradlew test (backend/banggoot, legacy/banggoot)
웹 (frontend/apps/web) pnpm test (Vitest)
모바일 (frontend/apps/mobile) pnpm test (Jest + jest-expo + React Native Testing Library)
rtc-server / storage-server go test ./... : rtc-server는 실제 Pion PeerConnection으로 RTP 포워딩 / 데이터채널 릴레이까지 검증하는 통합 테스트 포함
AI 모델 (ai-service) python verify_bundle.py : 번들 무결성 / 모델 복원 / 추론 검증
E2E / 부하 테스트 docs/testing/inspection_backend_e2e.py, infra/benchmark의 k6 시나리오(MSA vs Legacy 처리량 / 지연시간 비교)

각 기능의 설계 근거와 TDD 노트는 docs/testing/ 아래 문서를 참고하세요.

11. Contributors

A205 Team Members

👑천창현 황승기 안서진 윤영광 정지수 임찬혁
Backend Backend Frontend Frontend AI/Data Infra

About

[SSAFY 2학기 공통 프로젝트 - 최우수상] AR 원격 하자 검수로 임대차 분쟁을 예방하는 임대차 관리 서비스

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

0