yona

21세기 협업 개발 플랫폼
- Official Site: http://yona.io
- 이 저장소는 Yona(Play Framework/Java/Ebean 기반의 설치형 프로젝트 협업 플랫폼)를 Kotlin + Spring Boot + JPA(Hibernate) 스택으로 새로 옮겨 쓴 프로젝트입니다. 화면 구조·데이터 모델·동작 방식은 legacy Yona와 최대한 동일하게 유지하면서, 런타임과 빌드 도구만 현재 JVM 생태계로 교체하는 것을 목표로 합니다.
Yona란?
- Git/SVN/Mercurial 저장소가 내장된 설치형 이슈 트래커 + 게시판 + 코드 리뷰 플랫폼
- 네이버/네이버랩스를 비롯해 여러 기업·공공기관에서 수년간 실사용되며 다듬어진 애플리케이션
주요 기능
- 서비스 종료나 데이터 종속 걱정 없는 설치형
- 프로젝트 기반의 유연한 이슈 트래커와 게시판 — 프로젝트 간 이슈 이동, 서브 태스크, 본문 변경이력, 이슈 템플릿
- 내장 코드 저장소 — Git / SVN / Mercurial 3종 선택 가능, 온라인 수정·커밋, HTTP(S)뿐 아니라 SSH로도 접근 가능, 프로젝트 멤버 전용 접근 제어, Git LFS 지원
- 블록 기반 코드 리뷰 — 코드 블록 단위 리뷰 스레드, 리뷰 점수
- 그룹(조직) 기능 — 그룹 단위 이슈/게시글 통합 관리, 그룹 프로젝트·멤버
- 한글 기반 — 프로젝트 이름 및 그룹 이름에 한글 사용 가능
- 계정 보안 — LDAP 지원, 소셜 로그인(OAuth2), 2단계 인증(TOTP 앱 + WebAuthn/패스키), 백업 코드, 로그인 브루트포스 방지, 알려진 기기 인식
- 저장소 접근/서명 — SSH 공개키 등록, GPG 커밋 서명 검증, 저장소별 Deploy Key
- API 및 자동화 — 범위(scope) 지정 가능한 개인용 API 토큰(PAT), 서드파티 앱을 위한 OAuth2 Authorization Server(Dynamic Client Registration 포함), MCP(Model Context Protocol) 서버 내장 — Claude 등 AI 에이전트가 OAuth2로 인증해 이슈/PR/위키에 직접 접근 가능 (아래 참고)
- 감사 로그 — 주요 보안/관리 이벤트 추적
- 다른 서비스·다른 Yona 인스턴스로의 마이그레이션(GitHub 프로젝트 Import 등)
추가 읽을거리
Yona (New): 무엇이 바뀌었나
| Old Yona | New Yona | |
|---|---|---|
| 언어 | Java / Scala 템플릿 | Kotlin |
| 프레임워크 | Play Framework 2.x | Spring Boot |
| ORM | Ebean | JPA / Hibernate |
| 뷰 엔진 | Scala Template(.scala.html) |
Thymeleaf |
| JDK | Java 8 | Java 21 |
| 지원 DB | MariaDB(기본) 또는 H2(내장형) | MariaDB / PostgreSQL / MySQL / SQL Server / CUBRID / H2(내장형) |
| 지원 VCS | Git / SVN | Git / SVN / Mercurial |
포팅 진행 상황과 legacy 대비 의도적으로 남겨둔 차이점은 docs/parity/index.md,
docs/TEMPLATE_BACKLOG.md, docs/coverage/index.md에 기록돼 있습니다.
이식 과정에서 legacy에는 없던 기능도 새로 추가됐습니다:
- Mercurial 저장소 지원(기존 Git/SVN 2종에서 3종으로)
- 2단계 인증(TOTP 앱 + WebAuthn/패스키) 및 로그인 보안 강화(브루트포스 방지, 알려진 기기 인식)
- GPG 커밋 서명 검증, 저장소별 Deploy Key
- 범위 지정 API 토큰(PAT) 및 OAuth2 Authorization Server(서드파티 앱 연동, Dynamic Client Registration)
- MCP(Model Context Protocol) 서버 내장 — 자세한 내용은 아래 참고
- 감사 로그(보안/관리 이벤트 추적)
프론트엔드 위젯: Vue 3 Web Components로 점진 전환
일부 화면 위젯은 jQuery 기반 vanilla JS에서 Vue 3 Web Components로
옮겨가고 있습니다. 각 위젯은 하이브리드 어댑터 방식으로 적용됩니다 — 기존 vanilla yona.*.js
파일이 대상 엘리먼트가 새 커스텀 엘리먼트인지 확인해 맞으면 그 컴포넌트에 위임하고, 아니면 원래
로직을 그대로 씁니다. 그래서 화면 템플릿을 건드리지 않는 위젯(Typeahead/Pagination 등)도 있고,
템플릿의 태그 하나만 바뀌는 위젯도 있습니다.
- 위젯 소스:
yona-projects/components(Vue 3 SFC를 네이티브 커스텀 엘리먼트로 빌드, 위젯마다 자체 Shadow DOM을 가짐) - 빌드 산출물은
src/main/resources/static/lib/yona-vue-widgets/에 그대로 커밋돼 있어서, components 저장소를 따로 클론/빌드하지 않아도 이 저장소만으로 바로 실행됩니다. - 현재 적용된 위젯(17개): Dialog, Toast, Popover, LoginDialog, Switch, Dropdown, Typeahead, Pagination, Attachments, ScrollElevator, PageSlide, ReviewForm, 마크다운 도움말(HelpMarkdown), 라벨 편집기 3종(새 라벨 폼, 카테고리 편집 다이얼로그, 라벨 편집 다이얼로그)
- 화면 전반에서 공유하는 마크다운 에디터 프래그먼트는 이번 전환 범위에서 제외했습니다 — 에디터의 ``가 Shadow DOM에 완전히 캡슐화돼 있어, 그 프래그먼트를 참조하는 기존 JS(첨부파일 드래그드롭, 임시저장 등)가 여러 화면에서 깨지기 때문입니다. ReviewForm 안에서 쓰는 마크다운 에디터는 그 공용 프래그먼트와 무관한 별개 인스턴스라 이 문제가 없어 전환 대상에 포함했습니다.
AI 에이전트 연동 (MCP 서버)
yona는 MCP(Model Context Protocol) 서버를 내장하고 있어, Claude 같은 AI 에이전트가 이슈·PR·위키 페이지를 직접 조회·조작할 수 있습니다.
- 엔드포인트는
/mcp(Streamable HTTP) 하나이며,spring-ai-starter-mcp-server-webmvc가@Tool로 표시된 메서드를 자동으로 노출합니다(IssueMcpTools/PullRequestMcpTools/WikiMcpTools). - 인증은 OAuth2(yona 자체가 Dynamic Client Registration을 지원하는 OAuth2 Authorization
Server 역할을 겸함) 또는 범위 지정 API 토큰(PAT) 둘 다로 가능합니다 — 도구 호출마다
McpScopeGuard가 해당 토큰/토큰의 스코프로 실제 접근 가능한지 재검사합니다. - API 토큰 발급/스코프 관리는 사용자 설정 화면(API 토큰)에서, OAuth 앱 등록은 사용자 설정 화면 (OAuth 앱)에서 할 수 있습니다.
요구 사항
- JDK 21
- 운영/테스트 DB 중 하나: MariaDB(기본), PostgreSQL, MySQL, SQL Server, CUBRID, H2(설치 없이 바로 써보기)
빌드 & 실행
# Linux / macOS
./gradlew bootRun
# Windows
gradlew.bat bootRun
테스트:
./gradlew test # Linux/macOS
gradlew.bat test # Windows
데이터베이스 선택
기본 Spring 프로파일은 mariadb입니다. 다른 DB로 운영하려면 spring.profiles.active를
아래 중 하나로 지정하세요(src/main/resources/application.yml에 각 프로파일의 접속 설정이 있습니다).
로컬 개발용 MariaDB/PostgreSQL 컨테이너는 저장소 루트의 docker-compose.yml로 바로 띄울 수 있습니다.
| 프로파일 | DB |
|---|---|
mariadb (기본값) |
MariaDB |
postgres |
PostgreSQL |
mysql |
MySQL |
mssql |
Microsoft SQL Server |
cubrid |
CUBRID |
h2 |
H2(내장형) — Docker/별도 서버 설치 없이 파일 기반으로 바로 실행(./data/h2/yona) |
java -jar yona.jar --spring.profiles.active=postgres
# 설치 없이 바로 써보기(H2)
java -jar yona.jar --spring.profiles.active=h2
통합 테스트는 실제 Docker 컨테이너(Testcontainers) 기준으로 5개 서버 DB 전부 검증돼 있습니다 (H2는 내장형이라 컨테이너가 필요 없습니다). 특정 DB로만 테스트를 돌리려면(동시에 두 개 이상 돌리면 gradle 빌드 출력 디렉터리가 꼬이니 항상 한 번에 하나씩만 실행하세요):
./gradlew test -Dyona.it.db=postgres # mariadb|postgres|mysql|mssql|cubrid|h2
운영 환경 설정 (특히 Windows)
물리 저장소(git bare repo, svn repo, git-lfs 객체, 첨부파일 업로드)를 디스크의 어느 경로에 둘지는
아래 4개 설정으로 제어합니다. 기본값이 /tmp/yona/... 형태의 유닉스 절대경로이기 때문에,
Windows에서 운영할 때는 반드시 아래 값들을 Windows 경로로 재설정해야 합니다.
| 설정 키 | 기본값 | 용도 |
|---|---|---|
yona.git.base-dir |
/tmp/yona/git |
Git bare 저장소 루트 |
yona.svn.base-dir |
/tmp/yona/svn |
SVN 저장소 루트 |
yona.lfs.base-dir |
/tmp/yona/lfs |
Git LFS 객체 저장 루트 |
yona.upload.base-dir |
${yona.data:data}/uploads (상대경로) |
첨부파일 업로드 루트 |
설정 변경 방법
application.yml에 직접 지정 (가장 확실한 방법)yona: git: base-dir: "D:/yona-data/git" svn: base-dir: "D:/yona-data/svn" lfs: base-dir: "D:/yona-data/lfs" upload: base-dir: "D:/yona-data/uploads"Windows 경로도 슬래시(
/)로 적으면 됩니다(자바가 두 구분자를 모두 인식합니다). 백슬래시를 쓸 경우 YAML 이스케이프 때문에\\로 두 번 써야 하므로, 슬래시 표기를 권장합니다.실행 시 커맨드라인 인자로 지정 (
application.yml을 건드리지 않고 배포별로 다르게 줄 때)java -jar yona.jar --yona.git.base-dir=D:\yona-data\git --yona.svn.base-dir=D:\yona-data\svn --yona.lfs.base-dir=D:\yona-data\lfs --yona.upload.base-dir=D:\yona-data\uploads-D로 JVM 시스템 프로퍼티를 주는 방식(java -Dyona.git.base-dir=D:\... -jar yona.jar)도 동일하게 동작합니다.환경 변수 — Spring Boot의 relaxed binding 규칙상
yona.git.base-dir에 대응하는 환경 변수명은YONA_GIT_BASEDIR처럼 하이픈(-)이 빠진 형태입니다(다른YONA_*설정들처럼 밑줄로 치환되는 게 아님). 헷갈리기 쉬우므로 1번(yml) 또는 2번(커맨드라인 인자) 방식을 권장합니다.
Windows에서 Fork(하드링크 복제) 사용 시 전제 조건
프로젝트 Fork는 저장소를 실제로 복사하지 않고 파일시스템 하드링크로 복제합니다
(ProjectServiceImpl.cloneHardLinkedRepository). 이 방식이 정상 동작하려면:
yona.git.base-dir(및yona.svn.base-dir) 전체가 하나의 NTFS 볼륨(드라이브) 안에 있어야 합니다. 서로 다른 드라이브 간에는 하드링크가 불가능해 Fork가 실패합니다(폴백 복사 없음, 의도적 설계).- 저장 위치가 NTFS여야 합니다. FAT32/exFAT로 포맷된 외장 디스크나 일부 네트워크 드라이브는 하드링크 자체를 지원하지 않아 Fork가 실패합니다.
서버 관련 설정
- LDAP:
application.yml의ldap섹션 - 소셜 로그인(OAuth2):
application.yml의spring.security.oauth2섹션 - WebAuthn(패스키):
application.yml의yona.security.webauthn.relying-party-id/relying-party-name— 배포 도메인에 맞게 반드시 재설정해야 합니다(기본값은localhost). - 2단계 인증(TOTP) 암호화 키: 환경변수
YONA_TOTP_ENCRYPTION_PASSWORD/YONA_TOTP_ENCRYPTION_SALT를 배포 전 반드시 설정해야 합니다. 기본값은 저장소에 커밋된 placeholder 값(yona-totp-dev-only-password등)이라, 프로덕션에서 이 값을 그대로 쓰면 모든 사용자의 TOTP 시크릿이 소스코드로 노출된 키로 암호화되어 2단계 인증이 실질적인 보호 효과가 없어집니다. 이 값을 설정하지 않고 부팅하면 서버 로그에[SECURITY WARNING] TOTP encryption key is still the committed placeholder default에러가 남으니, 배포 파이프라인에서 이 로그를 감시하는 것도 권장합니다(TotpEncryptionKeyGuard). - SSH(Git/Mercurial 접근, SSH 키 등록): SSH: 시스템 sshd 연동
- GPG 커밋 서명 검증, Deploy Key, API 토큰/OAuth2 앱은 별도 설정 없이 기본 활성화되어 있으며, 사용자별 설정 화면에서 바로 쓸 수 있습니다.
Google Analytics
legacy와 동일하게 Google Analytics 트래킹 스크립트가 실제로 구현되어 있습니다 (
GlobalModelAttributeAdvice가sendYonaUsage모델 속성을 채우면templates/site/layout.html이 그 값에 따라 GA 스크립트를 렌더링합니다).다만 기본값은 legacy(
application.send.yona.usage = true, 기본 켜짐)와 반대로 꺼짐(false) 입니다. 켜고 싶다면application.yml에서 아래 항목을true로 설정합니다.yona: analytics: send-usage: true
마이그레이션
- GitHub 프로젝트를 이 저장소로 Import하는 기능을 제공합니다(
MigrationService,MigrationApiController).github.client.id/github.client.secret/github.allow.migration설정으로 활성화합니다. - Yona의 별도 백업/이관 도구인 Yona Export는
이 저장소(Kotlin/Spring 이식판) 대상으로는 아직 포팅되지 않았습니다 — 진행 상황은
docs/parity/index.md참고.
Contribution
- 코드 기여의 기준이 되는 브랜치는
next입니다(main은 오래된 스냅샷이라 실제 개발은 전부next에서 이루어지고 있습니다 — 저장소의 기본 브랜치도next입니다). - 저장소를 fork한 다음
next브랜치를 기준으로 작업하신 다음next브랜치로 pull request를 보내주세요.
운영 가이드
legacy Yona의 설치/운영 문서를 yona 기준으로 다시 쓴 것들이다 — docs/guide/:
- 설치
- 실행 및 재시작
- 실행 옵션
- 업그레이드
- 백업 및 복구
- 메일 알림 설정
- 소셜 로그인 설정
- SSH: 시스템 sshd 연동
- 트러블슈팅
- 설정 레퍼런스(application.yml)
- 시스템 요구 사항
- 사용자 가이드 — 화면별 사용법
- 기술 문서 — 권한 규칙, JS 모듈 구조, 첨부파일/웹훅/마크다운 내부 동작 등
영문 버전은 legacy와 동일하게 별도 위치에 있다 — 운영 문서는 docs/*.md,
사용자 가이드는 docs/userManual/, 기술 문서는 영문 원본이
있던 5개(markdown/mailbox/watch/label-typeahead/name-validation)만 docs/technical/에
있다(나머지 11개는 legacy도 한글 전용이었다).
서비스로 상시 구동할 때 참고할 systemd 유닛 예시와 DB 튜닝 샘플은 support-script/에 있다.
legacy Yona(Yobi/nFORGE 포함)의 설계 스펙·비전 문서·릴리즈노트는 원문 그대로
docs/legacy-reference/에 보존되어 있다.
코드 구조 개요
docs/parity/index.md, docs/TEMPLATE_BACKLOG.md, docs/coverage/index.md에 legacy yona 대비
이식 진행 상황과 의도적으로 남겨둔 차이점들이 기록되어 있습니다.
문서 작성 규칙: docs/parity/, docs/coverage/, docs/golden/는 docs/yona-wiki/ 방식(인덱스는
표만, 상세 서술은 개별 파일)을 따릅니다. 신규 티켓/배치/발견 사항을 기록할 때는 인덱스 표 아래에
서술을 이어 쓰지 말고, 해당 디렉터리의 새 파일(tickets/.md, batches/.md,
findings/.md 등)을 만든 뒤 인덱스에 표 한 줄과 링크만 추가하세요.
라이선스
yona는 Apache License 2.0으로 제공됩니다. 서드파티 구성 요소 고지는 NOTICE, 원 프로젝트 기여자 명단은 AUTHORS를 참고하세요.
yona
Yona is a web-based project hosting software.
- Official Site (original project): http://yona.io
- This repository (
search5/yona) is a rewrite of the original Yona (a self-hosted project collaboration platform built on Play Framework/Java/Ebean) onto a Kotlin + Spring Boot + JPA (Hibernate) stack. The goal is to keep screen structure, data model, and behavior as close as possible to legacy Yona while replacing only the runtime and build tooling with the current JVM ecosystem.
What is Yona?
- A self-hosted issue tracker + bulletin board + code review platform with an embedded Git/SVN/Mercurial repository
- An application battle-tested for years at NAVER, NAVER LABS, and various companies and public institutions
Key features
- Self-hosted — no dependency on a third-party service that could shut down or lock in your data
- A flexible, project-based issue tracker and bulletin board — issue transfer between projects, sub-tasks, body change history, issue templates
- Embedded code repository — choose Git, SVN, or Mercurial, online edit/commit, access over SSH as well as HTTP(S), access restricted to project members, Git LFS support
- Block-based code review — review threads per code block, review scores
- Group (organization) features — unified management of issues/posts across a group, group projects and members
- Korean-friendly — project and group names can use Korean characters
- Account security — LDAP support, social login (OAuth2), two-factor authentication (TOTP apps + WebAuthn/passkeys), backup codes, login brute-force protection, known-device recognition
- Repository access/signing — SSH public keys, GPG commit signature verification, per-repository deploy keys
- API & automation — scoped personal access tokens (PATs), an OAuth2 Authorization Server for third-party apps (including Dynamic Client Registration), and a built-in MCP (Model Context Protocol) server — AI agents such as Claude can authenticate via OAuth2 and access issues, pull requests, and wiki pages directly (see below)
- Audit log for key security/admin events
- Migration to/from other services or Yona instances (GitHub project import, etc.)
Further reading (original project resources)
Yona (original) → yona (this port): what changed
| legacy Yona | yona (this port) | |
|---|---|---|
| Language | Java / Scala templates | Kotlin |
| Framework | Play Framework 2.x | Spring Boot |
| ORM | Ebean | JPA / Hibernate |
| View engine | Scala Template (.scala.html) |
Thymeleaf |
| JDK | Java 8 | Java 21 |
| Supported DB | MariaDB (default) or embedded H2 | MariaDB / PostgreSQL / MySQL / SQL Server / CUBRID / embedded H2 |
| Supported VCS | Git / SVN | Git / SVN / Mercurial |
Porting progress and deliberate differences from legacy are tracked in docs/parity/index.md,
docs/TEMPLATE_BACKLOG.md, and docs/coverage/index.md.
Some features were added during the port that legacy never had:
- Mercurial repository support (Git/SVN grew to three VCS types)
- Two-factor authentication (TOTP apps + WebAuthn/passkeys) and stronger login security (brute-force protection, known-device recognition)
- GPG commit signature verification and per-repository deploy keys
- Scoped personal access tokens (PATs) and an OAuth2 Authorization Server for third-party apps (including Dynamic Client Registration)
- A built-in MCP (Model Context Protocol) server — see below for details
- An audit log for security/admin events
Frontend widgets: gradual migration to Vue 3 Web Components
Some UI widgets are being migrated from jQuery-based vanilla JS to
Vue 3 Web Components. Each widget is applied via a
hybrid-adapter pattern — the existing vanilla yona.*.js file checks whether its target element is
now the new custom element and delegates to it if so, otherwise falling back to the original logic
unchanged. That means some widgets (Typeahead, Pagination, etc.) need no template changes at all,
while others need only a single tag swap.
- Widget source:
yona-projects/components(Vue 3 SFCs built as native custom elements, each with its own Shadow DOM) - The build output is committed as-is under
src/main/resources/static/lib/yona-vue-widgets/, so this repository runs on its own without cloning or building the components repo separately. - Widgets applied so far (17): Dialog, Toast, Popover, LoginDialog, Switch, Dropdown, Typeahead, Pagination, Attachments, ScrollElevator, PageSlide, ReviewForm, the markdown help panel (HelpMarkdown), and the 3-part label editor (new-label form, category-edit dialog, label-edit dialog).
- The shared markdown editor fragment used across many screens is excluded from this migration — its `` is fully encapsulated inside Shadow DOM, which would break the existing JS that reaches into it from other screens (attachment drag-and-drop, draft autosave, etc.). ReviewForm's own markdown editor instance is self-contained and unrelated to that shared fragment, so it does not have this problem and is included.
AI agent integration (MCP server)
yona has a built-in MCP (Model Context Protocol) server, so AI agents such as Claude can directly query and act on issues, pull requests, and wiki pages.
- A single
/mcpendpoint (Streamable HTTP) exposes all methods annotated@Toolviaspring-ai-starter-mcp-server-webmvc(IssueMcpTools/PullRequestMcpTools/WikiMcpTools). - Authentication works with either OAuth2 (yona itself acts as an OAuth2 Authorization Server
with Dynamic Client Registration support) or a scoped personal access token (PAT) — every
tool call is re-checked against the caller's actual scopes by
McpScopeGuard. - Issue/manage API tokens from the user settings screen (API Tokens), and register OAuth apps from the user settings screen (OAuth Apps).
Requirements
- JDK 21
- One of the supported/tested DBs: MariaDB (default), PostgreSQL, MySQL, SQL Server, CUBRID, or embedded H2 (no install needed)
Build & Run
# Linux / macOS
./gradlew bootRun
# Windows
gradlew.bat bootRun
Tests:
./gradlew test # Linux/macOS
gradlew.bat test # Windows
Choosing a database
The default Spring profile is mariadb. To run against a different DB, set
spring.profiles.active to one of the profiles below (connection settings for each profile live
in src/main/resources/application.yml). A local MariaDB/PostgreSQL container can be started
directly from the docker-compose.yml at the repository root.
| Profile | DB |
|---|---|
mariadb (default) |
MariaDB |
postgres |
PostgreSQL |
mysql |
MySQL |
mssql |
Microsoft SQL Server |
cubrid |
CUBRID |
h2 |
Embedded H2 — runs immediately from a local file (./data/h2/yona), no Docker/server install |
java -jar yona.jar --spring.profiles.active=postgres
# Try it with zero setup (H2)
java -jar yona.jar --spring.profiles.active=h2
Integration tests are verified against all 5 server DBs using real Docker containers (Testcontainers); H2 is embedded and needs no container. To run tests against a single DB (never run two or more at once — the gradle build output directory gets corrupted; always run one at a time):
./gradlew test -Dyona.it.db=postgres # mariadb|postgres|mysql|mssql|cubrid|h2
Deployment configuration (especially on Windows)
Where physical storage lives on disk (git bare repos, svn repos, git-lfs objects, attachment
uploads) is controlled by the 4 settings below. The defaults are Unix absolute paths in the form
/tmp/yona/..., so when operating on Windows you must reconfigure these to Windows paths.
| Setting key | Default | Purpose |
|---|---|---|
yona.git.base-dir |
/tmp/yona/git |
Git bare repository root |
yona.svn.base-dir |
/tmp/yona/svn |
SVN repository root |
yona.lfs.base-dir |
/tmp/yona/lfs |
Git LFS object storage root |
yona.upload.base-dir |
${yona.data:data}/uploads (relative) |
Attachment upload root |
How to change these settings
Set directly in
application.yml(the most reliable way)yona: git: base-dir: "D:/yona-data/git" svn: base-dir: "D:/yona-data/svn" lfs: base-dir: "D:/yona-data/lfs" upload: base-dir: "D:/yona-data/uploads"Windows paths can be written with forward slashes (
/) too — Java accepts both separators. If you use backslashes, YAML escaping requires doubling them (\\), so forward slashes are recommended.Pass as command-line arguments at runtime (to vary per deployment without touching
application.yml)java -jar yona.jar --yona.git.base-dir=D:\yona-data\git --yona.svn.base-dir=D:\yona-data\svn --yona.lfs.base-dir=D:\yona-data\lfs --yona.upload.base-dir=D:\yona-data\uploadsPassing JVM system properties with
-D(java -Dyona.git.base-dir=D:\... -jar yona.jar) works the same way.Environment variables — under Spring Boot's relaxed binding rules, the environment variable corresponding to
yona.git.base-dirisYONA_GIT_BASEDIR(the hyphen is simply dropped, not replaced with an underscore like otherYONA_*settings). This is easy to get wrong, so option 1 (yml) or option 2 (command-line arguments) is recommended.
Prerequisites for using Fork (hard-link cloning) on Windows
Project Fork does not physically copy the repository — it clones via filesystem hard links
(ProjectServiceImpl.cloneHardLinkedRepository). For this to work correctly:
yona.git.base-dir(andyona.svn.base-dir) must live entirely within a single NTFS volume (drive). Hard links cannot cross drives, so Fork fails between different drives (no copy fallback — this is intentional).- The storage location must be NTFS. External disks formatted as FAT32/exFAT, and some network drives, don't support hard links at all, so Fork fails there.
Server settings
- LDAP: the
ldapsection ofapplication.yml - Social login (OAuth2): the
spring.security.oauth2section ofapplication.yml - WebAuthn (passkeys):
yona.security.webauthn.relying-party-id/relying-party-nameinapplication.yml— you must reconfigure these to match your deployment domain (the default islocalhost). - Two-factor authentication (TOTP) encryption key: you must set the
YONA_TOTP_ENCRYPTION_PASSWORD/YONA_TOTP_ENCRYPTION_SALTenvironment variables before deploying to production. The defaults are placeholder values committed to source control (yona-totp-dev-only-password, etc.) — leaving them as-is in production means every user's TOTP secret is encrypted with a key anyone can read from the repo, so two-factor authentication provides no real protection. Booting without setting these logs a[SECURITY WARNING] TOTP encryption key is still the committed placeholder defaulterror, which your deployment pipeline should monitor for (TotpEncryptionKeyGuard). - SSH (Git/Mercurial access, SSH key registration): see SSH: system sshd integration (Korean only for now).
- GPG commit signature verification, deploy keys, and API tokens/OAuth apps need no extra setup — they're enabled by default and available directly from each user's settings screens.
Google Analytics
The Google Analytics tracking script is actually implemented, same as legacy (
GlobalModelAttributeAdvicepopulates asendYonaUsagemodel attribute, andtemplates/site/layout.htmlrenders the GA script based on that value).Unlike legacy (
application.send.yona.usage = true, on by default), the default here is off (false). To enable it, set the following totrueinapplication.yml.yona: analytics: send-usage: true
Migration
- Provides GitHub project import into this repository (
MigrationService,MigrationApiController). Enable it via thegithub.client.id/github.client.secret/github.allow.migrationsettings. - The original Yona's separate backup/migration tool,
Yona Export, has not yet been ported to this
repository (the Kotlin/Spring port) — see
docs/parity/index.mdfor status.
Contribution
- The branch for contributions is
next(mainis a stale old snapshot — all active development happens onnext, which is also the repository's default branch). - Fork the repository, work on top of the
nextbranch, then send a pull request to thenextbranch.
Operations guide
legacy Yona kept English docs at docs/*.md and Korean docs at docs/ko/*.md. yona keeps that
same split: this section lists the English set (same filenames/locations as legacy), rewritten
for yona. The Korean set lives under docs/guide/ — see the 운영 가이드 section
above (it's reorganized slightly differently, e.g. install docs merged into one file, so the two
sets aren't a strict 1:1 file mirror).
- Install (MariaDB)
- Install (yona server)
- Run and restart
- Run options
- Upgrade
- Backup and restore
- Mail notification settings
- Social login settings
- Troubleshooting
- MariaDB 767 byte error
- application.yml reference
- System requirements
- Logging
User manual: legacy's docs/userManual/ was English-only, so it's ported here at the same
location — docs/userManual/TOC.md. (The duplicate
projectSetting/projectSettings folders from a legacy typo were merged into one,
projectSetting/.)
Technical docs: legacy's docs/technical/ (English) and docs/ko/technical/ (Korean) were two
different, non-overlapping sets of files. Only the English set is mirrored here at the same
location — docs/technical/ (markdown, mailbox, watch,
label-typeahead, name-validation). The Korean set's 11 additional topics (access control, JS
module conventions, uploader/webhook internals, etc.) only ever existed in Korean, both in
legacy and here — see docs/guide/technical/README.md.
For a systemd unit example and DB tuning samples for running this as a standing service, see
support-script/.
Design specs, vision docs, and release notes from legacy Yona (including its Yobi/nFORGE
predecessors) are preserved verbatim under
docs/legacy-reference/.
Code structure overview
docs/parity/index.md, docs/TEMPLATE_BACKLOG.md, and docs/coverage/index.md record
porting progress against legacy yona and deliberately preserved differences.
Documentation convention: docs/parity/, docs/coverage/, and docs/golden/ follow the
docs/yona-wiki/ style (index = table only, details = individual files). When logging a new
ticket/batch/finding, don't append narrative under the index table — create a new file in the
relevant directory (tickets/.md, batches/.md, findings/.md, etc.) and add
just a table row + link to the index.
License
yona is provided under the Apache License 2.0, the same license as the original Yona/Yobi project. See NOTICE for third-party component notices and AUTHORS for the original project's contributor list.