userfront로 리펙토링 완료
@@ -11,7 +11,7 @@ DB_PORT=5432
|
|||||||
CLICKHOUSE_PORT_HTTP=8123
|
CLICKHOUSE_PORT_HTTP=8123
|
||||||
CLICKHOUSE_PORT_NATIVE=9000
|
CLICKHOUSE_PORT_NATIVE=9000
|
||||||
BACKEND_PORT=3000
|
BACKEND_PORT=3000
|
||||||
FRONTEND_PORT=5000
|
USERFRONT_PORT=5000
|
||||||
|
|
||||||
# --- Database Credentials (PostgreSQL) ---
|
# --- Database Credentials (PostgreSQL) ---
|
||||||
DB_USER=baron
|
DB_USER=baron
|
||||||
@@ -47,7 +47,7 @@ ADMIN_EMAIL=admin@baron.co.kr
|
|||||||
ADMIN_PASSWORD=adminPasswordIsNotSimple
|
ADMIN_PASSWORD=adminPasswordIsNotSimple
|
||||||
|
|
||||||
# --- URLs for Proxy/Handoff ---
|
# --- 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 주소
|
BACKEND_URL=https://sso.hmac.kr # 프론트엔드에서 참조할 백엔드 API 주소
|
||||||
|
|
||||||
# IDP_PROVIDER는 우선순위 순으로 콤마 구분 (예: Kratos/Hydra 우선, Descope 백업)
|
# IDP_PROVIDER는 우선순위 순으로 콤마 구분 (예: Kratos/Hydra 우선, Descope 백업)
|
||||||
|
|||||||
@@ -86,17 +86,17 @@ jobs:
|
|||||||
provenance: false
|
provenance: false
|
||||||
sbom: false
|
sbom: false
|
||||||
|
|
||||||
- name: Temporarily update frontend nginx port
|
- name: Temporarily update userfront nginx port
|
||||||
run: |
|
run: |
|
||||||
sed -i 's/listen 5000;/listen 80;/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' frontend/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
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: ./frontend
|
context: ./userfront
|
||||||
file: ./frontend/Dockerfile
|
file: ./userfront/Dockerfile
|
||||||
push: true
|
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
|
provenance: false
|
||||||
sbom: false
|
sbom: false
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ on:
|
|||||||
required: true
|
required: true
|
||||||
type: boolean
|
type: boolean
|
||||||
default: true
|
default: true
|
||||||
run_frontend_tests:
|
run_userfront_tests:
|
||||||
description: "Run frontend Flutter tests"
|
description: "Run userfront Flutter tests"
|
||||||
required: true
|
required: true
|
||||||
type: boolean
|
type: boolean
|
||||||
default: true
|
default: true
|
||||||
@@ -46,9 +46,9 @@ jobs:
|
|||||||
working-directory: backend
|
working-directory: backend
|
||||||
args: --enable-only=gofmt,gofumpt
|
args: --enable-only=gofmt,gofumpt
|
||||||
|
|
||||||
- name: Analyze Flutter frontend
|
- name: Analyze Flutter userfront
|
||||||
run: |
|
run: |
|
||||||
cd frontend
|
cd userfront
|
||||||
flutter analyze --no-fatal-warnings --no-fatal-infos
|
flutter analyze --no-fatal-warnings --no-fatal-infos
|
||||||
|
|
||||||
backend-tests:
|
backend-tests:
|
||||||
@@ -85,9 +85,9 @@ jobs:
|
|||||||
cd backend
|
cd backend
|
||||||
go test -v ./...
|
go test -v ./...
|
||||||
|
|
||||||
frontend-tests:
|
userfront-tests:
|
||||||
needs: lint
|
needs: lint
|
||||||
if: ${{ inputs.run_frontend_tests == true }}
|
if: ${{ inputs.run_userfront_tests == true }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
@@ -99,11 +99,11 @@ jobs:
|
|||||||
channel: "stable"
|
channel: "stable"
|
||||||
cache: true
|
cache: true
|
||||||
|
|
||||||
- name: Run frontend tests
|
- name: Run userfront tests
|
||||||
run: |
|
run: |
|
||||||
cd frontend
|
cd userfront
|
||||||
if [ -d test ]; then
|
if [ -d test ]; then
|
||||||
flutter test
|
flutter test
|
||||||
else
|
else
|
||||||
echo "No frontend tests: skipping (test/ directory not found)."
|
echo "No userfront tests: skipping (test/ directory not found)."
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -49,12 +49,12 @@ jobs:
|
|||||||
--src-tls-verify=false --dest-tls-verify=false \
|
--src-tls-verify=false --dest-tls-verify=false \
|
||||||
"docker://${HARBOR_HOSTNAME}/baron_sso/backend:${BASE_TAG}" "docker://${HARBOR_HOSTNAME}/baron_sso/backend:${RE_TAG}"
|
"docker://${HARBOR_HOSTNAME}/baron_sso/backend:${BASE_TAG}" "docker://${HARBOR_HOSTNAME}/baron_sso/backend:${RE_TAG}"
|
||||||
|
|
||||||
# Re-tag frontend image
|
# Re-tag userfront image
|
||||||
echo "Re-tagging frontend image..."
|
echo "Re-tagging userfront image..."
|
||||||
skopeo copy --preserve-digests \
|
skopeo copy --preserve-digests \
|
||||||
--src-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" --dest-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" \
|
--src-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" --dest-creds "${HARBOR_USER}:${HARBOR_PASSWORD}" \
|
||||||
--src-tls-verify=false --dest-tls-verify=false \
|
--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"
|
echo "final_image_tag=${RE_TAG}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
IMAGE_TAG: ${{ steps.retag.outputs.final_image_tag }}
|
IMAGE_TAG: ${{ steps.retag.outputs.final_image_tag }}
|
||||||
BACKEND_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/backend
|
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 }}
|
DEPLOY_PATH: ${{ vars.PROD_DEPLOY_PATH }}
|
||||||
PROD_HOST: ${{ vars.PROD_HOST }}
|
PROD_HOST: ${{ vars.PROD_HOST }}
|
||||||
PROD_USER: ${{ vars.PROD_USER }}
|
PROD_USER: ${{ vars.PROD_USER }}
|
||||||
@@ -102,7 +102,7 @@ jobs:
|
|||||||
"CLICKHOUSE_USER=${{ vars.PROD_CLICKHOUSE_USER }}" \
|
"CLICKHOUSE_USER=${{ vars.PROD_CLICKHOUSE_USER }}" \
|
||||||
"CLICKHOUSE_PASSWORD=${{ secrets.PROD_CLICKHOUSE_PASSWORD }}" \
|
"CLICKHOUSE_PASSWORD=${{ secrets.PROD_CLICKHOUSE_PASSWORD }}" \
|
||||||
"BACKEND_PORT=${{ vars.PROD_BACKEND_PORT }}" \
|
"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_USER=${{ vars.PROD_DB_USER }}" \
|
||||||
"DB_PASSWORD=${{ secrets.PROD_DB_PASSWORD }}" \
|
"DB_PASSWORD=${{ secrets.PROD_DB_PASSWORD }}" \
|
||||||
"DB_NAME=${{ vars.PROD_DB_NAME }}" \
|
"DB_NAME=${{ vars.PROD_DB_NAME }}" \
|
||||||
@@ -119,7 +119,7 @@ jobs:
|
|||||||
"AWS_ACCESS_KEY_ID=${{ vars.AWS_ACCESS_KEY_ID }}" \
|
"AWS_ACCESS_KEY_ID=${{ vars.AWS_ACCESS_KEY_ID }}" \
|
||||||
"AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" \
|
"AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" \
|
||||||
"AWS_SES_SENDER=${{ vars.AWS_SES_SENDER }}" \
|
"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 }}" \
|
"BACKEND_URL=${{ vars.PROD_BACKEND_URL }}" \
|
||||||
> .env
|
> .env
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ jobs:
|
|||||||
echo "${HARBOR_ROBOT_KEY}" | ssh "${PROD_USER}@${PROD_HOST}" \
|
echo "${HARBOR_ROBOT_KEY}" | ssh "${PROD_USER}@${PROD_HOST}" \
|
||||||
"export DEPLOY_PATH='${DEPLOY_PATH}'; \
|
"export DEPLOY_PATH='${DEPLOY_PATH}'; \
|
||||||
export BACKEND_IMAGE_NAME='${BACKEND_IMAGE_NAME}'; \
|
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 IMAGE_TAG='${IMAGE_TAG}'; \
|
||||||
export HARBOR_ENDPOINT='${HARBOR_ENDPOINT}'; \
|
export HARBOR_ENDPOINT='${HARBOR_ENDPOINT}'; \
|
||||||
export HARBOR_ROBOT_ACCOUNT='${HARBOR_ROBOT_ACCOUNT}'; \
|
export HARBOR_ROBOT_ACCOUNT='${HARBOR_ROBOT_ACCOUNT}'; \
|
||||||
|
|||||||
14
.gitignore
vendored
@@ -17,10 +17,10 @@ backend/vendor/
|
|||||||
backend/tmp/
|
backend/tmp/
|
||||||
backend/.env
|
backend/.env
|
||||||
|
|
||||||
# Frontend (Flutter)
|
# userfront (Flutter)
|
||||||
# Note: Frontend might have its own .gitignore, but adding here just in case
|
# Note: userfront might have its own .gitignore, but adding here just in case
|
||||||
frontend/build/
|
userfront/build/
|
||||||
frontend/.dart_tool/
|
userfront/.dart_tool/
|
||||||
frontend/.packages
|
userfront/.packages
|
||||||
frontend/.pub/
|
userfront/.pub/
|
||||||
frontend/.env
|
userfront/.env
|
||||||
|
|||||||
32
README.md
@@ -21,22 +21,22 @@
|
|||||||
- **Features**:
|
- **Features**:
|
||||||
- 인증용 SMS 발송 등 Ory-Stack으로 구현 어려운 부분 직접 구현
|
- 인증용 SMS 발송 등 Ory-Stack으로 구현 어려운 부분 직접 구현
|
||||||
- `POST /api/v1/audit`: 감사 로그 수집 API
|
- `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+
|
- **Framework**: Flutter 3.32+
|
||||||
- **Key Packages**: `flutter_riverpod`, `go_router`
|
- **Key Packages**: `flutter_riverpod`, `go_router`
|
||||||
- **Features**:
|
- **Features**:
|
||||||
- 탭 기반 로그인 UI (비밀번호 기반 / 링크 기반 / QR 기반 등)
|
- 탭 기반 로그인 UI (비밀번호 기반 / 링크 기반 / QR 기반 등)
|
||||||
|
|
||||||
### 3. Admin-Front(Web)
|
### 3. adminfront(Web)
|
||||||
- **Framework**: Vite, React 19+, Shadcn/ui 등
|
- **Framework**: Vite, React 19+, Shadcn/ui 등
|
||||||
- **Features**:
|
- **Features**:
|
||||||
- 사용자 관리, 권한 부여 등 관리자 기능
|
- 사용자 관리, 권한 부여 등 관리자 기능
|
||||||
- 앱 별 사용량(호출량) 등 통계
|
- 앱 별 사용량(호출량) 등 통계
|
||||||
- 핵심 Audit 대상
|
- 핵심 Audit 대상
|
||||||
|
|
||||||
### 4. Dev-Front(Web) - 향후 분리 예정
|
### 4. devfront(Web) - 향후 분리 예정
|
||||||
- **Framework**: Vite, React 19+, Shadcn/ui 등
|
- **Framework**: Vite, React 19+, Shadcn/ui 등
|
||||||
- **Features**:
|
- **Features**:
|
||||||
- RP 등록 및 관리
|
- RP 등록 및 관리
|
||||||
@@ -55,9 +55,9 @@
|
|||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart LR
|
flowchart LR
|
||||||
AF[Admin Front] -->|"OIDC authorize/token (PKCE)"| HY["Hydra (OIDC 엔진)"]
|
AF[adminfront] -->|"OIDC authorize/token (PKCE)"| HY["Hydra (OIDC 엔진)"]
|
||||||
DF[Dev Front] -->|"OIDC authorize/token (PKCE)"| HY
|
DF[devfront] -->|"OIDC authorize/token (PKCE)"| HY
|
||||||
UF["User Front (Login/Consent UI)"] <-->|Hydra login/consent redirect| HY
|
UF["userfront (Login/Consent UI)"] <-->|Hydra login/consent redirect| HY
|
||||||
UF -->|Kratos Browser Flow| KR["Kratos (SoT: identities/traits)"]
|
UF -->|Kratos Browser Flow| KR["Kratos (SoT: identities/traits)"]
|
||||||
KR -->|subject=identity.id| HY
|
KR -->|subject=identity.id| HY
|
||||||
HY -->|ID/Access Token| RP[Relying Party Apps]
|
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. 애플리케이션 실행
|
#### 3. 애플리케이션 실행
|
||||||
Frontend와 Backend 서비스를 실행합니다.
|
userfront와 backend 서비스를 실행합니다.
|
||||||
```bash
|
```bash
|
||||||
docker compose -f docker-compose.yaml up -d
|
docker compose -f docker-compose.yaml up -d
|
||||||
```
|
```
|
||||||
(또는 한번에 실행: `docker compose -f compose.infra.yaml -f compose.ory.yaml -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 접속
|
- **userfront**: http://localhost:5000 접속
|
||||||
- **Backend**: http://localhost:3000 (API)
|
- **backend**: http://localhost:3000 (API)
|
||||||
- **ClickHouse**: http://localhost:8123
|
- **ClickHouse**: http://localhost:8123
|
||||||
- **Kratos Public**: http://localhost:4433
|
- **Kratos Public**: http://localhost:4433
|
||||||
- **Hydra Public**: http://localhost:4444
|
- **Hydra Public**: http://localhost:4444
|
||||||
@@ -134,9 +134,9 @@ go mod tidy
|
|||||||
go run cmd/server/main.go
|
go run cmd/server/main.go
|
||||||
```
|
```
|
||||||
|
|
||||||
**Frontend:**
|
**userfront:**
|
||||||
```bash
|
```bash
|
||||||
cd frontend
|
cd userfront
|
||||||
flutter pub get
|
flutter pub get
|
||||||
flutter run -d chrome
|
flutter run -d chrome
|
||||||
```
|
```
|
||||||
@@ -151,10 +151,10 @@ baron_sso/
|
|||||||
│ ├── cmd/server/ # 진입점 (Entry point)
|
│ ├── cmd/server/ # 진입점 (Entry point)
|
||||||
│ ├── internal/ # 도메인, 핸들러, 저장소(Repository)
|
│ ├── internal/ # 도메인, 핸들러, 저장소(Repository)
|
||||||
│ └── Dockerfile
|
│ └── Dockerfile
|
||||||
├── user-front/ # Flutter 애플리케이션
|
├── userfront/ # Flutter 애플리케이션
|
||||||
│ ├── src/ # UI 및 로직
|
│ ├── src/ # UI 및 로직
|
||||||
│ └── pubspec.yaml
|
│ └── pubspec.yaml
|
||||||
├── admin-front/ # React 기반 관리
|
├── adminfront/ # React 기반 관리
|
||||||
│ ├── src/ # UI 및 로직
|
│ ├── src/ # UI 및 로직
|
||||||
│ └── pubspec.yaml
|
│ └── pubspec.yaml
|
||||||
├── compose.ory-stack.yaml # DB 서비스 (Postgres, ClickHouse)
|
├── compose.ory-stack.yaml # DB 서비스 (Postgres, ClickHouse)
|
||||||
@@ -167,6 +167,6 @@ baron_sso/
|
|||||||
## 📝 상태 및 로드맵 (Status & Roadmap)
|
## 📝 상태 및 로드맵 (Status & Roadmap)
|
||||||
- [x] **Phase 1**: 초기 설정 및 아키텍처 설계 (완료)
|
- [x] **Phase 1**: 초기 설정 및 아키텍처 설계 (완료)
|
||||||
- [x] **Phase 2**: Backend Audit API 구현 (일부 완료)
|
- [x] **Phase 2**: Backend Audit API 구현 (일부 완료)
|
||||||
- [x] **Phase 3**: User Front 로그인 UI 인증 로직 (완료)
|
- [x] **Phase 3**: userfront 로그인 UI 인증 로직 (완료)
|
||||||
- [ ] **Phase 4**: Admin Front 기능 추가 (예정)
|
- [ ] **Phase 4**: adminfront 기능 추가 (예정)
|
||||||
- [ ] **Phase 5**: 대시보드 및 통합 런처 구현 (예정)
|
- [ ] **Phase 5**: 대시보드 및 통합 런처 구현 (예정)
|
||||||
|
|||||||
14
README_en.md
@@ -24,7 +24,7 @@ It leverages **Descope** for secure, passwordless authentication (Enchanted Link
|
|||||||
|
|
||||||
### 3. Infrastructure (Docker)
|
### 3. Infrastructure (Docker)
|
||||||
- **Services**: `postgres`, `clickhouse` (defined in `compose.infra.yaml`)
|
- **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
|
#### 2. Start Applications
|
||||||
Start the Frontend and Backend services.
|
Start the userfront and backend services.
|
||||||
```bash
|
```bash
|
||||||
docker compose up
|
docker compose up
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Frontend**: Accessible at http://localhost:5000
|
- **userfront**: Accessible at http://localhost:5000
|
||||||
- **Backend**: API active at http://localhost:3000
|
- **backend**: API active at http://localhost:3000
|
||||||
- **ClickHouse**: http://localhost:8123
|
- **ClickHouse**: http://localhost:8123
|
||||||
|
|
||||||
### Local Development (Manual)
|
### Local Development (Manual)
|
||||||
@@ -79,9 +79,9 @@ go mod tidy
|
|||||||
go run cmd/server/main.go
|
go run cmd/server/main.go
|
||||||
```
|
```
|
||||||
|
|
||||||
**Frontend:**
|
**userfront:**
|
||||||
```bash
|
```bash
|
||||||
cd frontend
|
cd userfront
|
||||||
flutter pub get
|
flutter pub get
|
||||||
flutter run -d chrome
|
flutter run -d chrome
|
||||||
```
|
```
|
||||||
@@ -96,7 +96,7 @@ baron_sso/
|
|||||||
│ ├── cmd/server/ # Entry point
|
│ ├── cmd/server/ # Entry point
|
||||||
│ ├── internal/ # Domain, Handlers, Repository
|
│ ├── internal/ # Domain, Handlers, Repository
|
||||||
│ └── Dockerfile
|
│ └── Dockerfile
|
||||||
├── frontend/ # Flutter Application
|
├── userfront/ # Flutter Application
|
||||||
│ ├── lib/ # UI & Logic
|
│ ├── lib/ # UI & Logic
|
||||||
│ └── pubspec.yaml
|
│ └── pubspec.yaml
|
||||||
├── compose.infra.yaml # DB Services (Postgres, ClickHouse)
|
├── compose.infra.yaml # DB Services (Postgres, ClickHouse)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>admin-front</title>
|
<title>adminfront</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "admin-front",
|
"name": "adminfront",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "admin-front",
|
"name": "adminfront",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/react-avatar": "^1.1.4",
|
"@radix-ui/react-avatar": "^1.1.4",
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "admin-front",
|
"name": "adminfront",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
@@ -54,7 +54,7 @@ function DashboardPage() {
|
|||||||
<div className="space-y-3 max-w-2xl">
|
<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)]">
|
<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} />
|
<Sparkles size={14} />
|
||||||
admin-front ready
|
adminfront ready
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-3xl font-semibold leading-tight">
|
<h2 className="text-3xl font-semibold leading-tight">
|
||||||
Build the admin plane with{" "}
|
Build the admin plane with{" "}
|
||||||
@@ -74,8 +74,8 @@ func main() {
|
|||||||
"app_env", getEnv("APP_ENV", "dev"),
|
"app_env", getEnv("APP_ENV", "dev"),
|
||||||
"db_port", getEnv("DB_PORT", "5532"),
|
"db_port", getEnv("DB_PORT", "5532"),
|
||||||
"backend_port", getEnv("BACKEND_PORT", "3000"),
|
"backend_port", getEnv("BACKEND_PORT", "3000"),
|
||||||
"frontend_port", getEnv("FRONTEND_PORT", "5000"),
|
"userfront_port", getEnv("USERFRONT_PORT", "5000"),
|
||||||
"frontend_url", getEnv("FRONTEND_URL", "http://sso.hmac.kr"),
|
"userfront_url", getEnv("USERFRONT_URL", "http://sso.hmac.kr"),
|
||||||
"redis_addr", getEnv("REDIS_ADDR", "redis:6379"),
|
"redis_addr", getEnv("REDIS_ADDR", "redis:6379"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -418,7 +418,7 @@ func (h *AuthHandler) saveSignupState(key string, state *signupState, ttl time.D
|
|||||||
return h.RedisService.Set(key, string(data), ttl)
|
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 {
|
func (h *AuthHandler) GetPasswordPolicy(c *fiber.Ctx) error {
|
||||||
if h.DescopeClient == nil {
|
if h.DescopeClient == nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Descope client not configured"})
|
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)
|
h.RedisService.Set(prefixToken+token, fmt.Sprintf(`{"pendingRef":"%s","loginId":"%s"}`, pendingRef, loginID), defaultExpiration)
|
||||||
|
|
||||||
// Generate Link
|
// Generate Link
|
||||||
frontendURL := os.Getenv("FRONTEND_URL")
|
userfrontURL := os.Getenv("USERFRONT_URL")
|
||||||
slog.Info("[Enchanted] Read FRONTEND_URL", "url", frontendURL)
|
slog.Info("[Enchanted] Read USERFRONT_URL", "url", userfrontURL)
|
||||||
if frontendURL == "" {
|
if userfrontURL == "" {
|
||||||
frontendURL = "http://sso.hmac.kr"
|
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
|
// Route based on LoginID type
|
||||||
if strings.Contains(loginID, "@") {
|
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"})
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Authentication service not configured"})
|
||||||
}
|
}
|
||||||
|
|
||||||
frontendURL := os.Getenv("FRONTEND_URL")
|
userfrontURL := os.Getenv("USERFRONT_URL")
|
||||||
if frontendURL == "" {
|
if userfrontURL == "" {
|
||||||
ale.Status = fiber.StatusInternalServerError
|
ale.Status = fiber.StatusInternalServerError
|
||||||
ale.LatencyMs = time.Since(startTime)
|
ale.LatencyMs = time.Since(startTime)
|
||||||
ale.DescopeError = "FRONTEND_URL is not set"
|
ale.DescopeError = "USERFRONT_URL is not set"
|
||||||
ale.Log(slog.LevelError, "FRONTEND_URL is not set")
|
ale.Log(slog.LevelError, "USERFRONT_URL is not set")
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "FRONTEND_URL environment variable 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)
|
// [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
|
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"})
|
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.RedirectTo = resetLink
|
||||||
ale.Operation = "SendPasswordReset"
|
ale.Operation = "SendPasswordReset"
|
||||||
ale.Log(slog.LevelInfo, "Initiating password reset via internal token")
|
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.
|
// 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 {
|
func (h *AuthHandler) ProcessPasswordResetToken(c *fiber.Ctx) error {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
ale := logger.NewAuditLogEntry(c, "verify")
|
ale := logger.NewAuditLogEntry(c, "verify")
|
||||||
@@ -960,7 +960,7 @@ func (h *AuthHandler) ProcessPasswordResetToken(c *fiber.Ctx) error {
|
|||||||
ale.LoginIDs["loginId_normalized"] = loginID
|
ale.LoginIDs["loginId_normalized"] = loginID
|
||||||
|
|
||||||
redirectURL := fmt.Sprintf("%s/reset-password?loginId=%s&token=%s",
|
redirectURL := fmt.Sprintf("%s/reset-password?loginId=%s&token=%s",
|
||||||
os.Getenv("FRONTEND_URL"),
|
os.Getenv("USERFRONT_URL"),
|
||||||
loginID,
|
loginID,
|
||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
@@ -968,7 +968,7 @@ func (h *AuthHandler) ProcessPasswordResetToken(c *fiber.Ctx) error {
|
|||||||
ale.RedirectTo = redirectURL
|
ale.RedirectTo = redirectURL
|
||||||
ale.Status = fiber.StatusFound
|
ale.Status = fiber.StatusFound
|
||||||
ale.LatencyMs = time.Since(startTime)
|
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)
|
return c.Redirect(redirectURL)
|
||||||
}
|
}
|
||||||
@@ -1127,11 +1127,11 @@ func (h *AuthHandler) InitQRLogin(c *fiber.Ctx) error {
|
|||||||
pendingRef := GenerateSecureToken(16)
|
pendingRef := GenerateSecureToken(16)
|
||||||
|
|
||||||
// QR 코드 페이로드를 실제 접속 가능한 URL로 변경합니다.
|
// QR 코드 페이로드를 실제 접속 가능한 URL로 변경합니다.
|
||||||
frontendURL := os.Getenv("FRONTEND_URL")
|
userfrontURL := os.Getenv("USERFRONT_URL")
|
||||||
if frontendURL == "" {
|
if userfrontURL == "" {
|
||||||
frontendURL = "https://sso.hmac.kr"
|
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)
|
slog.Info("[QR] Init", "pendingRef", pendingRef, "url", qrPayload)
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func NewDescopeProvider(projectID, managementKey string) *DescopeProvider {
|
|||||||
|
|
||||||
return &DescopeProvider{
|
return &DescopeProvider{
|
||||||
Client: descopeClient,
|
Client: descopeClient,
|
||||||
FrontendURL: os.Getenv("FRONTEND_URL"),
|
FrontendURL: os.Getenv("USERFRONT_URL"),
|
||||||
fieldMapping: mapping,
|
fieldMapping: mapping,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,5 +52,6 @@ volumes:
|
|||||||
|
|
||||||
networks:
|
networks:
|
||||||
baron_net:
|
baron_net:
|
||||||
name: baron_network
|
name: baron_net
|
||||||
|
external: true
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ services:
|
|||||||
command: >
|
command: >
|
||||||
clients create
|
clients create
|
||||||
--endpoint http://hydra:4445
|
--endpoint http://hydra:4445
|
||||||
--id admin-front
|
--id adminfront
|
||||||
--secret admin-secret
|
--secret admin-secret
|
||||||
--grant-types authorization_code,refresh_token
|
--grant-types authorization_code,refresh_token
|
||||||
--response-types code
|
--response-types code
|
||||||
|
|||||||
@@ -1,91 +1,91 @@
|
|||||||
services:
|
services:
|
||||||
backend:
|
backend:
|
||||||
build:
|
build:
|
||||||
context: ./backend
|
context: ./backend
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: baron_backend
|
container_name: baron_backend
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
- APP_ENV=${APP_ENV:-development}
|
- APP_ENV=${APP_ENV:-development}
|
||||||
- GO_ENV=${APP_ENV:-development}
|
- GO_ENV=${APP_ENV:-development}
|
||||||
- COOKIE_SECRET=${COOKIE_SECRET}
|
- COOKIE_SECRET=${COOKIE_SECRET}
|
||||||
- JWT_SECRET=${JWT_SECRET}
|
- JWT_SECRET=${JWT_SECRET}
|
||||||
- DESCOPE_PROJECT_ID=${DESCOPE_PROJECT_ID}
|
- DESCOPE_PROJECT_ID=${DESCOPE_PROJECT_ID}
|
||||||
- DESCOPE_MANAGEMENT_KEY=${DESCOPE_MANAGEMENT_KEY}
|
- DESCOPE_MANAGEMENT_KEY=${DESCOPE_MANAGEMENT_KEY}
|
||||||
- NAVER_CLOUD_ACCESS_KEY=${NAVER_CLOUD_ACCESS_KEY}
|
- NAVER_CLOUD_ACCESS_KEY=${NAVER_CLOUD_ACCESS_KEY}
|
||||||
- NAVER_CLOUD_SECRET_KEY=${NAVER_CLOUD_SECRET_KEY}
|
- NAVER_CLOUD_SECRET_KEY=${NAVER_CLOUD_SECRET_KEY}
|
||||||
- NAVER_CLOUD_SERVICE_ID=${NAVER_CLOUD_SERVICE_ID}
|
- NAVER_CLOUD_SERVICE_ID=${NAVER_CLOUD_SERVICE_ID}
|
||||||
- NAVER_SENDER_PHONE_NUMBER=${NAVER_SENDER_PHONE_NUMBER}
|
- NAVER_SENDER_PHONE_NUMBER=${NAVER_SENDER_PHONE_NUMBER}
|
||||||
- FRONTEND_URL=${FRONTEND_URL}
|
- USERFRONT_URL=${USERFRONT_URL}
|
||||||
- IDP_PROVIDER=${IDP_PROVIDER:-ory,descope}
|
- IDP_PROVIDER=${IDP_PROVIDER:-ory,descope}
|
||||||
- KRATOS_ADMIN_URL=${KRATOS_ADMIN_URL:-http://kratos:4434}
|
- KRATOS_ADMIN_URL=${KRATOS_ADMIN_URL:-http://kratos:4434}
|
||||||
- HYDRA_ADMIN_URL=${HYDRA_ADMIN_URL:-http://hydra:4445}
|
- HYDRA_ADMIN_URL=${HYDRA_ADMIN_URL:-http://hydra:4445}
|
||||||
- DB_HOST=postgres
|
- DB_HOST=postgres
|
||||||
- CLICKHOUSE_HOST=clickhouse
|
- CLICKHOUSE_HOST=clickhouse
|
||||||
- CLICKHOUSE_PORT=${CLICKHOUSE_PORT_NATIVE:-9000}
|
- CLICKHOUSE_PORT=${CLICKHOUSE_PORT_NATIVE:-9000}
|
||||||
- CLICKHOUSE_USER=${CLICKHOUSE_USER:-baron}
|
- CLICKHOUSE_USER=${CLICKHOUSE_USER:-baron}
|
||||||
- CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:-password}
|
- CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:-password}
|
||||||
ports:
|
ports:
|
||||||
- "${BACKEND_PORT:-3000}:3000"
|
- "${BACKEND_PORT:-3000}:3000"
|
||||||
depends_on:
|
depends_on:
|
||||||
- infra_check
|
- infra_check
|
||||||
networks:
|
networks:
|
||||||
- baron_net
|
- baron_net
|
||||||
- ory-net
|
- ory-net
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend:/app
|
- ./backend:/app
|
||||||
command: ["go", "run", "./cmd/server/main.go"]
|
command: ["go", "run", "./cmd/server/main.go"]
|
||||||
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/health"]
|
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/health"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 3
|
retries: 3
|
||||||
start_period: 10s
|
start_period: 10s
|
||||||
|
|
||||||
frontend:
|
userfront:
|
||||||
build:
|
build:
|
||||||
context: ./frontend
|
context: ./userfront
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: baron_frontend
|
container_name: baron_userfront
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
- DESCOPE_PROJECT_ID=${DESCOPE_PROJECT_ID}
|
- DESCOPE_PROJECT_ID=${DESCOPE_PROJECT_ID}
|
||||||
- BACKEND_URL=${BACKEND_URL}
|
- BACKEND_URL=${BACKEND_URL}
|
||||||
- FRONTEND_URL=${FRONTEND_URL}
|
- USERFRONT_URL=${USERFRONT_URL}
|
||||||
- APP_ENV=${APP_ENV}
|
- APP_ENV=${APP_ENV}
|
||||||
ports:
|
ports:
|
||||||
- "${FRONTEND_PORT:-5000}:5000"
|
- "${USERFRONT_PORT:-5000}:5000"
|
||||||
networks:
|
networks:
|
||||||
- baron_net
|
- baron_net
|
||||||
depends_on:
|
depends_on:
|
||||||
backend:
|
backend:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
command: >
|
command: >
|
||||||
/bin/sh -c "mkdir -p /usr/share/nginx/html/assets &&
|
/bin/sh -c "mkdir -p /usr/share/nginx/html/assets &&
|
||||||
echo \"DESCOPE_PROJECT_ID=$${DESCOPE_PROJECT_ID}\" > /usr/share/nginx/html/assets/.env &&
|
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 \"BACKEND_URL=$${BACKEND_URL}\" >> /usr/share/nginx/html/assets/.env &&
|
||||||
echo \"FRONTEND_URL=$${FRONTEND_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 &&
|
echo \"APP_ENV=$${APP_ENV}\" >> /usr/share/nginx/html/assets/.env &&
|
||||||
cp /usr/share/nginx/html/assets/.env /usr/share/nginx/html/.env &&
|
cp /usr/share/nginx/html/assets/.env /usr/share/nginx/html/.env &&
|
||||||
nginx -g 'daemon off;'"
|
nginx -g 'daemon off;'"
|
||||||
|
|
||||||
# Dummy service to wait for infra network if needed,
|
# Dummy service to wait for infra network if needed,
|
||||||
# but essentially we assume infra is running.
|
# but essentially we assume infra is running.
|
||||||
# In a real unified stack, we might include infra here or use external links.
|
# In a real unified stack, we might include infra here or use external links.
|
||||||
# Here we attach to the same network.
|
# Here we attach to the same network.
|
||||||
infra_check:
|
infra_check:
|
||||||
image: alpine
|
image: alpine
|
||||||
command: ["echo", "Infrastructure assumed running"]
|
command: ["echo", "Infrastructure assumed running"]
|
||||||
networks:
|
networks:
|
||||||
- baron_net
|
- baron_net
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
baron_net:
|
baron_net:
|
||||||
external: true
|
external: true
|
||||||
name: baron_network
|
name: baron_net
|
||||||
ory-net:
|
ory-net:
|
||||||
external: true
|
external: true
|
||||||
name: ory-net
|
name: ory-net
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ Backend와 Frontend 애플리케이션을 각각의 Dockerfile을 사용하여
|
|||||||
```bash
|
```bash
|
||||||
# Backend 이미지 빌드
|
# Backend 이미지 빌드
|
||||||
# v1.2601.1-RC1 부분은 실제 배포 버전에 맞게 수정하세요.
|
# 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 이미지 빌드
|
# 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
|
docker push reg.hmac.kr/baron_sso/backend:v1.2601.1-RC1
|
||||||
|
|
||||||
# Frontend 이미지 푸시
|
# 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
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ services:
|
|||||||
- CLICKHOUSE_PORT=${CLICKHOUSE_PORT_NATIVE:-9000}
|
- CLICKHOUSE_PORT=${CLICKHOUSE_PORT_NATIVE:-9000}
|
||||||
- CLICKHOUSE_USER=${CLICKHOUSE_USER:-baron}
|
- CLICKHOUSE_USER=${CLICKHOUSE_USER:-baron}
|
||||||
- CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:-password}
|
- CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:-password}
|
||||||
- FRONTEND_URL=${FRONTEND_URL:-https://sso.hmac.kr}
|
- USERFRONT_URL=${USERFRONT_URL:-https://sso.hmac.kr}
|
||||||
ports:
|
ports:
|
||||||
- "${BACKEND_PORT:-3010}:3010"
|
- "${BACKEND_PORT:-3010}:3010"
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -30,15 +30,15 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- baron_net
|
- baron_net
|
||||||
|
|
||||||
frontend:
|
userfront:
|
||||||
image: ${FRONTEND_IMAGE_NAME}:${IMAGE_TAG}
|
image: ${USERFRONT_IMAGE_NAME}:${IMAGE_TAG}
|
||||||
container_name: baron_frontend
|
container_name: baron_userfront
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
- FRONTEND_URL=${FRONTEND_URL:-https://sso.hmac.kr}
|
- USERFRONT_URL=${USERFRONT_URL:-https://sso.hmac.kr}
|
||||||
- BACKEND_URL=${FRONTEND_URL:-https://sso.hmac.kr}
|
- BACKEND_URL=${USERFRONT_URL:-https://sso.hmac.kr}
|
||||||
ports:
|
ports:
|
||||||
- "${FRONTEND_PORT:-80}:80"
|
- "${USERFRONT_PORT:-80}:80"
|
||||||
depends_on:
|
depends_on:
|
||||||
backend:
|
backend:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
## Workspace Structure
|
## Workspace Structure
|
||||||
Root: `/home/lectom/.gemini/antigravity/scratch/baron_sso`
|
Root: `/home/lectom/.gemini/antigravity/scratch/baron_sso`
|
||||||
- `/backend`: Go Fiber Application
|
- `/backend`: Go Fiber Application
|
||||||
- `/frontend`: Flutter Application
|
- `/userfront`: Flutter Application
|
||||||
- `/docs`: Documentation (PRD, API Specs)
|
- `/docs`: Documentation (PRD, API Specs)
|
||||||
|
|
||||||
## Current Status
|
## Current Status
|
||||||
|
|||||||
@@ -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_HTTP=8123
|
||||||
CLICKHOUSE_PORT_NATIVE=9000
|
CLICKHOUSE_PORT_NATIVE=9000
|
||||||
BACKEND_PORT=3000
|
BACKEND_PORT=3000
|
||||||
FRONTEND_PORT=5000
|
USERFRONT_PORT=5000
|
||||||
|
|
||||||
# --- Database Credentials (PostgreSQL) ---
|
# --- Database Credentials (PostgreSQL) ---
|
||||||
DB_USER=baron
|
DB_USER=baron
|
||||||
@@ -6,7 +6,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "kr.co.baroncs.frontend"
|
namespace = "kr.co.baroncs.userfront"
|
||||||
compileSdk = flutter.compileSdkVersion
|
compileSdk = flutter.compileSdkVersion
|
||||||
ndkVersion = flutter.ndkVersion
|
ndkVersion = flutter.ndkVersion
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// 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.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||||
minSdk = flutter.minSdkVersion
|
minSdk = flutter.minSdkVersion
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<uses-permission android:name="android.permission.CAMERA"/>
|
<uses-permission android:name="android.permission.CAMERA"/>
|
||||||
<application
|
<application
|
||||||
android:label="frontend"
|
android:label="userfront"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package kr.co.baroncs.frontend
|
package kr.co.baroncs.userfront
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 544 B |
|
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 442 B |
|
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 721 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -368,7 +368,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.frontend;
|
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -384,7 +384,7 @@
|
|||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.frontend.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
@@ -401,7 +401,7 @@
|
|||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.frontend.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
@@ -416,7 +416,7 @@
|
|||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.frontend.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
@@ -547,7 +547,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.frontend;
|
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
@@ -569,7 +569,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.frontend;
|
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 295 B |
|
Before Width: | Height: | Size: 406 B After Width: | Height: | Size: 406 B |
|
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 450 B |
|
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 282 B |
|
Before Width: | Height: | Size: 462 B After Width: | Height: | Size: 462 B |