Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VITE_API_BASE_URL=${{ vars.VITE_API_BASE_URL || 'https://api.caquick.site' }}
VITE_API_BASE_URL=${{ vars.VITE_API_BASE_URL || 'https://api.caquick.com' }}
VITE_NAVER_MAP_CLIENT_ID=${{ vars.VITE_NAVER_MAP_CLIENT_ID }}
cache-from: type=gha
cache-to: type=gha,mode=max
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ RUN corepack enable
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
ARG VITE_API_BASE_URL=https://api.caquick.site
ARG VITE_API_BASE_URL=https://api.caquick.com
ENV VITE_API_BASE_URL=${VITE_API_BASE_URL}
# 네이버 지도 키(공개 키지만 레포가 public이라 기본값을 두지 않는다). 비면 지도 미리보기만 꺼진다
ARG VITE_NAVER_MAP_CLIENT_ID=
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# caquick-admin-fe

케이퀵(CaQuick) 관리자 웹입니다. React + Vite + TypeScript SPA로, 백엔드([caquick-be](https://github.com/CaQuick/caquick-be))의 관리자 GraphQL·REST API를 사용합니다. 운영 주소는 `admin.caquick.site`입니다.
케이퀵(CaQuick) 관리자 웹입니다. React + Vite + TypeScript SPA로, 백엔드([caquick-be](https://github.com/CaQuick/caquick-be))의 관리자 GraphQL·REST API를 사용합니다. 운영 주소는 `admin.caquick.com`입니다.

## 스택

Expand Down
2 changes: 1 addition & 1 deletion docs/guide/architecture-conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## 1. 큰 그림

```
브라우저(admin.caquick.site) ──GraphQL·REST──> api.caquick.site (caquick-be)
브라우저(admin.caquick.com) ──GraphQL·REST──> api.caquick.com (caquick-be)
```

- SPA 1개. 서버 코드가 없다. 정적 파일을 nginx가 서빙하고, 데이터는 전부 백엔드 관리자 API에서 온다.
Expand Down
1 change: 1 addition & 0 deletions docs/guide/decisions.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
| D15 | 2026-09-27 | 의존 방향은 ESLint boundaries로 강제(shared→features 금지, feature 간은 index.ts만). 검사기는 반증 케이스로 확인하고 넣는다 | BE `arch:check`와 같은 역할 |
| D16 | 2026-10-05 | 커버리지 임계를 실측 정수 내림으로 상향: statements 95 · branches 88 · functions 94 · lines 96. CI는 테스트를 3샤드로 나누고 coverage-report가 합친 결과로 검사 | 실측(95.54·88.07·94.29·96.07)보다 한참 낮은 임계는 회귀를 못 잡는다. 샤드 합산이 단일 실행과 같음을 확인 |
| D17 | 2026-10-06 | 리뷰 봇은 Codex만 쓴다. CodeRabbit은 BE 전용 — `.coderabbit.yaml`은 자동 리뷰를 끈 최소 설정만 둔다 | 사용자 결정(판매자 앱도 같음) |
| D18 | 2026-11-01 | 도메인을 `admin.caquick.com`·API `https://api.caquick.com`으로 옮긴다(D9 대체). 이미지 하나에 API 주소와 CSP가 같이 들어가므로 둘을 한 번에 바꾼다 | caquick.site 만료(2026-11-29). 관리자 웹과 API가 같은 사이트여야 refresh 쿠키가 실린다 |
4 changes: 2 additions & 2 deletions infra/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# infra — 홈서버 배포

관리자 웹은 nginx 정적 이미지 1개다. BE compose(프로젝트 `caquick`)의 네트워크 `caquick_default`에 external로 참여하고, BE 쪽 cloudflared가 `admin.caquick.site → http://caquick-admin:80`으로 라우팅한다. 인바운드 포트는 열지 않는다.
관리자 웹은 nginx 정적 이미지 1개다. BE compose(프로젝트 `caquick`)의 네트워크 `caquick_default`에 external로 참여하고, BE 쪽 cloudflared가 `admin.caquick.com → http://caquick-admin:80`으로 라우팅한다. 인바운드 포트는 열지 않는다.

| 파일 | 역할 |
| ----------------------------------- | ----------------------------------------------------------------- |
Expand All @@ -18,7 +18,7 @@

1. BE compose가 떠 있어야 한다(네트워크 `caquick_default`).
2. 이 레포용 셀프호스트 러너를 같은 맥미니에 등록한다(라벨 `macmini`). Settings → Actions → Runners → New self-hosted runner. 러너 디렉터리는 BE 러너와 분리(예 `~/actions-runner-admin`).
3. Cloudflare Zero Trust → Tunnel → Public hostname 추가: `admin.caquick.site` → `HTTP` → `caquick-admin:80`.
3. Cloudflare Zero Trust → Tunnel → Public hostname 추가: `admin.caquick.com` → `HTTP` → `caquick-admin:80`.
4. GitHub Environment `production`(선택: 시크릿 `DISCORD_WEBHOOK_URL`, 변수 `DEPLOY_DIR` 기본 `/opt/caquick-admin`).

## 점검
Expand Down
2 changes: 1 addition & 1 deletion infra/compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# 운영 compose(홈서버). BE compose(프로젝트 caquick)의 네트워크에 external로 참여해 기존 cloudflared가
# admin.caquick.site → http://caquick-admin:80 으로 라우팅한다. 인바운드 포트는 열지 않는다(진단용 127.0.0.1만).
# admin.caquick.com → http://caquick-admin:80 으로 라우팅한다. 인바운드 포트는 열지 않는다(진단용 127.0.0.1만).
# 값은 .env — 배포 잡이 IMAGE·IMAGE_TAG를 쓴다. 롤백은 IMAGE_TAG를 이전 sha로 바꿔 다시 실행.
name: caquick-admin

Expand Down
2 changes: 1 addition & 1 deletion infra/security-headers.inc
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://t1.kakaocdn.net https://oapi.map.naver.com https://nrbe.pstatic.net; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://api.caquick.site https://*.amazonaws.com https://kr-col-ext.nelo.navercorp.com; frame-src https://postcode.map.kakao.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://t1.kakaocdn.net https://oapi.map.naver.com https://nrbe.pstatic.net; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://api.caquick.com https://*.amazonaws.com https://kr-col-ext.nelo.navercorp.com; frame-src https://postcode.map.kakao.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" always;
2 changes: 1 addition & 1 deletion src/app/shell/app-shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function Brand() {
<img src="/logo.png" alt="" className="size-7 rounded-lg" />
<div className="leading-tight">
<div className="text-[15px] font-bold">케이퀵 어드민</div>
<div className="text-[11px] text-muted-foreground">admin.caquick.site</div>
<div className="text-[11px] text-muted-foreground">admin.caquick.com</div>
</div>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion src/shared/api/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** API 오리진. 개발은 빈 문자열(same-origin, Vite 프록시), 운영 빌드는 VITE_API_BASE_URL(예 https://api.caquick.site). */
/** API 오리진. 개발은 빈 문자열(same-origin, Vite 프록시), 운영 빌드는 VITE_API_BASE_URL(예 https://api.caquick.com). */
const API_BASE_URL: string =
(import.meta.env.VITE_API_BASE_URL as string | undefined)?.replace(/\/$/, '') ?? '';

Expand Down
4 changes: 2 additions & 2 deletions src/test/infra/nginx-config.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('nginx 설정', () => {

it('CSP는 API·S3 오리진을 허용하고 프레임을 막는다', () => {
const csp = /Content-Security-Policy "([^"]+)"/.exec(read('security-headers.inc'))?.[1] ?? '';
expect(csp).toContain("connect-src 'self' https://api.caquick.site https://*.amazonaws.com");
expect(csp).toContain("connect-src 'self' https://api.caquick.com https://*.amazonaws.com");
expect(csp).toContain("frame-ancestors 'none'");
expect(csp).not.toContain('\n');
});
Expand Down Expand Up @@ -58,7 +58,7 @@ describe('nginx 설정', () => {
// maps.js의 오류 수집 XHR. 막아도 지도는 뜨지만 콘솔 위반이 장애로 오인된다
expect(d.get('connect-src')).toEqual([
"'self'",
'https://api.caquick.site',
'https://api.caquick.com',
'https://*.amazonaws.com',
'https://kr-col-ext.nelo.navercorp.com',
]);
Expand Down
2 changes: 1 addition & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';

// 로컬 개발은 /graphql·/auth를 백엔드(기본 localhost:4000)로 프록시해 same-origin으로 만든다 — CORS·쿠키 설정 없이 refresh 쿠키가 돈다.
// 운영 빌드는 VITE_API_BASE_URL(절대 URL)로 api.caquick.site에 직접 붙는다.
// 운영 빌드는 VITE_API_BASE_URL(절대 URL)로 api.caquick.com에 직접 붙는다.
export default defineConfig({
plugins: [
tanstackRouter({
Expand Down
Loading