userfront로 리펙토링 완료

This commit is contained in:
Lectom C Han committed 2026-01-28 08:28:25 +09:00
1 parent 6d88c81217
commit 1aaa772907
154 files changed
+339 -314

No files matched your search

+2 -2
View File
@@ -11,7 +11,7 @@ DB_PORT=5432
CLICKHOUSE_PORT_HTTP=8123
CLICKHOUSE_PORT_NATIVE=9000
BACKEND_PORT=3000
FRONTEND_PORT=5000
USERFRONT_PORT=5000
# --- Database Credentials (PostgreSQL) ---
DB_USER=baron
@@ -47,7 +47,7 @@ ADMIN_EMAIL=admin@baron.co.kr
ADMIN_PASSWORD=adminPasswordIsNotSimple
# --- URLs for Proxy/Handoff ---
FRONTEND_URL=https://sso.hmac.kr # 프론트엔드 접속 주소 (이메일/SMS 링크 생성 시 사용)
USERFRONT_URL=https://sso.hmac.kr # 프론트엔드 접속 주소 (이메일/SMS 링크 생성 시 사용)
BACKEND_URL=https://sso.hmac.kr # 프론트엔드에서 참조할 백엔드 API 주소
# IDP_PROVIDER는 우선순위 순으로 콤마 구분 (예: Kratos/Hydra 우선, Descope 백업)
+7 -7
View File
@@ -86,17 +86,17 @@ jobs:
provenance: false
sbom: false
- name: Temporarily update frontend nginx port
- name: Temporarily update userfront nginx port
run: |
sed -i 's/listen 5000;/listen 80;/g' frontend/nginx.conf
sed -i 's/proxy_pass http:\/\/baron_backend:3000;/proxy_pass http:\/\/baron_backend:3010;/g' frontend/nginx.conf
sed -i 's/listen 5000;/listen 80;/g' userfront/nginx.conf
sed -i 's/proxy_pass http:\/\/baron_backend:3000;/proxy_pass http:\/\/baron_backend:3010;/g' userfront/nginx.conf
- name: Build and push frontend RC image
- name: Build and push userfront RC image
uses: docker/build-push-action@v5
with:
context: ./frontend
file: ./frontend/Dockerfile
context: ./userfront
file: ./userfront/Dockerfile
push: true
tags: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/frontend:${{ steps.rc_calculator.outputs.new_rc_tag }}
tags: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/userfront:${{ steps.rc_calculator.outputs.new_rc_tag }}
provenance: false
sbom: false
+9 -9
View File
@@ -13,8 +13,8 @@ on:
required: true
type: boolean
default: true
run_frontend_tests:
description: "Run frontend Flutter tests"
run_userfront_tests:
description: "Run userfront Flutter tests"
required: true
type: boolean
default: true
@@ -46,9 +46,9 @@ jobs:
working-directory: backend
args: --enable-only=gofmt,gofumpt
- name: Analyze Flutter frontend
- name: Analyze Flutter userfront
run: |
cd frontend
cd userfront
flutter analyze --no-fatal-warnings --no-fatal-infos
backend-tests:
@@ -85,9 +85,9 @@ jobs:
cd backend
go test -v ./...
frontend-tests:
userfront-tests:
needs: lint
if: ${{ inputs.run_frontend_tests == true }}
if: ${{ inputs.run_userfront_tests == true }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
@@ -99,11 +99,11 @@ jobs:
channel: "stable"
cache: true
- name: Run frontend tests
- name: Run userfront tests
run: |
cd frontend
cd userfront
if [ -d test ]; then
flutter test
else
echo "No frontend tests: skipping (test/ directory not found)."
echo "No userfront tests: skipping (test/ directory not found)."
fi
+7 -7
View File
@@ -49,12 +49,12 @@ jobs:
--src-tls-verify=false --dest-tls-verify=false \
"docker://${HARBOR_HOSTNAME}/baron_sso/backend:${BASE_TAG}" "docker://${HARBOR_HOSTNAME}/baron_sso/backend:${RE_TAG}"
# Re-tag frontend image
echo "Re-tagging frontend image..."
# Re-tag userfront image
echo "Re-tagging userfront image..."
skopeo copy --preserve-digests \
--src-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" --dest-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" \
--src-tls-verify=false --dest-tls-verify=false \
"docker://${HARBOR_HOSTNAME}/baron_sso/frontend:${BASE_TAG}" "docker://${HARBOR_HOSTNAME}/baron_sso/frontend:${RE_TAG}"
"docker://${HARBOR_HOSTNAME}/baron_sso/userfront:${BASE_TAG}" "docker://${HARBOR_HOSTNAME}/baron_sso/userfront:${RE_TAG}"
echo "final_image_tag=${RE_TAG}" >> "$GITHUB_OUTPUT"
@@ -67,7 +67,7 @@ jobs:
env:
IMAGE_TAG: ${{ steps.retag.outputs.final_image_tag }}
BACKEND_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/backend
FRONTEND_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/frontend
USERFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/userfront
DEPLOY_PATH: ${{ vars.PROD_DEPLOY_PATH }}
PROD_HOST: ${{ vars.PROD_HOST }}
PROD_USER: ${{ vars.PROD_USER }}
@@ -102,7 +102,7 @@ jobs:
"CLICKHOUSE_USER=${{ vars.PROD_CLICKHOUSE_USER }}" \
"CLICKHOUSE_PASSWORD=${{ secrets.PROD_CLICKHOUSE_PASSWORD }}" \
"BACKEND_PORT=${{ vars.PROD_BACKEND_PORT }}" \
"FRONTEND_PORT=${{ vars.PROD_FRONTEND_PORT }}" \
"USERFRONT_PORT=${{ vars.PROD_USERFRONT_PORT }}" \
"DB_USER=${{ vars.PROD_DB_USER }}" \
"DB_PASSWORD=${{ secrets.PROD_DB_PASSWORD }}" \
"DB_NAME=${{ vars.PROD_DB_NAME }}" \
@@ -119,7 +119,7 @@ jobs:
"AWS_ACCESS_KEY_ID=${{ vars.AWS_ACCESS_KEY_ID }}" \
"AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" \
"AWS_SES_SENDER=${{ vars.AWS_SES_SENDER }}" \
"FRONTEND_URL=${{ vars.PROD_FRONTEND_URL }}" \
"USERFRONT_URL=${{ vars.PROD_USERFRONT_URL }}" \
"BACKEND_URL=${{ vars.PROD_BACKEND_URL }}" \
> .env
@@ -131,7 +131,7 @@ jobs:
echo "${HARBOR_ROBOT_KEY}" | ssh "${PROD_USER}@${PROD_HOST}" \
"export DEPLOY_PATH='${DEPLOY_PATH}'; \
export BACKEND_IMAGE_NAME='${BACKEND_IMAGE_NAME}'; \
export FRONTEND_IMAGE_NAME='${FRONTEND_IMAGE_NAME}'; \
export USERFRONT_IMAGE_NAME='${USERFRONT_IMAGE_NAME}'; \
export IMAGE_TAG='${IMAGE_TAG}'; \
export HARBOR_ENDPOINT='${HARBOR_ENDPOINT}'; \
export HARBOR_ROBOT_ACCOUNT='${HARBOR_ROBOT_ACCOUNT}'; \
+7 -7
View File
@@ -17,10 +17,10 @@ backend/vendor/
backend/tmp/
backend/.env
# Frontend (Flutter)
# Note: Frontend might have its own .gitignore, but adding here just in case
frontend/build/
frontend/.dart_tool/
frontend/.packages
frontend/.pub/
frontend/.env
# userfront (Flutter)
# Note: userfront might have its own .gitignore, but adding here just in case
userfront/build/
userfront/.dart_tool/
userfront/.packages
userfront/.pub/
userfront/.env
+16 -16
View File
@@ -21,22 +21,22 @@
- **Features**:
- 인증용 SMS 발송 등 Ory-Stack으로 구현 어려운 부분 직접 구현
- `POST /api/v1/audit`: 감사 로그 수집 API
- User-Front가 바라보는 backend
- userfront가 바라보는 backend
### 2. User-Front(Flutter Web/App)
### 2. userfront(Flutter Web/App)
- **Framework**: Flutter 3.32+
- **Key Packages**: `flutter_riverpod`, `go_router`
- **Features**:
- 탭 기반 로그인 UI (비밀번호 기반 / 링크 기반 / QR 기반 등)
### 3. Admin-Front(Web)
### 3. adminfront(Web)
- **Framework**: Vite, React 19+, Shadcn/ui 등
- **Features**:
- 사용자 관리, 권한 부여 등 관리자 기능
- 앱 별 사용량(호출량) 등 통계
- 핵심 Audit 대상
### 4. Dev-Front(Web) - 향후 분리 예정
### 4. devfront(Web) - 향후 분리 예정
- **Framework**: Vite, React 19+, Shadcn/ui 등
- **Features**:
- RP 등록 및 관리
@@ -55,9 +55,9 @@
```mermaid
flowchart LR
AF[Admin Front] -->|"OIDC authorize/token (PKCE)"| HY["Hydra (OIDC 엔진)"]
DF[Dev Front] -->|"OIDC authorize/token (PKCE)"| HY
UF["User Front (Login/Consent UI)"] <-->|Hydra login/consent redirect| HY
AF[adminfront] -->|"OIDC authorize/token (PKCE)"| HY["Hydra (OIDC 엔진)"]
DF[devfront] -->|"OIDC authorize/token (PKCE)"| HY
UF["userfront (Login/Consent UI)"] <-->|Hydra login/consent redirect| HY
UF -->|Kratos Browser Flow| KR["Kratos (SoT: identities/traits)"]
KR -->|subject=identity.id| HY
HY -->|ID/Access Token| RP[Relying Party Apps]
@@ -111,14 +111,14 @@ docker compose -f compose.infra.yaml -f compose.ory.yaml up -d
```
#### 3. 애플리케이션 실행
Frontend와 Backend 서비스를 실행합니다.
userfront와 backend 서비스를 실행합니다.
```bash
docker compose -f docker-compose.yaml up -d
```
(또는 한번에 실행: `docker compose -f compose.infra.yaml -f compose.ory.yaml -f docker-compose.yaml up -d`)
- **Frontend**: http://localhost:5000 접속
- **Backend**: http://localhost:3000 (API)
- **userfront**: http://localhost:5000 접속
- **backend**: http://localhost:3000 (API)
- **ClickHouse**: http://localhost:8123
- **Kratos Public**: http://localhost:4433
- **Hydra Public**: http://localhost:4444
@@ -134,9 +134,9 @@ go mod tidy
go run cmd/server/main.go
```
**Frontend:**
**userfront:**
```bash
cd frontend
cd userfront
flutter pub get
flutter run -d chrome
```
@@ -151,10 +151,10 @@ baron_sso/
│ ├── cmd/server/ # 진입점 (Entry point)
│ ├── internal/ # 도메인, 핸들러, 저장소(Repository)
│ └── Dockerfile
├── user-front/ # Flutter 애플리케이션
├── userfront/ # Flutter 애플리케이션
│ ├── src/ # UI 및 로직
│ └── pubspec.yaml
├── admin-front/ # React 기반 관리
├── adminfront/ # React 기반 관리
│ ├── src/ # UI 및 로직
│ └── pubspec.yaml
├── compose.ory-stack.yaml # DB 서비스 (Postgres, ClickHouse)
@@ -167,6 +167,6 @@ baron_sso/
## 📝 상태 및 로드맵 (Status & Roadmap)
- [x] **Phase 1**: 초기 설정 및 아키텍처 설계 (완료)
- [x] **Phase 2**: Backend Audit API 구현 (일부 완료)
- [x] **Phase 3**: User Front 로그인 UI 인증 로직 (완료)
- [ ] **Phase 4**: Admin Front 기능 추가 (예정)
- [x] **Phase 3**: userfront 로그인 UI 인증 로직 (완료)
- [ ] **Phase 4**: adminfront 기능 추가 (예정)
- [ ] **Phase 5**: 대시보드 및 통합 런처 구현 (예정)
+7 -7
View File
@@ -24,7 +24,7 @@ It leverages **Descope** for secure, passwordless authentication (Enchanted Link
### 3. Infrastructure (Docker)
- **Services**: `postgres`, `clickhouse` (defined in `compose.infra.yaml`)
- **App**: `frontend`, `backend` (defined in `docker-compose.yaml`)
- **App**: `userfront`, `backend` (defined in `docker-compose.yaml`)
---
@@ -60,13 +60,13 @@ docker compose -f compose.infra.yaml up -d
```
#### 2. Start Applications
Start the Frontend and Backend services.
Start the userfront and backend services.
```bash
docker compose up
```
- **Frontend**: Accessible at http://localhost:5000
- **Backend**: API active at http://localhost:3000
- **userfront**: Accessible at http://localhost:5000
- **backend**: API active at http://localhost:3000
- **ClickHouse**: http://localhost:8123
### Local Development (Manual)
@@ -79,9 +79,9 @@ go mod tidy
go run cmd/server/main.go
```
**Frontend:**
**userfront:**
```bash
cd frontend
cd userfront
flutter pub get
flutter run -d chrome
```
@@ -96,7 +96,7 @@ baron_sso/
│ ├── cmd/server/ # Entry point
│ ├── internal/ # Domain, Handlers, Repository
│ └── Dockerfile
├── frontend/ # Flutter Application
├── userfront/ # Flutter Application
│ ├── lib/ # UI & Logic
│ └── pubspec.yaml
├── compose.infra.yaml # DB Services (Postgres, ClickHouse)
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>admin-front</title>
<title>adminfront</title>
</head>
<body>
<div id="root"></div>
@@ -1,11 +1,11 @@
{
"name": "admin-front",
"name": "adminfront",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "admin-front",
"name": "adminfront",
"version": "0.0.0",
"dependencies": {
"@radix-ui/react-avatar": "^1.1.4",
@@ -1,5 +1,5 @@
{
"name": "admin-front",
"name": "adminfront",
"private": true,
"version": "0.0.0",
"type": "module",
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -54,7 +54,7 @@ function DashboardPage() {
<div className="space-y-3 max-w-2xl">
<div className="inline-flex items-center gap-2 rounded-full border border-[var(--color-border)] px-3 py-1 text-xs uppercase tracking-[0.2em] text-[var(--color-muted)]">
<Sparkles size={14} />
admin-front ready
adminfront ready
</div>
<h2 className="text-3xl font-semibold leading-tight">
Build the admin plane with{" "}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2 -2
View File
@@ -74,8 +74,8 @@ func main() {
"app_env", getEnv("APP_ENV", "dev"),
"db_port", getEnv("DB_PORT", "5532"),
"backend_port", getEnv("BACKEND_PORT", "3000"),
"frontend_port", getEnv("FRONTEND_PORT", "5000"),
"frontend_url", getEnv("FRONTEND_URL", "http://sso.hmac.kr"),
"userfront_port", getEnv("USERFRONT_PORT", "5000"),
"userfront_url", getEnv("USERFRONT_URL", "http://sso.hmac.kr"),
"redis_addr", getEnv("REDIS_ADDR", "redis:6379"),
)
+20 -20
View File
@@ -418,7 +418,7 @@ func (h *AuthHandler) saveSignupState(key string, state *signupState, ttl time.D
return h.RedisService.Set(key, string(data), ttl)
}
// GetPasswordPolicy exposes the current Descope password policy to the frontend for dynamic validation.
// GetPasswordPolicy exposes the current Descope password policy to the userfront for dynamic validation.
func (h *AuthHandler) GetPasswordPolicy(c *fiber.Ctx) error {
if h.DescopeClient == nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Descope client not configured"})
@@ -531,12 +531,12 @@ func (h *AuthHandler) InitEnchantedLink(c *fiber.Ctx) error {
h.RedisService.Set(prefixToken+token, fmt.Sprintf(`{"pendingRef":"%s","loginId":"%s"}`, pendingRef, loginID), defaultExpiration)
// Generate Link
frontendURL := os.Getenv("FRONTEND_URL")
slog.Info("[Enchanted] Read FRONTEND_URL", "url", frontendURL)
if frontendURL == "" {
frontendURL = "http://sso.hmac.kr"
userfrontURL := os.Getenv("USERFRONT_URL")
slog.Info("[Enchanted] Read USERFRONT_URL", "url", userfrontURL)
if userfrontURL == "" {
userfrontURL = "http://sso.hmac.kr"
}
link := fmt.Sprintf("%s/verify/%s", frontendURL, token)
link := fmt.Sprintf("%s/verify/%s", userfrontURL, token)
// Route based on LoginID type
if strings.Contains(loginID, "@") {
@@ -801,16 +801,16 @@ func (h *AuthHandler) InitiatePasswordReset(c *fiber.Ctx) error {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Authentication service not configured"})
}
frontendURL := os.Getenv("FRONTEND_URL")
if frontendURL == "" {
userfrontURL := os.Getenv("USERFRONT_URL")
if userfrontURL == "" {
ale.Status = fiber.StatusInternalServerError
ale.LatencyMs = time.Since(startTime)
ale.DescopeError = "FRONTEND_URL is not set"
ale.Log(slog.LevelError, "FRONTEND_URL is not set")
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "FRONTEND_URL environment variable is not set"})
ale.DescopeError = "USERFRONT_URL is not set"
ale.Log(slog.LevelError, "USERFRONT_URL is not set")
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "USERFRONT_URL environment variable is not set"})
}
// [Changed] Point to Backend API for verification (which then redirects to Frontend)
redirectURL := fmt.Sprintf("%s/api/v1/auth/password/reset/verify", frontendURL)
redirectURL := fmt.Sprintf("%s/api/v1/auth/password/reset/verify", userfrontURL)
ale.RedirectTo = redirectURL
// 내부 토큰 발급 + 우리 채널로 전송
@@ -831,7 +831,7 @@ func (h *AuthHandler) InitiatePasswordReset(c *fiber.Ctx) error {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to store reset token"})
}
resetLink := fmt.Sprintf("%s/reset-password?token=%s", frontendURL, resetToken)
resetLink := fmt.Sprintf("%s/reset-password?token=%s", userfrontURL, resetToken)
ale.RedirectTo = resetLink
ale.Operation = "SendPasswordReset"
ale.Log(slog.LevelInfo, "Initiating password reset via internal token")
@@ -923,7 +923,7 @@ func (h *AuthHandler) VerifyPasswordResetPage(c *fiber.Ctx) error {
}
// ProcessPasswordResetToken - Handles the POST request from the interstitial page.
// Verifies the token, sets the refresh token cookie, and redirects to the frontend.
// Verifies the token, sets the refresh token cookie, and redirects to the userfront.
func (h *AuthHandler) ProcessPasswordResetToken(c *fiber.Ctx) error {
startTime := time.Now()
ale := logger.NewAuditLogEntry(c, "verify")
@@ -960,7 +960,7 @@ func (h *AuthHandler) ProcessPasswordResetToken(c *fiber.Ctx) error {
ale.LoginIDs["loginId_normalized"] = loginID
redirectURL := fmt.Sprintf("%s/reset-password?loginId=%s&token=%s",
os.Getenv("FRONTEND_URL"),
os.Getenv("USERFRONT_URL"),
loginID,
token,
)
@@ -968,7 +968,7 @@ func (h *AuthHandler) ProcessPasswordResetToken(c *fiber.Ctx) error {
ale.RedirectTo = redirectURL
ale.Status = fiber.StatusFound
ale.LatencyMs = time.Since(startTime)
ale.Log(slog.LevelInfo, "Token verified, redirecting to frontend")
ale.Log(slog.LevelInfo, "Token verified, redirecting to userfront")
return c.Redirect(redirectURL)
}
@@ -1127,11 +1127,11 @@ func (h *AuthHandler) InitQRLogin(c *fiber.Ctx) error {
pendingRef := GenerateSecureToken(16)
// QR 코드 페이로드를 실제 접속 가능한 URL로 변경합니다.
frontendURL := os.Getenv("FRONTEND_URL")
if frontendURL == "" {
frontendURL = "https://sso.hmac.kr"
userfrontURL := os.Getenv("USERFRONT_URL")
if userfrontURL == "" {
userfrontURL = "https://sso.hmac.kr"
}
qrPayload := fmt.Sprintf("%s/approve?ref=%s", frontendURL, pendingRef)
qrPayload := fmt.Sprintf("%s/approve?ref=%s", userfrontURL, pendingRef)
slog.Info("[QR] Init", "pendingRef", pendingRef, "url", qrPayload)
+1 -1
View File
@@ -44,7 +44,7 @@ func NewDescopeProvider(projectID, managementKey string) *DescopeProvider {
return &DescopeProvider{
Client: descopeClient,
FrontendURL: os.Getenv("FRONTEND_URL"),
FrontendURL: os.Getenv("USERFRONT_URL"),
fieldMapping: mapping,
}
}
+2 -1
View File
@@ -52,5 +52,6 @@ volumes:
networks:
baron_net:
name: baron_network
name: baron_net
external: true
driver: bridge
+1 -1
View File
@@ -173,7 +173,7 @@ services:
command: >
clients create
--endpoint http://hydra:4445
--id admin-front
--id adminfront
--secret admin-secret
--grant-types authorization_code,refresh_token
--response-types code
+85 -85
View File
@@ -1,91 +1,91 @@
services:
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: baron_backend
env_file:
- .env
environment:
- APP_ENV=${APP_ENV:-development}
- GO_ENV=${APP_ENV:-development}
- COOKIE_SECRET=${COOKIE_SECRET}
- JWT_SECRET=${JWT_SECRET}
- DESCOPE_PROJECT_ID=${DESCOPE_PROJECT_ID}
- DESCOPE_MANAGEMENT_KEY=${DESCOPE_MANAGEMENT_KEY}
- NAVER_CLOUD_ACCESS_KEY=${NAVER_CLOUD_ACCESS_KEY}
- NAVER_CLOUD_SECRET_KEY=${NAVER_CLOUD_SECRET_KEY}
- NAVER_CLOUD_SERVICE_ID=${NAVER_CLOUD_SERVICE_ID}
- NAVER_SENDER_PHONE_NUMBER=${NAVER_SENDER_PHONE_NUMBER}
- FRONTEND_URL=${FRONTEND_URL}
- IDP_PROVIDER=${IDP_PROVIDER:-ory,descope}
- KRATOS_ADMIN_URL=${KRATOS_ADMIN_URL:-http://kratos:4434}
- HYDRA_ADMIN_URL=${HYDRA_ADMIN_URL:-http://hydra:4445}
- DB_HOST=postgres
- CLICKHOUSE_HOST=clickhouse
- CLICKHOUSE_PORT=${CLICKHOUSE_PORT_NATIVE:-9000}
- CLICKHOUSE_USER=${CLICKHOUSE_USER:-baron}
- CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:-password}
ports:
- "${BACKEND_PORT:-3000}:3000"
depends_on:
- infra_check
networks:
- baron_net
- ory-net
volumes:
- ./backend:/app
command: ["go", "run", "./cmd/server/main.go"]
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: baron_backend
env_file:
- .env
environment:
- APP_ENV=${APP_ENV:-development}
- GO_ENV=${APP_ENV:-development}
- COOKIE_SECRET=${COOKIE_SECRET}
- JWT_SECRET=${JWT_SECRET}
- DESCOPE_PROJECT_ID=${DESCOPE_PROJECT_ID}
- DESCOPE_MANAGEMENT_KEY=${DESCOPE_MANAGEMENT_KEY}
- NAVER_CLOUD_ACCESS_KEY=${NAVER_CLOUD_ACCESS_KEY}
- NAVER_CLOUD_SECRET_KEY=${NAVER_CLOUD_SECRET_KEY}
- NAVER_CLOUD_SERVICE_ID=${NAVER_CLOUD_SERVICE_ID}
- NAVER_SENDER_PHONE_NUMBER=${NAVER_SENDER_PHONE_NUMBER}
- USERFRONT_URL=${USERFRONT_URL}
- IDP_PROVIDER=${IDP_PROVIDER:-ory,descope}
- KRATOS_ADMIN_URL=${KRATOS_ADMIN_URL:-http://kratos:4434}
- HYDRA_ADMIN_URL=${HYDRA_ADMIN_URL:-http://hydra:4445}
- DB_HOST=postgres
- CLICKHOUSE_HOST=clickhouse
- CLICKHOUSE_PORT=${CLICKHOUSE_PORT_NATIVE:-9000}
- CLICKHOUSE_USER=${CLICKHOUSE_USER:-baron}
- CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:-password}
ports:
- "${BACKEND_PORT:-3000}:3000"
depends_on:
- infra_check
networks:
- baron_net
- ory-net
volumes:
- ./backend:/app
command: ["go", "run", "./cmd/server/main.go"]
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 10s
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 10s
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
container_name: baron_frontend
env_file:
- .env
environment:
- DESCOPE_PROJECT_ID=${DESCOPE_PROJECT_ID}
- BACKEND_URL=${BACKEND_URL}
- FRONTEND_URL=${FRONTEND_URL}
- APP_ENV=${APP_ENV}
ports:
- "${FRONTEND_PORT:-5000}:5000"
networks:
- baron_net
depends_on:
backend:
condition: service_healthy
command: >
/bin/sh -c "mkdir -p /usr/share/nginx/html/assets &&
echo \"DESCOPE_PROJECT_ID=$${DESCOPE_PROJECT_ID}\" > /usr/share/nginx/html/assets/.env &&
echo \"BACKEND_URL=$${BACKEND_URL}\" >> /usr/share/nginx/html/assets/.env &&
echo \"FRONTEND_URL=$${FRONTEND_URL}\" >> /usr/share/nginx/html/assets/.env &&
echo \"APP_ENV=$${APP_ENV}\" >> /usr/share/nginx/html/assets/.env &&
cp /usr/share/nginx/html/assets/.env /usr/share/nginx/html/.env &&
nginx -g 'daemon off;'"
userfront:
build:
context: ./userfront
dockerfile: Dockerfile
container_name: baron_userfront
env_file:
- .env
environment:
- DESCOPE_PROJECT_ID=${DESCOPE_PROJECT_ID}
- BACKEND_URL=${BACKEND_URL}
- USERFRONT_URL=${USERFRONT_URL}
- APP_ENV=${APP_ENV}
ports:
- "${USERFRONT_PORT:-5000}:5000"
networks:
- baron_net
depends_on:
backend:
condition: service_healthy
command: >
/bin/sh -c "mkdir -p /usr/share/nginx/html/assets &&
echo \"DESCOPE_PROJECT_ID=$${DESCOPE_PROJECT_ID}\" > /usr/share/nginx/html/assets/.env &&
echo \"BACKEND_URL=$${BACKEND_URL}\" >> /usr/share/nginx/html/assets/.env &&
echo \"USERFRONT_URL=$${USERFRONT_URL}\" >> /usr/share/nginx/html/assets/.env &&
echo \"APP_ENV=$${APP_ENV}\" >> /usr/share/nginx/html/assets/.env &&
cp /usr/share/nginx/html/assets/.env /usr/share/nginx/html/.env &&
nginx -g 'daemon off;'"
# Dummy service to wait for infra network if needed,
# but essentially we assume infra is running.
# In a real unified stack, we might include infra here or use external links.
# Here we attach to the same network.
infra_check:
image: alpine
command: ["echo", "Infrastructure assumed running"]
networks:
- baron_net
# Dummy service to wait for infra network if needed,
# but essentially we assume infra is running.
# In a real unified stack, we might include infra here or use external links.
# Here we attach to the same network.
infra_check:
image: alpine
command: ["echo", "Infrastructure assumed running"]
networks:
- baron_net
networks:
baron_net:
external: true
name: baron_network
ory-net:
external: true
name: ory-net
baron_net:
external: true
name: baron_net
ory-net:
external: true
name: ory-net
+3 -3
View File
@@ -13,10 +13,10 @@ Backend와 Frontend 애플리케이션을 각각의 Dockerfile을 사용하여
```bash
# Backend 이미지 빌드
# v1.2601.1-RC1 부분은 실제 배포 버전에 맞게 수정하세요.
docker build -t reg.hmac.kr/baron_sso/backend:v1.2601.1-RC1 -f docker/Dockerfile.backend .
docker build -t reg.hmac.kr/baron_sso/backend:v1.2601.1-RC1 -f backend/Dockerfile .
# Frontend 이미지 빌드
docker build -t reg.hmac.kr/baron_sso/frontend:v1.2601.1-RC1 -f docker/Dockerfile.frontend .
docker build -t reg.hmac.kr/baron_sso/userfront:v1.2601.1-RC1 -f userfront/Dockerfile .
```
---
@@ -42,7 +42,7 @@ docker login reg.hmac.kr
docker push reg.hmac.kr/baron_sso/backend:v1.2601.1-RC1
# Frontend 이미지 푸시
docker push reg.hmac.kr/baron_sso/frontend:v1.2601.1-RC1
docker push reg.hmac.kr/baron_sso/userfront:v1.2601.1-RC1
```
---
+7 -7
View File
@@ -16,7 +16,7 @@ services:
- CLICKHOUSE_PORT=${CLICKHOUSE_PORT_NATIVE:-9000}
- CLICKHOUSE_USER=${CLICKHOUSE_USER:-baron}
- CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:-password}
- FRONTEND_URL=${FRONTEND_URL:-https://sso.hmac.kr}
- USERFRONT_URL=${USERFRONT_URL:-https://sso.hmac.kr}
ports:
- "${BACKEND_PORT:-3010}:3010"
depends_on:
@@ -30,15 +30,15 @@ services:
networks:
- baron_net
frontend:
image: ${FRONTEND_IMAGE_NAME}:${IMAGE_TAG}
container_name: baron_frontend
userfront:
image: ${USERFRONT_IMAGE_NAME}:${IMAGE_TAG}
container_name: baron_userfront
restart: unless-stopped
environment:
- FRONTEND_URL=${FRONTEND_URL:-https://sso.hmac.kr}
- BACKEND_URL=${FRONTEND_URL:-https://sso.hmac.kr}
- USERFRONT_URL=${USERFRONT_URL:-https://sso.hmac.kr}
- BACKEND_URL=${USERFRONT_URL:-https://sso.hmac.kr}
ports:
- "${FRONTEND_PORT:-80}:80"
- "${USERFRONT_PORT:-80}:80"
depends_on:
backend:
condition: service_healthy
+1 -1
View File
@@ -35,7 +35,7 @@
## Workspace Structure
Root: `/home/lectom/.gemini/antigravity/scratch/baron_sso`
- `/backend`: Go Fiber Application
- `/frontend`: Flutter Application
- `/userfront`: Flutter Application
- `/docs`: Documentation (PRD, API Specs)
## Current Status
-98
View File
@@ -1,98 +0,0 @@
name: frontend
description: "A new Flutter project."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: "none" # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1
environment:
sdk: ^3.10.4
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
flutter_riverpod: ^3.0.3
go_router: ^17.0.1
descope: ^0.9.11
http: ^1.6.0
google_fonts: ^6.3.3
flutter_dotenv: ^5.1.0
url_launcher: ^6.3.2
logging: ^1.2.0
logger: ^2.0.0
qr_flutter: ^4.1.0
mobile_scanner: ^6.0.0
dev_dependencies:
flutter_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^6.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - .env
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/to/asset-from-package
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/to/font-from-package
@@ -11,7 +11,7 @@ DB_PORT=5432
CLICKHOUSE_PORT_HTTP=8123
CLICKHOUSE_PORT_NATIVE=9000
BACKEND_PORT=3000
FRONTEND_PORT=5000
USERFRONT_PORT=5000
# --- Database Credentials (PostgreSQL) ---
DB_USER=baron
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -6,7 +6,7 @@ plugins {
}
android {
namespace = "kr.co.baroncs.frontend"
namespace = "kr.co.baroncs.userfront"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
@@ -21,7 +21,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "kr.co.baroncs.frontend"
applicationId = "kr.co.baroncs.userfront"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
@@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.CAMERA"/>
<application
android:label="frontend"
android:label="userfront"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
@@ -1,4 +1,4 @@
package kr.co.baroncs.frontend
package kr.co.baroncs.userfront
import io.flutter.embedding.android.FlutterActivity
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -368,7 +368,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.frontend;
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@@ -384,7 +384,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.frontend.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -401,7 +401,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.frontend.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -416,7 +416,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.frontend.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -547,7 +547,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.frontend;
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -569,7 +569,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.frontend;
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
File renamed without changes.
Loaded 100 of 154 files, more files were not shown because too many files have changed in this diff. Show more