简体中文 | English
Kistack is a compact technical forum for publishing Markdown articles and discussing them through threaded comments. It includes a responsive public site, account and profile management, article moderation, interaction metrics, and a session-based administration console.
- Markdown article editor with live preview and sanitized rendering
- Article discovery by hot score, author, title, and tag
- Effective-view deduplication, idempotent likes, and time-decayed hot scores
- Threaded comments and replies with soft deletion for non-leaf comments
- Public author profiles, avatar upload, and personal article management
- Username-or-email login, email verification, password reset, and login lockout
- Administrator user management and post/comment moderation
- Responsive light/dark interface built without a frontend build step
- Java 21
- Spring Boot 4.1, Spring MVC, Spring Security, Spring Data JPA
- SQLite and Hibernate's community SQLite dialect
- Thymeleaf, vanilla JavaScript, and CSS
- Caffeine, markdown-it, DOMPurify, and Lucide icons
- JUnit 6, Mockito, MockMvc, and SQLite integration tests
- JDK 21 or newer
- An SMTP account for registration and account-recovery email
The Maven Wrapper is included, so a system Maven installation is not required. Node.js is not required to run the application.
Kistack reads configuration from environment variables. KISTACK_ADMIN_PASSWORD has no default and must be set to a value between 6 and 128 characters before the application can start.
Minimum local PowerShell setup:
$env:KISTACK_ADMIN_PASSWORD = "replace-with-a-strong-password"
$env:KISTACK_MAIL_HOST = "smtp.example.com"
$env:KISTACK_MAIL_USERNAME = "forum@example.com"
$env:KISTACK_MAIL_PASSWORD = "smtp-password"
$env:KISTACK_EMAIL_FROM_FROM = "forum@example.com"Equivalent Bash setup:
export KISTACK_ADMIN_PASSWORD='replace-with-a-strong-password'
export KISTACK_MAIL_HOST='smtp.example.com'
export KISTACK_MAIL_USERNAME='forum@example.com'
export KISTACK_MAIL_PASSWORD='smtp-password'
export KISTACK_EMAIL_FROM_FROM='forum@example.com'Useful optional variables:
| Variable | Default | Purpose |
|---|---|---|
KISTACK_ADMIN_USERNAME |
admin |
Initial administrator username |
KISTACK_ADMIN_EMAIL |
admin@kistack.com |
Initial administrator email |
KISTACK_ADMIN_RESET_ENABLED |
false |
Recreate administrator accounts on startup; use only for intentional recovery |
KISTACK_DATASOURCE_URL |
jdbc:sqlite:./data/kistack.db |
SQLite connection URL |
KISTACK_DATA_PATH |
./data |
Avatar and application data directory |
KISTACK_JPA_HIBERNATE_DDL_AUTO |
update |
Hibernate schema behavior |
KISTACK_LOGGING_LEVEL_ROOT |
INFO |
Root log level |
On an empty database, Kistack creates the configured administrator. When an administrator already exists and reset is disabled, it is retained. Enabling KISTACK_ADMIN_RESET_ENABLED deletes existing administrator accounts and creates the configured one, so it should never be enabled as a routine production setting.
All configuration keys and defaults are listed in application.properties.
Windows:
.\mvnw.cmd spring-boot:runLinux or macOS:
./mvnw spring-boot:runOpen http://localhost:8080/ after startup.
.\mvnw.cmd clean test
.\mvnw.cmd -DskipTests packageThe test suite uses databases under target/ and does not modify data/kistack.db.
SQLite data is stored in data/kistack.db by default, while avatars are stored in data/avatars/. Database files and logs are ignored by Git; the default avatar is versioned.
This pre-1.0 project intentionally targets a fresh database and currently relies on Hibernate schema initialization. It does not include compatibility migrations for development databases from older source revisions. Delete or back up an obsolete development database before starting a revision with an incompatible schema. Before maintaining multiple released database versions, introduce Flyway or Liquibase and change production schema handling from update to validate.
For deployment, use HTTPS, keep credentials in environment or secret storage, back up the SQLite database and avatar directory together, and run only one application instance unless the SQLite and in-memory deduplication constraints are replaced.