- Описание на проекта
- Технологии
- Архитектура на системата
- Диаграми
- База данни
- Подробна документация на функциите
- Конфигурация
- Старт на приложението
Version Control System е Spring Boot приложение за управление на документи с версии, одобрения и аудит. Системата поддържа ролево базиран достъп (RBAC) и пълна история на промените.
- Управление на потребители с роли (READER, AUTHOR, REVIEWER, ADMINISTRATOR)
- Създаване и управление на документи
- Версиониране на документи (semantic versioning)
- Процес на одобрение на версии
- Качване и управление на файлове към документи
- Експорт на документи в PDF формат
- Пълен аудит лог на всички действия
- Сравняване на версии
- Java 17+
- Spring Boot 3.x
- Spring Security - автентикация и авторизация
- Spring Data JPA - ORM слой
- MySQL - релационна база данни
- Hibernate - JPA имплементация
- iText PDF - генериране на PDF документи
- Lombok - редуциране на boilerplate код
- BCrypt - криптиране на пароли
Проектът следва многослойна архитектура:
┌─────────────────┐
│ UI Layer │ - ConsoleRunner
├─────────────────┤
│ Service Layer │ - Business Logic
├─────────────────┤
│Repository Layer │ - Data Access
├─────────────────┤
│ Entity Layer │ - Database Models
└─────────────────┘
main.entities- JPA ентитита (модели на базата данни)main.repositories- Spring Data репозиторииmain.services- Логикаmain.web- DTOs и уеб слойmain.config- Конфигурационни класовеmain.exceptions- Персонализирани изключенияmain.ui- Потребителски интерфейс
Системата използва MySQL база данни с име version_control_system.
1. users - Потребители на системата
user_id(UUID, PK) - уникален идентификаторusername(VARCHAR(50), UNIQUE) - потребителско имеemail(VARCHAR(100), UNIQUE) - имейл адресfull_name(VARCHAR(100)) - пълно имеpassword(VARCHAR) - хеширана парола (BCrypt)role(ENUM) - роля: READER, AUTHOR, REVIEWER, ADMINISTRATORis_active(BOOLEAN) - активен/деактивиран акаунтcreated_at(TIMESTAMP) - дата на създаванеupdated_at(TIMESTAMP) - дата на последна промянаupdated_by(UUID, FK) - кой е направил промяната
2. documents - Документи
document_id(UUID, PK) - уникален идентификаторtitle(VARCHAR(200)) - заглавие на документаdescription(TEXT) - описаниеcreated_by(UUID, FK → users) - автор на документаcreated_at(TIMESTAMP) - дата на създаванеupdated_at(TIMESTAMP) - дата на последна промяна
3. document_versions - Версии на документи
version_id(UUID, PK) - уникален идентификатор на версиятаdocument_id(UUID, FK → documents) - към кой документ принадлежиversion_major(INT) - major версияversion_minor(INT) - minor версияversion_patch(INT) - patch версияversion_number(VARCHAR(20)) - пълен номер на версията (напр. "1.2.3")content(TEXT) - съдържание на версиятаstatus(ENUM) - статус: DRAFT, PENDING, APPROVED, REJECTEDcreated_by(UUID, FK → users) - създател на версиятаcreated_at(TIMESTAMP) - дата на създаванеupdated_at(TIMESTAMP) - дата на промянаparent_version_id(UUID, FK → document_versions) - родителска версияcomment(TEXT) - коментар (при отхвърляне)is_active(BOOLEAN) - активна ли е версията
4. approvals - Одобрения на версии
approval_id(UUID, PK) - уникален идентификаторversion_id(UUID, FK → document_versions) - версия за одобрениеreviewed_by(UUID, FK → users) - reviewerdecision(ENUM) - APPROVED или REJECTEDcomment(TEXT) - коментар от reviewerreviewed_at(TIMESTAMP) - дата на одобрение/отхвърляне
5. document_files - Файлове прикачени към документи
file_id(UUID, PK) - уникален идентификаторdocument_id(UUID, FK → documents) - към кой документ принадлежиfile_name(VARCHAR) - име на файлаfile_path(VARCHAR) - път до файла на дискаfile_size_bytes(BIGINT) - размер на файла в байтовеmime_type(VARCHAR(100)) - MIME типuploaded_by(UUID, FK → users) - кой е качил файлаuploaded_at(TIMESTAMP) - дата на качванеis_deleted(BOOLEAN) - изтрит ли е (soft delete)
6. file_changes - История на промените на файлове
change_id(UUID, PK) - уникален идентификаторversion_id(UUID, FK → document_versions) - версия на документаfile_id(UUID, FK → document_files) - файлchange_type(ENUM) - ADDED, MODIFIED, DELETEDchange_summary(TEXT) - описание на промянатаchanged_by(UUID, FK → users) - кой е направил промянатаchanged_at(TIMESTAMP) - дата на промяната
7. audit_log - Аудит лог на всички действия
log_id(UUID, PK) - уникален идентификаторuser_id(UUID, FK → users) - потребител, извършил действиетоaction(VARCHAR(100)) - тип на действиетоdocument_id(UUID, FK → documents) - засегнат документ (nullable)version_id(UUID, FK → document_versions) - засегната версия (nullable)file_id(UUID, FK → document_files) - засегнат файл (nullable)target_user_id(UUID, FK → users) - целеви потребител (nullable)details(TEXT) - подробностиperformed_at(TIMESTAMP) - дата и час на действието
- One-to-Many: User → Documents (потребител може да създаде много документи)
- One-to-Many: Document → DocumentVersions (документ има много версии)
- One-to-Many: DocumentVersion → Approvals (версия може да има много одобрения)
- One-to-Many: Document → DocumentFiles (документ може да има много файлове)
- Many-to-One: DocumentVersion → DocumentVersion (parent-child връзка за версии)
Локация: src/main/java/main/services/UserService.java
Управлява потребителите и автентикацията.
Регистрира нов потребител в системата.
Параметри:
userDto- DTO обект съдържащ username, email, fullName, password, confirmPassword
Валидации:
- Username трябва да е между 3 и 20 символа
- Паролата трябва да е поне 6 символа
- Email трябва да съдържа '@'
- Username трябва да е уникален
- Email трябва да е уникален
- Паролите трябва да съвпадат
Логика:
- Първият регистриран потребител получава роля ADMINISTRATOR
- Всички останали получават роля READER по подразбиране
- Паролата се хешира с BCrypt
- Създава се audit log запис
Изключения:
IllegalArgumentException- при невалидни входни данниEntityAlreadyExistsException- при съществуващо username/emailPasswordsDoNotMatchException- при несъвпадащи пароли
Влиза в системата.
Параметри:
username- потребителско имеpassword- парола
Логика:
- Проверява дали потребителят е активен
- Проверява паролата с BCrypt
- Създава Security Context с роля на потребителя
- Записва login в audit log
Изключения:
UserNotFoundException- потребителят не съществуваDisabledException- потребителят е деактивиранBadCredentialsException- грешна парола
Променя ролята на потребител (само за ADMINISTRATOR).
Аннотации: @PreAuthorize("hasRole('ADMINISTRATOR')")
Параметри:
userId- ID на потребителяnewRole- новата роля
Логика:
- Взема текущия администратор от Security Context
- Променя ролята на целевия потребител
- Записва промяната в audit log
Локация в кода: UserService.java:132
Променя паролата на потребител.
Параметри:
userId- ID на потребителяoldPassword- текуща паролаnewPassword- нова парола
Валидации:
- Потребителят трябва да е активен
- Старата парола трябва да е вярна
Изключения:
DisabledException- потребителят е деактивиранIncorrectPasswordException- грешна текуща парола
Локация в кода: UserService.java:152
Деактивира потребител (само за ADMINISTRATOR).
Аннотации: @PreAuthorize("hasRole('ADMINISTRATOR')")
Параметри:
userId- ID на потребителя за деактивиранеadminId- ID на администратора
Изключения:
IllegalStateException- потребителят вече е деактивиран
Локация в кода: UserService.java:172
Активира деактивиран потребител (само за ADMINISTRATOR).
Аннотации: @PreAuthorize("hasRole('ADMINISTRATOR')")
Параметри:
userId- ID на потребителяadminId- ID на администратора
Изключения:
IllegalStateException- потребителят вече е активен
Локация в кода: UserService.java:191
Spring Security метод за зареждане на потребител.
Параметри:
username- потребителско име
Връща: UserDetails обект за Spring Security
Изключения:
UsernameNotFoundException- потребителят не съществуваDisabledException- потребителят е деактивиран
Локация в кода: UserService.java:214
Локация: src/main/java/main/services/DocumentService.java
Управлява документи и техните операции.
Създава нов документ с първоначална версия 1.0.0.
Аннотации: @PreAuthorize("hasRole('AUTHOR')")
Параметри:
dto- DTO с title, description, content, filePathauthor- потребител-автор
Валидации:
- Заглавието трябва да е поне 3 символа
Логика:
- Създава документ със статус DRAFT
- Автоматично създава версия 1.0.0
- Ако е предоставен filePath, качва файл
- Записва всичко в audit log
Локация в кода: DocumentService.java:48
Подава версия за одобрение от reviewer.
Аннотации: @PreAuthorize("hasRole('AUTHOR')")
Параметри:
versionId- ID на версиятаauthor- автор на документа
Валидации:
- Само авторът може да подаде за review
- Само DRAFT версии могат да се подават
Логика:
- Променя статуса на версията от DRAFT на PENDING
- Записва в audit log
Изключения:
UnauthorizedException- потребителят не е авторInvalidVersionStatusException- версията не е DRAFT
Локация в кода: DocumentService.java:75
Създава нова версия на съществуващ документ.
Аннотации: @PreAuthorize("hasRole('AUTHOR')")
Параметри:
documentId- ID на документаchangeType- "major", "minor" или "patch"content- ново съдържаниеfilePath- път до файл (optional)
Логика:
- Взема активната версия
- Инкрементва версията според changeType:
- "major": 1.2.3 → 2.0.0
- "minor": 1.2.3 → 1.3.0
- "patch": 1.2.3 → 1.2.4
- Създава нова версия със статус DRAFT
- Качва файл, ако е предоставен
Изключения:
DocumentNotFoundException- документът не съществуваActiveVersionNotFoundException- няма активна версия
Локация в кода: DocumentService.java:94
Връща историята на версиите на документ.
Аннотации: @PreAuthorize("hasAnyRole('AUTHOR', 'REVIEWER', 'ADMINISTRATOR')")
Параметри:
documentId- ID на документа
Връща: List<DocumentVersion> - всички версии, сортирани по дата
Локация в кода: DocumentService.java:103
Сравнява две версии на документ.
Аннотации: @PreAuthorize("hasAnyRole('AUTHOR', 'REVIEWER', 'READER', 'ADMINISTRATOR')")
Параметри:
versionId1- ID на първата версияversionId2- ID на втората версия
Връща: VersionComparisonResult обект съдържащ:
- Метаданни на двете версии
- Добавени редове
- Премахнати редове
Локация в кода: DocumentService.java:111
Връща активната версия на документ.
Аннотации: @PreAuthorize("hasAnyRole('READER', 'AUTHOR', 'REVIEWER', 'ADMINISTRATOR')")
Параметри:
documentId- ID на документа
Връща: DocumentVersion - активната версия
Изключения:
ActiveVersionNotFoundException- няма активна версия
Локация в кода: DocumentService.java:116
Връща всички одобрени версии на документ.
Аннотации: @PreAuthorize("hasAnyRole('READER', 'AUTHOR', 'REVIEWER', 'ADMINISTRATOR')")
Параметри:
documentId- ID на документа
Връща: List<DocumentVersion> - всички APPROVED версии
Локация в кода: DocumentService.java:123
Експортира активната версия на документ в PDF формат.
Аннотации: @PreAuthorize("hasAnyRole('READER', 'AUTHOR', 'REVIEWER', 'ADMINISTRATOR')")
Параметри:
documentId- ID на документа
Връща: byte[] - PDF файл като байтов масив
PDF съдържа:
- Заглавие на документа
- Номер на версията
- Автор
- Дата на създаване
- Статус
- Съдържание
Логика:
- Използва iText библиотека
- Записва експорт действието в audit log
Изключения:
RuntimeException- грешка при генериране на PDF
Локация в кода: DocumentService.java:131
Локация: src/main/java/main/services/DocumentVersionService.java
Управлява версиите на документите.
createDocumentVersion(Document document, DocumentVersion lastVersion, int versionMajor, int versionMinor, int versionPatch, String versionNumber, String content)
Създава нова версия на документ.
Параметри:
document- документътlastVersion- родителска версия (може да е null за първа версия)versionMajor- major номерversionMinor- minor номерversionPatch- patch номерversionNumber- пълен номер (напр. "1.2.3")content- съдържание
Логика:
- Създава версия със статус DRAFT
- Версията е неактивна по подразбиране
- Записва автора от документа
- Свързва с parent версията
Връща: Създадената DocumentVersion
Локация в кода: DocumentVersionService.java:39
Създава нова версия базирана на активната.
Аннотации: @PreAuthorize("hasRole('AUTHOR')")
Параметри:
document- документътchangeType- "major", "minor" или "patch"content- ново съдържаниеfilePath- път до файл (optional)
Логика:
- Намира активната версия
- Изчислява новия номер на версията според типа промяна
- Създава нова версия
- Качва файл ако е предоставен
Изключения:
ActiveVersionNotFoundException- няма активна версия
Локация в кода: DocumentVersionService.java:62
Активира версия и деактивира текущата активна.
Параметри:
version- версията за активиранеreviewer- потребител, който активира
Логика:
- Намира текущата активна версия и я деактивира
- Активира новата версия
- Записва в audit log
Локация в кода: DocumentVersionService.java:98
Връща към предишна версия при отхвърляне.
Параметри:
version- отхвърлената версияreviewer- reviewer
Логика:
- Деактивира текущата версия
- Ако има parent версия, активира я
- Ако няма parent (първа версия), връща я към DRAFT статус
- Записва в audit log
Локация в кода: DocumentVersionService.java:111
Сравнява съдържанието на две версии.
Параметри:
version1- ID на първата версияversion2- ID на втората версия
Връща: VersionComparisonResult с:
- Метаданни (версия, автор, дата, статус) за двете версии
- Добавени редове (в version2, но не в version1)
- Премахнати редове (в version1, но не в version2)
Алгоритъм:
- Разделя съдържанието на редове
- Филтрира редовете за намиране на разлики
Локация в кода: DocumentVersionService.java:128
Намира активната версия на документ.
Параметри:
documentId- ID на документа
Връща: Optional<DocumentVersion>
Локация в кода: DocumentVersionService.java:158
Връща всички версии на документ, сортирани по дата.
Параметри:
documentId- ID на документа
Връща: List<DocumentVersion>
Локация в кода: DocumentVersionService.java:167
Връща всички одобрени версии на документ.
Параметри:
documentId- ID на документа
Връща: List<DocumentVersion> - версии със статус APPROVED
Локация в кода: DocumentVersionService.java:171
Локация: src/main/java/main/services/ApprovalService.java
Управлява процеса на одобрение на версии.
Одобрява или отхвърля версия.
Аннотации: @PreAuthorize("hasRole('REVIEWER')")
Параметри:
versionId- ID на версиятаisApproved- true за одобрение, false за отхвърлянеcomment- коментар от reviewerreviewer- потребител reviewer
Валидации:
- Само PENDING версии могат да се одобряват
Логика:
- Създава Approval запис
- При одобрение: активира версията
- При отхвърляне: връща към предишна версия
- Записва всичко в audit log
Изключения:
InvalidVersionStatusException- версията не е PENDING
Локация в кода: ApprovalService.java:33
Одобрява версия.
Аннотации: @PreAuthorize("hasRole('REVIEWER')")
Параметри:
version- версиятаreviewer- reviewer
Логика:
- Променя статуса на APPROVED
- Активира версията
- Обновява updatedAt на документа
- Записва в audit log
Локация в кода: ApprovalService.java:60
Отхвърля версия.
Аннотации: @PreAuthorize("hasRole('REVIEWER')")
Параметри:
version- версиятаreviewer- reviewerreason- причина за отхвърляне
Логика:
- Променя статуса на REJECTED
- Записва причината в коментар
- Rollback към предишна версия
- Обновява updatedAt на документа
- Записва в audit log
Локация в кода: ApprovalService.java:72
Локация: src/main/java/main/services/DocumentFileService.java
Управлява файлове, прикачени към документи.
Качва файл към документ.
Параметри:
sourcePath- път до файла на локалната системаdocument- документътversion- версията на документаuploadedBy- потребител, който качва
Валидации:
- Файлът трябва да съществува
Логика:
- Копира файла в директория
uploads/{documentId}/{filename} - Създава директории ако не съществуват
- Записва метаданни (име, размер, MIME тип)
- Създава FileChange запис с тип ADDED
- Записва в audit log
Връща: Създадения DocumentFile
Изключения:
IllegalArgumentException- файлът не съществуваRuntimeException- грешка при копиране
Локация в кода: DocumentFileService.java:33
Изтрива файл (soft delete).
Параметри:
fileId- ID на файлаversion- версията на документаdeletedBy- потребител, който изтрива
Логика:
- Маркира файла като изтрит (isDeleted = true)
- Създава FileChange запис с тип DELETED
- Записва в audit log
Изключения:
IllegalArgumentException- файлът не е намерен
Локация в кода: DocumentFileService.java:72
Връща всички файлове на документ.
Параметри:
documentId- ID на документа
Връща: List<DocumentFile> - всички неизтрити файлове
Локация в кода: DocumentFileService.java:89
Локация: src/main/java/main/services/AuditLogService.java
Създава записи в audit log за всички действия в системата.
Създава лог за действие свързано с потребител.
Параметри:
user- потребител, извършил действиетоaction- тип на действието (напр. "USER REGISTERED", "CHANGE ROLE")targetUser- целеви потребителdetails- подробности
Локация в кода: AuditLogService.java:22
createLogForDocument(User user, String action, Document document, DocumentVersion version, DocumentFile file, String details)
Създава лог за действие свързано с документ.
Параметри:
user- потребител, извършил действиетоaction- тип на действиетоdocument- документътversion- версията (nullable)file- файлът (nullable)details- подробности
Примери за действия:
- "CREATE DOCUMENT"
- "SUBMIT FOR REVIEW"
- "APPROVE VERSION"
- "REJECT VERSION"
- "EXPORT TO PDF"
Локация в кода: AuditLogService.java:33
createLogForDocumentFile(User user, String action, Document document, DocumentVersion documentVersion, DocumentFile file, String details)
Създава лог за действие с файл.
Параметри:
user- потребителaction- действиеdocument- документdocumentVersion- версияfile- файлdetails- подробности
Примери за действия:
- "UPLOAD DOCUMENT FILE"
- "DELETE DOCUMENT FILE"
- "CHANGE DOCUMENT FILE"
Локация в кода: AuditLogService.java:47
createLogForDocumentVersion(User reviewer, String action, Document document, DocumentVersion documentVersion, String details)
Създава лог за действие с версия.
Параметри:
reviewer- потребителaction- действиеdocument- документdocumentVersion- версияdetails- подробности
Примери за действия:
- "ACTIVATE VERSION"
- "ROLLBACK TO DRAFT"
Локация в кода: AuditLogService.java:60
Локация: src/main/java/main/services/FileChangeService.java
Управлява промени на файлове между версии.
Записва промяна на файл.
Параметри:
fileChange- обект FileChange
Локация в кода: FileChangeService.java:19
spring.application.name=version-control-system
# MySQL Database Configuration
spring.datasource.url=jdbc:mysql://localhost:3306/version_control_system?createDatabaseIfNotExist=true
spring.datasource.username=YOUR_USERNAME
spring.datasource.password=YOUR_PASSWORD
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA/Hibernate Configuration
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true- Инсталирайте MySQL Server
- Заменете
YOUR_USERNAMEиYOUR_PASSWORDс вашите MySQL credentials - Базата данни ще се създаде автоматично при първо стартиране
- Java 17 или по-нова версия
- Maven 3.6+
- MySQL Server 8.0+
Приложението е конзолно. Стартирайте го като изпълните VersionControlSystemApplication.java, след което ConsoleRunner ще поеме управлението на потребителския интерфейс.
- Преглед на документи
- Преглед на одобрени версии
- Сравняване на версии
- Експорт на документи в PDF
- Всички права на READER
- Създаване на документи
- Създаване на нови версии
- Подаване за одобрение
- Качване на файлове
- Всички права на READER
- Одобряване на версии
- Отхвърляне на версии
- Преглед на версии в очакване
- Всички права на AUTHOR и REVIEWER
- Промяна на роли на потребители
- Активиране/Деактивиране на потребители
- Пълен достъп до audit log
- AUTHOR създава документ (статус: DRAFT, версия 1.0.0)
- AUTHOR подава за одобрение (статус: PENDING)
- REVIEWER преглежда и взима решение:
- APPROVED: Версията става активна (статус: APPROVED)
- REJECTED: Връща се към предишна версия или DRAFT
- AUTHOR може да създаде нова версия базирана на одобрената
Системата използва semantic versioning (MAJOR.MINOR.PATCH):
- MAJOR (1.0.0 → 2.0.0): Съществени промени, несъвместими с предишни версии
- MINOR (1.0.0 → 1.1.0): Нова функционалност, съвместима с предишни версии
- PATCH (1.0.0 → 1.0.1): Малки корекции и bug fixes
Всички действия в системата се записват в audit log:
- Потребителски действия (регистрация, login, промяна на роля)
- Документни действия (създаване, редакция, одобрение)
- Файлови операции (качване, изтриване)
- Промени на версии (създаване, активиране, rollback)
Всеки лог съдържа:
- Кой е извършил действието
- Какво действие е извършено
- Кога е извършено
- Подробности за действието