Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
284 changes: 282 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,282 @@
# Platform-Server
ํ‚คํ‚คํ•˜์ด - ์„œ๋ฒ„ ํ”Œ๋žซํผ
# KiKiHi Backend Server

์ปค์Šคํ…€ ํ‚ค๋ณด๋“œ ํ”Œ๋žซํผ์„ ์œ„ํ•œ Spring Boot ๊ธฐ๋ฐ˜ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„

## ๐Ÿ“‹ ๋ชฉ์ฐจ

- [๊ฐœ์š”](#๊ฐœ์š”)
- [๊ธฐ์ˆ  ์Šคํƒ](#๊ธฐ์ˆ -์Šคํƒ)
- [์•„ํ‚คํ…์ฒ˜](#์•„ํ‚คํ…์ฒ˜)
- [MongoDB ์„ค์ • ๋ฐ ์šด์˜](#mongodb-์„ค์ •-๋ฐ-์šด์˜)
- [ELK Stack ์„ค์ • ๋ฐ ์šด์˜](#elk-stack-์„ค์ •-๋ฐ-์šด์˜)
- [๋ฐ์ดํ„ฐ ๋™๊ธฐํ™”: Monstache](#๋ฐ์ดํ„ฐ-๋™๊ธฐํ™”-monstache)
- [๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ •](#๋กœ์ปฌ-๊ฐœ๋ฐœ-ํ™˜๊ฒฝ-์„ค์ •)
- [์ฃผ์š” ๋ช…๋ น์–ด](#์ฃผ์š”-๋ช…๋ น์–ด)

## ๊ฐœ์š”

KiKiHi Backend๋Š” ์ปค์Šคํ…€ ํ‚ค๋ณด๋“œ ๋ถ€ํ’ˆ ๊ฒ€์ƒ‰, ์ถ”์ฒœ, ๋ถ๋งˆํฌ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค.
๋ฉ€ํ‹ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ „๋žต์„ ์‚ฌ์šฉํ•˜๋ฉฐ, MongoDB์—์„œ Elasticsearch๋กœ์˜ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ๋™๊ธฐํ™”๋ฅผ ํ†ตํ•ด ๊ฐ•๋ ฅํ•œ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

## ๊ธฐ์ˆ  ์Šคํƒ

### Core
- **Java 17** / **Spring Boot 3.4.3**
- **Gradle 8.13**

### ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค
- **MySQL 8.0**: ์‚ฌ์šฉ์ž, ๋ถ๋งˆํฌ, ์ปค์Šคํ…€ ํ‚ค๋ณด๋“œ ๋ฐ์ดํ„ฐ
- **MongoDB**: ์ƒํ’ˆ ์นดํƒˆ๋กœ๊ทธ (Replica Set ๊ตฌ์„ฑ)
- **Redis 7.2.5**: JWT ํ† ํฐ ๊ด€๋ฆฌ, ์„ธ์…˜ ์บ์‹œ
- **Elasticsearch 8.x**: ๊ฒ€์ƒ‰ ์—”์ง„ (analysis-nori ํ”Œ๋Ÿฌ๊ทธ์ธ)

### ๋ชจ๋‹ˆํ„ฐ๋ง & ๋กœ๊น…
- **ELK Stack**
- Elasticsearch: ๋กœ๊ทธ ์ €์žฅ ๋ฐ ๊ฒ€์ƒ‰
- Logstash: ๋กœ๊ทธ ์ˆ˜์ง‘ ๋ฐ ๋ณ€ํ™˜
- Kibana: ๋กœ๊ทธ ์‹œ๊ฐํ™” ๋ฐ ๋ถ„์„

### ๋ฐ์ดํ„ฐ ๋™๊ธฐํ™”
- **Monstache**: MongoDB โ†’ Elasticsearch ์‹ค์‹œ๊ฐ„ ๋™๊ธฐํ™”

### ๋ณด์•ˆ & ์ธ์ฆ
- **Spring Security 6.x**
- **JWT** (jjwt 0.11.5)
- **OAuth2** (Google, Kakao)

## ์•„ํ‚คํ…์ฒ˜

### ๋ฉ€ํ‹ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ „๋žต

```
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ MySQL โ”‚ โ”‚ MongoDB โ”‚ โ”‚ Redis โ”‚
โ”‚ (JPA/RDB) โ”‚ โ”‚ (Products) โ”‚ โ”‚ (Session) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚
Monstache
(Change Stream)
โ”‚
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚Elasticsearchโ”‚
โ”‚ (Search) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
```

- **MySQL**: ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ (User, Bookmark, CustomKeyboard)
- **MongoDB**: ์œ ์—ฐํ•œ ์Šคํ‚ค๋งˆ๊ฐ€ ํ•„์š”ํ•œ ์ƒํ’ˆ ๋ฐ์ดํ„ฐ (Product)
- **Elasticsearch**: ํ•œ๊ธ€ ํ˜•ํƒœ์†Œ ๋ถ„์„ ๊ธฐ๋ฐ˜ ์ƒํ’ˆ ๊ฒ€์ƒ‰
- **Redis**: JWT ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ ๊ด€๋ฆฌ

### ๋ฐ์ดํ„ฐ ํ๋ฆ„

```
Application โ†’ MongoDB (์ƒํ’ˆ ๋“ฑ๋ก/์ˆ˜์ •/์‚ญ์ œ)
โ†“
Change Stream (์‹ค์‹œ๊ฐ„ ๊ฐ์ง€)
โ†“
Monstache (๋™๊ธฐํ™”)
โ†“
Elasticsearch (๊ฒ€์ƒ‰ ์ธ๋ฑ์Šค ์—…๋ฐ์ดํŠธ)
โ†“
Application โ†’ ๊ฒ€์ƒ‰ API ์ œ๊ณต
```

## MongoDB ์„ค์ • ๋ฐ ์šด์˜

### Replica Set ๊ตฌ์„ฑ

MongoDB๋Š” **Replica Set** ๋ชจ๋“œ๋กœ ๊ตฌ์„ฑ๋˜์–ด Change Stream์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค:

```yaml
services:
mongodb1:
image: mongo:latest
ports:
- "27017:27017"
command:
- mongod
- "--replSet"
- "replication"
- "--keyFile"
- "/etc/mongodb.key"
- "--bind_ip_all"

mongodb2:
image: mongo:latest
ports:
- "27018:27017"
command:
- mongod
- "--replSet"
- "replication"
- "--keyFile"
- "/etc/mongodb.key"
- "--bind_ip_all"
```

### Replica Set ์ดˆ๊ธฐํ™”

Replica Set์€ `mongosetup` ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ž๋™์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค:

```javascript
rs.initiate({
_id: "replication",
members: [
{ _id: 0, host: "mongodb1:27017" },
{ _id: 1, host: "mongodb2:27017" }
]
})
```

## ELK Stack ์„ค์ • ๋ฐ ์šด์˜

### Elasticsearch ์„ค์ •

#### ๋ณด์•ˆ ์ธ์ฆ์„œ ์ƒ์„ฑ

Elasticsearch๋Š” TLS/SSL์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณด์•ˆ ํ†ต์‹ ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. `setup` ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ž๋™์œผ๋กœ ์ธ์ฆ์„œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค:

```bash
# CA ์ธ์ฆ์„œ ์ƒ์„ฑ
elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip

# ๋…ธ๋“œ๋ณ„ ์ธ์ฆ์„œ ์ƒ์„ฑ (es01, kibana, monstache)
elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip
```

#### Elasticsearch ๊ตฌ์„ฑ

```yaml
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:8.x
ports:
- "9200:9200"
environment:
- node.name=es01
- cluster.name=kikihi-cluster
- discovery.type=single-node
- ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
- xpack.security.enabled=true
- xpack.security.http.ssl.enabled=true
```

#### analysis-nori ํ”Œ๋Ÿฌ๊ทธ์ธ (ํ•œ๊ธ€ ํ˜•ํƒœ์†Œ ๋ถ„์„)

Elasticsearch ์‹œ์ž‘ ์‹œ ์ž๋™์œผ๋กœ `analysis-nori` ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์„ค์น˜ํ•˜์—ฌ ํ•œ๊ธ€ ๊ฒ€์ƒ‰์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค:

```bash
# Dockerfile entrypoint์—์„œ ์ž๋™ ์‹คํ–‰
bin/elasticsearch-plugin install -b analysis-nori
```

#### ์ธ๋ฑ์Šค ๋งคํ•‘ ์˜ˆ์‹œ

```json
{
"settings": {
"analysis": {
"analyzer": {
"korean_analyzer": {
"type": "custom",
"tokenizer": "nori_tokenizer",
"filter": ["lowercase", "nori_readingform"]
}
}
}
},
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "korean_analyzer"
},
"category": {
"type": "keyword"
},
"price": {
"type": "integer"
}
}
}
}
```

### Logstash ์„ค์ •

#### Logstash ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์„ฑ

Logstash๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๊ทธ๋ฅผ Elasticsearch๋กœ ์ „์†กํ•ฉ๋‹ˆ๋‹ค:

```ruby
# docker/logstash/logstash.conf
input {
tcp {
port => 5044
codec => json
}
}

filter {
# JSON ๋กœ๊ทธ ํŒŒ์‹ฑ
if [message] =~ /^\{/ {
json {
source => "message"
}
}

# ํƒ€์ž„์Šคํƒฌํ”„ ์„ค์ •
date {
match => ["timestamp", "ISO8601"]
target => "@timestamp"
}
}

output {
elasticsearch {
hosts => ["https://es01:9200"]
index => "app-logs-%{+YYYY.MM.dd}"
user => "elastic"
password => "${ELASTIC_PASSWORD}"
cacert => "/usr/share/logstash/certs/ca/ca.crt"
}

stdout {
codec => rubydebug
}
}
```

#### Spring Boot Logback ์„ค์ •

```xml
<!-- src/main/resources/logback-spring.xml -->
<configuration>
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>localhost:5044</destination>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"app":"kikihi-backend"}</customFields>
</encoder>
</appender>

<root level="INFO">
<appender-ref ref="LOGSTASH"/>
</root>
</configuration>
```

### Kibana ์„ค์ •

#### ์ฃผ์š” ํ™œ์šฉ

1. **Discover**: ์‹ค์‹œ๊ฐ„ ๋กœ๊ทธ ๊ฒ€์ƒ‰ ๋ฐ ํ•„ํ„ฐ๋ง
2. **Dashboard**: ์ปค์Šคํ…€ ๋Œ€์‹œ๋ณด๋“œ ์ƒ์„ฑ
- API ์š”์ฒญ ์ˆ˜ ์ถ”์ด
- ์—๋Ÿฌ ๋ฐœ์ƒ ํ†ต๊ณ„
- ์‘๋‹ต ์‹œ๊ฐ„ ๋ถ„์„
3. **Alerting**: ํŠน์ • ์กฐ๊ฑด ๋ฐœ์ƒ ์‹œ ์•Œ๋ฆผ ์„ค์ •

## ๋ผ์ด์„ ์Šค

์ด ํ”„๋กœ์ ํŠธ๋Š” KiKiHi ํŒ€์˜ ์†Œ์œ ์ž…๋‹ˆ๋‹ค.
Loading