yaojingang/GEOFlow는 Docker 한 방으로 띄우는 자체 호스팅 콘텐츠 관리 시스템(CMS)이다. 관리자가 AI 모델·소재(제목/키워드/이미지/지식베이스)·프롬프트를 세팅해 두면, 스케줄러가 태스크를 큐에 넣고 워커가 AI를 호출해 기사를 대량 생성한다. 생성된 글은 초안 → 검토 → 발행 흐름을 타고, 자체 프론트 사이트에 SEO 페이지로 나오거나, 설정한 WordPress·GEOFlow Agent 사이트로 자동 분배된다.
가장 먼저 풀어야 할 개념 — 이 프로젝트의 전제는 "SEO가 아니라 GEO"다. 지금까지 콘텐츠는 구글 검색 순위를 노리고 썼다면, 이제는 사용자가 AI에게 물어볼 때 그 답변 안에 내 브랜드·정보가 인용되는 것을 노린다. 그래서 GEOFlow는 기사마다 llms.txt(AI 크롤러용 안내 파일)·Schema.org 구조화 데이터·깔끔한 마크다운을 함께 뽑고, 어떤 AI 봇이 내 사이트를 긁어갔는지까지 분석한다. 이 "AI에게 잘 읽히는 출력"이 일반 CMS와의 결정적 차이다.
전통적인 콘텐츠 제작은 기자가 자료를 모으고, 글을 쓰고, 데스크가 검토하고, 여러 매체에 배포하는 수작업의 연속이다. GEOFlow는 이 편집국 전체를 하나의 공장 라인으로 묶는다 — 자료 창고(지식베이스), 원고 작성기(AI 워커), 데스크(검토 큐), 배송부(분배 채널)가 컨베이어 벨트로 이어진다.
다만 이 공장에는 엄격한 원칙이 하나 박혀 있다. README가 거듭 강조하듯 "진짜·양질·지속 관리되는 지식베이스"가 맨 앞에 와야 한다는 것 — 자동화가 강할수록 원재료가 쓰레기면 쓰레기를 대량 생산할 뿐이다. GEOFlow는 "정보 오염을 찍어내는 기계"가 아니라 "믿을 만한 콘텐츠를 효율적으로 관리·분배하는 조립 라인"이 되겠다고 문서에 명시해 두었다.
GEOFlow가 트렌딩에 오른 이유는 새로운 알고리즘이어서가 아니다. "AI가 검색을 대체하면 콘텐츠 최적화는 어떻게 바뀌나"라는 시대적 질문에, 당장 docker compose up으로 돌려볼 수 있는 완성형 답을 내놨기 때문이다. 개념(GEO)은 뜨겁지만 실물 도구는 드물던 영역에, 지식베이스·RAG·다중 채널 분배·AI 봇 분석까지 갖춘 오픈소스 시스템이 통째로 등장했다.
| 포인트 | 내용 |
|---|---|
| 정체 | GEO 특화 자체 호스팅 CMS. Laravel 12 + PostgreSQL(pgvector) + Redis 위에, AI 생성·RAG·검토·발행·다중 사이트 분배·분석을 한 몸에 담은 추적 파일 1,533개 규모의 PHP 애플리케이션. |
| 차별점 ① | 출력이 "AI 친화적". 기사마다 SEO 메타·Open Graph·Schema.org JSON-LD·GFM 마크다운과 함께 llms.txt·sitemap.txt를 생성. AI 크롤러가 읽기 좋은 형태로 뽑는다. |
| 차별점 ② | 지식베이스 RAG 내장. 업로드 자료를 규칙+LLM 시맨틱으로 청킹→pgvector 임베딩→기사 생성 시 관련 근거를 [K1] 형태로 인용. "환각 대신 내 자료 기반"을 노린다. |
| 차별점 ③ | 진짜 다중 사이트 분배. GEOFlow Agent(HMAC 서명)·WordPress REST·범용 HTTP API 3개 채널로 한 기사를 여러 목적지에 발행·수정·삭제하고 큐로 관리. |
| 차별점 ④ | AI 봇 트래픽 분석. TrafficClassifier가 GPTBot·ClaudeBot·PerplexityBot 등을 식별해 "어떤 AI가 내 콘텐츠를 얼마나 긁어갔나"를 대시보드로 — GEO의 성과 측정 지표. |
| 제작자 · 라이선스 | 개인 개발자 yaojingang. Apache-2.0(상업적 사용 허용). 커밋 248개·PR 61+·다국어 문서 6종(中·英·日·西·露·葡)의 활발한 저장소. |
AI 답변이 검색을 잠식하면서 "기존 SEO는 죽고 GEO가 온다"는 논의가 2025~2026년 마케팅·개발 커뮤니티의 핫이슈가 됐다. 하지만 대부분은 "이렇게 하라"는 팁 수준이고, 실제로 GEO 콘텐츠를 생산·관리·분배하는 엔진은 상용 SaaS 몇 개뿐이었다. GEOFlow는 그 자리에 오픈소스 + 자체 호스팅 + Apache-2.0으로 들어섰다. "내 서버에서, 내 데이터로, 상업적으로도" 돌릴 수 있다는 점이 개발자·소규모 팀에게 매력적이다.
이 저장소의 힘은 이론이 아니라 즉시 실행 가능한 완결성에 있다. docker compose up -d 한 번에 PostgreSQL(pgvector)·Redis·앱·큐 워커·스케줄러·WebSocket 서버가 한꺼번에 뜬다. 관리자 화면에는 대시보드·데이터 분석·태스크 관리·소재 라이브러리·모델 설정이 이미 다 있고, 백엔드 6개 언어까지 지원한다. "AI 콘텐츠 파이프라인"을 밑바닥부터 짜지 않고 통째로 얻는 셈이라, 학습용으로도 실사용으로도 진입장벽이 낮다.
기술 학습 표본으로도 훌륭하다. Laravel Queue·Horizon·Scheduler·Reverb(WebSocket)·Sanctum(API 토큰)·pgvector·Laravel AI SDK가 한 프로젝트에 실전 배치돼 있다. 여기에 v2.1.1이 보강한 SSRF 방어 게이트웨이·봉투 암호화 자격증명·읽기 전용 보안 감사까지 — "장난감 예제"가 아니라 보안·운영을 신경 쓴 프로덕션급 Laravel 코드가 어떻게 생겼는지 통째로 읽을 수 있다.
냉정히 보면 GEOFlow는 콘텐츠를 자동 생성·분배하는 도구일 뿐, 콘텐츠가 실제로 AI에 인용되도록 보장하지 않는다. 인용 여부는 결국 자료의 진실성·품질·독창성에 달려 있고, README도 이 점을 반복해 못 박는다("자동화가 강할수록 원재료가 쓰레기면 노이즈만 증폭된다"). 또 이 도구는 대량 콘텐츠 생성 기능을 갖고 있어, 오용하면 저품질 페이지를 양산하는 스팸 도구가 될 위험도 있다(제작자는 문서에서 명시적으로 이를 지양한다). 그리고 기본값 보안 이슈(뒤에서 상술)나 대규모에서의 벡터 검색 성능 한계도 있다. 즉 "설치만 하면 GEO가 되는 마법"이 아니라 "믿을 만한 지식베이스를 갖춘 사람이, 콘텐츠 운영을 공정화하는 잘 만든 Laravel 도구"로 보는 게 정확하다.
GEOFlow는 화려한 신기술 없이, 검증된 Laravel 부품만으로 지어졌다. 이게 오히려 강점이다 — 낯선 프레임워크를 배울 필요 없이 "실무 Laravel 앱"의 정석을 그대로 볼 수 있다. 코드 구성비는 PHP 46.7% · Blade 27.6% · CSS 24.0% · JavaScript 1.1%로, 압도적으로 서버 중심이다(프론트는 관리자 화면 Blade + 약간의 Vite/Tailwind). 스택을 ① 웹·프레임워크, ② 데이터·검색, ③ 큐·실시간, ④ AI 연동, ⑤ 프론트·개발도구로 나눠 지도를 그려 보자.
| 영역 | 기술 · 버전 |
|---|---|
| 런타임 | PHP ^8.3(composer 제약) — 단 Docker 이미지와 Boost 가이드라인은 PHP 8.4를 씀(버전 표기 주의, 뒤 함정 참조) |
| 프레임워크 | laravel/framework ^12.0 — 라우팅·컨트롤러·Eloquent ORM·미들웨어·서비스 컨테이너의 표준 |
| 템플릿 | Blade — 관리자 화면 418개 뷰가 전부 Blade. 서버 렌더링 UI |
| API 인증 | laravel/sanctum ^4.3 — /api/v1/*의 Bearer 토큰 + ability(scope) 기반 권한 |
| 패키지 관리 | Composer 2.x(PHP), npm(프론트 자산). 라이선스 Apache-2.0 |
| 구분 | 기술 · 버전 |
|---|---|
| 주 데이터베이스 | PostgreSQL 16 + pgvector(pgvector/pgvector:pg16 이미지) — 기사·태스크·지식베이스 등 관계형 데이터와 임베딩 벡터를 한 DB에 |
| 벡터 컬럼 | knowledge_chunks.embedding_vector vector(3072) — 코사인 거리 연산자 <=>로 유사도 검색(pgvector) |
| 캐시·큐 저장소 | Redis 7(phpredis 클라이언트) — 큐 백엔드, 캐시(단 기본 CACHE_STORE=database) |
| 테스트 DB | SQLite :memory: — 테스트는 인메모리 SQLite로 빠르게(별도 최소 스키마 마이그레이션 존재) |
AI 생성은 느리고 실패할 수 있어, GEOFlow는 전 과정을 큐(비동기 대기열)로 처리한다. 큐 이름은 용도별로 geoflow(생성)·distribution(분배)·theme-replication(테마 복제)·default 넷으로 나뉜다. 프로덕션은 Laravel Horizon(큐 대시보드·감독자)으로, 개발용 Docker는 queue:work 직접 실행으로 워커를 돌린다. 스케줄러(schedule:work)는 매분 geoflow:schedule-tasks를 돌려 실행 시각이 된 태스크를 큐에 넣는다. 태스크 진행 상황은 Laravel Reverb(내장 WebSocket 서버) + Laravel Echo로 관리자 대시보드에 실시간 브로드캐스트된다(admin.tasks 채널).
| 영역 | 기술 · 설명 |
|---|---|
| AI SDK | laravel/ai ^0.6.0 — Laravel 공식 AI SDK. 에이전트·프로바이더 옵션·타임아웃을 표준화 |
| 프로바이더 분기 | OpenAiRuntimeProvider가 URL로 OpenAI(Responses API)·Gemini(v1beta)·OpenAI 호환 게이트웨이(DeepSeek 드라이버 재사용)를 자동 판별 |
| 임베딩 | chat 모델과 별개로 embedding 타입 모델을 등록 → 지식베이스 청크를 벡터화. 배치 크기 기본 1(보수적) |
| 키 보관 | ai_models.api_key를 ApiKeyCrypto enc:v1로 암호화(루트키 = Laravel APP_KEY) |
프론트엔드는 무겁지 않다 — tailwindcss ^4.0 + vite ^7로 자산을 빌드하고, laravel-echo+pusher-js로 Reverb 실시간을 받고, 마크다운 편집은 vditor, 이미지 크롭은 cropperjs를 쓴다. 개발 도구는 laravel/pint(코드 포매터)·phpunit ^11(테스트)·laravel/pail(로그 뷰어)·laravel/sail(Docker 개발)·laravel/boost ^2.4(AI 코딩 에이전트 연동, 뒤에서 상술)로 구성된다.
vector 타입과 유사도 연산자(<=> 코사인 거리 등)를 추가해 준다. GEOFlow는 이 덕분에 관계형 데이터와 벡터를 DB 하나로 관리한다 — 인프라가 단순해지는 대신, 대규모에서는 성능 한계가 있다(뒤 함정 참조).GEOFlow의 핵심 질문은 "어떻게 AI 생성을 안정적인 공정으로 만드나?"이다. 답은 전형적인 Laravel 방식이다 — 무거운 작업을 큐 잡으로 쪼개고, 스케줄러가 시간을 관리하고, 서비스 클래스에 도메인 로직을 몰아넣는다. 전체 지도를 먼저 그리자.
GEOFlow에서 가장 정교한 부분이다. 지식베이스 자료를 임베딩하려면 긴 글을 적당한 조각(청크)으로 잘라야 하는데, KnowledgeChunkSyncService::planChunks()가 3단계 전략을 쓴다. 전략은 관리자 설정 knowledge_chunk_strategy(rule/semantic_llm/auto, 기본 rule)로 고른다.
// KnowledgeChunkSyncService::planChunks() — 3단 청킹 (요지)
1) splitStructuredBlocks() // 코드펜스·제목·리스트·표·문단 인식해 블록으로
→ expandOversizedBlocks() // 너무 큰 블록은 문자 단위로 재분할
→ buildStructuredRuleChunks() // 제목 만나면 flush, 900자(기본) 초과 시 flush
2) // 전략이 semantic_llm/auto 이고, 블록 ≤120개 & 프롬프트 ≤20000자일 때만
buildSemanticChunks() // MarkdownContentWriterAgent(LLM) 호출
// LLM은 원문을 재작성/요약/번역하지 않고, 블록 '인덱스'만 그룹핑
// 출력 스키마: {"chunks":[{"title":"..","block_indexes":[0,1]}]}
3) // 시맨틱 스킵/실패 시 → 규칙 청크로 폴백(semantic_fallback 라벨)
// 임베딩도 실패하면 crc32 해시 기반 256차원 벡터로 대체
여기서 배울 설계는 "LLM에게 창작을 맡기지 않는다"는 절제다. 시맨틱 청킹조차 LLM이 하는 일은 "몇 번 블록과 몇 번 블록을 한 덩어리로 묶어라"는 인덱스 그룹핑뿐 — 실제 텍스트는 언제나 원문에서 그대로 재조립된다. LLM 시스템 프롬프트에 "You only group original block indexes into chunks. Do not rewrite/summarize/translate."라고 못 박혀 있다. LLM이 사실을 바꿔치기할 여지를 원천 차단하는 이 태도는 RAG 파이프라인 설계의 좋은 본보기다.
기사 생성 시 관련 근거를 찾는 KnowledgeRetrievalService::retrieveEvidence()는 네 가지 신호를 가중 합산한다. 벡터 유사도만 쓰면 놓치는 키워드 매칭을 어휘(lexical) 점수로 보완하는 실전 패턴이다.
// 하이브리드 스코어링 (retrieveEvidence)
score = vector*0.45 + lexical*0.35 + title*0.12 + metadata*0.08
// 벡터 점수: pgvector 가능 시 SQL에서 코사인 거리로
ORDER BY embedding_vector <=> CAST(? AS vector) // <=> = 코사인 거리
// pgvector 불가 시 → embedding_json 로컬 벡터 dot product 폴백
더 인상적인 건 근거 충돌 해소다. resolveEvidenceConflicts()가 같은 주제의 상충하는 자료를 감지하면, compareEvidenceAuthority()가 검토 상태(review_status)·위험도(risk_level)·발효일(effective_date)로 권위를 매겨 우선순위를 정하고, 거버넌스 규칙으로 배제할 것은 뺀다. 그리고 본문 생성 프롬프트에 [K1] 형식으로 근거를 인용하라는 지시를 주입한다 — "출처 있는 글"을 유도하는 장치다.
흥미로운 반(反)직관 설계다. GEOFlow의 모든 잡은 tries = 1로, Laravel의 자동 재시도를 꺼 놨다. 대신 재시도를 비즈니스 로직(DB)으로 직접 관리한다. ProcessGeoFlowTaskJob은 실행 시 task_runs 테이블에서 잡을 "클레임"(claim)하고, 실패하면 JobQueueService::failJob이 상태를 기록한 뒤 필요 시 재-dispatch한다.
택배 자동 재배송(큐 재시도)은 편하지만, "왜 실패했는지, 몇 번 시도했는지, 지금 누가 처리 중인지"를 한눈에 보기 어렵다. GEOFlow는 대신 배송 대장(task_runs 테이블)을 직접 쓴다 — 워커가 일감을 집을 때 대장에 "내가(호스트:PID) 이거 처리 중"이라 적고(claim), 실패하면 사유와 함께 기록한 뒤 다시 큐에 올린다. AI 생성처럼 느리고·비싸고·부분 실패가 잦은 작업은 이렇게 상태를 DB로 투명하게 관리하는 편이, 관리자 대시보드에서 추적·재시도·통계를 내기에 유리하다. 코드가 조금 늘어나는 대신 운영 가시성을 얻는 트레이드오프다.
발행된 기사를 외부로 내보내는 DistributionPublisherManager::forChannel()는 채널 타입에 따라 3개 퍼블리셔로 분기한다(match 문). 각 채널은 publish/update/delete/health 동작을 공통 인터페이스로 구현한다.
| 채널 | 동작 방식 |
|---|---|
| GEOFlow Agent | 목적지에 심는 독립 PHP 사이트 패키지. 요청마다 DistributionSigningService가 HMAC-SHA256 서명(method·path·timestamp·nonce·bodyHash)을 헤더에 붙여 위·변조를 막는다 |
| WordPress REST | 표준 /wp/v2/posts API로 글 생성·수정, /wp/v2/posts/{id}로 삭제(휴지통). 이미지는 WordPressMediaSyncService로 미디어 라이브러리에 업로드 |
| 범용 HTTP API | GenericHttpEndpointResolver+RequestFactory+ResponseMapper로 임의의 커스텀 API에 매핑 |
백미는 GEOFlow Agent 목표 사이트 패키지다. DistributionTargetSitePackageBuilder(무려 3,085줄의 최대 서비스 파일)가 채널마다 완전한 독립 PHP 사이트를 ZIP으로 만들어 준다. 그 안에는 프론트 컨트롤러(public/index.php), 홈·상세 페이지, .htaccess+nginx 예시, 그리고 GEO의 핵심인 llms.txt·sitemap.txt·Schema.org JSON-LD(홈=WebSite, 목록=CollectionPage, 상세=Article+Person+Organization+BreadcrumbList)가 들어간다. 발행할 때마다 llms.txt·sitemap이 자동 갱신된다.
v2.1.1은 실질적 보안 릴리스다. 외부로 나가는 모든 HTTP 요청(WordPress 발행, 원격 이미지 등)이 app/Services/Outbound/의 SafeOutboundHttpClient 게이트웨이를 통과한다. 이건 SSRF(서버측 요청 위조)를 막는 장치로, 사설 대역(10/8·127/8)과 클라우드 메타데이터 주소(169.254/16)를 차단하고, DNS를 전수 검증해 IP를 고정하며, 리다이렉트를 통제하고 응답 크기에 상한을 둔다. 자격증명은 ApiKeyCrypto로 암호화(루트키=APP_KEY)하고, JSON-LD는 Js::encode로 </script> 인젝션을 차단한다. php artisan geoflow:security-audit --json으로 읽기 전용 보안 점검도 제공한다.
app/Services가 두뇌 · resources/views가 418개 BladeLaravel을 써 봤다면 구조가 익숙할 것이다 — app/가 애플리케이션 코드, routes/가 URL 지도, resources/views/가 화면, database/migrations/가 DB 스키마다. GEOFlow의 도메인 로직은 대부분 app/Services/GeoFlow/에 몰려 있으니 여기부터 보면 된다.
읽는 순서는 이렇다. ① README.md(전체 그림·운영 철학) → ② routes/web.php+routes/api.php(무엇을 하는 앱인지) → ③ app/Jobs/ProcessGeoFlowTaskJob.php(생성 파이프라인 진입점) → ④ app/Services/GeoFlow/WorkerExecutionService.php(본문 생성) → ⑤ KnowledgeChunkSyncService+KnowledgeRetrievalService(RAG의 심장) → ⑥ DistributionPublisherManager+DistributionTargetSitePackageBuilder(분배). 도메인 로직은 app/Services/GeoFlow, 화면은 resources/views, 스키마는 database/migrations — 이 세 곳이 전부다.
① Horizon은 있지만 개발 컴포즈는 raw queue:work다. Horizon이 설치돼 있어 "Horizon으로 큐를 돌린다"고 단정하기 쉽지만, 개발용 docker-compose.yml의 queue 서비스는 php artisan queue:work 직접 실행이다. Horizon supervisor는 프로덕션 설정에서 쓴다. ② composer.json이 Laravel 스켈레톤 그대로다 — "name": "laravel/laravel", description도 "The skeleton application…"이고 .env.example의 APP_NAME=Laravel이다. 프로젝트 메타가 커스터마이징 안 된 것일 뿐, 코드는 GEOFlow가 맞다(오해 주의). ③ bak/ 폴더는 레포에 없다 — 일부 소스 주석이 bak/api/v1/… 같은 레거시 단일 진입 PHP를 대조용으로 언급하지만 실제 파일은 미포함이다. 역사적 맥락일 뿐이다.
GEOFlow가 학습 표본으로 훌륭한 이유는 실무 Laravel의 큐·스케줄·실시간·API 인증·서비스 설계에, RAG·다중 채널 분배·SSRF 방어까지 한 저장소에 모여 있기 때문이다. 관심사별로 배울 것을 짚어 보자.
이 저장소는 "실무 Laravel 앱은 어떻게 생겼나"의 통짜 교재다. 컨트롤러는 얇게, 도메인 로직은 app/Services에 몰고, 무거운 일은 Job으로, 시간 기반 작업은 Scheduler로, API는 Sanctum 토큰+scope 미들웨어로 보호하는 — Laravel 베스트 프랙티스의 실제 적용을 볼 수 있다. 43개 컨트롤러·84개 서비스·57개 모델의 책임 분리가 어떻게 되는지 따라가 보라.
KnowledgeChunkSyncService+KnowledgeRetrievalService는 RAG의 전 과정을 밑바닥부터 보여 준다 — 문서 청킹(규칙+LLM 시맨틱), 임베딩 생성, pgvector 저장, 하이브리드(벡터+어휘) 검색, 근거 충돌 해소, 인용 지시 주입까지. LangChain 같은 프레임워크에 가려 잘 안 보이던 "RAG 내부"를 SQL과 PHP로 직접 읽을 수 있는 드문 자료다.
주목할 태도는 LLM에게 최소한만 맡긴다는 것이다. 시맨틱 청킹에서 LLM은 텍스트를 재작성하지 않고 블록 인덱스만 그룹핑하고, 본문은 원문에서 재조립한다. 근거는 권위(검토상태·위험도·발효일)로 랭킹한다. "환각을 구조적으로 차단하는" 이 설계는 신뢰할 수 있는 AI 콘텐츠 시스템을 짜려는 사람에게 값진 참고다.
DistributionPublisherManager는 이질적 외부 시스템(WordPress·커스텀 API·자체 Agent)을 공통 인터페이스로 추상화하는 법을 보여 준다. 여기에 HMAC-SHA256 요청 서명(DistributionSigningService), SSRF 방어 게이트웨이(SafeOutboundHttpClient), 봉투 암호화 자격증명까지 — "외부와 안전하게 통신하는" 실무 보안 패턴이 함께 담겨 있다.
추상적으로만 논의되는 GEO가 코드로 어떻게 구현되는지를 볼 수 있다 — 기사마다 llms.txt·Schema.org JSON-LD를 뽑고, TrafficClassifier로 GPTBot·ClaudeBot·PerplexityBot 등 AI 크롤러를 식별해 "성과"를 측정한다. "AI 시대의 콘텐츠 최적화가 실제로 무엇을 하는가"의 참조 구현이다.
docker compose up -d로 전체 스택을 띄우고 /geo_admin에 로그인해 모델 등록 → 소재 준비 → 태스크 생성 3단계를 직접 밟아 본다(README "후관 3단 온보딩"). ② app/Services/GeoFlow/KnowledgeChunkSyncService.php를 열어 청킹 3단 전략이 코드상 어떻게 갈라지는지 읽는다. ③ database/migrations에서 knowledge_chunks의 embedding_vector vector(3072) 컬럼과 pgvector 확장 마이그레이션을 찾아, "관계형 DB가 어떻게 벡터 DB가 되는지" 확인한다.GEOFlow는 무거운 모델을 직접 돌리지 않는다 — AI 생성은 전부 외부 API(OpenAI/Gemini/호환) 호출이므로 GPU가 필요 없다. 필요한 건 PHP 실행 환경과 PostgreSQL·Redis뿐이고, Docker Compose가 이걸 다 묶어 준다.
| 항목 | 요구/설명 |
|---|---|
| 가장 쉬운 실행 | Docker Compose — docker compose up -d 하나로 postgres(pgvector)·redis·app·queue·scheduler·reverb가 뜬다. 기본 포트 18080 |
| PHP | 8.3+(Docker 이미지는 8.4). pdo_pgsql·redis 등 Laravel 상용 확장 필요 |
| 데이터베이스 | PostgreSQL + pgvector(권장 pgvector/pgvector:pg16) — 벡터 컬럼 때문에 pgvector 필수 |
| Redis | 큐·캐시용(Redis 7). 로컬 극단 디버그 시 QUEUE_CONNECTION=sync로 대체 가능(프로덕션 비권장) |
| AI 모델 | 외부 API 키 — 최소 chat 모델 1개, RAG 쓰려면 embedding 모델 1개 추가 등록(GPU·로컬 모델 불필요) |
| 프로덕션 | docker-compose.prod.yml(Nginx + php-fpm) 사용. 웹 루트는 public/(저장소 루트 노출 금지) |
# 1) 개발/데모 — Docker
git clone https://github.com/yaojingang/GEOFlow.git
cd GEOFlow
cp .env.example .env # DB/Redis/APP_URL/ADMIN_BASE_PATH 등 편집
docker compose build
docker compose up -d
# 전면: http://localhost:18080
# 후관: http://localhost:18080/geo_admin/login
# 2) 로컬 PHP (Docker 없이)
composer install --no-interaction --prefer-dist
php artisan key:generate
php artisan migrate --force
php artisan geoflow:install # 최초 空 DB에만 기본 관리자·초기값 시드
php artisan storage:link
# 상주 프로세스(개발): queue:work · schedule:work · reverb:start 각각 실행
① 기본 관리자 계정이 약하다 — .env.example의 기본값이 admin / password다. 프로덕션 배포 전 반드시 GEOFLOW_ADMIN_PASSWORD를 설정해야 한다(생산에서 비우면 최초 1회 랜덤 비번을 로그에 출력). 완화책은 있다 — 관리자 경로가 /geo_admin(변경 가능)이고, 로그인 5회 실패 시 900초 잠금, php artisan geoflow:admin-unlock <user>로 수동 해제. ② PHP 버전 표기가 엇갈린다 — composer는 ^8.3, README 배지도 8.3+이지만 Docker와 Boost 가이드라인은 8.4다("최소 8.3 / Docker 8.4"로 이해). ③ 대규모에서 벡터 검색이 느릴 수 있다 — embedding_vector가 3072차원이라 pgvector의 HNSW/IVFFlat 근사 인덱스 상한(≈2000)을 넘어, ANN 인덱스 없이 전량(brute-force) 코사인 검색을 한다. 지식베이스가 커지면 성능에 유의하고, 필요하면 ≤2000차원 임베딩 모델을 쓰거나 pgvector를 업그레이드해야 한다. ④ 중국어 우선 프로젝트 — 기본 로케일 zh_CN·타임존 Asia/Shanghai다. 후관 다국어 6종을 지원하지만 주석·프롬프트 다수가 중국어다.
Docker로 GEOFlow를 띄우고 /geo_admin에서 모델 등록 → 소재(제목·지식베이스) 준비 → 태스크 생성을 거쳐 첫 기사가 초안→검토→발행되는 전 과정을 눈으로 본다. 목표: "지식베이스 → AI 생성 → 발행" 파이프라인을 몸으로 이해.
발행된 기사의 프론트 페이지 소스에서 Schema.org JSON-LD·Open Graph 메타를 찾고, 사이트의 llms.txt·sitemap.txt를 열어 본다. "AI 크롤러에게 무엇을, 어떤 형식으로 노출하는가"를 확인한다. 목표: GEO의 구체적 출력이 무엇인지 체감.
같은 지식베이스 자료로 knowledge_chunk_strategy를 rule → semantic_llm으로 바꿔 청킹 결과(knowledge_chunks 행)를 비교한다. knowledge_chunk_max_chars도 조절해 본다. 목표: 청킹 방식이 검색 품질에 미치는 영향을 실측으로 이해.
분배 채널로 임의의 웹훅/커스텀 API를 등록하고, GenericHttpEndpointResolver·GenericHttpRequestFactory·GenericHttpResponseMapper가 요청·응답을 어떻게 매핑하는지 코드로 따라간다. 발행이 실제로 그 엔드포인트에 도달하는지 큐·로그로 확인. 목표: 다중 채널 추상화와 큐 기반 분배의 실제를 체득.
app/Support/Analytics/TrafficClassifier.php를 읽고 새로운 AI 크롤러 시그니처(User-Agent 패턴)를 추가한 뒤, 접근 로그가 ai_bot으로 분류되는지 확인한다. 이어 php artisan geoflow:security-audit --json을 돌려 SSRF 게이트웨이·자격증명 암호화 상태를 점검한다. 목표: GEO 성과 측정과 실무 보안 감사를 동시에 경험.
| 주차 | 주제 · 학습 목표 |
|---|---|
| 1주차 Laravel 기초 다지기 | MVC와 서비스 계층. 라우팅·컨트롤러·Eloquent ORM·Blade·미들웨어의 기본. 그리고 "컨트롤러는 얇게, 로직은 서비스로"라는 GEOFlow의 구조를 app/Http/Controllers↔app/Services/GeoFlow로 대조하며 익힌다. |
| 2주차 큐 · 스케줄 · 실시간 | 비동기 파이프라인. Queue·Job·Horizon·Scheduler의 원리, 그리고 GEOFlow의 "앱 레벨 재시도"(tries=1 + task_runs) 설계 의도. Reverb+Echo로 진행 상황을 실시간 브로드캐스트하는 흐름을 ProcessGeoFlowTaskJob부터 따라간다. |
| 3주차 RAG · pgvector | 검색 증강 생성의 내부. 임베딩·청킹 전략(규칙 vs 시맨틱)·pgvector 코사인 검색(<=>)·하이브리드 스코어링. KnowledgeChunkSyncService·KnowledgeRetrievalService를 교재로, "왜 벡터만으로는 부족한가"를 코드로 정리한다. |
| 4주차 GEO · 분배 · 보안 | AI 시대 콘텐츠와 실무 보안. GEO의 출력물(llms.txt·Schema.org·AI 봇 분석), 다중 채널 분배 추상화, HMAC 서명, SSRF 방어·봉투 암호화. 나아가 Laravel Boost로 이 코드베이스를 AI 코딩 에이전트에 연결하는 법까지. |
<=><=>는 코사인 거리 연산자. 관계형 DB 하나로 벡터 검색까지 하게 해 준다.geoflow:schedule-tasks로 실행 시각이 된 태스크를 큐에 넣는다.tries=1로 Laravel 자동 재시도를 끄고, 대신 task_runs DB에 claim·실패를 기록해 재시도·통계를 직접 관리한다. 운영 가시성을 얻는 설계.admin.tasks 채널로 실시간 브로드캐스트한다.llms.txt · Schema.org JSON-LDllms.txt)과 페이지 의미를 기계가 읽게 표현한 구조화 데이터(JSON-LD). GEO의 핵심 산출물로, 발행 사이트마다 자동 생성된다.SafeOutboundHttpClient가 사설·메타데이터 대역을 차단해 SSRF를 막고, 자격증명은 ApiKeyCrypto(루트키=APP_KEY)로 암호화. v2.1.1의 보안 강화 핵심..claude/skills 등을 생성한다.| 도구 | GEOFlow와의 관계 |
|---|---|
| WordPress + AI 플러그인 | 범용 CMS + 애드온. GEOFlow는 GEO·다중 사이트 분배·RAG를 처음부터 내장한 특화형(오히려 WordPress를 분배 목적지로 다룸) |
| 상용 GEO SaaS | 유료·폐쇄형 클라우드 서비스. GEOFlow는 오픈소스·자체 호스팅·Apache-2.0으로 데이터·인프라를 직접 소유 |
| LangChain 등 RAG 프레임워크 | RAG 부품 라이브러리. GEOFlow는 그 위의 완성형 애플리케이션(청킹·검색이 코드에 통합돼 내부를 읽기 쉬움) |
| 일반 Laravel 스타터 | 빈 골격. GEOFlow는 큐·실시간·RAG·분배·보안이 실전 배치된 참조 애플리케이션 |
저장소 · 제품
· GitHub: github.com/yaojingang/GEOFlow (Apache-2.0 · v2.1.1 · 최신 커밋 2026-07-17 · ★2.9k·포크 668)
· 영문 README: docs/readme/README_en.md
· 배포 가이드: docs/deployment/DEPLOYMENT.md
핵심 파일(클론 후)
· app/Jobs/ProcessGeoFlowTaskJob.php — 생성 파이프라인 진입점
· app/Services/GeoFlow/WorkerExecutionService.php — 본문 생성(프롬프트 조립·모델 폴백)
· app/Services/GeoFlow/KnowledgeChunkSyncService.php — RAG 청킹 3단 전략
· app/Services/GeoFlow/KnowledgeRetrievalService.php — 하이브리드 검색·근거 충돌 해소
· app/Services/GeoFlow/DistributionTargetSitePackageBuilder.php — 목표 사이트 패키지(3085줄)
· app/Services/Outbound/SafeOutboundHttpClient.php — SSRF 방어 게이트웨이
배경 지식
· Laravel 공식 문서 · Horizon · Reverb
· pgvector — PostgreSQL 벡터 확장
· llms.txt 제안 · Schema.org Article
· Laravel Boost — AI 코딩 에이전트 연동
① GEO 보장 아님 — 콘텐츠를 생성·분배할 뿐, AI 인용 여부는 자료 품질에 달렸다(README도 "노이즈 증폭 지양"을 명시). ② 기본 관리자 비번 password — 배포 전 반드시 변경(경로 obscurity·5회 잠금·admin-unlock은 완화책일 뿐). ③ PHP 버전 표기 엇갈림 — composer ^8.3 vs Docker/Boost 8.4. ④ pgvector ANN 인덱스 없음 — 3072차원이라 대규모에서 brute-force 코사인(성능 주의). ⑤ 재시도는 앱 레벨 — 잡 tries=1, task_runs로 재시도(큐 자동 재시도 아님). ⑥ Horizon vs raw worker — 개발 컴포즈는 queue:work 직접 실행, Horizon은 프로덕션. ⑦ 중국어 우선 — 기본 zh_CN·Asia/Shanghai, composer.json은 Laravel 스켈레톤 이름 그대로. 수치·기본값은 클론한 소스 기준으로 재확인.