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
54 changes: 54 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: CI

on:
pull_request:
push:
branches:
- main

jobs:
verify:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"

- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 9.0.0

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Type check
run: pnpm check-types

- name: Test core package
run: pnpm --filter ground-codes test

- name: Test standalone package
run: pnpm --filter ground-codes test:standalone

- name: Test API
run: pnpm --filter api-ground-codes test

- name: Test web client
run: pnpm --filter web test

- name: Install Playwright browser
run: pnpm --filter web exec playwright install --with-deps chromium

- name: Browser smoke test
run: pnpm --filter web test:e2e
4 changes: 4 additions & 0 deletions .github/workflows/deploy-grok-spiral.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ on:
- main
paths:
- "apps/grok-spiral/**"
- "packages/ui/**"
- ".github/workflows/deploy-grok-spiral.yml"
- "package.json"
- "pnpm-lock.yaml"
- "pnpm-workspace.yaml"
workflow_dispatch:

jobs:
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/deploy-web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ on:
- main
paths:
- "apps/web/**"
- "packages/ui/**"
- ".github/workflows/deploy-web.yml"
- "package.json"
- "pnpm-lock.yaml"
- "pnpm-workspace.yaml"
workflow_dispatch:

jobs:
Expand Down Expand Up @@ -56,6 +60,12 @@ jobs:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY: ${{ secrets.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY }}
NEXT_PUBLIC_GOOGLE_MAPS_ROADMAP_ID: ${{ secrets.NEXT_PUBLIC_GOOGLE_MAPS_ROADMAP_ID }}
NEXT_PUBLIC_GROUND_CODES_API_URL: ${{ secrets.NEXT_PUBLIC_GROUND_CODES_API_URL }}
NEXT_PUBLIC_CESIUM_ION_TOKEN: ${{ secrets.NEXT_PUBLIC_CESIUM_ION_TOKEN }}
NEXT_PUBLIC_CESIUM_MOON_ASSET_ID: ${{ secrets.NEXT_PUBLIC_CESIUM_MOON_ASSET_ID }}
NEXT_PUBLIC_CESIUM_MARS_ASSET_ID: ${{ secrets.NEXT_PUBLIC_CESIUM_MARS_ASSET_ID }}
GOOGLE_MAPS_NODEJS_API_KEY: ${{ secrets.GOOGLE_MAPS_NODEJS_API_KEY }}
OPENWEATHER_API_KEY: ${{ secrets.OPENWEATHER_API_KEY }}
run: |
cd apps/web
pnpm run pages:build && wrangler pages deploy
20 changes: 20 additions & 0 deletions .github/workflows/production-smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Production Smoke

on:
workflow_dispatch:
schedule:
- cron: "*/30 * * * *"

jobs:
smoke:
runs-on: ubuntu-latest

steps:
- name: Check API readiness
run: curl -fsS https://api.ground.codes/readyz

- name: Check web robots
run: curl -fsS https://ground.codes/robots.txt

- name: Check web sitemap
run: curl -fsS https://ground.codes/sitemap.xml
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ PR 제출 전 위 4개를 모두 통과시킵니다.
- `packages/geoint` 데이터 갱신 시 sample 검증.
- Web 앱의 시각 회귀는 수동을 우선합니다.
- 지구·달·화성 등 행성 지도 렌더링을 변경한 경우, 배포 후 실제 production URL 에서 이미지 스크린샷을 반드시 확인합니다. 네트워크 요청 성공, canvas 생성 여부, 타입 체크만으로 완료 처리하지 않습니다.
- 행성 지도 UI 변경은 데스크톱과 모바일 폭 모두에서 직접 확인합니다. 특히 좌측 하단 출처 라벨, 하단 인코딩 패널, 우측 하단 컨트롤이 서로 겹치지 않아야 합니다.

---

Expand All @@ -147,3 +148,9 @@ PR 제출 전 위 4개를 모두 통과시킵니다.
- **좌표 정확도**: GCS(Geographic Coordinate System) 기반이므로 부동소수 정밀도 손실에 주의 — high-zoom 영역의 인코딩은 fixed-point 또는 BigInt 처리.
- **외부 의존**: Google Maps SDK 변경에 추적이 필요합니다 (Maps Platform 의 deprecation 알림 모니터링).
- **행성 지도 품질**: 행성 기본 뷰는 고화질을 우선하며, 각 행성의 실제색에 가까운 자연스러운 색감을 선호합니다. 화질 향상을 위해 적외선·고도·relief 레이어를 사용할 때도 기본 색상이 과도하게 알록달록하거나 실제 행성색에서 벗어나지 않도록 합니다.
- **행성 지도 출처**: 달·화성 3D 지도에서 USGS WMS imagery 를 쓰는 경우, 지도 출처 라벨은 좌측 하단에 유지합니다. Cesium ion asset 을 쓰지 않는 WMS-only 렌더에서는 Cesium ion credit/logo 가 행성 전환이나 카메라 조작 후 다시 노출되지 않아야 합니다.
- **3D 지도 컨트롤**: 달·화성에는 내 위치 버튼을 표시하지 않습니다. 숨김 상태에서도 우측 하단 컨트롤 스택에 빈 슬롯을 남기지 않고, 그리드 버튼과 나침반 버튼이 자연스럽게 붙어 보여야 합니다.
- **3D 나침반 동작**: 지구·달·화성 3D 뷰에서 나침반은 양방향 동기화되어야 합니다. 나침반 드래그는 3D 카메라를 회전해야 하고, 사용자가 구체를 직접 회전하면 나침반도 현재 화면 방향을 따라 회전해야 합니다. 나침반을 단순 클릭하면 북쪽이 화면 위로 오도록 `0deg` 로 정렬합니다.
- **Google Maps 3D 지구**: Earth 3D 는 Google `Map3DElement.heading` 을 부모 나침반 상태와 동기화합니다. 직접 구체를 돌리는 경우 `steadychange` 이벤트와 짧은 polling 으로 heading 변화를 감지합니다.
- **Cesium 달·화성 3D**: Cesium 구체는 `camera.heading` 또는 `camera.setView({ orientation.heading })` 만으로는 화면상 회전이 체감되지 않을 수 있습니다. 나침반 기반 회전은 현재 시야 축 기준 `camera.twistRight()` 에 최단 heading delta 를 적용합니다. 직접 구체 조작 후 나침반 동기화는 화면 중심점에서 실제 북쪽이 화면상 어느 방향을 향하는지 계산해 부모 나침반 상태로 올립니다.
- **Cesium 초기화 주의**: 달·화성 3D 초기 카메라는 북쪽 기준으로 세팅한 뒤 필요한 나침반 heading 만 별도 twist 로 적용합니다. 초기 `setView` heading 과 `twistRight` 를 동시에 같은 heading 으로 적용하면 재마운트 시 회전이 중복될 수 있습니다.
3 changes: 3 additions & 0 deletions apps/api-ground-codes/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
PORT=3000
CORS_ALLOWED_ORIGINS=https://ground.codes
API_RATE_LIMIT_PER_MINUTE=600
31 changes: 20 additions & 11 deletions apps/api-ground-codes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ The API uses these optimization techniques in several key endpoints:

- `/v1/region/around`: Finds regions near specified coordinates using GeoKDBush spatial indexing
- `/v1/region/info`: Retrieves region information using LevelDB's fast key-value lookups
- `/encode`: Utilizes the optimized region search to find the nearest region for encoding coordinates
- `/decode`: Uses efficient region data retrieval when decoding ground codes
- `/v1/encode`: Utilizes the optimized region search to find the nearest region for encoding coordinates
- `/v1/decode`: Uses efficient region data retrieval when decoding ground codes
- `/v1/search`: Resolves encoded Ground Codes, `lat,lng` coordinate pairs, and region names/codes

The API uses the shared `ground-codes` package for encode/decode behavior and
loads `@ground-codes/geoint` embedded databases for region lookup endpoints.
Expand Down Expand Up @@ -117,14 +118,17 @@ changes from the same commit.

### 🧩 Core Endpoints

- `POST /encode`: Encode geographic coordinates to a ground code
- `POST /decode`: Decode a ground code to geographic coordinates
- `GET /v1/region/around`: Get regions around specific coordinates
- `GET /v1/region/info`: Get information about a specific region
- `POST /v1/encode`: Encode geographic coordinates to a ground code
- `POST /v1/decode`: Decode a ground code to geographic coordinates
- `POST /v1/search`: Search by encoded ground code, coordinate pair, or region name
- `POST /v1/region/around`: Get regions around specific coordinates
- `POST /v1/region/info`: Get information about a specific region

### 🔧 Utility Endpoints

- `GET /healthz`: Health check endpoint
- `GET /readyz`: Readiness endpoint for deploy/load-balancer checks
- `GET /metrics`: Lightweight JSON operational counters
- `GET /swagger`: Swagger UI for API documentation
- `GET /`: Redirects to Swagger documentation

Expand All @@ -133,7 +137,7 @@ changes from the same commit.
### 🔄 Encode Coordinates

```bash
curl -X POST http://localhost:3000/encode \
curl -X POST http://localhost:3000/v1/encode \
-H "Content-Type: application/json" \
-d '{"lat": 37.422, "lng": 127.024, "regionLevel": 2, "language": "english"}'
```
Expand All @@ -147,7 +151,7 @@ Response:
### 🔍 Decode Ground Code

```bash
curl -X POST http://localhost:3000/decode \
curl -X POST http://localhost:3000/v1/decode \
-H "Content-Type: application/json" \
-d '{"code": "Seoul-Happy-Tiger", "regionLevel": 2, "language": "english"}'
```
Expand All @@ -164,7 +168,7 @@ Response:
### 🌕 Encode Moon or Mars Coordinates

```bash
curl -X POST http://localhost:3000/encode \
curl -X POST http://localhost:3000/v1/encode \
-H "Content-Type: application/json" \
-d '{"lat": 8.35, "lng": 30.84, "body": "moon", "regionLevel": 2}'
```
Expand All @@ -178,7 +182,7 @@ Response:
Japanese labels are also available:

```bash
curl -X POST http://localhost:3000/encode \
curl -X POST http://localhost:3000/v1/encode \
-H "Content-Type: application/json" \
-d '{"lat": 18.6528, "lng": 226.1975, "body": "mars", "regionLevel": 2, "language": "japanese"}'
```
Expand All @@ -190,7 +194,7 @@ Response:
```

```bash
curl -X POST http://localhost:3000/decode \
curl -X POST http://localhost:3000/v1/decode \
-H "Content-Type: application/json" \
-d '{"code": "Mare Tranquillitatis-...", "body": "moon", "regionLevel": 2}'
```
Expand All @@ -209,6 +213,11 @@ The API supports various configuration options:
- 🌐 **Language**: Select from supported languages (English, Korean, Chinese, Japanese)
- 📏 **Precision**: Adjust the precision of encoded locations in meters
- 🪐 **Body**: Select `earth`, `moon`, or `mars` for coordinate conversion and labels
- 🔐 **CORS**: Set `CORS_ALLOWED_ORIGINS` as a comma-separated production allowlist
- 🛡️ **Rate Limit**: Set `API_RATE_LIMIT_PER_MINUTE`; use `0` only to disable it intentionally

Search responses include short-lived shared-cache headers so production edges can
cache common lookups without caching mutable operational checks.

## 📚 Documentation

Expand Down
4 changes: 3 additions & 1 deletion apps/api-ground-codes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
"scripts": {
"dev": "bun run --watch src/index.ts",
"build": "node scripts/build.mjs",
"start": "bun run src/index.ts"
"start": "bun run src/index.ts",
"check-types": "tsc --noEmit",
"test": "pnpm --filter ground-codes build && bun test src/*.test.ts"
},
"dependencies": {
"@elysiajs/cors": "^1.2.0",
Expand Down
Loading
Loading