Closes the last big spec gap: a single bundled React+Vite+Tailwind+Recharts SPA that renders any report's dataset_v2.json under /api/reports/:id/dashboard/. Spec deviation (intentional): rather than per-brief Vite builds (Netlify- portable case), one bundle serves every report and fetches its dataset at runtime. The portable HTML bundle (§10b) still ships per-report for offline upload to claude.ai. Dashboard template (v2/templates/dashboard_template): - React 18 + Vite + TypeScript + Tailwind + Recharts. Same dark theme tokens as the operator app. - 9 views: Overview, Categories, Trends explorer (filters + sort + drilldown), Lenses (4 sub-tabs for Hooks Library / Visual Vernacular / Audio Atlas / Sentiment Map), Charts (engagement-vs-reach scatter, category treemap, paid-vs-organic stacked bar), Compare (MoM new/returning/faded + category momentum), Paid creators appendix, Methodology. - Tab-based navigation with hash-stable URLs so deep links work. Server: - GET /api/reports/:id/dataset returns the on-disk dataset_v2.json (auth- gated; 404 if Stage 10 hasn't built it yet). - handleDashboardServe rewrite: serves (1) the explicit dashboard.html bundle, (2) per-report on-disk static (covers, dataset_v2.json), (3) the bundled SPA's assets/* and index.html with SPA fallback. Build: - v2/package.json workspaces re-includes templates/dashboard_template (was excluded after earlier cutover-prep). - Dockerfile.v2 builds the dashboard template alongside operator-app and copies dist/ into the runtime image. Local build: 838 modules transformed, 580 kB / 166 kB gzipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
54 lines
1.8 KiB
Text
54 lines
1.8 KiB
Text
# V2 image: builds operator-app SPA, copies server + pipeline + templates, runs Node.
|
|
FROM node:20-slim AS ui-build
|
|
|
|
WORKDIR /build
|
|
COPY v2/package.json v2/package-lock.json* ./
|
|
COPY v2/operator-app/package.json operator-app/package.json
|
|
COPY v2/templates/dashboard_template/package.json templates/dashboard_template/package.json
|
|
RUN npm install --include=dev --no-audit --no-fund
|
|
|
|
COPY v2/operator-app ./operator-app
|
|
COPY v2/templates ./templates
|
|
COPY v2/tsconfig.base.json ./tsconfig.base.json
|
|
|
|
# Vite reads VITE_* vars at build time (they're inlined into the bundle), not runtime.
|
|
# Pass these from compose `build.args` so the SPA knows the Azure tenant/client IDs.
|
|
ARG VITE_AZURE_TENANT_ID=""
|
|
ARG VITE_AZURE_CLIENT_ID=""
|
|
ARG VITE_BASE="/social-reports/"
|
|
ENV VITE_AZURE_TENANT_ID=$VITE_AZURE_TENANT_ID
|
|
ENV VITE_AZURE_CLIENT_ID=$VITE_AZURE_CLIENT_ID
|
|
ENV VITE_BASE=$VITE_BASE
|
|
RUN npm run build --workspace operator-app
|
|
# Per-report dashboard SPA (V3 §10a). Built once; same dist serves any report id.
|
|
RUN npm run build --workspace v2-dashboard-template
|
|
|
|
FROM node:20-slim AS runtime
|
|
|
|
# ffmpeg for Stage 4 frame extraction
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends ffmpeg ca-certificates \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
WORKDIR /app
|
|
ENV NODE_ENV=production
|
|
|
|
COPY v2/package.json v2/package-lock.json* ./
|
|
RUN npm install --omit=dev --no-audit --no-fund
|
|
|
|
COPY v2/tsconfig.base.json v2/tsconfig.json ./
|
|
COPY v2/server ./server
|
|
COPY v2/pipeline ./pipeline
|
|
COPY v2/templates ./templates
|
|
COPY v2/db ./db
|
|
|
|
# UI build artifacts
|
|
COPY --from=ui-build /build/operator-app/dist ./operator-app/dist
|
|
COPY --from=ui-build /build/templates/dashboard_template/dist ./templates/dashboard_template/dist
|
|
|
|
RUN mkdir -p briefs && useradd -u 1000 -m -s /bin/bash node-v2 || true
|
|
RUN chown -R 1000:1000 /app
|
|
|
|
USER 1000
|
|
EXPOSE 3457
|
|
CMD ["npx", "tsx", "server/index.ts"]
|