Skip to content

Commit 420cea6

Browse files
committed
feat: add production hardening with Fastlane, Firebase Crashlytics, OpenTelemetry
- Add Next.js 16 proxy.ts with security headers and i18n routing - Add OpenTelemetry instrumentation for web (GCP Cloud Trace) - Add Firebase Crashlytics and Fastlane for mobile CI/CD - Add structured logging and global exception handler for API - Add better-auth session middleware for API - Update mobile-ci.yml to use Fastlane with Firebase App Distribution - Update README with mobile setup instructions
1 parent f79ef35 commit 420cea6

Some content is hidden

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

46 files changed

+1397
-29
lines changed

.github/workflows/mobile-ci.yml

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
name: Mobile CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- "apps/mobile/**"
8+
- ".github/workflows/mobile-ci.yml"
9+
pull_request:
10+
branches: [main]
11+
paths:
12+
- "apps/mobile/**"
13+
workflow_dispatch:
14+
15+
env:
16+
FLUTTER_VERSION: "3.32.0"
17+
RUBY_VERSION: "3.3"
18+
19+
jobs:
20+
analyze:
21+
name: Analyze & Test
22+
runs-on: ubuntu-latest
23+
defaults:
24+
run:
25+
working-directory: apps/mobile
26+
27+
steps:
28+
- uses: actions/checkout@v4
29+
30+
- name: Set up Flutter
31+
uses: subosito/flutter-action@v2
32+
with:
33+
flutter-version: ${{ env.FLUTTER_VERSION }}
34+
channel: stable
35+
cache: true
36+
37+
- name: Install dependencies
38+
run: flutter pub get
39+
40+
- name: Set up Ruby
41+
uses: ruby/setup-ruby@v1
42+
with:
43+
ruby-version: ${{ env.RUBY_VERSION }}
44+
bundler-cache: true
45+
working-directory: apps/mobile
46+
47+
- name: Run lint
48+
run: bundle exec fastlane lint
49+
50+
- name: Run tests
51+
run: bundle exec fastlane test
52+
53+
- name: Upload coverage
54+
uses: codecov/codecov-action@v5
55+
if: github.event_name == 'push'
56+
with:
57+
files: apps/mobile/coverage/lcov.info
58+
flags: mobile
59+
fail_ci_if_error: false
60+
61+
build-android:
62+
name: Build Android
63+
needs: analyze
64+
runs-on: ubuntu-latest
65+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
66+
defaults:
67+
run:
68+
working-directory: apps/mobile
69+
70+
steps:
71+
- uses: actions/checkout@v4
72+
73+
- name: Set up Java
74+
uses: actions/setup-java@v4
75+
with:
76+
distribution: "temurin"
77+
java-version: "17"
78+
79+
- name: Set up Flutter
80+
uses: subosito/flutter-action@v2
81+
with:
82+
flutter-version: ${{ env.FLUTTER_VERSION }}
83+
channel: stable
84+
cache: true
85+
86+
- name: Install dependencies
87+
run: flutter pub get
88+
89+
- name: Set up Ruby
90+
uses: ruby/setup-ruby@v1
91+
with:
92+
ruby-version: ${{ env.RUBY_VERSION }}
93+
bundler-cache: true
94+
working-directory: apps/mobile
95+
96+
- name: Build Android APK
97+
run: bundle exec fastlane android build
98+
99+
- name: Upload APK
100+
uses: actions/upload-artifact@v4
101+
with:
102+
name: android-release
103+
path: apps/mobile/build/app/outputs/flutter-apk/*.apk
104+
retention-days: 7
105+
106+
build-ios:
107+
name: Build iOS
108+
needs: analyze
109+
runs-on: macos-latest
110+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
111+
defaults:
112+
run:
113+
working-directory: apps/mobile
114+
115+
steps:
116+
- uses: actions/checkout@v4
117+
118+
- name: Set up Flutter
119+
uses: subosito/flutter-action@v2
120+
with:
121+
flutter-version: ${{ env.FLUTTER_VERSION }}
122+
channel: stable
123+
cache: true
124+
125+
- name: Install dependencies
126+
run: flutter pub get
127+
128+
- name: Set up Ruby
129+
uses: ruby/setup-ruby@v1
130+
with:
131+
ruby-version: ${{ env.RUBY_VERSION }}
132+
bundler-cache: true
133+
working-directory: apps/mobile
134+
135+
- name: Build iOS (no codesign)
136+
run: bundle exec fastlane ios build
137+
138+
- name: Upload iOS build
139+
uses: actions/upload-artifact@v4
140+
with:
141+
name: ios-release
142+
path: apps/mobile/build/ios/iphoneos
143+
retention-days: 7
144+
145+
deploy-firebase:
146+
name: Deploy to Firebase
147+
needs: [build-android, build-ios]
148+
runs-on: ubuntu-latest
149+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
150+
environment: staging
151+
defaults:
152+
run:
153+
working-directory: apps/mobile
154+
155+
steps:
156+
- uses: actions/checkout@v4
157+
158+
- name: Download Android artifact
159+
uses: actions/download-artifact@v4
160+
with:
161+
name: android-release
162+
path: apps/mobile/build/app/outputs/flutter-apk
163+
164+
- name: Set up Ruby
165+
uses: ruby/setup-ruby@v1
166+
with:
167+
ruby-version: ${{ env.RUBY_VERSION }}
168+
bundler-cache: true
169+
working-directory: apps/mobile
170+
171+
- name: Authenticate to Google Cloud
172+
uses: google-github-actions/auth@v2
173+
with:
174+
credentials_json: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_JSON }}
175+
176+
- name: Deploy to Firebase App Distribution
177+
env:
178+
FIREBASE_ANDROID_APP_ID: ${{ secrets.FIREBASE_ANDROID_APP_ID }}
179+
FIREBASE_TESTERS_GROUP: ${{ vars.FIREBASE_TESTERS_GROUP }}
180+
run: |
181+
bundle exec fastlane android firebase

.serena/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/cache

README.ko.md

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
- **모던 스택**: Next.js 16 + React 19, FastAPI, Flutter 3.32, TailwindCSS v4
1010
- **타입 안전성**: TypeScript, Pydantic, Dart 전체 타입 지원
11-
- **인증**: better-auth 기반 OAuth (Google, GitHub, Kakao)
11+
- **인증**: better-auth 기반 OAuth (Google, GitHub, Facebook)
1212
- **국제화**: next-intl (웹), Flutter ARB (모바일), 공용 i18n 패키지
1313
- **API 클라이언트 자동 생성**: Orval (웹), swagger_parser (모바일)
1414
- **인프라 as 코드**: Terraform + GCP (Cloud Run, Cloud SQL, Cloud Storage)
@@ -22,7 +22,7 @@
2222
|--------|------|
2323
| **프론트엔드** | Next.js 16, React 19, TailwindCSS v4, shadcn/ui, TanStack Query, Jotai |
2424
| **백엔드** | FastAPI, SQLAlchemy (async), PostgreSQL 16, Redis 7 |
25-
| **모바일** | Flutter 3.32, Riverpod 3, go_router 17 |
25+
| **모바일** | Flutter 3.32, Riverpod 3, go_router 17, Firebase Crashlytics, Fastlane |
2626
| **워커** | FastAPI + CloudTasks/PubSub |
2727
| **인프라** | Terraform, GCP (Cloud Run, Cloud SQL, Cloud Storage, CDN) |
2828
| **CI/CD** | GitHub Actions, Workload Identity Federation |
@@ -127,6 +127,7 @@ mise tasks --all
127127
| `mise test` | 모든 앱 테스트 |
128128
| `mise typecheck` | 타입 체크 |
129129
| `mise i18n:build` | 다국어 파일 빌드 |
130+
| `mise gen:api` | OpenAPI 스키마 및 API 클라이언트 생성 |
130131

131132
### 앱별 태스크
132133

@@ -141,6 +142,7 @@ mise tasks --all
141142
| `mise //apps/api:format` | 코드 포맷 |
142143
| `mise //apps/api:migrate` | 마이그레이션 실행 |
143144
| `mise //apps/api:migrate:create` | 새 마이그레이션 생성 |
145+
| `mise //apps/api:gen:openapi` | OpenAPI 스키마 생성 |
144146
| `mise //apps/api:infra:up` | 로컬 인프라 시작 |
145147
| `mise //apps/api:infra:down` | 로컬 인프라 중지 |
146148

@@ -169,6 +171,7 @@ mise tasks --all
169171
| `mise //apps/mobile:test` | 테스트 실행 |
170172
| `mise //apps/mobile:lint` | 분석기 실행 |
171173
| `mise //apps/mobile:gen:l10n` | 다국어 파일 생성 |
174+
| `mise //apps/mobile:gen:api` | API 클라이언트 생성 |
172175

173176
</details>
174177

@@ -251,6 +254,8 @@ cp apps/infra/terraform.tfvars.example apps/infra/terraform.tfvars
251254
| `GCP_REGION` | GCP 리전 (예: `asia-northeast3`) |
252255
| `WORKLOAD_IDENTITY_PROVIDER` | Terraform output에서 확인 |
253256
| `GCP_SERVICE_ACCOUNT` | Terraform output에서 확인 |
257+
| `FIREBASE_SERVICE_ACCOUNT_JSON` | Firebase 서비스 계정 JSON (모바일 배포용) |
258+
| `FIREBASE_ANDROID_APP_ID` | Firebase Android 앱 ID |
254259

255260
## 배포
256261

@@ -260,6 +265,7 @@ cp apps/infra/terraform.tfvars.example apps/infra/terraform.tfvars
260265
- `apps/api/` 변경 → API 배포
261266
- `apps/web/` 변경 → Web 배포
262267
- `apps/worker/` 변경 → Worker 배포
268+
- `apps/mobile/` 변경 → Firebase App Distribution 빌드 및 배포
263269

264270
### 수동 배포
265271

@@ -273,6 +279,43 @@ docker push gcr.io/PROJECT_ID/api
273279
gcloud run deploy api --image gcr.io/PROJECT_ID/api --region REGION
274280
```
275281

282+
## 모바일 설정
283+
284+
### Firebase 설정
285+
286+
1. FlutterFire CLI 설치:
287+
288+
```bash
289+
dart pub global activate flutterfire_cli
290+
```
291+
292+
2. Firebase 설정:
293+
294+
```bash
295+
cd apps/mobile
296+
flutterfire configure
297+
```
298+
299+
이 명령어로 `lib/firebase_options.dart`가 생성됩니다.
300+
301+
### Fastlane
302+
303+
모바일 앱은 Fastlane을 사용하여 빌드 자동화 및 배포를 수행합니다.
304+
305+
```bash
306+
cd apps/mobile
307+
308+
# Ruby 의존성 설치
309+
bundle install
310+
311+
# 사용 가능한 레인
312+
bundle exec fastlane android build # APK 빌드
313+
bundle exec fastlane android firebase # Firebase App Distribution 배포
314+
bundle exec fastlane android internal # Play Store 배포 (internal)
315+
bundle exec fastlane ios build # iOS 빌드 (서명 없음)
316+
bundle exec fastlane ios testflight_deploy # TestFlight 배포
317+
```
318+
276319
## AI 에이전트 지원
277320

278321
이 템플릿은 AI 코딩 에이전트(Gemini, Claude 등)와 함께 사용하도록 설계되었습니다.

README.md

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Production-ready fullstack monorepo template with Next.js 16, FastAPI, Flutter,
88

99
- **Modern Stack**: Next.js 16 + React 19, FastAPI, Flutter 3.32, TailwindCSS v4
1010
- **Type Safety**: Full type support with TypeScript, Pydantic, and Dart
11-
- **Authentication**: OAuth with better-auth (Google, GitHub, Kakao)
11+
- **Authentication**: OAuth with better-auth (Google, GitHub, Facebook)
1212
- **Internationalization**: next-intl (web), Flutter ARB (mobile), shared i18n package
1313
- **Auto-generated API Clients**: Orval (web), swagger_parser (mobile)
1414
- **Infrastructure as Code**: Terraform + GCP (Cloud Run, Cloud SQL, Cloud Storage)
@@ -22,7 +22,7 @@ Production-ready fullstack monorepo template with Next.js 16, FastAPI, Flutter,
2222
|-------|------------|
2323
| **Frontend** | Next.js 16, React 19, TailwindCSS v4, shadcn/ui, TanStack Query, Jotai |
2424
| **Backend** | FastAPI, SQLAlchemy (async), PostgreSQL 16, Redis 7 |
25-
| **Mobile** | Flutter 3.32, Riverpod 3, go_router 17 |
25+
| **Mobile** | Flutter 3.32, Riverpod 3, go_router 17, Firebase Crashlytics, Fastlane |
2626
| **Worker** | FastAPI + CloudTasks/PubSub |
2727
| **Infrastructure** | Terraform, GCP (Cloud Run, Cloud SQL, Cloud Storage, CDN) |
2828
| **CI/CD** | GitHub Actions, Workload Identity Federation |
@@ -127,6 +127,7 @@ mise tasks --all
127127
| `mise test` | Test all apps |
128128
| `mise typecheck` | Type check |
129129
| `mise i18n:build` | Build i18n files |
130+
| `mise gen:api` | Generate OpenAPI schema and API clients |
130131

131132
### App-specific Tasks
132133

@@ -141,6 +142,7 @@ mise tasks --all
141142
| `mise //apps/api:format` | Format code |
142143
| `mise //apps/api:migrate` | Run migrations |
143144
| `mise //apps/api:migrate:create` | Create new migration |
145+
| `mise //apps/api:gen:openapi` | Generate OpenAPI schema |
144146
| `mise //apps/api:infra:up` | Start local infrastructure |
145147
| `mise //apps/api:infra:down` | Stop local infrastructure |
146148

@@ -169,6 +171,7 @@ mise tasks --all
169171
| `mise //apps/mobile:test` | Run tests |
170172
| `mise //apps/mobile:lint` | Run analyzer |
171173
| `mise //apps/mobile:gen:l10n` | Generate localizations |
174+
| `mise //apps/mobile:gen:api` | Generate API client |
172175

173176
</details>
174177

@@ -251,6 +254,8 @@ Set these secrets in your repository:
251254
| `GCP_REGION` | GCP region (e.g., `asia-northeast3`) |
252255
| `WORKLOAD_IDENTITY_PROVIDER` | From Terraform output |
253256
| `GCP_SERVICE_ACCOUNT` | From Terraform output |
257+
| `FIREBASE_SERVICE_ACCOUNT_JSON` | Firebase service account JSON (for mobile deployment) |
258+
| `FIREBASE_ANDROID_APP_ID` | Firebase Android app ID |
254259

255260
## Deployment
256261

@@ -260,6 +265,7 @@ Push to `main` branch triggers automatic deployment:
260265
- `apps/api/` changes → Deploy API
261266
- `apps/web/` changes → Deploy Web
262267
- `apps/worker/` changes → Deploy Worker
268+
- `apps/mobile/` changes → Build & Deploy to Firebase App Distribution
263269

264270
### Manual Deployment
265271

@@ -273,6 +279,43 @@ docker push gcr.io/PROJECT_ID/api
273279
gcloud run deploy api --image gcr.io/PROJECT_ID/api --region REGION
274280
```
275281

282+
## Mobile Setup
283+
284+
### Firebase Configuration
285+
286+
1. Install FlutterFire CLI:
287+
288+
```bash
289+
dart pub global activate flutterfire_cli
290+
```
291+
292+
2. Configure Firebase for your project:
293+
294+
```bash
295+
cd apps/mobile
296+
flutterfire configure
297+
```
298+
299+
This generates `lib/firebase_options.dart` with your Firebase configuration.
300+
301+
### Fastlane
302+
303+
The mobile app uses Fastlane for build automation and deployment.
304+
305+
```bash
306+
cd apps/mobile
307+
308+
# Install Ruby dependencies
309+
bundle install
310+
311+
# Available lanes
312+
bundle exec fastlane android build # Build APK
313+
bundle exec fastlane android firebase # Deploy to Firebase App Distribution
314+
bundle exec fastlane android internal # Deploy to Play Store (internal)
315+
bundle exec fastlane ios build # Build iOS (no codesign)
316+
bundle exec fastlane ios testflight_deploy # Deploy to TestFlight
317+
```
318+
276319
## AI Agent Support
277320

278321
This template is designed to work with AI coding agents (Gemini, Claude, etc.).

0 commit comments

Comments
 (0)