Initial implementation of Bluetooth toy control app
Next.js app with a browser-side buttplug/buttplug-wasm control layer (server never touches real-time device commands), SQLite storage via Drizzle, single-secret auth, recordings/replay with device remapping, a usage stats dashboard, Docker deployment, and Gitea CI. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W8WkFF5ppURBAB918593Eb
This commit is contained in:
+54
@@ -0,0 +1,54 @@
|
||||
# `output: 'standalone'` in next.config.ts (no custom server here, unlike
|
||||
# pulsenode's, so standalone is viable) traces only what's actually required
|
||||
# and copies better-sqlite3's compiled native binary along with it - verified
|
||||
# by inspecting .next/standalone/node_modules after a local build.
|
||||
|
||||
FROM node:22-alpine AS base
|
||||
RUN corepack enable
|
||||
|
||||
FROM base AS deps
|
||||
WORKDIR /app
|
||||
# better-sqlite3 ships prebuilt binaries for linux-musl (this image's libc),
|
||||
# but the toolchain is installed defensively in case no prebuild matches this
|
||||
# Node version - prebuild-install falls back to compiling from source then.
|
||||
RUN apk add --no-cache python3 make g++
|
||||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
FROM base AS build
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
RUN pnpm build
|
||||
|
||||
FROM node:22-alpine AS runtime
|
||||
RUN apk add --no-cache tini
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
# Docker auto-sets HOSTNAME to the container id; the standalone server.js
|
||||
# binds to `process.env.HOSTNAME || '0.0.0.0'`, so left unset it would bind
|
||||
# only to that container-id hostname's address instead of all interfaces,
|
||||
# making the app unreachable via the published port.
|
||||
ENV HOSTNAME=0.0.0.0
|
||||
|
||||
RUN addgroup -g 10001 -S app && adduser -u 10001 -S app -G app
|
||||
|
||||
# Standalone output ships its own minimal node_modules + server.js; static
|
||||
# assets, public/, and the drizzle migrations aren't traced (they're read
|
||||
# from disk at runtime, not imported), so they're copied in separately.
|
||||
COPY --from=build /app/.next/standalone ./
|
||||
COPY --from=build /app/.next/static ./.next/static
|
||||
COPY --from=build /app/public ./public
|
||||
COPY --from=build /app/drizzle ./drizzle
|
||||
COPY --from=build /app/healthcheck.mjs ./healthcheck.mjs
|
||||
|
||||
RUN mkdir -p /app/data && chown -R app:app /app
|
||||
|
||||
USER app
|
||||
EXPOSE 3000
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
||||
CMD ["node", "healthcheck.mjs"]
|
||||
|
||||
ENTRYPOINT ["tini", "--"]
|
||||
CMD ["node", "server.js"]
|
||||
Reference in New Issue
Block a user