Files
shopdb-flask/Dockerfile
cproudlock cd353b6432
Some checks failed
CI / backend (push) Has been cancelled
CI / naming (push) Has been cancelled
CI / frontend (push) Has been cancelled
Review safe-polish: docs accuracy, dead imports, no-emoji, geenforce robustness
From the full multi-agent review (0 high, 7 medium, 17 low findings). Applies
the mechanical, low-risk items; design/policy findings left for a decision.

Docs accuracy: CLAUDE.md contract 0.10.0 -> 0.11.0 and both stale Alembic head
citations -> 7d24_customfield_searchable / 31 migrations; Dockerfile bundled-
plugin comment fixed (drop nonexistent "equipment", add machines +
measuringtools, count eleven).

Style/naming (LOCKED rules): remove a CSS-escaped pushpin emoji before location
search results (no-emoji policy); rename ManifestEditor shareRoot -> shareroot
(variable mirrors the API field verbatim).

Dead code: remove confirmed-unused imports across ~20 modules (require_role/
require_permission scaffold residue, stray db/Vendor/Model/current_user/Optional/
error_response); drop unused build_scope import + a stale GEENFORCE_API_KEY
docstring clause in geenforce. Migration files left untouched.

Correctness: geenforce ingest robustness - record_enforcement_report now 400s
on a non-dict counts / non-list results instead of 500; _apply_app_link ignores
a non-numeric appid per its docstring instead of 500. Regression tests added.

Backend query.get sweep finished: auth.py refresh -> db.session.get (last one).

910 backend tests pass; pyflakes clean; naming green; frontend build green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 08:02:43 -04:00

81 lines
2.3 KiB
Docker

# shopdb-flask single-site container.
#
# One image, one site. Per ADR-004, each adopting facility runs its own
# stack with its own DB, secrets, and enabled-plugin list. This image
# bundles all eleven core plugins (computers, employees, knowledgebase,
# machines, measuringtools, network, notifications, printers, slides, usb,
# warranty);
# install them at runtime with `flask plugin install <name>`.
#
# The frontend is built in a first stage and its dist output is copied into
# the final image so Flask can serve the SPA (register_frontend_routes in
# shopdb/__init__.py resolves <repo>/frontend/dist).
#
# Build:
# docker build -t shopdb-flask .
# Run (with .env):
# docker run --env-file .env -p 5001:5001 shopdb-flask
# ---- Stage 1: build the Vue frontend ----
FROM node:20-slim AS frontendbuild
WORKDIR /build
# Copy only the manifests first so `npm ci` caches on dependency changes.
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
RUN npm run build
# Output lands in /build/dist (Vite default), copied into the final stage below.
# ---- Stage 2: Python application image ----
FROM python:3.12-slim AS base
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
WORKDIR /app
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
default-libmysqlclient-dev \
pkg-config \
curl \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt \
&& pip install --no-cache-dir gunicorn
COPY shopdb/ ./shopdb/
COPY plugins/ ./plugins/
COPY migrations/ ./migrations/
COPY scripts/ ./scripts/
COPY wsgi.py ./
# Built SPA from stage 1. Flask serves it via register_frontend_routes.
COPY --from=frontendbuild /build/dist ./frontend/dist
RUN useradd --create-home --shell /bin/bash shopdb \
&& chown -R shopdb:shopdb /app
USER shopdb
EXPOSE 5001
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD curl --fail --silent http://localhost:5001/api/auth/login -X POST \
-H "Content-Type: application/json" -d '{}' \
| grep -q "VALIDATION_ERROR" || exit 1
CMD ["gunicorn", \
"--bind", "0.0.0.0:5001", \
"--workers", "4", \
"--timeout", "60", \
"--access-logfile", "-", \
"--error-logfile", "-", \
"wsgi:app"]