d3ro-voice/apps/web/Dockerfile
Yun Chan b6fe588a7c feat(web): serve the web app under /app and send every billing link there (WS-B)
apps/web was never deployed, so /billing on the public domain returned the
landing page and d3ro.dev (desktop "upgrade") did not resolve.

- apps/web runs with basePath /app and output standalone; /download and
  /releases redirect to the site's #download. A Dockerfile and a d3ro-web
  compose service (port 3002) deploy it to the NAS with the other images.
- The site bridge worker forwards /app/* to WEB_APP_ORIGIN (the tunnel host)
  and rewrites upstream redirects; everything else still goes to Pages.
  With no origin configured /app answers 503 instead of the landing page.
- Desktop upgrade, desktop Stripe return, mobile subscription management,
  the web checkout/portal returns and the site all use billingUrl(); the
  return query is success=1 / canceled=1, which the billing page reads.
  The billing page highlights ?tier=pro|pro_plus, and signing in from a
  billing link returns to the same plan.
- auth/callback pins the redirect origin in production and rejects
  protocol-relative next= values (open redirect).
- Mobile legal links use SITE_URLS (fixes the missing slash on /terms).
- Compose drops the unused NEXT_PUBLIC_API_URL and the dead wwwroot legal
  mounts; deploy scripts add the web image and the SUPABASE_* values the NAS
  compose already required; .dockerignore keeps app .env files out of images.
- Supabase auth redirects allow /app/** (remote dashboard must match).

Policy: docs/REFACTOR_POLICY.md Wave 3, W3-3 and W3-4.
2026-09-26 15:48:30 +09:00

45 lines
1.8 KiB
Docker

# apps/web/Dockerfile
# 웹앱(@d3ro/web) standalone 이미지. 빌드 컨텍스트는 저장소 루트다.
# docker build -t d3ro-voice-web:latest -f apps/web/Dockerfile \
# --build-arg NEXT_PUBLIC_SUPABASE_URL=... \
# --build-arg NEXT_PUBLIC_SUPABASE_ANON_KEY=... \
# --build-arg NEXT_PUBLIC_PAYPLE_CLIENT_KEY=... .
# 공개 경로는 https://d3ro.chanpaca.net/app (Next basePath '/app', 정본 packages/core/src/web-urls.ts).
FROM node:24.19.0-alpine AS base
FROM base AS builder
WORKDIR /app
# NEXT_PUBLIC_* 는 next build 때 클라이언트·서버 번들에 박힌다. 런타임 환경변수로는 바뀌지 않는다.
ARG NEXT_PUBLIC_SUPABASE_URL
ARG NEXT_PUBLIC_SUPABASE_ANON_KEY
ARG NEXT_PUBLIC_PAYPLE_CLIENT_KEY=""
ENV NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL \
NEXT_PUBLIC_SUPABASE_ANON_KEY=$NEXT_PUBLIC_SUPABASE_ANON_KEY \
NEXT_PUBLIC_PAYPLE_CLIENT_KEY=$NEXT_PUBLIC_PAYPLE_CLIENT_KEY \
NEXT_TELEMETRY_DISABLED=1
RUN test -n "$NEXT_PUBLIC_SUPABASE_URL" && test -n "$NEXT_PUBLIC_SUPABASE_ANON_KEY" \
|| (echo "NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY build args are required" >&2 && exit 1)
COPY package*.json tsconfig*.json ./
COPY packages ./packages
COPY apps/web ./apps/web
# 개발자 로컬 .env* 가 컨텍스트에 섞여 들어와도 빌드 값은 위 build arg 만 쓴다.
RUN rm -f apps/web/.env apps/web/.env.*
RUN npm ci
RUN npm run build --workspace=@d3ro/web
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=3002
ENV HOSTNAME="0.0.0.0"
ENV NEXT_TELEMETRY_DISABLED=1
# node 사용자로 실행하므로 .next/cache 쓰기가 가능하도록 소유권을 넘긴다.
COPY --from=builder --chown=node:node /app/apps/web/.next/standalone ./
COPY --from=builder --chown=node:node /app/apps/web/.next/static ./apps/web/.next/static
USER node
EXPOSE 3002
CMD ["node", "apps/web/server.js"]