애플리케이션 아키텍처 (AA)
2026-08-17 기록. 현재 문서와 내용이 다를 수 있다. 아래 내용은 당시 상태를 보존하며 수정하지 않는다.
코드와 애플리케이션의 책임을 어떻게 나눌 것인가?
무엇이 무엇을 책임지는가를 그린다. 여기서 처음으로 기술 이름이 나온다.
- 집중하는 것 — Application / Module / Domain
- 담는 것 — Frontend, Backend, Agent, STT 등의 책임과 내부 모듈
- 빼는 것 — EC2 · ECS · Subnet 같은 인프라
- 구체성 — 중간
애플리케이션과 모듈까지만 내려간다. 모듈 하나가 어떤 클래스로 갈리고 엔드포인트가 어떤 경로를 갖는지는 이 층의 관심이 아니다.
한 장에 다 그리지 않는다. 그림 하나는 질문 하나에 답한다. 한 그림이 두 질문에 답하기 시작하면 선이 교차하고, 하나를 이해하려고 나머지 서른 개를 봐야 하게 된다.
| 그림 | 답하는 질문 |
|---|---|
| §1 | 애플리케이션은 몇 개이고 무엇에 기대나 |
| §2 | 서버 모듈은 무엇이고 누가 부르나 |
| §3 | ai 모듈은 무엇이고 무엇에 붙나 |
1. 전체 — 애플리케이션은 몇 개이고 무엇에 기대나
10초 안에 읽혀야 하는 것은 셋이다 — 애플리케이션이 셋이라는 것, 비동기로 갈린 자리가 있다는 것, 그리고 데이터의 주인이 갈려 있다는 것.
| 그림이 말하는 것 | 무엇 |
|---|---|
| 비동기 경계가 있다 | 회의 종료 뒤의 일을 요청 처리와 떼어 놨다. 구현 방식이 아니라 책임 분리다 — 떼어 놨기 때문에 ai 가 죽어도 회의가 안 끊기고, 실패한 것을 다시 태울 수 있다 |
| 수단은 SQS 다 | 런타임 경계를 넘는 곳에만 넣는다. 같은 프로세스 안의 일은 DB 행으로 남는다 |
| ai 만 되부르는 방향이 점선이다 | 서버가 맡기고 ai 가 되묻는다. 그 방향이 있는 이유는 §5 |
| 브라우저에서 ai 로 가는 선이 없다 | 도달 수단 자체가 없다 |
⚠️ 한 저장소 상자 안에 주인이 둘이다. PostgreSQL 인스턴스는 하나인데 heymoa 는 서버가, heymoa_ai 는 ai 가 소유하고 그 둘을 조인하지 않는다 → §4.
2. heymoa-server — 모듈과 부르는 쪽
부르는 쪽과 모듈 사이는 한 줄씩 긋는다. 어느 책임이 어느 모듈을 부르는지가 이 그림이 답하는 것이고, 거기서 빠진 선은 만들 것에서도 빠진다.
인증을 상자로 그리지 않는다. 모든 요청이 지나므로 그려 봐야 아는 게 늘지 않고, 모든 선을 그 상자로 몰면 어느 책임이 어느 모듈을 부르는지가 도리어 안 보인다.
| 그림이 말하는 것 | 무엇 |
|---|---|
agentcontext 만 브라우저에서 오는 화살표가 없다 | 들어오는 것이 heymoa-ai 쪽뿐이다. 사람이 아니라 에이전트가 쓰는 표면이다 |
| 회의 진행이 모듈 넷을 부른다 | 오디오는 transcription, 시작·중지·재개는 note, 종료는 analysis, 회의 중 질의는 agentchat |
| 채팅으로 들어가는 문이 둘이다 | 회의 밖 채팅은 범위를 고르고 회의록을 고칠 수 있고, 회의 중 질의는 지금까지의 전사만 본다 |
analysis 만 비동기 경계 양쪽에 있다 | 종료를 받아 발행하고, 나중에 결과를 받아 쓴다. 한 모듈이 동기와 비동기를 다 지는 자리다 |
| 초대 수락만 로그인 앞에 선다 | 세션이 없는 상태에서 시작하므로 다른 책임과 들어오는 길이 다르다 |
모듈이 무엇을 지나
| 모듈 | 무엇을 책임지나 | 실리는 실행 단위 |
|---|---|---|
auth · user | 로그인 · 세션 · 계정 | api |
workspace · project | 조직과 멤버, 초대, 회의록을 묶는 단위 | api |
note | 회의록과 참가자, 회의 상태 전이 | api |
transcription | 전사 세션과 세그먼트, 오디오 중계 | realtime |
analysis | 회의 종료, 분석 잡, 회의 항목과 근거, 분리 제출과 화자 결과 수용, 기계 매핑 | api |
agentchat | 채팅과 메시지, 도구 승인 기록 | api · realtime |
agentcontext | heymoa-ai 에게 회의 맥락을 준다. 화면이 없는 유일한 모듈 | api |
integration | 외부 도구 연결과 토큰 보관 | api |
notification | 알림 생성과 읽음 처리 | api |
common | 예외 처리 · 보안 설정 · 요청 로깅 | 전부 |
모듈은 presentation · application · domain · infra 넷으로 나뉜다. 자기 상태가 없는 agentcontext 에는 domain 이 없고, 횡단 관심사만 드는 common 에는 application 이 없다.
⚠️ 모듈과 실행 단위는 1:1 이 아니다. agentchat 은 채팅 API 를 api 에서 받고 응답 스트림 중계를 realtime 에서 하며, transcription 은 세션 관리를 realtime 에서 하되 그 결과를 api 가 읽는다. 이 어긋남이 SA에서 실행 단위를 가르는 근거가 된다.
worker가 오른쪽 열에서 사라졌다. 조립이 Spring 밖의 함수로 나갔기 때문이다 → SA. 그래서 이 표에 조립 함수 열이 없다. 그건 Kotlin 코드가 아니고 아무도 import 하지 않는다 — AA 의 단위가 아니다.analysis는 그 함수를 부르는 쪽으로만 남는다.
3. heymoa-ai — 모듈과 바깥
| 그림이 말하는 것 | 무엇 |
|---|---|
| 들어오는 문이 셋이다 | 채팅은 런타임으로, 분석은 두 갈래로 — 서버가 직접 맡기는 길과 비동기 경계를 지나는 길이 따로 있다 |
| 맥락은 갖고 있지 않고 되묻는다 | 그래서 맥락을 복제하지 않아도 된다 |
| Redis · S3 · 메일로 가는 선이 없다 | ai 는 그것들을 쓰지 않는다. 없다고 확인한 것이다 |
| 도구 실행만 승인을 기다린다 | 쓰기 도구는 사람 승인을 거친다 → 에이전트 채팅 |
의존 방향이 CI 에 걸려 있다 — 웹 표면은 조립을 모르고, 안쪽 계층은 프레임워크를 모르며, 외부 호출 계층은 에이전트 프레임워크를 모른다. 셋 중 하나라도 어기면 빌드가 깨진다.
4. 소유 규칙
한 데이터를 두 곳에서 쓰지 않는다. 두 곳이 쓰면 순서와 잠금을 코드가 관리해야 하고, 그건 실행 단위를 늘릴수록 지킬 수 없는 약속이 된다.
| 무엇 | 쓰는 곳 | 왜 |
|---|---|---|
| 전사 세션 · 세그먼트 | transcription | 오디오를 받는 쪽이 그대로 쓴다 |
| 회의 상태 | note | 종료·중지의 조건부 갱신이 한 곳에 모여야 한다 |
| 화자 결과와 매핑 | analysis | 벤더 결과를 받는 쪽이 쓴다 |
| 조립 잡의 진행 상태 | analysis | 조립 함수는 DB 를 안 본다. 발행과 완료 수용이 둘 다 api 쪽이다 |
| 회의록 간 관계 | analysis | heymoa 안의 테이블이다. 어느 모듈이 질지는 노드·엣지 타입이 정해져야 정한다 |
| 분석 결과 · 임베딩 · 체크포인트 | heymoa-ai | 자기 데이터베이스를 따로 갖는다 |
| 그 밖의 업무 데이터 전부 | api |
⚠️ 업무 데이터베이스와 에이전트 데이터베이스는 다른 것이다. 같은 인스턴스 안에 있어도 한 쿼리로 두 쪽을 조인하지 않는다. 조인이 생기는 순간 두 애플리케이션이 스키마 하나를 공유하게 되고 따로 배포할 수 없게 된다.
5. 의존 방향
서버와 AI 만 서로를 부른다. 브라우저는 heymoa-ai 의 주소를 알지 못하고, 그 규칙을 실제로 강제하는 것은 문서가 아니라 CA의 보안그룹이다.
AI 가 서버를 되부르는 방향은 의도된 것이다 — 에이전트는 회의 맥락을 갖고 있지 않고 권한 판단도 하지 않는다. 필요한 것을 그때그때 물어보게 두면 맥락을 복제하지 않아도 된다.
실행 단위를 가르는 방법이 스프링 프로필에서 빌드 단위로 바뀌면서, "realtime 이 인증 모듈을 부르지 않는다" 같은 약속이 적지 않으면 컴파일이 안 되는 것이 된다. 리뷰로 지키던 것을 빌드가 지킨다.
6. 아직 책임자가 없는 것
제품이 요구하는데 어느 모듈도 지지 않는 것들이다. 화면을 먼저 그려도 그 아래가 서 있지 않으면 만들 수 없다.
| 무엇 | 무엇이 먼저인가 |
|---|---|
| 회의 관리 매니저 — 종료 임박 · 주제 이탈 · 결정 충돌 · 개입 설정 | 넷 중 셋이 담을 자리부터 없다 → 회의 중 에이전트 |
| 회의 중 항목 갱신 — 안건·결정·액션이 회의 중에 자란다 | 갱신 시점과 저장 자리 → 회의 중 에이전트 |
| 프로젝트 페이지 — 타임라인 · 회의록 간 의존 · 전역 액션과 결정 | 무엇을 관계로 볼지가 안 정해졌다 |
| 화자 확인 화면 | 종료 후 흐름이 요구하는데 IA 트리에 그 화면이 없다 |
| 그래프 투영을 어느 모듈이 지나 | 위가 정해져야 정할 수 있다. 지금은 어느 모듈에도 없다 |
| 요약 완료 알림을 어느 모듈이 만드나 | analysis 가 notification 을 부르는 의존이 없다 |
| 회의 전 구간 — 안건 · 맥락 · 일정 | 담을 자리가 없다 |
| 요약 항목의 담당자와 마감일 · 전사에 화자 표시 | 〃 |
| 온보딩과 녹음 약관 동의 · 회원 탈퇴 · MCP · 알림 설정 | 〃 |