Additive, zero-risk-to-running-sites prep for the plugin catalog. No distribution or lean-build behavior yet; fixes latent bugs and adds the declarative + validate tooling later phases build on. Fixes: - upgrade_all_plugins iterates registry.get_all(); only adopted plugins are migrated. Removes the phantom hasattr(registry, 'list_installed') probe that always fell through to migrating every folder on disk (unadopted DDL ran with full DB rights on every deploy). - Reverse-dependency checks on uninstall/disable read dependencies from the manifest on disk via _installed_dependents, so an installed-but-unloaded or disabled dependent is counted. Uninstall blocks on any installed dependent; disable blocks on an enabled dependent. - _sort_by_dependencies detects a dependency cycle (back edge in the DFS) and raises PluginDependencyError instead of looping or dropping a plugin. New: - flask plugin validate <name>: manifest loads + name match, manifest-schema check, core_version admits the framework contract, declared dependencies exist on disk. No new dependency (lightweight checker); schema ships in the package at shopdb/plugins/manifest_schema.json (docs/ is stripped on publish). The check caught that provides is an object, not an array. - flask plugin apply-profile <file>: declarative install AND enable of a chosen plugin set plus its hard-dependency closure, in dependency order, idempotent. Replaces the hand-ordered runbook sequences that could enable a plugin that was never installed. deploy/site-profile.example.json template. - Dockerfile header corrected (all 13 catalog plugins, not "eleven core"). 10 new lifecycle tests (reverse-deps from disk, cycle detection, upgrade-all scope, profile closure, schema, all 13 manifests match schema). 1018 pass, naming green.
83 lines
2.5 KiB
Docker
83 lines
2.5 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 13 catalog plugins (computers, employees, geenforce,
|
|
# knowledgebase, machines, measuringtools, network, notifications,
|
|
# printedparts, printers, slides, usb, warranty); a site installs + enables
|
|
# the ones it wants with `flask plugin install <name>` (or, declaratively,
|
|
# `flask plugin apply-profile <profile.json>`). Per ADR-013 a future lean
|
|
# build stages only the chosen plugin directories into this image.
|
|
#
|
|
# 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"]
|