📚 Полный список документации · Сравнение с конкурентами
ProjectForge — корпоративный веб-портал для управления проектами, задачами, календарями, сотрудниками, отпусками, книгами и другими бизнес-сущностями. Проектно-ориентированная система для средних компаний с сильным акцентом на управление проектами и учёт рабочего времени.
Разрабатывается Micromata GmbH (Германия) с 2001 года. Открытый исходный код, двойная лицензия (GPLv3 / коммерческая).
Монолитное веб-приложение. Один JAR-файл, внутри которого:
| Фронтенд | URL | Технология | Состояние | ||||
|---|---|---|---|---|---|---|---|
| Wicket | / | Java Wicket (серверный рендеринг) | Основной, legacy | ||||
| React | /react/** | React + Redux + Vite (клиентский рендеринг) | Активно развивается, мигрирует с CRA на Vite |
Оба фронтенда живут в одном JAR и работают одновременно — пользователь переключается между ними незаметно.
./gradlew bootRunОткрыть
http://localhost:8080(Wicket) илиhttp://localhost:8080/react/(React).Для фронтенд-разработки (React, hot reload):
cd projectforge-webapp && npm install && npm run devVite-сервер на
http://localhost:5173, проксирует API-запросы наlocalhost:8080.2. Структура директорий (что где лежит)
projectforge/ ├── projectforge-business/ ← бизнес-логика (Kotlin/Java), сервисы, работа с БД │ └── src/main/ │ ├── kotlin/org/projectforge/ │ │ ├── login/ ← аутентификация (LoginService, LoginHandler) │ │ └── business/user/ ← пользователи, группы, куки (CookieService) │ └── resources/ │ ├── application.properties ← конфигурация │ └── flyway/ ← миграции БД ├── projectforge-rest/ ← REST API (Kotlin/Java, Spring MVC) │ └── src/main/kotlin/org/projectforge/rest/ │ ├── pub/ ← публичные эндпоинты (логин, статус) │ ├── UserStatusRest.kt ← GET /rs/userStatus — «кто я?» │ └── config/Rest.java ← URL-префиксы (/rs, /rsPublic) ├── projectforge-webapp/ ← React-фронтенд (JavaScript, Vite) │ ├── src/ │ │ ├── actions/ ← Redux thunk'и (логин, проверка сессии) │ │ ├── reducers/ ← Redux редьюсеры (состояние аутентификации) │ │ ├── utilities/rest.js ← fetch-обёртка (baseURL, handleHTTPErrors) │ │ ├── components/ ← UI-компоненты │ │ └── containers/ ← страницы (ProjectForge.jsx — точка входа) │ ├── vite.config.ts ← конфигурация Vite │ └── package.json ← зависимости (React, Redux, Vitest, …) ├── projectforge-idp/ ← интеграция с IdP (Keycloak / Authentik) ├── projectforge-model/ ← общие Java-модели │ └── rest/RestPaths.java ← константы: REST = "rs", REST_PUBLIC = "rsPublic" └── buildSrc/ ← Gradle-конвенции3. Как фронтенд общается с бэкендом
React делает
fetch()на REST API:React (браузер) Java (Spring Boot) ───────────────── ──────────────────── login(username, password) → POST /rsPublic/login → LoginPageRest.kt loadUserStatus() → GET /rs/userStatus → UserStatusRest.ktВсе запросы идут с
credentials: 'include'— браузер отправляет сессионную кукуJSESSIONID. Сервер проверяет её и возвращает либо данные пользователя (200), либо 401 (не залогинен).Ключевые файлы для понимания этого моста:
| Фронтенд | Бэкенд | Что делает | |||
|---|---|---|---|---|---|
actions/authentication.js | rest/pub/LoginPageRest.kt | Логин | |||
actions/authentication.js | rest/UserStatusRest.kt | Проверка сессии | |||
utilities/rest.js | model/rest/RestPaths.java | URL-префиксы | |||
utilities/rest.js | business/…/CookieService.kt | Куки | |||
reducers/authentication.js | — | Состояние на фронтенде |
В проекте два типа «входа»:
Сессия (JSESSIONID) — стандартная Java-сессия. Ставится сервером после логина. Живёт пока браузер открыт.
Постоянный вход (stayLoggedIn) — отдельная кука на 30 дней. Если сессия истекла но кука жива — сервер автоматически пересоздаёт сессию без пароля.
Фронтенд при старте делает loadUserStatus() — спрашивает сервер «кто я?». Если сессия жива — получает данные пользователя. Если нет — редирект на страницу логина.
| Слой | Технология | ||
|---|---|---|---|
| Бэкенд | Kotlin, Java 17, Spring Boot, Hibernate/JPA, Flyway | ||
| База данных | HSQLDB (dev), PostgreSQL (prod) | ||
| Фронтенд | React 18, Redux, Vite 6, react-big-calendar, reactstrap | ||
| Тесты (фронтенд) | Vitest, redux-mock-store | ||
| Сборка | Gradle (Kotlin DSL), npm | ||
| Старый фронтенд | Apache Wicket (Java-фреймворк, серверный рендеринг) |
1. Пользователь вводит логин/пароль в React-форме 2. React: login(username, password, keepSignedIn) 3. fetch: POST /rsPublic/login { username, password, stayLoggedIn } 4. Java: LoginPageRest → LoginService.authenticate() 5. Java: LoginHandler.checkLogin() → проверка пароля в БД 6. Java: если keepSignedIn — ставит куку stayLoggedIn на 30 дней 7. Java: создаёт сессию (JSESSIONID) 8. React: .then(() => loadUserStatus()(dispatch)) 9. fetch: GET /rs/userStatus 10. Java: UserStatusRest → проверяет сессию → возвращает userData 11. React: dispatch(USER_LOGIN_SUCCESS) → Redux знает кто залогинен7. Что ещё полезно знать
/rs — префикс REST API, определён в RestPaths.java:31 как public static final String REST = "rs". Весь REST API живёт под /rs/*./rsPublic — публичные эндпоинты (логин, восстановление пароля) — не требуют аутентификации.JSESSIONID — создаётся не кодом ProjectForge, а сервлет-контейнером (Tomcat). ProjectForge только управляет её жизненным циклом (инвалидация после логина для защиты от session fixation)./) и React (/react/**). Wicket использует index.html, React использует react-app.html (переименовывается при сборке Gradle'ом).projectforge-business/src/main/resources/flyway/migrate/.Подробное сравнение с 7 конкурентами →
Кратко: OpenProject — самый прямой конкурент (GPLv3, немецкий, PM-фокус, но без финансов/HR). ERPNext/Odoo — шире по ERP, сложнее в деплое. Jira — уходит с self-hosted рынка к 2029. Personio — только HR (SaaS). Monday.com — красивый SaaS без self-hosted. Уникальность ProjectForge — единственный кто даёт PM + финансы + HR + календарь в одном JAR со встроенной БД.