Skip to content

Commit

Permalink
chore: v1.0.0을 배포한다.
Browse files Browse the repository at this point in the history
Co-authored-by: seungpang <[email protected]>
Co-authored-by: yxxnghwan <[email protected]>
Co-authored-by: kth990303 <[email protected]>
Co-authored-by: asebn1 <[email protected]>
Co-authored-by: prefer2 <[email protected]>
Co-authored-by: soyi47 <[email protected]>
  • Loading branch information
6 people authored Oct 20, 2022
2 parents 00a03e8 + 0b8dcbf commit e4c3be3
Show file tree
Hide file tree
Showing 180 changed files with 3,325 additions and 1,337 deletions.
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@
<p align="middle">내 마음을 편지로, 내편</p>

### 프로젝트 소개 💌
내편은 롤링페이퍼 서비스입니다. 원하는 사람들과 모임을 만들어 롤링페이퍼를 작성할 수 있습니다.
내편 서비스를 통해 `내 편`에게 마음을 전달해보아요!

내편은 롤링페이퍼 서비스입니다. 원하는 사람들과 모임을 만들어 롤링페이퍼를 작성할 수 있습니다.
내편 서비스를 통해 `내 편`에게 마음을 전달해보아요!

### 팀원 👩‍👦‍👦

|프론트엔드|프론트엔드|백엔드|백엔드|백엔드|백엔드|
|:-:|:-:|:-:|:-:|:-:|:-:|
|![도리](https://user-images.githubusercontent.com/57438644/194012074-b174c57c-73a1-4987-ba7f-c43e9275bbe2.png?size=100)|![소피아](https://user-images.githubusercontent.com/57438644/194012003-85309c16-a8b9-4cb8-9f29-ea6c41b5dac8.png?size=100)|![케이](https://user-images.githubusercontent.com/57438644/194011499-0d1445fc-6ad8-473b-aec1-55b47ad3bf57.png?size=100)|![승팡](https://user-images.githubusercontent.com/57438644/194011899-3c2ad161-d79e-4d30-b480-b7855ebeeb2c.png?size=100)|![알렉스](https://user-images.githubusercontent.com/57438644/194011294-6a49501a-3cac-4973-8b12-22edb6c3619f.png?size=100)|![제로](https://user-images.githubusercontent.com/57438644/194011739-accc3a55-4d93-435f-aa4c-94db4933ca2f.png?size=100)|
|[도리](https://github.com/prefer2)|[소피아](https://github.com/soyi47)|[케이](https://github.com/kth990303)|[승팡](https://github.com/seungpang)|[알렉스](https://github.com/yxxnghwan)|[제로](https://github.com/asebn1)|

| 프론트엔드 | 프론트엔드 | 백엔드 | 백엔드 | 백엔드 | 백엔드 |
| :---------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------: |
| ![도리](https://user-images.githubusercontent.com/57438644/194012074-b174c57c-73a1-4987-ba7f-c43e9275bbe2.png?size=100) | ![소피아](https://user-images.githubusercontent.com/57438644/194012003-85309c16-a8b9-4cb8-9f29-ea6c41b5dac8.png?size=100) | ![케이](https://user-images.githubusercontent.com/57438644/194011499-0d1445fc-6ad8-473b-aec1-55b47ad3bf57.png?size=100) | ![승팡](https://user-images.githubusercontent.com/57438644/194011899-3c2ad161-d79e-4d30-b480-b7855ebeeb2c.png?size=100) | ![알렉스](https://user-images.githubusercontent.com/57438644/194011294-6a49501a-3cac-4973-8b12-22edb6c3619f.png?size=100) | ![제로](https://user-images.githubusercontent.com/57438644/194011739-accc3a55-4d93-435f-aa4c-94db4933ca2f.png?size=100) |
| [도리](https://github.com/prefer2) | [소피아](https://github.com/soyi47) | [케이](https://github.com/kth990303) | [승팡](https://github.com/seungpang) | [알렉스](https://github.com/yxxnghwan) | [제로](https://github.com/asebn1) |

## 프로젝트 기술스택 🏰

Expand All @@ -25,17 +24,20 @@

### 프론트엔드 🏡

![프론트엔드기술스택](https://user-images.githubusercontent.com/67692759/195179519-bc23f088-c225-462a-bfcc-bed231ae98d7.png)

## 프로젝트 아키텍처 📚

### 백엔드 프로젝트 아키텍처 📙

![백엔드_프로젝트_아키텍처](https://user-images.githubusercontent.com/57438644/194009329-48f0d8a1-66e3-4624-98be-b6ff44ae04f9.JPG)

### 프론트엔드 프로젝트 아키텍처 📘

### CI/CD
![슬라이드5](https://user-images.githubusercontent.com/57438644/194009306-18b6b7be-9ed1-439f-8109-45f94eef9888.JPG)

![슬라이드5](https://user-images.githubusercontent.com/57438644/194009306-18b6b7be-9ed1-439f-8109-45f94eef9888.JPG)

## 팀 문화
![팀문화](https://user-images.githubusercontent.com/57438644/194008156-205b797c-8592-41d2-924c-c6472f549dde.JPG)

![팀문화](https://user-images.githubusercontent.com/57438644/194008156-205b797c-8592-41d2-924c-c6472f549dde.JPG)
1 change: 1 addition & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ dependencies {
implementation 'org.flywaydb:flyway-core:6.4.2'
implementation 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.3'
implementation "com.querydsl:querydsl-jpa:5.0.0"
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
annotationProcessor "com.querydsl:querydsl-apt:5.0.0"

compileOnly 'org.projectlombok:lombok'
Expand Down
83 changes: 83 additions & 0 deletions backend/docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
## local에서 간편하게 mysql 이중화 설정하기

### 도커 실행하기

```shell
# docker-compose.yml있는 디렉토리로 이동 후
docker-compose up -d
```

### source mysql 접속해서 복제 계정 생성
```shell
docker ps
docker exec -it {SOURCE_CONTAINER_ID} bash
mysql -uroot -p
#비밀번호는 password

# 복제 계정 준비
CREATE USER 'repl_user'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* To 'repl_user'@'%';
flush privileges;
```

### source 서버 host 알기
```shell
docker network ls
docker inspect {CONTAINER ID}
# docker_net-mysql
```

### replica mysql 접속하기
```shell
docker ps
docker exec -it {REPLICA_CONTAINER_ID} bash
mysql -uroot -p
#비밀번호는 password
```

### replica 도커 접속해서 복제 설정 입력하기
```shell
stop replica;

CHANGE REPLICATION SOURCE TO
SOURCE_HOST='소스서버 host주소',
SOURCE_PORT=3306,
SOURCE_USER='repl_user',
SOURCE_PASSWORD='password',
SOURCE_AUTO_POSITION=1,
GET_SOURCE_PUBLIC_KEY=1;

start replica;
```

### replica mysql 상태 확인하기
```
show replica status\G;
```

```shell
Replica_IO_Running: No 상태이고
Last_IO_Error: Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server ids;
these ids must be different for replication to work 이런 에러상태이면

해당 레플리카 서버의 server_id가 소스서버와 같은 상태
stop replica;

SET GLOBAL server_id=2

start replica;
```

### 이중화가 정상적으로 이루어 지는지 확인하는 법
```shell
#mysql 접속
#log상태 확인
show variables like 'general%';

#log 활성화
set global general_log = ON;

show variables like 'general%';

#해당 위치에 있는 로그 파일을 확인하면서 CUD, R로 잘 분기되는지 확인해볼 수 있음
```
46 changes: 46 additions & 0 deletions backend/docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
version: "3"
services:
db-source:
build:
context: ./
dockerfile: source/Dockerfile
restart: always
environment:
MYSQL_DATABASE: 'naepyeon'
MYSQL_USER: 'user'
MYSQL_PASSWORD: 'password'
MYSQL_ROOT_PASSWORD: 'password'
ports:
- '3306:3306'
# Where our data will be persisted
volumes:
- my-db-source:/var/lib/mysql
- my-db-source:/var/lib/mysql-files
networks:
- net-mysql

db-replica:
build:
context: ./
dockerfile: replica/Dockerfile
restart: always
environment:
MYSQL_DATABASE: 'naepyeon'
MYSQL_ROOT_PASSWORD: 'password'
ports:
- '3307:3306'
# Where our data will be persisted
volumes:
- my-db-replica:/var/lib/mysql
- my-db-replica:/var/lib/mysql-files
networks:
- net-mysql

# Names our volume
volumes:
my-db-source:
my-db-replica:

networks:
net-mysql:
driver: bridge
2 changes: 2 additions & 0 deletions backend/docker/replica/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FROM --platform=linux/x86_64 mysql:8.0
ADD ./replica/my.cnf /etc/mysql/my.cnf
8 changes: 8 additions & 0 deletions backend/docker/replica/my.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[mysqld]
gtid_mode=ON
enforce_gtid_consistency=ON
server_id=2
relay_log =/var/lib/mysql/mysql-relay-bin
relay_log_purge=ON
read_only
log_slave_updates
2 changes: 2 additions & 0 deletions backend/docker/source/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FROM --platform=linux/x86_64 mysql:8.0
ADD ./source/my.cnf /etc/mysql/my.cnf
5 changes: 5 additions & 0 deletions backend/docker/source/my.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[mysqld]
gtid_mode=ON
enforce_gtid_consistency=ON
server_id=1
log_bin = mysql-bin
21 changes: 21 additions & 0 deletions backend/src/docs/asciidoc/errorCodes.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@
| "구글 리소스 서버 요청시 에러 발생 accessToken={%s}\nerrorMessage={%s}"
| "구글 로그인에 실패했습니다. 관리자에게 문의하세요."
| `401 Unauthorized`

| `3018`
| "올바르지 않은 리프레시 토큰입니다."
| "올바르지 않은 리프레시 토큰입니다."
| `401 Unauthorized`
|===

=== 모임 에러
Expand Down Expand Up @@ -187,3 +192,19 @@
| 토큰의 유효기간이 만료됐습니다.
| `400 Bad Request`
|===

=== 알림 에러
|===
| error code | error message | show message | status code

|`5001`
| 해당 알림은 존재하지 않습니다. id={%d}
| 올바르지 않은 알림입니다.
| `404 Not Found`

|`5002`
| 유효하지 않은 reids message입니다. message={%s}
| 유효하지 않은 redis message입니다.
| `400 Bad Request`

|===
13 changes: 13 additions & 0 deletions backend/src/docs/asciidoc/notifications.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
== 알림

=== 구독
operation::notification-controller-test/subscribe[snippets='http-request,http-response']

=== 안 읽은 알림 전체 조회
operation::notification-controller-test/notifications[snippets='http-request,http-response']

=== 읽지 않은 알림 단건 읽기
operation::notification-controller-test/read-notification[snippets='http-request,http-response']

=== 읽지 않은 알림 모두 읽기
operation::notification-controller-test/read-all-notifications[snippets='http-request,http-response']
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ public class AuthenticationPrincipalConfig implements WebMvcConfigurer {
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor(jwtTokenProvider))
.addPathPatterns("/api/v1/**")
.excludePathPatterns("/api/v1/oauth/**")
.excludePathPatterns("/api/v1/oauth/*")
.excludePathPatterns("/api/v1/members")
.excludePathPatterns("/api/v1/renewal-token")
.excludePathPatterns("/api/v1/logout");
.excludePathPatterns("/api/v1/logout")
.excludePathPatterns("/api/v1/subscribe");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.woowacourse.naepyeon.config;

import com.woowacourse.naepyeon.support.db.DatabaseType;
import com.woowacourse.naepyeon.support.db.RoutingDataSource;
import java.util.HashMap;
import javax.sql.DataSource;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy;

@Configuration
@RequiredArgsConstructor
public class DataSourceConfig {

@Bean
@ConfigurationProperties(prefix = "spring.datasource.source.hikari")
public DataSource sourceDataSource() {
return DataSourceBuilder.create()
.build();
}

@Bean
@ConfigurationProperties(prefix = "spring.datasource.replica.hikari")
public DataSource replicaDataSource() {
return DataSourceBuilder.create()
.build();
}

@Bean
public DataSource routingDataSource() {
final RoutingDataSource routingDataSource = new RoutingDataSource();
final HashMap<Object, Object> dataSources = new HashMap<>();

dataSources.put(DatabaseType.SOURCE, sourceDataSource());
dataSources.put(DatabaseType.REPLICA, replicaDataSource());

routingDataSource.setDefaultTargetDataSource(sourceDataSource());
routingDataSource.setTargetDataSources(dataSources);

return routingDataSource;
}

@Primary
@Bean
@DependsOn({"sourceDataSource", "replicaDataSource", "routingDataSource"})
public DataSource dataSource() {
return new LazyConnectionDataSourceProxy(routingDataSource());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.woowacourse.naepyeon.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.woowacourse.naepyeon.service.dto.NotificationResponseDto;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

@Configuration
public class RedisConfig {

@Value("${spring.redis.host}")
private String host;

@Value("${spring.redis.port}")
private int port;

@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}

@Bean
public RedisOperations<String, NotificationResponseDto> eventRedisOperations(
RedisConnectionFactory redisConnectionFactory, ObjectMapper objectMapper) {
final Jackson2JsonRedisSerializer<NotificationResponseDto> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(
NotificationResponseDto.class);
jsonRedisSerializer.setObjectMapper(objectMapper);
final RedisTemplate<String, NotificationResponseDto> eventRedisTemplate = new RedisTemplate<>();
eventRedisTemplate.setConnectionFactory(redisConnectionFactory);
eventRedisTemplate.setKeySerializer(RedisSerializer.string());
eventRedisTemplate.setValueSerializer(jsonRedisSerializer);
eventRedisTemplate.setHashKeySerializer(RedisSerializer.string());
eventRedisTemplate.setHashValueSerializer(jsonRedisSerializer);
return eventRedisTemplate;
}

@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory) {
final RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
return redisMessageListenerContainer;
}
}
Loading

0 comments on commit e4c3be3

Please sign in to comment.