Build-Up Platformμ λ°±μλ μλΉμ€μ λλ€.
- Language: Java 21 (LTS)
- Framework: Spring Boot 3.5.7
- Database: MySQL
- ORM: Spring Data JPA
- Security: Spring Security
- Build Tool: Gradle
- Others: Lombok
- Java 21 μ΄μ
- MySQL 8.0 μ΄μ
- Gradle 8.x (λλ Gradle Wrapper μ¬μ©)
νλ‘μ νΈ λ£¨νΈμ .env νμΌμ μμ±νμ¬ νκ²½ λ³μλ₯Ό κ΄λ¦¬ν©λλ€:
# env.exampleμ .envλ‘ λ³΅μ¬
cp env.example .env.env νμΌ μμ:
# Spring νλ‘νμΌ
SPRING_PROFILES_ACTIVE=prod
# JWT λ° μνΈν
JWT_SECRET=your-secret-key-min-256-bits-long-for-hs256-algorithm
ENCRYPTION_KEY=your_32_byte_secure_encryption_key
# κ΄λ¦¬μ κ³μ
ADMIN_USERNAME=admin
ADMIN_PASSWORD=your_secure_admin_password
# λ°μ΄ν°λ² μ΄μ€
MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_DATABASE=buildup
MYSQL_USER=buildup_user
MYSQL_PASSWORD=your_mysql_password
MYSQL_PORT=3306
# AWS S3
AWS_S3_ENABLED=true
AWS_S3_BUCKET=your-s3-bucket-name
AWS_REGION=ap-northeast-2
AWS_ACCESS_KEY_ID=your_aws_access_key_id
AWS_SECRET_ACCESS_KEY=your_aws_secret_access_key
# AI Face Similarity API (μ νμ¬ν)
AI_FACE_SIMILARITY_BASE_URL=http://localhost:8000
AI_FACE_SIMILARITY_API_KEY=your_face_api_keyνκ²½ λ³μ μμ± λꡬ:
# JWT Secret μμ± (32λ°μ΄νΈ μ΄μ)
openssl rand -hex 32
# μνΈν ν€ μμ± (32λ°μ΄νΈ)
openssl rand -hex 32νμΌ μ λ‘λ κΈ°λ₯μ μ¬μ©νλ €λ©΄ AWS S3 μ€μ μ΄ νμν©λλ€.
π μμΈ κ°μ΄λ: AWS S3 μ€μ κ°μ΄λ
μ£Όμ λ¨κ³:
- AWS S3 λ²ν· μμ±
- IAM μ¬μ©μ μμ± λ° κΆν μ€μ
- μ‘μΈμ€ ν€ λ°κΈ
.envνμΌμ μ격 μ¦λͺ μ λ ₯
git clone <repository-url>
cd buildupνλ‘μ νΈ μ€ν λ°©λ²μ μΈ κ°μ§κ° μμ΅λλ€:
Docker Composeλ₯Ό μ¬μ©νμ¬ λͺ¨λ μλΉμ€(μ ν리μΌμ΄μ , MySQL, Nginx)λ₯Ό ν λ²μ μ€νν©λλ€.
Prerequisites:
- Docker Desktop μ€ν μ€μ΄μ΄μΌ ν¨
.envνμΌ μ€μ μλ£
# λͺ¨λ μλΉμ€ μμ
docker-compose up -d
# λ‘κ·Έ νμΈ
docker-compose logs -f app
# μλΉμ€ μ€μ§
docker-compose down
# λ³Όλ₯¨κΉμ§ μμ (λ°μ΄ν°λ² μ΄μ€ μ΄κΈ°ν)
docker-compose down -vμλΉμ€ μ μ:
- μ ν리μΌμ΄μ : http://localhost:8080/api
- Swagger UI: http://localhost:8080/api/swagger-ui/index.html (dev νλ‘νμΌμμλ§)
- MySQL: localhost:3306
- Nginx: http://localhost (80), https://localhost (443)
Dockerλ₯Ό μ¬μ©νμ¬ MySQLκ³Ό phpMyAdminμ μλμΌλ‘ μ€μ νκ³ μ ν리μΌμ΄μ μ μ€νν©λλ€.
Prerequisites:
- Docker Desktop μ€ν μ€μ΄μ΄μΌ ν¨
docker-compose.dev.ymlνμΌ νμ
# μ€ν¬λ¦½νΈμ μ€ν κΆν λΆμ¬
chmod +x ./start-dev.sh
# κ°λ° νκ²½ μμ
./start-dev.shμ΄ μ€ν¬λ¦½νΈλ λ€μμ μλμΌλ‘ μνν©λλ€:
- Docker Composeλ‘ MySQLκ³Ό phpMyAdmin 컨ν μ΄λ μμ
- MySQL μ°κ²° λκΈ° λ° νμΈ
- Spring Boot μ ν리μΌμ΄μ
μ
devνλ‘νμΌλ‘ μ€ν - μ’ λ£ μ(Ctrl+C) Docker 컨ν μ΄λ μ 리 μ΅μ μ 곡
μλΉμ€ μ μ:
- μ ν리μΌμ΄μ : http://localhost:8080/api
- Swagger UI: http://localhost:8080/api/swagger-ui/index.html
- phpMyAdmin: http://localhost:8081
λ‘컬 MySQLμ μ¬μ©νκ±°λ Docker μμ΄ μ€ννλ κ²½μ°:
# λ°μ΄ν°λ² μ΄μ€ μμ± (MySQLμ΄ μ΄λ―Έ μ€μΉλμ΄ μμ΄μΌ ν¨)
mysql -u root -p
CREATE DATABASE buildup CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
exit;
# μ ν리μΌμ΄μ
λΉλ
./gradlew build
# μ ν리μΌμ΄μ
μ€ν
./gradlew bootRunλλ λΉλλ JAR νμΌ μ§μ μ€ν:
java -jar build/libs/buildup-0.0.1-SNAPSHOT.jarμ ν리μΌμ΄μ
μ΄ μ μμ μΌλ‘ μ€νλλ©΄ http://localhost:8080μμ μ κ·Όν μ μμ΅λλ€.
# λͺ¨λ ν
μ€νΈ μ€ν
./gradlew test
# νΉμ ν
μ€νΈ μ€ν
./gradlew test --tests com.concrete.buildup.BuildupApplicationTests
# λΉλ μ 리
./gradlew cleanκΈ°λ³Έ ν¨ν€μ§: com.concrete.buildup
Domain μ€μ¬ ꡬ쑰λ₯Ό μ±ννμ¬ κ° λλ©μΈλ³λ‘ κ΄λ ¨ λ μ΄μ΄λ₯Ό κ·Έλ£Ήνν©λλ€.
src/main/java/com/concrete/buildup/
βββ domain/ # λλ©μΈλ³ κΈ°λ₯ λͺ¨λ
β βββ auth/ # μΈμ¦/μΈκ° (νμκ°μ
, λ‘κ·ΈμΈ, ν ν°)
β β βββ controller/
β β βββ service/
β β βββ repository/
β β βββ dto/
β β βββ entity/
β βββ employee/ # μ¬μ κ΄λ¦¬
β β βββ controller/
β β βββ service/
β β βββ repository/
β β βββ dto/
β β βββ entity/
β βββ site/ # νμ₯ κ΄λ¦¬
β βββ contract/ # κ³μ½ κ΄λ¦¬
β βββ payroll/ # κΈμ¬ κ΄λ¦¬
β βββ attendance/ # κ·Όν κ΄λ¦¬
β βββ workreport/ # μμ
μΌλ³΄
β βββ safetydoc/ # μμ κ΅μ‘μΌμ§
βββ global/ # μ μ μ€μ λ° κ³΅ν΅ κΈ°λ₯
β βββ config/ # μ€μ ν΄λμ€ (Security, JPA, Web)
β βββ exception/ # μμΈ μ²λ¦¬
β βββ common/ # κ³΅ν΅ μ νΈλ¦¬ν°, μμ
β βββ util/ # μ νΈλ¦¬ν° ν΄λμ€
βββ BuildupApplication.java # λ©μΈ μ ν리μΌμ΄μ
| λλ©μΈ | μ€λͺ | μ£Όμ κΈ°λ₯ |
|---|---|---|
| auth | μΈμ¦/μΈκ° | νμκ°μ , λ‘κ·ΈμΈ, ν ν° κ΄λ¦¬ |
| employee | μ¬μ κ΄λ¦¬ | μ¬μ λͺ©λ‘, κ²μ |
| site | νμ₯ κ΄λ¦¬ | νμ₯ λ±λ‘, μ‘°ν, λμ보λ |
| contract | κ³μ½ κ΄λ¦¬ | κ·Όλ‘κ³μ½μ μμ±, μλͺ |
| payroll | κΈμ¬ κ΄λ¦¬ | κΈμ¬ λͺ©λ‘, λͺ μΈμ μμ± |
| attendance | κ·Όν κ΄λ¦¬ | μΆν΄κ·Ό κΈ°λ‘ |
| workreport | μμ μΌλ³΄ | μμ μΌλ³΄ μμ±, PDF |
| safetydoc | μμ κ΅μ‘μΌμ§ | μμ κ΅μ‘ μμ±, μλͺ |
μΆν μΆκ° μμ
API μλν¬μΈνΈλ λ€μκ³Ό κ°μ νμμΌλ‘ λ¬Έμνλ μμ μ λλ€:
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /api/users |
μ¬μ©μ λͺ©λ‘ μ‘°ν | Yes |
| POST | /api/users |
μ μ¬μ©μ μμ± | Yes |
μΆν μΆκ° μμ
νλ‘μ νΈμ μ£Όμ κΈ°λ₯λ€μ΄ μ¬κΈ°μ λ¬Έμνλ μμ μ λλ€:
- μ¬μ©μ κ΄λ¦¬
- μΈμ¦ λ° κΆν κ΄λ¦¬
- [μΆκ° κΈ°λ₯λ€]
λͺ¨λ APIλ μΌκ΄λ μλ΅ νμμ μ¬μ©ν©λλ€:
{
"success": true,
"message": "μμ²μ΄ μ±κ³΅μ μΌλ‘ μ²λ¦¬λμμ΅λλ€",
"data": {
// μλ΅ λ°μ΄ν°
}
}{
"success": false,
"message": "μλ¬ λ©μμ§",
"data": null
}νλ‘μ νΈλ GitHub Actionsλ₯Ό μ¬μ©ν μλνλ CI/CD νμ΄νλΌμΈμ μ 곡ν©λλ€.
- μλ μ€ν: PR μμ± μ,
main/developλΈλμΉ νΈμ μ - μμ λ΄μ©: μλ ν μ€νΈ, λΉλ, Docker μ΄λ―Έμ§ λΉλ
- νμ μ€μ : μμ (μ¦μ μ¬μ© κ°λ₯)
- μλ λ°°ν¬:
mainλΈλμΉ β μ΄μ νκ²½ (Production) λ°°ν¬developλΈλμΉ β κ°λ° νκ²½ (Staging) λ°°ν¬
- νμ μ€μ : GitHub Secrets λ±λ‘ νμ
π μμΈ κ°μ΄λ: GitHub Actions μ€μ κ°μ΄λ
- ν΄λμ€: PascalCase (μ:
UserService,OrderController) - λ©μλ/λ³μ: camelCase (μ:
findUserById,userName) - μμ: UPPER_SNAKE_CASE (μ:
MAX_RETRY_COUNT)
- Entity: JPA μν°ν°,
@Entityμ¬μ©, Lombok νμ© - Repository:
JpaRepositoryμμ, λ©μλλͺ κΈ°λ° μΏΌλ¦¬ - Service:
@Service,@Transactionalνμ©, λΉμ¦λμ€ λ‘μ§ κ΅¬ν - Controller:
@RestController, RESTful API,ResponseEntityμ¬μ©
Domain μ€μ¬ ꡬ쑰μμμ κ°λ° μμ:
- λλ©μΈ ν¨ν€μ§ μμ± (
domain/{domain-name}/) - Entity μ μ (
domain/{domain-name}/entity/) - Repository μμ± (
domain/{domain-name}/repository/) - DTO μμ± (
domain/{domain-name}/dto/) - Service μμ± (
domain/{domain-name}/service/) - Controller μμ± (
domain/{domain-name}/controller/) - ν μ€νΈ μ½λ μμ±
μμ: μλ‘μ΄ project λλ©μΈ μΆκ° μ
domain/project/
βββ controller/
β βββ ProjectController.java
βββ service/
β βββ ProjectService.java
βββ repository/
β βββ ProjectRepository.java
βββ dto/
β βββ ProjectRequestDto.java
β βββ ProjectResponseDto.java
βββ entity/
βββ Project.java
- Spring Security: λͺ¨λ μλν¬μΈνΈλ κΈ°λ³Έμ μΌλ‘ μΈμ¦ νμ
- Lombok:
@Data,@Builder,@RequiredArgsConstructorλ± μ κ·Ή νμ© - JPA μ΅μ ν: N+1 λ¬Έμ μ£Όμ, fetch join/EntityGraph νμ©
- νΈλμμ
: μ½κΈ° μ μ©μ
@Transactional(readOnly = true)μ¬μ©
λΌμ΄μ μ€ μ 보 μΆκ° μμ
κΈ°μ¬ κ°μ΄λλΌμΈ μΆκ° μμ
λ¬Έμμ² μ 보 μΆκ° μμ