GitHub - yona-projects/yona: Project Hosting SW · GitHub
Skip to content
yona-projectsPublic

Repository files navigation

[English]

yona

Yona logo

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종(새 라벨 폼, 카테고리 편집 다이얼로그, 라벨 편집 다이얼로그)
  • 화면 전반에서 공유하는 마크다운 에디터 프래그먼트는 이번 전환 범위에서 제외했습니다 — 에디터의 <textarea>가 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
  • Node.js 22 이상과 npm 10 이상 (PATH에서 사용 가능해야 함). ./gradlew test를 포함한 리소스 빌드는 frontend/에서 잠금 파일 기반 npm ci를 실행합니다. 최초 빌드에는 npm 레지스트리 접근 또는 미리 채운 npm 캐시가 필요합니다. 공식 @hotwired/turbo 배포 파일은 Gradle 빌드 출력에 복사되어 애플리케이션에 포함되며, 실행 시 Node.js나 CDN은 필요하지 않습니다.
  • 운영/테스트 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

cubrid 프로파일은 CUBRID에서 사용할 수 없는 TEXT와 NOT NULL LOB 보안 필드만 META-INF/orm-cubrid.xml의 VARCHAR/BIT VARYING 매핑으로 대체합니다. 다른 DB의 컬럼 형식은 변경하지 않습니다. 해당 필드에 수동으로 만든 기존 CLOB/BLOB 컬럼이 있으면 스키마 갱신 전에 기동을 중단합니다. 원본 DB를 백업하고 값을 보존하는 별도 마이그레이션을 먼저 수행해야 하며, 애플리케이션은 LOB를 자동 변환하거나 삭제하지 않습니다. 메타데이터 조회는 설정된 Hibernate 스키마(미설정 시 DB 접속 사용자)로 제한해 다른 소유자의 동명 테이블을 갱신 대상으로 오인하지 않습니다.

통합 테스트는 실제 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 (상대경로) 첨부파일 업로드 루트

설정 변경 방법

  1. 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 이스케이프 때문에 \\로 두 번 써야 하므로, 슬래시 표기를 권장합니다.

  2. 실행 시 커맨드라인 인자로 지정 (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)도 동일하게 동작합니다.

  3. 환경 변수 — 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

  • 설치/사용 현황 집계용 Google Analytics 4(gtag) 태그가 포함되어 있습니다 (templates/common/analytics.html, 측정 ID는 yona.analytics.measurement-id).

  • 기본값은 켜짐입니다. 원치 않으면 application.yml에서 아래처럼 끄면 태그가 렌더링되지 않습니다 (환경변수 YONA_ANALYTICS_SEND_USAGE=false도 동일).

    yona:
      analytics:
        send-usage: false
  • 수집 항목: 화면 종류만 담은 페이지뷰(/:owner/:project/issue 형태로 마스킹 — 소유자·프로젝트명·이슈 번호· 제목·쿼리스트링·리퍼러는 어떤 이벤트에도 전송하지 않음), 왼쪽 사이드바 사용 여부, 이슈·게시판·PR 목록 등의 "2단 보기" 켜짐/꺼짐과 토글 횟수, 이 설치를 구분하는 익명 UUID(yona.data/analytics/install-id). 입력한 데이터는 읽지 않으며, 서버가 GA로 직접 보내는 이벤트는 없고, 사용자 식별자와 광고 신호는 사용하지 않습니다.

마이그레이션

  • 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/:

영문 버전은 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/<id>.md, batches/<slug>.md, findings/<slug>.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 <textarea> 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 /mcp endpoint (Streamable HTTP) exposes all methods annotated @Tool via spring-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
  • Node.js 22+ and npm 10+ available on PATH. Resource builds, including ./gradlew test, run lockfile-based npm ci in frontend/. The first build needs npm registry access or a pre-populated npm cache. The official @hotwired/turbo distribution is copied into Gradle build output and packaged with the application; Node.js and a CDN are not needed at runtime.
  • 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

The cubrid profile overrides only security fields using unsupported TEXT or NOT NULL LOB storage with VARCHAR/BIT VARYING mappings in META-INF/orm-cubrid.xml. Column types on other databases are unchanged. Existing custom CLOB/BLOB columns in those fields stop startup before schema update. Back up the source database and migrate those values explicitly before starting the application; it never automatically converts or deletes existing LOBs. Metadata lookup is restricted to the configured Hibernate schema, or the database login owner when unspecified, so same-named tables belonging to another owner are not mistaken for application tables.

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

  1. 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.

  2. 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\uploads

    Passing JVM system properties with -D (java -Dyona.git.base-dir=D:\... -jar yona.jar) works the same way.

  3. Environment variables — under Spring Boot's relaxed binding rules, the environment variable corresponding to yona.git.base-dir is YONA_GIT_BASEDIR (the hyphen is simply dropped, not replaced with an underscore like other YONA_* 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 (and yona.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 ldap section of application.yml
  • Social login (OAuth2): the spring.security.oauth2 section of application.yml
  • WebAuthn (passkeys): yona.security.webauthn.relying-party-id/relying-party-name in application.yml — you must reconfigure these to match your deployment domain (the default is localhost).
  • Two-factor authentication (TOTP) encryption key: you must set the YONA_TOTP_ENCRYPTION_PASSWORD/YONA_TOTP_ENCRYPTION_SALT environment 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 default error, 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

  • A Google Analytics 4 (gtag) tag for install/usage statistics is included (templates/common/analytics.html, measurement ID via yona.analytics.measurement-id).

  • It is on by default. To turn it off, set the following (or the environment variable YONA_ANALYTICS_SEND_USAGE=false); the tag is then not rendered at all.

    yona:
      analytics:
        send-usage: false
  • What is collected: page views carrying only the screen type (masked to shapes like /:owner/:project/issue — owner/project names, issue numbers, titles, query strings and referrers are never sent with any event), whether the left sidebar is used, whether the "two-column view" of issue/board/pull-request lists is on or off and how often it is toggled, and an anonymous UUID that tells installations apart (yona.data/analytics/install-id). Nothing a user types is read, the server sends nothing to GA by itself, and no user identifiers or advertising signals are used.

Migration

  • Provides GitHub project import into this repository (MigrationService, MigrationApiController). Enable it via the github.client.id / github.client.secret / github.allow.migration settings.
  • 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.md for status.

Contribution

  • The branch for contributions is next (main is a stale old snapshot — all active development happens on next, which is also the repository's default branch).
  • Fork the repository, work on top of the next branch, then send a pull request to the next branch.

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).

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/<id>.md, batches/<slug>.md, findings/<slug>.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.

Releases

Packages

Used by

Contributors

Languages