TestcaseCraft is a free, open source test case management system (TCMS) you can self-host with Docker in minutes. Design, organize, execute, and trace your test cases β manual and automated β with built-in AI/RAG assistance, Jira integration, and a clean React UI. A modern alternative to Kiwi TCMS, TestLink, and Squash.
docker pull xmlangel/testcasecraft:latest
TestcaseCraft is an all-in-one, open source QA platform that manages the full test lifecycle β from test case design to execution and result analysis β in a single self-hosted application.
Built on a robust Spring Boot + React architecture, with a FastAPI-based RAG (Retrieval-Augmented Generation) service layered on top, TestcaseCraft goes beyond simple record-keeping to deliver an intelligent testing environment.
If you are looking for a self-hosted, Docker-ready, open source test management tool that your team fully owns β with no per-seat SaaS pricing and no vendor lock-in β TestcaseCraft is built for you.
Keywords: open source test case management Β· self-hosted TCMS Β· Docker test management Β· QA test case tool Β· manual & automated test tracking Β· AI test assistant Β· Jira test management.
| π³ Self-hosted in minutes | One docker compose up brings up app, AI service, PostgreSQL, and object storage. Your data never leaves your servers. |
| π² Hierarchical test cases | Folder-based tree structure to organize, classify, and reorganize test cases intuitively. |
| π§© Multi-project | Manage test assets for many projects from a single system. |
| π Test plans & cycles | Bundle cases into runnable plans per release or test cycle. |
| π Execution & traceability | Record Pass / Fail / Skip results and transparently track historical runs. |
| π€ AI-powered (LLM + RAG) | Ask questions in natural language, refine scenarios, and get context-aware answers grounded in your own documents. |
| π Jira integration | Link Jira issues directly to test cases and sync development & testing status in real time. |
| π JWT security | Token-based authentication for safe access control and data protection. |
| π§ͺ Automation import | Import JUnit XML results and manage manual + automated tests in one place. |
| π Open source & free | No per-seat licensing. Own your QA platform. |
TestcaseCraft supports several ways to inject environment variables, so you can pick what fits your situation. Full .env and docker-compose.yml samples are in the shared Configuration section at the bottom of this page.
.env file (recommended)Create a .env file in the project root. Docker Compose loads it automatically at startup.
# 1. Create a .env file (see Configuration below)
# 2. Start the containers
docker compose up -d --build
Useful for one-off tests or overriding settings. Takes precedence over the .env file.
PROTOCOL=https DOMAIN=mydomain.com SERVER_PORT=443 docker compose up -d --build
--env-file)Use this to keep separate configurations for production, development, etc.
docker compose --env-file myenvfile.env up -d --build
Then open http://localhost:8080β and log in with the default admin account.
| Service | URL | Description |
|---|---|---|
| Application | http://localhost:8080β | Main web app |
| App API Docs | http://localhost:8080/swagger-ui.htmlβ | Backend API (Swagger) |
| RAG API Docs | http://localhost:8001/docsβ | AI / RAG service API |
| MinIO Console | http://localhost:9001β | File storage console |
| Health Check | http://localhost:8080/actuator/healthβ | Service status |
| Username | Password |
|---|---|
admin | admin123 |
β οΈ Security note: Change the default password immediately after your first login.
| Layer | Technology |
|---|---|
| Frontend | React |
| Backend | Spring Boot |
| AI Service | FastAPI (RAG & LLM integration) |
| Database | PostgreSQL 18 (+ pgvector for RAG) |
| Object Storage | MinIO (S3-compatible) |
| Auth | JWT |
Supported LLM providers: Ollama Β· OpenWebUI Β· OpenAI Β· Perplexity Β· OpenRouter.
| Capability | TestcaseCraft | Kiwi TCMS | TestLink | Squash |
|---|---|---|---|---|
| Self-hosted via Docker | β | β | β | β |
| Hierarchical (folder tree) test cases | β | β | β | β |
| Test plans & execution tracking | β | β | β | β |
| JUnit XML automation import | β | β | partial | β |
| Built-in AI assistant (LLM) | β | β | β | β |
| RAG over your own docs | β | β | β | β |
| Jira integration | β | β | β | β |
| Modern React UI | β | partial | β | β |
Comparison reflects publicly documented capabilities and is provided for orientation only.
Is TestcaseCraft really open source and free? Yes. TestcaseCraft is open source and free to self-host. You own your data and your deployment.
Can I run it entirely on-premise / offline? Yes. Everything runs in Docker containers on your infrastructure. With a local LLM provider (e.g. Ollama), even the AI features can run fully offline.
Does it support automated test results? Yes β import JUnit XML to manage automated and manual tests together.
Which databases does it use? PostgreSQL 18 for application data and PostgreSQL 18 + pgvector for RAG embeddings.
Is there an API? Yes β a full REST API documented via Swagger, plus an MCP server so LLM clients (Claude Desktop, Cline, Cursor) can drive TestcaseCraft in natural language.
/swagger-ui.html on a running instanceTestcaseCraft: The Finishing Touch β¨ "μ½λλΌλ μμμ΄ μλ²½ν μ νμΌλ‘ λΉλλ μκ°, κ·Έ λ§μ§λ§ μκΈΈμ ν¨κ»ν©λλ€."
μννΈμ¨μ΄ κ°λ°μ λλ¨μμ νμ§μ μ± μμ§λ QA(Quality Assurance)λ λ¨μν μ€λ₯ κ²μΆμ΄ μλλλ€. κ·Έκ²μ κ±°μΉ μμκ³Όλ κ°μ μ½λλ₯Ό λ€λ¬κ³ , λμ§νΈ λΈλ‘μ λ§μ§λ§ μ‘°κ°μ λΌμ λ§μΆ° λΉλ‘μ μ νμ λΉλκ² νλ 'μ₯μΈ(Craftsman)'μ κ³Όμ μ λλ€.
TestcaseCraftλ μ΄λ¬ν μ₯μΈ μ μ μ λ΄μμ΅λλ€. QA μμ§λμ΄μ μ¬μΈν μκ°κ³Ό μλ ¨λ κ²½νμ΄ λμ§νΈ νκ²½μμ μ¨μ ν λ°νλ μ μλλ‘, κ°μ₯ μ§κ΄μ μ΄κ³ νλμ μΈ λꡬλ₯Ό μ 곡ν©λλ€. λΉμ μ μλμμ μννΈμ¨μ΄μ μμ±μ κ²½ννμΈμ.
TestcaseCraftλ ν μ€νΈ μΌμ΄μ€ μ€κ³λΆν° μ€ν, κ²°κ³Ό λΆμκΉμ§μ μ 체 λΌμ΄νμ¬μ΄ν΄μ ν΅ν© κ΄λ¦¬νλ All-in-One QA νλ«νΌμ λλ€.
Spring Bootμ Reactλ‘ κ΅¬μΆλ κ²¬κ³ ν μν€ν μ² μμ, FastAPI κΈ°λ°μ RAG(κ²μ μ¦κ° μμ±) μλΉμ€λ₯Ό λν΄ λ¨μν κ΄λ¦¬λ₯Ό λμ΄μ 'μ§λ₯ν ν μ€νΈ νκ²½'μ μ 곡ν©λλ€.
ν μ€νΈ μμ°μ 체κ³μ μΌλ‘ ꡬ쑰ννμ¬ κ΄λ¦¬μ 볡μ‘ν¨μ μ€μ λλ€.
ν μ€νΈ κ³νλΆν° μ€ν κ²°κ³ΌκΉμ§, μμ±μΌλ‘ κ°λ λͺ¨λ λ°μμ·¨λ₯Ό κΈ°λ‘ν©λλ€.
λ¨μ λ°λ³΅ μ 무λ₯Ό λμ΄, AIμ ν¨κ» λ κΉμ΄ μλ ν μ€νΈλ₯Ό μνν©λλ€.
π Getting Started
TestcaseCraftλ μ μ°ν μ€μ μ μν΄ λ€μν νκ²½ λ³μ μ£Όμ λ°©μμ μ§μν©λλ€. μν©μ λ§λ λ°©λ²μ μ ννμΈμ.
νλ‘μ νΈ λ£¨νΈμ .env νμΌμ μμ±νμ¬ μ€μ μ κ΄λ¦¬ν©λλ€. Docker Composeκ° μ€ν μ μλμΌλ‘ μ΄ νμΌμ λ‘λν©λλ€.
# 1. .env νμΌ μμ± (νλ¨μ Configuration μ°Έμ‘°)
# 2. 컨ν
μ΄λ μ€ν
docker compose up -d --build
μΌμμ μΈ ν μ€νΈλ μ€μ μ€λ²λΌμ΄λ©μ΄ νμν λ μ μ©ν©λλ€. .env νμΌλ³΄λ€ μ°μ μμκ° λμ΅λλ€.
PROTOCOL=https DOMAIN=mydomain.com SERVER_PORT=443 docker compose up -d --build
μ΄μ νκ²½(prod), κ°λ° νκ²½(dev) λ± μ€μ μ λΆλ¦¬νμ¬ κ΄λ¦¬ν λ μ¬μ©ν©λλ€.
docker compose --env-file myenvfile.env up -d --build
컨ν μ΄λκ° μ μμ μΌλ‘ μ€νλ ν, μλ μ 보λ₯Ό ν΅ν΄ κ° μλΉμ€μ λ°μ΄ν°λ² μ΄μ€μ μ μν μ μμ΅λλ€.
μμ€ν μ΅μ΄ μ μ μ μ¬μ©λλ κ΄λ¦¬μ κ³μ μ λλ€.
β οΈ λ³΄μ μ£Όμ: μ΅μ΄ λ‘κ·ΈμΈ ν λ°λμ λΉλ°λ²νΈλ₯Ό λ³κ²½νμκΈ° λ°λλλ€.
adminadmin123κ°λ°, λλ²κΉ λλ μΈλΆ λꡬ(DBeaver λ±) μ°κ²° μ μ¬μ©νλ κ³μ μ 보μ λλ€.
| Component | Host Port | Username | Password | Note |
|---|---|---|---|---|
| PostgreSQL (Main) | localhost:5434 | testcase_user | testcase_password | μ£Όμ λ°μ΄ν° μ μ₯μ (v18) |
| PostgreSQL (RAG) | localhost:5433 | rag_user | rag_dev_password_123 | λ²‘ν° DB (pgvector + v18) |
| MinIO | localhost:9000 / 9001 | minioadmin | minioadmin_dev_password_789 | S3 νΈν μ€ν λ¦¬μ§ |
β¨ .env sample
# Protocol Configuration (http or https)
PROTOCOL=http
# Server Configuration
HTTP_PORT=8080
HTTPS_PORT=443
DOMAIN=localhost
SERVER_PORT=8080
SERVER_SSL_ENABLED=false
# SSL Configuration (only used when PROTOCOL=https)
SSL_KEYSTORE_PATH=/app/ssl/keystore.p12
SSL_KEYSTORE_PASSWORD=changeit
SSL_KEYSTORE_TYPE=PKCS12
# Database Configuration
POSTGRES_DB=testcase_management
POSTGRES_USER=testcase_user
POSTGRES_PASSWORD=testcase_password
DATABASE_URL=jdbc:postgresql://postgres:5432/testcase_management
# JWT Configuration (512-bit key required for HS512)
JWT_SECRET=512-bit key required for HS512
# SessionTime
JWT_EXPIRATION=604800000
JWT_REFRESH_EXPIRATION=2592000000
# Spring Boot Configuration
SPRING_PROFILES_ACTIVE=prod
# JPA Configuration
# Use validate to avoid Hibernate attempting to recreate existing indexes on startup
SPRING_JPA_HIBERNATE_DDL_AUTO=update
SPRING_JPA_SHOW_SQL=false
# Logging Configuration
LOGGING_LEVEL_COM_TESTCASE=INFO
LOGGING_LEVEL_ROOT=WARN
# Frontend API Configuration
REACT_APP_API_BASE_URL=http://:localhost:8080
DOCUMENT_PARSER=pymupdf4llm
# Upstage API Key
UPSTAGE_API_KEY=up
TESTCASE_INIT_ENABLED=false
# MinIO Configuration
MINIO_SECRET_KEY=minioadmin_dev_password_789
# RAG Database Configuration
POSTGRES_RAG_PASSWORD=rag_dev_password_123
# Encryption Configuration (AES-256, 32-byte Base64)
# Encrypts LLM API keys, Jira API tokens, mail passwords and Google service account JSON.
# Generate: openssl rand -base64 32
# Without a value, none of the above can be saved (the prod profile has no default).
JIRA_ENCRYPTION_KEY=
β¨ Docker Compose sample(docker-compose.yml)
services:
# Spring Boot Application
app:
image: xmlangel/testcasecraft:latest
container_name: testcasecraft
environment:
# Spring Profile
- SPRING_PROFILES_ACTIVE=prod
# Protocol and Domain Configuration
- PROTOCOL=${PROTOCOL}
- DOMAIN=${DOMAIN}
# Server Configuration
- SERVER_PORT=${SERVER_PORT}
# SSL Configuration (only when HTTPS)
- SERVER_SSL_ENABLED=${SERVER_SSL_ENABLED}
- SERVER_SSL_KEYSTORE=${SSL_KEYSTORE_PATH}
- SERVER_SSL_KEYSTORE_PASSWORD=${SSL_KEYSTORE_PASSWORD}
- SERVER_SSL_KEYSTORE_TYPE=${SSL_KEYSTORE_TYPE}
# Database Configuration
- DATABASE_URL=${DATABASE_URL}
- DATABASE_USERNAME=${POSTGRES_USER}
- DATABASE_PASSWORD=${POSTGRES_PASSWORD}
# JWT Configuration
- JWT_SECRET=${JWT_SECRET}
- JWT_EXPIRATION=${JWT_EXPIRATION}
- JWT_REFRESH_EXPIRATION=${JWT_REFRESH_EXPIRATION}
# Encryption key for stored secrets (LLM API keys, Jira tokens, mail passwords, Google JSON)
- JIRA_ENCRYPTION_KEY=${JIRA_ENCRYPTION_KEY:-}
# Application Configuration
- SPRING_JPA_HIBERNATE_DDL_AUTO=${SPRING_JPA_HIBERNATE_DDL_AUTO:-update}
- SPRING_JPA_SHOW_SQL=false
- LOGGING_LEVEL_COM_TESTCASE=INFO
- LOGGING_LEVEL_ROOT=WARN
- RAG_API_URL=http://rag-service:8000
- TESTCASE_INIT_ENABLED=${TESTCASE_INIT_ENABLED:-false}
# MinIO Configuration (TestCase Attachments)
- MINIO_ENDPOINT=minio:9000
- MINIO_ACCESS_KEY=minioadmin
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
- MINIO_TESTCASE_BUCKET=testcase-attachments
- MINIO_SECURE=false
# Mail Configuration (optional - can be empty for development)
- MAIL_USERNAME=${MAIL_USERNAME:-}
- MAIL_PASSWORD=${MAIL_PASSWORD:-}
- MAIL_HOST=${MAIL_HOST:-localhost}
- MAIL_PORT=${MAIL_PORT:-587}
# Frontend API Configuration
- REACT_APP_API_BASE_URL=${REACT_APP_API_BASE_URL:-http://localhost:8080}
ports:
- "${HTTP_PORT}:${SERVER_PORT}"
- "${HTTPS_PORT}:${SERVER_PORT}"
volumes:
- ./logs:/app/logs
- ./ssl:/app/ssl:ro
networks:
- testcasecraft-network
depends_on:
postgres:
condition: service_healthy
minio:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -f -k ${PROTOCOL}://localhost:${SERVER_PORT}/actuator/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
restart: unless-stopped
platform: linux/amd64
# FastAPI RAG Service
rag-service:
image: xmlangel/testcasecraft-rag-service:latest
container_name: testcasecraft-rag-service
environment:
# Database
DATABASE_URL: postgresql://rag_user:${POSTGRES_RAG_PASSWORD}@postgres:5432/rag_db
# MinIO (Docker Compose MinIO μ¬μ©)
MINIO_ENDPOINT: minio:9000
MINIO_ACCESS_KEY: minioadmin
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
MINIO_BUCKET: rag-documents
MINIO_SECURE: "false"
# Document Parser Configuration
# Options: upstage, pymupdf, pymupdf4llm, pypdf2, auto
# Using pymupdf4llm for LLM-optimized markdown extraction (no API key required)
DOCUMENT_PARSER: ${DOCUMENT_PARSER:-pymupdf4llm}
# Upstage API (not used when using pymupdf4llm)
UPSTAGE_API_KEY: ${UPSTAGE_API_KEY:-your_upstage_api_key}
# Application
APP_ENV: development
LOG_LEVEL: DEBUG
ports:
- "8001:8000"
networks:
- testcasecraft-network
depends_on:
postgres:
condition: service_healthy
minio:
condition: service_healthy
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
# PostgreSQL 18 with pgvector β ν΅ν© λ¨μΌ μΈμ€ν΄μ€
# - testcase_management (μ± DB, testcase_user)
# - rag_db (RAG λ²‘ν° DB, rag_user) : init-scripts κ° μ΅μ΄ κΈ°λ μ μλ μμ±
postgres:
image: pgvector/pgvector:pg18
container_name: testcasecraft-postgres
environment:
POSTGRES_DB: testcase_management
POSTGRES_USER: testcase_user
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
# μ΅μ΄ κΈ°λ μ rag_user/rag_db μμ±μ μ¬μ© (init-scripts/01-init-rag.sh)
POSTGRES_RAG_PASSWORD: ${POSTGRES_RAG_PASSWORD}
ports:
- "5434:5432"
volumes:
- ./data/postgres:/var/lib/postgresql
- ./init-scripts:/docker-entrypoint-initdb.d
networks:
- testcasecraft-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U testcase_user -d testcase_management"]
interval: 10s
timeout: 5s
retries: 5
# MinIO Object Storage (RAG)
minio:
image: minio/minio:latest
container_name: testcasecraft-minio
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY}
ports:
- "9000:9000" # API
- "9001:9001" # Console
volumes:
- ./data/minio:/data
networks:
- testcasecraft-network
command: server /data --console-address ":9001"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 10s
timeout: 5s
retries: 5
networks:
testcasecraft-network:
name: testcasecraft-network-spring
driver: bridge
Content type
Image
Digest
sha256:7e5fbf1c0β¦
Size
219.4 MB
Last updated
3 days ago
docker pull xmlangel/testcasecraft