Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
aead06a
chore: stage central Drive OAuth implementation payload
122yjs Aug 24, 2026
4cb3beb
chore: trigger central Drive OAuth payload expansion
122yjs Aug 24, 2026
8c0ff9a
chore: allow payload expansion from pull request
122yjs Aug 24, 2026
2b75709
fix: unpack binary payload without double decoding
122yjs Aug 24, 2026
9c5e87d
Add encrypted OAuth token utilities
122yjs Aug 24, 2026
390c49d
Support multi-teacher Google OAuth runtime settings
122yjs Aug 24, 2026
1bd1992
Replace global admin auth with tenant sessions
122yjs Aug 24, 2026
ff7ce45
Add tenant and non-PII receipt data access
122yjs Aug 24, 2026
8223d70
Add drive.file OAuth and Google Drive storage adapter
122yjs Aug 24, 2026
5687bf9
Add tenant and non-PII receipt schema
122yjs Aug 24, 2026
a53e5ee
Add central Drive OAuth D1 migration
122yjs Aug 24, 2026
5c48525
Add Google OAuth authorization start route
122yjs Aug 24, 2026
4e6feb8
Add Google OAuth callback and tenant provisioning
122yjs Aug 24, 2026
abb6f4a
Make student sessions class-tenant aware
122yjs Aug 24, 2026
3dfbfb1
Store observations in each teacher Google Drive
122yjs Aug 24, 2026
28d24dd
Proxy protected images from teacher Google Drive
122yjs Aug 24, 2026
af3779c
Check tenant tables and OAuth readiness
122yjs Aug 24, 2026
9f9146f
Use Google OAuth teacher sessions
122yjs Aug 24, 2026
c529891
Add teacher profile and class settings API
122yjs Aug 24, 2026
1fb716f
Make invite links teacher-specific and rotatable
122yjs Aug 24, 2026
0af879a
Read teacher observations from Google Drive
122yjs Aug 24, 2026
5712a98
Manage Drive-backed observation visibility and deletion
122yjs Aug 24, 2026
3b0384f
Add teacher OAuth disconnect and data cleanup
122yjs Aug 24, 2026
bf5daf6
Replace single-admin UI with Google Drive tenant management
122yjs Aug 24, 2026
414be81
Add privacy notice for Drive OAuth service
122yjs Aug 24, 2026
e1aef76
Add service terms for classroom use
122yjs Aug 24, 2026
d65c317
Send joined students directly to the observation app
122yjs Aug 24, 2026
ceba468
Route the home page directly to the student app
122yjs Aug 24, 2026
366bec7
Add per-class student UI settings
122yjs Aug 24, 2026
88f64b2
Inject tenant settings into the existing student UI
122yjs Aug 24, 2026
10bc399
Document the central drive.file deployment architecture
122yjs Aug 24, 2026
43ca43b
Add Drive OAuth privacy and storage regression tests
122yjs Aug 24, 2026
d21f4cb
Add CI for Drive OAuth migration
122yjs Aug 24, 2026
6eac772
Remove temporary deployment payload
122yjs Aug 24, 2026
eae4d7a
Remove temporary self-applying workflow
122yjs Aug 24, 2026
8c7a9ed
Scope lint exceptions to OAuth admin hydration
122yjs Aug 24, 2026
0daef3d
Remove unused tenant script catch binding
122yjs Aug 24, 2026
7661933
Run Sites environment helper through bash in CI
122yjs Aug 24, 2026
6fd0341
Run install environment helper through bash in CI
122yjs Aug 24, 2026
e60cfae
Make Sites shell wrapper portable across GitHub Actions
122yjs Aug 24, 2026
6d2003b
Test the actual OAuth scope expression precisely
122yjs Aug 24, 2026
60d5a3e
Preserve verified Worker build output
122yjs Aug 24, 2026
41a66db
Add direct Cloudflare Worker configuration
122yjs Aug 24, 2026
b101817
Add clean non-PII D1 schema for direct Cloudflare deployment
122yjs Aug 24, 2026
6081c3b
Generate owned-domain Cloudflare deployment config
122yjs Aug 24, 2026
f5029d6
Build Sites and direct Cloudflare targets from separate configs
122yjs Aug 24, 2026
bf2203f
Test direct Cloudflare bindings and non-PII schema
122yjs Aug 24, 2026
258ccfe
Verify the direct Cloudflare deployment target in CI
122yjs Aug 24, 2026
a93a9ee
Add guarded production Cloudflare deployment workflow
122yjs Aug 24, 2026
bb9b5fb
Fix secure production workflow argument handling
122yjs Aug 24, 2026
a662dc7
Ignore generated production Wrangler config
122yjs Aug 24, 2026
c1b59da
Build metadata for the production custom domain
122yjs Aug 24, 2026
e12292d
Rewrite static metadata to the active production origin
122yjs Aug 24, 2026
3a6effa
Document direct Cloudflare production deployment
122yjs Aug 24, 2026
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
129 changes: 129 additions & 0 deletions .github/workflows/deploy-gongju-moon-observation-cloudflare.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
name: Deploy Gongju Moon Observation to Cloudflare

on:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: gongju-moon-observation-production
cancel-in-progress: false

jobs:
deploy:
runs-on: ubuntu-latest
environment: production
defaults:
run:
working-directory: gongju-moon-observation
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_CUSTOM_DOMAIN: ${{ vars.CLOUDFLARE_CUSTOM_DOMAIN }}
SESSION_SECRET: ${{ secrets.SESSION_SECRET }}
TOKEN_ENCRYPTION_KEY: ${{ secrets.TOKEN_ENCRYPTION_KEY }}
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: gongju-moon-observation/package-lock.json
- run: npm ci
- run: npm run lint
- name: Validate production configuration
shell: bash
run: |
set -euo pipefail
required=(
CLOUDFLARE_ACCOUNT_ID
CLOUDFLARE_API_TOKEN
CLOUDFLARE_CUSTOM_DOMAIN
SESSION_SECRET
TOKEN_ENCRYPTION_KEY
GOOGLE_CLIENT_ID
GOOGLE_CLIENT_SECRET
)
for name in "${required[@]}"; do
if [[ -z "${!name:-}" ]]; then
echo "필수 production secret/variable ${name}가 없습니다." >&2
exit 78
fi
done
if [[ ${#SESSION_SECRET} -lt 32 || ${#TOKEN_ENCRYPTION_KEY} -lt 32 ]]; then
echo "SESSION_SECRET과 TOKEN_ENCRYPTION_KEY는 각각 32자 이상이어야 합니다." >&2
exit 78
fi
node scripts/configure-cloudflare-deploy.mjs
- name: Build and verify direct Cloudflare target
env:
CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH: wrangler.cloudflare.deploy.json
NEXT_PUBLIC_SITE_ORIGIN: https://${{ vars.CLOUDFLARE_CUSTOM_DOMAIN }}
run: |
npm run build
node --test tests/cloudflare-deploy.test.mjs
- name: Create ephemeral Wrangler secrets file
shell: bash
run: |
node --input-type=module <<'NODE'
import { writeFile } from "node:fs/promises";
const values = {
SESSION_SECRET: process.env.SESSION_SECRET,
TOKEN_ENCRYPTION_KEY: process.env.TOKEN_ENCRYPTION_KEY,
GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID,
GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET,
PUBLIC_ORIGIN: `https://${process.env.CLOUDFLARE_CUSTOM_DOMAIN}`,
};
await writeFile(process.env.RUNNER_TEMP + "/gongju-worker-secrets.json", JSON.stringify(values));
NODE
- name: Deploy Worker and provision D1
shell: bash
run: |
npx wrangler deploy \
--config dist/server/wrangler.json \
--secrets-file "$RUNNER_TEMP/gongju-worker-secrets.json" \
--message "${GITHUB_SHA} central drive.file release"
- name: Apply D1 migrations
shell: bash
run: |
npx wrangler d1 migrations apply DB \
--remote \
--config dist/server/wrangler.json
- name: Verify production health
shell: bash
run: |
set -euo pipefail
endpoint="https://${CLOUDFLARE_CUSTOM_DOMAIN}/api/health"
for attempt in {1..12}; do
if payload="$(curl --fail --silent --show-error --max-time 15 "$endpoint")"; then
HEALTH_PAYLOAD="$payload" node --input-type=module <<'NODE'
const health = JSON.parse(process.env.HEALTH_PAYLOAD || "{}");
if (health.ok !== true || health.database !== true || health.googleOAuth !== true) {
throw new Error(`운영 상태가 준비되지 않았습니다: ${JSON.stringify(health)}`);
}
NODE
echo "운영 상태 확인 완료: $endpoint"
break
fi
if [[ $attempt -eq 12 ]]; then
echo "운영 상태 확인에 실패했습니다: $endpoint" >&2
exit 1
fi
sleep 5
done
- name: Remove ephemeral secrets file
if: always()
run: rm -f "$RUNNER_TEMP/gongju-worker-secrets.json"
- name: Publish deployment summary
run: |
{
echo "## 공주 달 관찰 탐험대 배포 완료"
echo
echo "- 운영 주소: https://${CLOUDFLARE_CUSTOM_DOMAIN}"
echo "- OAuth callback: https://${CLOUDFLARE_CUSTOM_DOMAIN}/api/oauth/google/callback"
echo "- Health: https://${CLOUDFLARE_CUSTOM_DOMAIN}/api/health"
echo "- Commit: ${GITHUB_SHA}"
} >> "$GITHUB_STEP_SUMMARY"
50 changes: 50 additions & 0 deletions .github/workflows/gongju-moon-observation-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Gongju Moon Observation CI

on:
pull_request:
paths:
- "gongju-moon-observation/**"
- ".github/workflows/gongju-moon-observation-ci.yml"
push:
branches: [main]
paths:
- "gongju-moon-observation/**"
- ".github/workflows/gongju-moon-observation-ci.yml"

permissions:
contents: read

concurrency:
group: gongju-moon-observation-${{ github.ref }}
cancel-in-progress: true

jobs:
verify:
runs-on: ubuntu-latest
defaults:
run:
working-directory: gongju-moon-observation
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: gongju-moon-observation/package-lock.json
- run: npm ci
- run: npm run lint
- name: Verify existing application build and behavior
run: npm test
- name: Build direct Cloudflare target
env:
CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH: wrangler.cloudflare.jsonc
run: npm run build
- name: Verify direct Cloudflare deployment contract
run: node --test tests/cloudflare-deploy.test.mjs
- name: Preserve verified Worker build output
uses: actions/upload-artifact@v4
with:
name: gongju-moon-observation-build
path: gongju-moon-observation/dist
if-no-files-found: error
retention-days: 7
1 change: 1 addition & 0 deletions gongju-moon-observation/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ next-env.d.ts
/.sites-runtime/
/outputs/
/work/
/wrangler.cloudflare.deploy.json
Loading
Loading