Skip to content

Commit 33de998

Browse files
committed
Merge branch 'fix/#52-ec2-oom' into release-server
# Conflicts: # .gitignore
2 parents 7273999 + 63d3878 commit 33de998

411 files changed

Lines changed: 32809 additions & 3030 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/deploy.yml

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ jobs:
6363
REDIS_PORT=${{ secrets.REDIS_PORT }}
6464
KAKAO_REST_API_KEY=${{ secrets.KAKAO_REST_API_KEY }}
6565
DDL_AUTO=${{ secrets.DDL_AUTO }}
66+
FIREBASE_CREDENTIALS_PATH=${{ secrets.FIREBASE_CREDENTIALS_PATH }}
6667
EOF
6768
6869
# EC2로 .env 업로드
@@ -76,13 +77,26 @@ jobs:
7677
target: "/home/${{ secrets.EC2_USER }}/app"
7778
overwrite: true
7879

80+
# EC2로 docker-compose.prod.yml 업로드 (레포가 배포 파일의 단일 출처가 되도록)
81+
- name: Upload docker-compose.prod.yml to EC2
82+
uses: appleboy/scp-action@v0.1.7
83+
with:
84+
host: ${{ secrets.EC2_HOST }}
85+
username: ${{ secrets.EC2_USER }}
86+
key: ${{ secrets.EC2_SSH_KEY }}
87+
source: "backend/docker-compose.prod.yml"
88+
target: "/home/${{ secrets.EC2_USER }}/app"
89+
strip_components: 1
90+
overwrite: true
91+
7992
# EC2에서 최신 이미지 pull + 재기동
8093
- name: Deploy on EC2
8194
uses: appleboy/ssh-action@v1.0.3
8295
with:
8396
host: ${{ secrets.EC2_HOST }}
8497
username: ${{ secrets.EC2_USER }}
8598
key: ${{ secrets.EC2_SSH_KEY }}
99+
envs: ECR_REPO_URI
86100
script: |
87101
set -e
88102
cd /home/${{ secrets.EC2_USER }}/app
@@ -91,6 +105,9 @@ jobs:
91105
aws ecr get-login-password --region ap-northeast-2 \
92106
| docker login --username AWS --password-stdin ${{ secrets.ECR_REGISTRY }}
93107
94-
docker pull ${{ secrets.ECR_REPO_URI }}:latest
95-
docker compose up -d --pull always --force-recreate
108+
export APP_IMAGE="${ECR_REPO_URI}:latest"
109+
docker pull "$APP_IMAGE"
110+
docker compose -f docker-compose.prod.yml up -d --pull always --force-recreate
96111
docker image prune -f
112+
env:
113+
ECR_REPO_URI: ${{ secrets.ECR_REPO_URI }}

.gitignore

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,22 @@ android/**/*.dex
5353
# Adjust later to actual backend stack
5454
# =========================
5555

56-
backend/.env
57-
backend/.env.*
56+
backend/.env.local
5857
backend/build/
5958
backend/out/
6059
backend/target/
6160
backend/node_modules/
62-
61+
backend/AGENTS.md
62+
backend/.claude/plans
63+
backend/.claude/rules/*.local.md
64+
backend/.claude/settings.local.json
65+
backend/.gradle
66+
backend/build
67+
backend/out
68+
backend/gilbut-firebase-adminsdk.json
69+
# test data
70+
/backend/src/test/resources/test-data
6371
# Keep placeholder
6472
!backend/.gitkeep
6573

66-
# env files
67-
.env
68-
.env.*
69-
70-
# test data
71-
/backend/src/test/resources/test-data
74+
/reference

README.md

Lines changed: 88 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,121 @@
1-
[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/Lvs6kcL8)
2-
# Welcome to GitHub
1+
<div align="center">
32

4-
캡스톤 팀 생성을 축하합니다.
3+
<h1>
4+
<img src="docs/images/길벗 로고.png" alt="길벗 로고" width="36" align="absmiddle">
5+
길벗 - 위치 기반 기억 보조 • 보호자 안심 확인 서비스
6+
</h1>
57

6-
## 팀소개 및 페이지를 꾸며주세요.
8+
</div>
79

8-
- 프로젝트 소개
9-
- 프로젝트 설치방법 및 데모, 사용방법, 프리뷰등을 readme.md에 작성.
10-
- Api나 사용방법등 내용이 많을경우 wiki에 꾸미고 링크 추가.
10+
<div align="center">
1111

12-
- 팀페이지 꾸미기
13-
- 프로젝트 소개 및 팀원 소개
14-
- index.md 예시보고 수정.
12+
### 당신의 하루를 대신 기억합니다
1513

16-
- GitHub Pages 리파지토리 Settings > Options > GitHub Pages
17-
- Source를 marster branch
18-
- Theme Chooser에서 태마선택
19-
- 수정후 팀페이지 확인하여 점검.
14+
위치 데이터를 수집해 사용자의 하루 경로를 기록 · 가공하여 개인 사용자에겐 **기억 보조**를, 보호자에겐 **안심 확인**을 제공합니다.
2015

21-
**팀페이지 주소** -> https://kookmin-sw.github.io/ '{{자신의 리파지토리 아이디}}'
16+
<img src="docs/images/메인컨셉.png" alt="길벗 메인컨셉">
2217

23-
**예시)** 2023년 0조 https://kookmin-sw.github.io/capstone-2023-00/
18+
<br>
2419

20+
위치 데이터를 분석하여 15분 이상 **체류한 장소**의 상호명과 **외출 • 귀가 시각**을 자동 저장합니다.
21+
<br>
22+
이를 통해 사용자는 자신의 생활 패턴을 쉽게 확인할 수 있으며, 보호자는 일상 흐름을 안심하고 살펴볼 수 있습니다.
2523

26-
## 내용에 아래와 같은 내용들을 추가하세요.
24+
</div>
2725

28-
### 1. 프로잭트 소개
26+
<br>
2927

30-
프로젝트
28+
## 주요 기능
3129

32-
### 2. 소개 영상
30+
### 1️⃣ 이동 경로 기록 및 조회
3331

34-
프로젝트 소개하는 영상을 추가하세요
32+
- 백그라운드 위치 수집
33+
- 날짜별 이동경로 조회
34+
- 위치수집 on/off
35+
<img src="docs/images/이동경로 기록 및 조회.png" alt="나의길 화면이미지">
3536

36-
### 3. 팀 소개
37+
### 2️⃣ 기억 보조를 위한 개인 기록 도구
3738

38-
팀을 소개하세요.
39+
- 하루 단위 메모 작성
40+
- 학교, 회사 등 즐겨찾는 장소 등록
41+
- 방문장소 직접 추가
42+
- 날짜별 즐겨찾기
43+
<img src="docs/images/개인 기록 도구.png" alt="함께가는길 화면이미지">
3944

40-
팀원정보 및 담당이나 사진 및 SNS를 이용하여 소개하세요.
45+
### 3️⃣ 위치 데이터 분석
4146

42-
### 4. 사용법
47+
- 위치 데이터를 분석하여 사용자에게 의미있는 정보로 변환
48+
- 분석 기반 15분 이상 체류한 장소 상호명 및 체류 시간 저장
49+
- 분석 기반 외출/귀가 시각 저장
50+
<img src="docs/images/위치 데이터 분석.png" alt="장소저장 화면이미지">
4351

44-
소스코드제출시 설치법이나 사용법을 작성하세요.
52+
### 4️⃣ 보호자 안심 확인
4553

46-
### 5. 기타
54+
- 보호 대상자의 실시간 위치 확인
55+
- 보호 대상자의 날짜별 이동 경로, 외출/귀가 시각, 체류 장소, 방문한 지역 등 확인
56+
<img src="docs/images/보호자 안심 기능.png" alt="하루요약 화면이미지">
4757

48-
추가적인 내용은 자유롭게 작성하세요.
58+
### 5️⃣ 요약 통계
4959

60+
- 기간별(1주/1개월/6개월/1년) 생활패턴 지표 변화량 파악
61+
- 기간별 가장 많이 방문한 장소 및 지역 top 5 확인
62+
<img src="docs/images/요약통계.png" alt="요약통계 화면이미지">
5063

51-
## Markdown을 사용하여 내용꾸미기
64+
<br>
5265

53-
Markdown은 작문을 스타일링하기위한 가볍고 사용하기 쉬운 구문입니다. 여기에는 다음을위한 규칙이 포함됩니다.
66+
## 시스템 아키텍처
5467

55-
```markdown
56-
Syntax highlighted code block
68+
<div align="center">
5769

58-
# Header 1
59-
## Header 2
60-
### Header 3
70+
![img.png](docs/images/img_6.png)
71+
</div>
6172

62-
- Bulleted
63-
- List
73+
<br>
6474

65-
1. Numbered
66-
2. List
75+
## 실행 방법
6776

68-
**Bold** and _Italic_ and `Code` text
77+
### 사전 요구사항
6978

70-
[Link](url) and ![Image](src)
79+
- MySQL (기본 포트 `3306`, `capstone` 데이터베이스)
80+
- Redis (기본 포트 `6379`)
81+
- Android Studio + Android SDK (API 36), 에뮬레이터 또는 실기기 (API 24 이상)
82+
83+
### 1. 백엔드 실행
84+
85+
```bash
86+
cd backend
87+
```
88+
89+
`backend/.env.example`을 참고해 `backend/.env.local` 파일을 생성하고 값을 채워 넣습니다.
90+
91+
애플리케이션을 실행합니다.
92+
93+
```bash
94+
./gradlew bootRun
95+
```
96+
97+
실행 후 아래 주소에서 API 문서를 확인할 수 있습니다.
98+
99+
- Swagger UI: http://localhost:8080/swagger-ui.html
100+
101+
### 2. Android 앱 실행
102+
103+
`android` 디렉토리의 `local.properties.example`을 참고하여 `android/local.properties` 파일을 생성합니다.
104+
105+
```properties
106+
sdk.dir=<Android SDK 경로>
107+
kakao.nativeAppKey=<Kakao Native App Key>
108+
app.baseUrl=<백엔드 서버 주소, 예: http://<PC-IP>:8080/>
109+
google.mapsApiKey=<Google Maps API Key>
71110
```
72111

73-
자세한 내용은 [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/).
112+
> 실기기 또는 에뮬레이터에서 로컬 백엔드와 통신하려면 `app.baseUrl``localhost`가 아닌 PC의 IP 주소로 설정해야 합니다.
113+
114+
Android Studio로 `android` 디렉토리를 열어 실행하거나, CLI로 아래 명령을 사용합니다.
74115

75-
### Support or Contact
116+
```bash
117+
cd android
118+
./gradlew installDebug
119+
```
76120

77-
readme 파일 생성에 추가적인 도움이 필요하면 [도움말](https://help.github.com/articles/about-readmes/) 이나 [contact support](https://github.com/contact) 을 이용하세요.
121+
<br>

android/app/build.gradle.kts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44
alias(libs.plugins.android.application)
55
alias(libs.plugins.kotlin.android)
66
alias(libs.plugins.kotlin.compose)
7-
id("org.jetbrains.kotlin.kapt")
7+
alias(libs.plugins.ksp)
88
}
99

1010
val localProperties = Properties().apply {
@@ -62,6 +62,9 @@ android {
6262
buildConfig = true
6363
compose = true
6464
}
65+
testOptions {
66+
unitTests.isReturnDefaultValues = true
67+
}
6568
}
6669

6770
dependencies {
@@ -76,7 +79,10 @@ dependencies {
7679
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
7780
implementation("com.squareup.retrofit2:converter-scalars:2.9.0")
7881
implementation("com.squareup.okhttp3:okhttp:4.12.0")
82+
implementation("com.squareup.okhttp3:okhttp-sse:4.12.0")
7983
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
84+
implementation("io.coil-kt.coil3:coil-compose:3.0.2")
85+
implementation("io.coil-kt.coil3:coil-network-okhttp:3.0.2")
8086
implementation("com.kakao.sdk:v2-user:2.20.0")
8187
implementation("com.kakao.sdk:v2-auth:2.20.0")
8288

@@ -90,9 +96,7 @@ dependencies {
9096
implementation(libs.androidx.compose.ui.graphics)
9197
implementation(libs.androidx.compose.ui.tooling.preview)
9298
implementation(libs.androidx.compose.material3)
93-
implementation("androidx.compose.material:material-icons-extended")
94-
95-
kapt(libs.androidx.room.compiler)
99+
ksp(libs.androidx.room.compiler)
96100

97101
testImplementation(libs.junit)
98102
testImplementation(libs.kotlinx.coroutines.test)

android/app/src/main/AndroidManifest.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@
4343
<action android:name="android.intent.action.MAIN" />
4444
<category android:name="android.intent.category.LAUNCHER" />
4545
</intent-filter>
46+
47+
<intent-filter android:autoVerify="true">
48+
<action android:name="android.intent.action.VIEW" />
49+
50+
<category android:name="android.intent.category.DEFAULT" />
51+
<category android:name="android.intent.category.BROWSABLE" />
52+
53+
<data
54+
android:host="passedpath.site"
55+
android:path="/care-relationship/invite"
56+
android:scheme="https" />
57+
</intent-filter>
4658
</activity>
4759

4860
<!-- foreground service임을 OS에게 알림 -->

android/app/src/main/java/com/example/passedpath/MainActivity.kt

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,73 @@ package com.example.passedpath
22

33
import android.content.Context
44
import android.content.Intent
5+
import android.graphics.Color
56
import android.os.Bundle
67
import androidx.activity.ComponentActivity
8+
import androidx.activity.SystemBarStyle
79
import androidx.activity.compose.setContent
10+
import androidx.activity.enableEdgeToEdge
811
import androidx.activity.viewModels
912
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
13+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
1014
import androidx.navigation.compose.rememberNavController
1115
import com.example.passedpath.app.appContainer
16+
import com.example.passedpath.feature.care.presentation.deeplink.CareInviteDeepLinkParser
1217
import com.example.passedpath.navigation.AppEntryState
1318
import com.example.passedpath.navigation.AppEntryViewModel
1419
import com.example.passedpath.navigation.AppEntryViewModelFactory
1520
import com.example.passedpath.navigation.AppNavHost
1621
import com.example.passedpath.ui.theme.PassedPathTheme
22+
import kotlinx.coroutines.flow.MutableStateFlow
1723

1824
class MainActivity : ComponentActivity() {
1925
private val appEntryViewModel: AppEntryViewModel by viewModels {
2026
AppEntryViewModelFactory(applicationContext.appContainer)
2127
}
28+
private val pendingCareInviteCode = MutableStateFlow<String?>(null)
2229

2330
override fun onCreate(savedInstanceState: Bundle?) {
2431
installSplashScreen().setKeepOnScreenCondition {
2532
appEntryViewModel.state.value is AppEntryState.Loading
2633
}
34+
enableEdgeToEdge(
35+
statusBarStyle = SystemBarStyle.light(Color.TRANSPARENT, Color.TRANSPARENT),
36+
navigationBarStyle = SystemBarStyle.light(Color.TRANSPARENT, Color.TRANSPARENT)
37+
)
2738

2839
super.onCreate(savedInstanceState)
40+
publishCareInviteCode(intent)
2941

3042
setContent {
3143
PassedPathTheme {
3244
val navController = rememberNavController()
45+
val careInviteCode = pendingCareInviteCode.collectAsStateWithLifecycle().value
3346

3447
AppNavHost(
3548
navController = navController,
36-
appEntryViewModel = appEntryViewModel
49+
appEntryViewModel = appEntryViewModel,
50+
pendingCareInviteCode = careInviteCode,
51+
onCareInviteCodeConsumed = { consumedCode ->
52+
if (pendingCareInviteCode.value == consumedCode) {
53+
pendingCareInviteCode.value = null
54+
}
55+
}
3756
)
3857
}
3958
}
4059
}
4160

61+
override fun onNewIntent(intent: Intent) {
62+
super.onNewIntent(intent)
63+
setIntent(intent)
64+
publishCareInviteCode(intent)
65+
}
66+
67+
private fun publishCareInviteCode(intent: Intent?) {
68+
val inviteCode = CareInviteDeepLinkParser.extractInviteCode(intent?.data) ?: return
69+
pendingCareInviteCode.value = inviteCode
70+
}
71+
4272
companion object {
4373
fun createIntent(context: Context): Intent {
4474
return Intent(context, MainActivity::class.java).apply {

0 commit comments

Comments
 (0)