콘텐츠로 이동
✍️ 수정가능누구나 고쳐도 됩니다. 고치면 하단 frontmatter의 갱신일·작성자·변경요약을 남겨 주세요.작성 Claude · 2026-06-05 · 제품런타임→위키→마케팅 순 재편·파트별 도식·dev/prod 정정(프론트 둘다 Vercel)

시스템·인프라 아키텍처

코드/시스템 3문서백엔드 코드 아키텍처 = 서버 코드 구조(헥사고날·JPA·JWT) · 프론트엔드 코드 아키텍처 = 화면 코드 구조(FSD·라우팅·IA) · 시스템·인프라 아키텍처(이 문서) = 무엇이 어떻게 연결되고, 어디서 돌고, 어떻게 배포·운영되나(전체 지도 + 서버·CI/CD·시크릿·DB·관측성 — 운영의 SSOT).

디에듀는 사용자가 실제로 쓰는 ① 제품 런타임과, 그것을 만들고 운영하는 ② 위키 시스템·③ 마케팅 에이전트로 이루어진다. 이 문서는 먼저 셋의 전체 지도를 보여주고, 이어서 각 시스템을 차례로 — 개발자 관심사 순서대로 제품 → 위키 → 마케팅 — 파고든다. 시크릿·호스트·키 같은 실제 값은 여기 적지 않고 GitHub Actions Secrets와 raw에만 둔다(이 문서는 구조와 정책의 모양만 다룬다).


1. 전체 시스템 지도

세 시스템이 GitHub(코드)·Cloudflare(엣지)·Slack/Notion(협업)으로 묶인다.

flowchart TB
    subgraph USERS["사용자"]
        U1["강사·학생·학부모"]
        U2["팀원 (개발·기획·디자인·마케팅)"]
    end
    subgraph PRODUCT["① 제품 런타임 (§2) — dev/prod 환경 분리"]
        FE["프론트엔드 · Next.js<br/>▲ Vercel (dev·prod 공통)"]
        BFF["BFF<br/>app/api/v1/[...path]"]
        BE["백엔드 · Spring<br/>🏠 dev=온프레 · ☁️ prod=Lightsail"]
        DB[("MySQL dedu + Redis<br/>🏠 dev=온프레 · ☁️ prod=Lightsail")]
        OBS["관측성<br/>Prometheus·Loki·Grafana"]
        FE --> BFF --> BE --> DB
        BE -.metrics/logs.-> OBS
    end
    subgraph WIKI["② 위키 시스템 (§3)"]
        WC["wiki/ 마크다운 (정본)"]
        SITE["MkDocs → wiki.d-edu.site"]
        RAG["RAG 검색"]
        PIPE["Slack→Issue→PR"]
        WC --> SITE
        WC --> RAG
        PIPE --> WC
    end
    subgraph MKT["③ 마케팅 에이전트 (§4)"]
        MAI["marketing-AI (OpenClaw)<br/>별도 레포"]
        DASH["openclaw-dashboard"]
        MAI --> DASH
    end
    subgraph PLAT["플랫폼·협업"]
        GH["GitHub Actions (CI/CD)"]
        CF["Cloudflare<br/>Pages·Workers·R2·Tunnel"]
        SLACK["Slack"]
        NOTION["Notion (MCP)"]
    end
    U1 --> FE
    U2 --> SITE
    U2 --> SLACK
    GH --> PRODUCT
    GH --> SITE
    CF --> SITE & RAG & DASH
    SLACK --> PIPE
    NOTION -.확정본 이관.-> WC
    MAI -.유입.-> U1
  • ① 제품 런타임 — 프론트(Next.js·Vercel) → BFF → 백엔드(Spring) → MySQL/Redis, 그 위의 관측성(Prometheus·Loki·Grafana)까지. 환경이 둘로 갈린다: 프론트는 dev·prod 모두 Vercel, 백엔드·DB는 🏠 개발=온프레미스 / ☁️ 운영=AWS Lightsail. 코드 구조는 frontend-architecture·backend-architecture, 환경별 배치·배포는 §2(특히 §2 토폴로지 도식).
  • ② 위키 시스템wiki/ 마크다운이 정본, 세 갈래(정적 사이트·RAG 검색·Slack→PR 파이프라인)로 소비된다. §3, 협업 원칙은 ai-collaboration.
  • ③ 마케팅 에이전트 — 유입을 만드는 별도 레포 시스템. §4.

2. ① 제품 런타임 (사용자가 쓰는 것)

사용자가 보는 서비스 그 자체 — 프론트·백엔드·DB·관측성이 도는 곳. dev(개발)와 prod(운영)의 인프라가 다르다: 프론트는 둘 다 Vercel로 띄우되 private 모노레포를 public 미러로 싱크해 빌드하고, 백엔드는 개발=온프레미스 / 운영=AWS Lightsail 인스턴스+DB다.

flowchart TB
  subgraph REPO["📦 idealstudy/mvp-mono (private 모노레포)"]
    BE["mvp-back/ · Spring Boot"]
    FE["mvp-front/ · Next.js"]
  end
  FE -- "main·develop 머지<br/>front-sync-mirror (subtree split→push)" --> TEP["the-edu-project<br/>(public 미러 · Vercel 소스)"]
  TEP -- "Vercel 자동 빌드" --> VPROD & VDEV
  BE -- "main 머지 (back-deploy-aws)" --> LIGHT
  BE -- "develop 머지 (back-deploy-onprem)" --> ONP

  subgraph PRODENV["☁️ 운영 Prod — main"]
    VPROD["▲ Vercel<br/>d-edu.site"]
    LIGHT["AWS Lightsail 인스턴스<br/>api.d-edu.site"]
    PDB[("Lightsail MySQL · dedu")]
    LIGHT --- PDB
  end
  subgraph DEVENV["🏠 개발 Dev — develop"]
    VDEV["▲ Vercel<br/>dev.d-edu.site"]
    ONP["온프레미스 서버 (Docker)<br/>the-edu-staging · apidev.d-edu.site"]
    DDB[("mysql_dev")]
    RD[("theedu_redis")]
    ONP --- DDB
    ONP --- RD
  end
  VPROD -- "API (BFF 프록시)" --> LIGHT
  VDEV -- "API (BFF) · Cloudflare 터널" --> ONP
  LIGHT -- "미디어 presigned" --> S3
  ONP -- "미디어 presigned" --> S3[("☁️ AWS S3 · theedu (dev·prod 공용)")]

읽는 법: 개발자가 mvp-mono에 PR → 머지. develop 머지면 백엔드는 온프레로, 프론트는 the-edu-project(develop)→Vercel(dev.d-edu.site)로. main 머지면 백엔드는 Lightsail로, 프론트는 the-edu-project(main)→Vercel(d-edu.site)로. 프론트는 어느 쪽이든 Vercel이고, 사용자 화면은 API를 같은 환경 백엔드로 보낸다(dev=온프레 터널, prod=Lightsail).

2-1. 한눈에 — 하이브리드 구성

구분 Dev (개발 · develop) Prod (운영 · main)
백엔드 🏠 온프레미스 서버 (Docker) ☁️ AWS Lightsail 인스턴스
프론트 Vercel Vercel
프론트 소스 the-edu-project develop 브랜치 the-edu-project main 브랜치
DB 온프레 mysql_dev (MySQL 8.4, DB명 dedu) Lightsail MySQL dedu
Redis 온프레 theedu_redis 서버 내 컨테이너
백엔드 도메인 apidev.d-edu.site (Cloudflare 터널) api.d-edu.site
프론트 도메인 dev.d-edu.site d-edu.site
Spring 프로파일 staging prod
배포 트리거 develop 머지 main 머지

코드는 모노레포 idealstudy/mvp-mono 한 트리에 백엔드·프론트·위키가 함께 있다(ADR-0003). 2026년 5~6월에 Dev 백엔드를 AWS에서 온프레미스로 내렸다 — 클라우드 비용을 없애고 인프라·데이터를 직접 제어하기 위해서다. 그 배경·과정·거기서 얻은 교훈은 §2-9에 자세히 정리했다.

2-2. 구성 자원

Dev 백엔드 — 온프레미스 (Docker). 사무실 서버 1대 위 Docker 컨테이너. 외부 접속은 Cloudflare 터널(cloudflared)로 — 서버에 공인 IP/포트 개방 없이 안전.

컨테이너 / 자원 역할 비고
the-edu-staging 백엔드 Spring 앱 GHCR 이미지, staging 프로파일, 포트 8080
mysql_dev MySQL 8.4 (DB명 dedu) ~/mysql_dev docker-compose, 데이터=도커 볼륨
theedu_redis Redis (세션·인증코드) ~/redis_dev docker-compose
docker network theedu_backend 세 컨테이너 내부 통신망 external 네트워크 (⚠️ §2-8 리스크)
self-hosted GitHub Actions runner 온프레 배포 실행기 ~/actions-runner
cloudflared 터널 외부→서버 통로 apidev.d-edu.site, ssh.d-edu.site

cloudflared 터널 = 서버가 Cloudflare로 바깥 연결을 걸어두고 외부 요청을 그 연결로 받는 방식. 방화벽 포트를 안 열어도 됨.

프론트엔드 — Vercel (dev·prod 공통). Vercel이 보는 소스는 idealstudy/the-edu-project(public). 모노레포가 이 레포로 미러링(§2-3)되면 Vercel이 브랜치별로 자동 빌드/배포한다 — main → 운영(d-edu.site), develop → 개발(dev.d-edu.site). private 모노레포를 Vercel에 직접 붙이지 않고 public 미러를 거치는 게 핵심.

Prod 백엔드 — AWS Lightsail. Lightsail 인스턴스 + Lightsail MySQL 위에서 백엔드(api.d-edu.site)가 돈다. (과거엔 같은 서버가 nginx+certbot으로 React 정적 빌드까지 서빙했으나, 프론트가 Vercel로 이전되며 Lightsail은 백엔드 전용이 됐다 — 구 방식은 §2-9.)

공용 — AWS S3 theedu. 과제·QnA·게시판 썸네일 같은 미디어 저장소. Dev(온프레)와 운영이 같은 S3를 공유하므로 presigned URL 발급에 AWS 키가 필요하고 이 버킷은 삭제하면 안 된다. 공개/비공개는 targetType으로 S3 키 prefix를 나누고, 공개=CloudFront 고정 URL·비공개=presigned로 내보낼 계획(상세는 backend-architecture §7 미디어).

2-3. 배포 파이프라인 (CI/CD — 코드가 서버로 가는 길)

GitHub Actions로 빌드/배포 분리: Actions가 빌드 → 레지스트리/미러 push → 대상이 pull/build·run.

대상 워크플로 트리거 흐름
Dev 백엔드 back-deploy-onprem.yml develop 머지 + mvp-back/** self-hosted runner 빌드 → GHCR push → 온프레 docker run the-edu-staging헬스 게이트(응답 확인, 실패 시 중단)
Prod 백엔드 back-deploy-aws.yml main 머지 AWS Lightsail 배포
프론트 (dev·prod) front-sync-mirror.yml main·develop 머지 + mvp-front/** git subtree splitmvp-front/만 떼어 → SSH(deploy key)로 the-edu-project 같은 브랜치에 force push → Vercel 자동 빌드/배포(main→prod, develop→dev)

백엔드 빌드 골격: checkout → setup-java(21, temurin) → gradlew clean build -x test → Flyway 검증 → 이미지 빌드 → push → 서버 run.

  • subtree split = 모노레포에서 mvp-front/ 폴더만 별도 히스토리로 뽑아 public 미러에 올려 Vercel이 빌드하게 하는 방식(private 모노레포를 Vercel에 직접 안 붙임).
  • 컨테이너 구성·Compose 개념(Services/Networks/Volumes/Environment, ${VAR} 플레이스홀더), 로컬 IntelliJ 실행·로컬 HTTPS(Caddy 프록시) 가이드도 별도 정리돼 있다.
  • CI/CD 트러블슈팅(React 빌드시점 env 번들 / Spring 설정 우선순위 / Mixed Content / CORS)·시크릿 설정 상세는 [SENSITIVE] raw 격리.

새 환경변수/시크릿 추가는 컨테이너 실행부가 여러 배포 경로(aws·onprem·Jenkins)에 산발해 한 곳만 고치면 누락된다. 절차·active 경로 매트릭스는 §2-5.

2-4. 도메인 · 네트워크 · 쿠키

도메인 가리키는 곳 경유
d-edu.site Prod 프론트 (Vercel)
api.d-edu.site Prod 백엔드 AWS Lightsail
dev.d-edu.site Dev 프론트 (Vercel)
apidev.d-edu.site Dev 백엔드 (온프레) Cloudflare 터널 → 온프레 서버
  • 쿠키/CORS: 프론트(dev.d-edu.site) ↔ API(apidev.d-edu.site)가 형제 서브도메인이라 로그인 쿠키 도메인은 .d-edu.site + SameSite=None; Secure. 프론트는 dev.d-edu.site로 접속해야 쿠키가 붙음(raw *.vercel.app 직접 접속 시 안 붙음). Secure=HTTPS 전송, HttpOnly=JS 접근 차단(XSS), SameSite=교차 사이트 전송 허용 범위 — 형제 서브도메인 인증엔 None이 필요하므로 반드시 Secure와 함께. 로그인 페이지는 Cache-Control: no-store로 이전 사용자 캐시 노출 방지.
  • Vercel 프리뷰 URL: 브랜치별 동적(the-edu-front-git-{branch}-idealstudys-projects.vercel.app)이라 하드코딩 불가 → staging/dev 프로파일의 cors.allowed-origins·auth.frontend.allowed-origins에 와일드카드 https://the-edu-front-git-*-idealstudys-projects.vercel.app 허용(팀 네임스페이스 한정 — 임의 *.vercel.app 금지, prod 제외). WebConfig.setAllowedOriginPatterns + OriginResolver.isValidOrigin* 패턴 지원.

2-5. 환경 · 프로파일 · 시크릿

Spring 프로파일 (⚠️ "develop = dev 프로파일"이 아니다): local · staging(온프레 Dev) · dev(구 AWS, 비활성 잔재) · prod(운영). 활성 프로파일은 이미지가 아니라 배포 워크플로의 -e SPRING_PROFILES_ACTIVE로 주입. application-staging.yamlapplication-dev.yaml이나 OAuth redirect-uri 호스트가 다름(staging=apidev.d-edu.site) — 온프레에 반영되는 건 staging.

Secrets(변수명만, 값은 GitHub Secrets/raw): 환경별(dev/staging/prod) 분리. 공통 EMAIL_*·DB_ADMIN_*·KAKAO_*, 환경별 DB_URL/USER/PASSWORD·JWT_SECRET·REDIS_*·SENS_*·NAVER_*, AI 코치 AI_PROVIDER·OPENAI_API_KEY.

새 시크릿 추가 절차 (active 경로 모두 주입 필수):

경로 파일 주입 위치
AWS (staging/prod, dev 비활성) back-deploy-aws.yml docker run 블록 3곳 모두
온프레 back-deploy-onprem.yml runner docker run 블록
Jenkins Jenkinsfile environment {} + ② .env heredoc 두 곳
~~CodeDeploy~~ scripts/start.sh·appspec.yml 미사용 — 갱신 대상 아님

절차: Secrets 등록 → 위 경로에 -e VAR='${{ secrets.VAR }}' 추가 → application-*.yml에서 ${VAR} 바인딩 → 배포 후 docker inspect|grep VAR 검증.

접근(구조만): Dev 서버=Cloudflare 터널 SSH(공인 IP 없음), Dev DB mysql_dev127.0.0.1:3306 바인딩 → SSH 터널로 접속. Prod=SSH 키(.pem, Google Drive 관리)+퍼블릭 IP. 계정·IAM·prod docker 내부 구조는 [SENSITIVE] raw 격리.

2-6. DB 마이그레이션 (Flyway) + 스키마

Flyway로 스키마 버전 관리, Spring Boot 시작 시 자동 적용, flyway_schema_history로 이력 추적.

  • 네이밍 V{버전}__{설명}.sql(스키마 V1~V999, 시드 V1000~), 디렉토리 db/migration/+db/seed/{local,dev}/.
  • 환경별 검증: Local·Dev(flywayInfo, 실패해도 진행) / Prod(flywayValidate — 실패 시 배포 중단). PROD는 Hibernate ddl-auto: none — DDL은 Flyway로만.
  • 규칙: 한 마이그레이션=한 목적, 롤백 미지원(새 V{n}__rollback_*), 적용된 파일 수정 금지(체크섬 불일치→validate 실패).

DB 스키마 ↔ 도메인 (운영 DDL). MySQL 8(utf8mb4_0900_ai_ci). 스키마 모양만 보존(자격증명 없음). ERD: theEdu (erdcloud).

테이블 도메인 PK / 핵심 컬럼 FK · 제약
member 회원 도메인 (Member) member_id, email UNIQUE, role native enum teacher·student@MapsId로 PK 공유(조인 전략)
connection 회원 도메인 (Member) id, state enum, accepted_date requester_id·recipient_idmember
study_room 스터디룸 도메인 (StudyRoom) id, visibility/modality/subject_type = varchar(50), capacity teacher_idmember
study_room_student 스터디룸 도메인 (StudyRoom) id, state enum student_id·study_room_id → 각 부모
teaching_note_group 수업노트 도메인 (TeachingNote) id, title study_room_idstudy_room ON DELETE CASCADE
teaching_note 수업노트 도메인 (TeachingNote) id, visibility native enum 6단계, view_count study_room_id·teaching_note_group_id (후자 ON DELETE SET NULL)
notification (Notification) id, type enum, is_read, target_id recipient_idmember
  • 공통: 모든 테이블 reg_date/mod_date(BaseEntity AUDIT). 소프트 딜리트 deleted_at은 도메인 코드 레벨(backend-architecture §4).
  • FK는 실제로 건다(JPA @ManyToOne). hard delete용 DB ON DELETE CASCADE/SET NULL은 위 두 곳만, soft delete 연쇄는 앱이 처리(engineering-principles).
  • enum 저장 혼재: member.role·teaching_note.visibility=native enum, study_room.visibility 등=varchar(50)(신규는 varchar 권장).

2-7. 관측성 (모니터링·로깅)

Dev/Prod 동일 아키텍처. 메트릭=Prometheus(pull), 로그=Loki(push, Promtail), 시각화=Grafana.

[메트릭] Actuator(Spring) / Node Exporter(호스트) ──pull── Prometheus
[로그]   앱 로그 ──push(Promtail)── Loki(라벨 기반 인덱스) ──→ Grafana 시각화
  • Prometheus name{labels} value ts, Loki는 전체 인덱싱 X·Label 기반만(성능). Actuator 커스텀(url 라벨 제거로 카디널리티 폭증 방지)+로그 MDC 필터, Micrometer로 JVM·CPU·HTTP·커넥션 수집.
  • Grafana: 컨테이너·서버 관측성 대시보드, P99/P95, RequestID 단위 로그 추적. 컨테이너(Prod) dedu-grafana(:3000)·dedu-loki(:3100). Grafana admin 등 시크릿은 raw에만.
  • 데이터 분석: GA4 이벤트 기반. 대규모 스트림/메시지 큐도 검토 대상.

2-8. 알려진 리스크 · TODO (ADR-0017 §Consequences)

  1. theedu_backend 네트워크 단일 소유자 부재 — 앱은 docker run, mysql/redis는 compose라 주인이 없음. 재생성 시 통신 끊긴 적 있음(장애 1회 incidents) → 최상위 compose 일원화.
  2. 온프레 MySQL 자동 백업 없음 — 볼륨 1곳에만 → 정기 mysqldump + off-box(S3).
  3. 모니터링·알림 부재 — apidev 다운 인지 불가 → Prometheus/Loki/Grafana 재구축.
  4. deploy 롤백 — 헬스 실패 시 알림+중단이 이전 이미지 롤백보다 나음.
  5. back-deploy-aws.yml의 deploy-dev job 잔존 — dev EC2 삭제로 develop 머지 시 실패 → 비활성화 필요.

2-9. AWS → 온프레미스 이전 (왜 · 어떻게 · 교훈)

왜 옮겼나. 기존 Dev 백엔드는 AWS였다 — EC2 프리티어 + RDS MySQL the_edu + ECR, 도메인 api.dev.d-edu.site. 프리티어가 만료되며 EC2/RDS 상시 과금이 시작됐고, IAM·VPC를 직접 손보기에도 제약이 있었다. 마침 사무실에 상시 가동 서버가 있어, Dev를 온프레로 내리면 클라우드 비용을 0으로 만들고 인프라·데이터를 직접 쥘 수 있었다. 운영(Prod)은 안정성 때문에 AWS Lightsail로 그대로 뒀다.

어떻게 옮겼나 (2026-05~06):

  1. 백엔드 → 온프레 Docker: the-edu-staging(Spring) + mysql_dev(MySQL 8.4) + theedu_redistheedu_backend 도커 네트워크로 묶고, 서버에 공인 IP/포트를 열지 않은 채 Cloudflare 터널apidev.d-edu.site·ssh.d-edu.site를 노출했다. 배포는 사무실 서버에 둔 self-hosted GitHub Actions runner가 돌린다.
  2. 프론트 → Vercel: 모노레포를 직접 붙이지 않고 public 미러(the-edu-project)를 거쳐 자동 배포로 전환(§2-2).
  3. 데이터 이관: AWS RDS the_edumysqldump → 온프레 mysql_dev(DB명 dedu). member 266건·study_room 416건 이관·검증.
  4. AWS S3 theedu는 유지: 온프레 백엔드도 미디어 presigned URL에 AWS 키를 계속 쓴다(그래서 deploy에 AWS_* 주입).
  5. 검증 후 dev EC2/RDS 삭제 — 되돌릴 때를 대비해 최종 스냅샷 dev-onpremise-260531을 보관.

무엇을 배웠나(교훈). 비용은 없앴지만, 관리형 클라우드(AWS)가 공짜로 주던 것들을 직접 떠안게 됐다 — 그 빚이 곧 후속 과제(§2-8)다:

  • 네트워크 주인이 없어 한 번 터졌다. 앱은 docker run, DB/Redis는 compose로 따로 띄워 theedu_backend 네트워크의 소유자가 모호했고, 네트워크를 재생성하자 컨테이너 간 통신이 끊겨 dev 백엔드가 502를 뱉었다(incidents 2026-05-31). → 최상위 compose로 일원화가 필요하다.
  • 자동 백업이 사라졌다. RDS 자동백업 대신 데이터가 도커 볼륨 한 곳에만 남는다 → 정기 mysqldump + off-box(S3) 백업이 숙제.
  • 다운을 알 길이 없다. 관측·알림이 없어 apidev가 죽어도 모른다 → Prometheus/Loki/Grafana 재구축(§2-7).

대안 검토(프리티어 2계정 / Dev도 Lightsail / 프론트도 온프레)와 결정의 전체 근거·기록은 ADR-0017에 있다(이 절은 그 결정을 본문으로 풀어 쓴 것).

구 AWS Dev 구성 (삭제됨, 스냅샷 보존):

항목
컴퓨팅 EC2 프리티어
DB RDS MySQL the_edu
레지스트리 ECR (theedu/back)
백엔드 도메인 api.dev.d-edu.site (nginx + certbot)
배포 deploy.yml deploy-dev → SSH로 EC2 docker 교체

구 Prod 프론트: 과거엔 Lightsail이 nginx+certbot으로 React 정적 빌드까지 서빙했다(SSR 대신 정적 빌드로 간 배경은 tech-decisions). 프론트가 Vercel로 이전되며 Lightsail은 백엔드 전용이 됐다.


3. ② 위키 시스템 (팀·LLM이 지식을 쌓는 것)

wiki/ 마크다운이 정본이고, 세 갈래로 소비된다 — ① 정적 사이트, ② RAG 검색, ③ Slack→PR 자동화. 전체를 LLM 하네스(CLAUDE.md·hooks·skills)가 규율한다.

flowchart LR
  WC["wiki/ 마크다운<br/>(5축 v12 정본)"]
  subgraph BUILD["정적 사이트"]
    MK["MkDocs Material<br/>+ wikilinks.py"]
    PG["Cloudflare Pages<br/>wiki.d-edu.site"]
    MK --> PG
  end
  subgraph SEARCH["AI 검색 (AutoRAG)"]
    R2[("R2: wiki/ 콘텐츠")]
    AR["dedu-wiki<br/>bge-m3 + 생성모델"]
    WK["Worker: dedu-wiki-rag"]
    R2 --> AR --> WK
  end
  subgraph PIPE["자동화 (Slack→PR)"]
    S1["stage1 Slack→raw+Issue"] --> S2["stage2 Issue→PR"] --> S3["stage3 merge→changelog"]
  end
  SRC["Slack 멘션 / Notion 확정본 / raw"] --> S1
  S2 --> WC
  WC --> MK
  WC --> R2
  PG -. ✨AI검색 위젯 .-> WK

정적 사이트: 코드와 같은 모노레포라 위키 .md 수정 = 사이트 콘텐츠 수정(별도 CMS 없음).

항목
빌더 MkDocs Material — mkdocs.yml(docs_dir: wikisite_dir: site)
호스팅 Cloudflare Pages 프로젝트 mvp-mono(git 연동) → mvp-mono.pages.devwiki.d-edu.site
빌드 pip install -r requirements.txt && mkdocs build
배포 트리거 develop 머지 시 CF Pages 자동 재빌드(production 브랜치 = develop)
wikilink 변환 .mkdocs/wikilinks.py(경로→제목 치환·basename·ADR 단축형)
빌드 가드 wiki-web-check.yml — wiki PR에서 mkdocs build --strict 선검증

wiki 변경 PR → develop 머지 → 1~2분 내 사이트 반영. 별도 배포 워크플로 불필요(CF Pages가 직접 빌드).

AI 검색 (AutoRAG — 별개 파이프라인): 사이트 검색 위젯 → dedu-wiki-rag Worker(services/wiki-rag) → Cloudflare AI Search 인스턴스 dedu-wiki aiSearch() → 답변+출처. ⚠️ 재색인은 CF 대시보드 설정 — 정적 사이트 자동배포와 분리되어 있어, 위키가 바뀌어도 재색인 안 하면 검색만 stale.

자동화 (Slack → wiki PR): Slack 멘션 → CF Worker wiki-bot(services/wiki-bot) → GitHub repository_dispatchwiki-stage1/2/3.yml(raw 박제→Issue→wiki:컴파일 라벨→Claude가 PR→merge→changelog). 라벨·시크릿·흐름: ADR-0014·ADR-0015.

조회수 집계(services/wiki-views Worker+D1)도 이 사이트에 붙어 popular 리포트를 만든다.


4. ③ 마케팅 에이전트 (유입을 만드는 것)

학생 유입을 만드는 콘텐츠 자동화 시스템. 모노레포와 분리된 별도 레포다.

flowchart LR
  GEN["① 생성<br/>Claude/OpenAI"] --> REV["② 사람 검수 게이트"] --> PUB["③ 채널 발행"] --> ANL["④ 성과 분석"] --> GEN
  PUB --> CH["SNS 채널<br/>릴스·카드뉴스·오픈챗"] --> U["학생 유입"]
  • 레포: idealstudy/marketing-AI (public, TypeScript). 모노레포 흡수 안 함(마케팅 전용·결합도 낮음 — 의도된 결정).
  • 파이프라인: 생성(Claude/OpenAI) → 사람 검수 → 채널별 자동 발행 → 성과 트래킹(OpenClaw 기반).
  • 대시보드: openclaw-dashboard.d-edu.site (Cloudflare Tunnel).
  • 위키 연결: 마케팅 전략·페르소나·캠페인 로그는 위키(5-hubs/hub-mkt)에, 실행 자산은 assets/에. 운영 가이드·콘텐츠 전략은 콘텐츠 자동화 (AI 파이프라인)·channel-playbooks.

관련

backend-architecture · frontend-architecture · version-control · version-control · tech-decisions · ADR-0017 · ADR-0003 · ADR-0014 · incidents