Framework:
- Per-plugin Alembic migration chains (ADR-008): every bundled plugin
carries its own chain with a stamp-only anchor at the ownership cutover;
new plugin schema lands in plugins/<name>/migrations/, never the core
chain. Deploys add flask plugin upgrade-all. Fixed a latent bug in the
shared alembic template (engine URL resolution) and taught the metadata
filter to include FK-referenced core tables.
- Frontend plugin route gating (ADR-009): plugin routes carry meta.plugin;
a disabled plugin's pages redirect to the dashboard via a cached,
fail-open check against the new public GET /api/plugins/enabled.
- get_reports() plugin hook (contract 0.5.0 -> 0.6.0): plugins contribute
report cards; warranty and toner cards moved off the hardcoded list.
Reports:
- Hub grouped by category with search; inline reports render at the top,
are URL-backed (?report=id, back-button and deep links work), expose
their server-side filter params as controls, and export CSV. Warranty
and Toner pages gained CSV export.
- Deleted the dead legacy Warranty Status report (always-zero buckets
from a retired column).
Theming and fonts:
- Inter (variable) bundled locally via @fontsource, replacing the Google
Fonts Roboto import - air-gapped installs now render correctly; tables
use tabular numerals.
- Optional brand_primary_dark_color, brand_accent_color,
brand_sidebar_color settings applied to CSS vars at bootstrap.
USB frontend repair (views were reading a dead legacy shape):
- List/detail/form and the employee profile USB panels remapped to the
real API shape (device_id/device_desc/checkinoutlog); employee panels
now use /usb/checkouts endpoints; external-mode /usb/checkouts/active
honors the badge filter; dead client methods pruned.
Also: warranties list page no longer requires login (matches app
convention); collector doc rewritten with a GE-Enforce integration guide
and paste-ready PowerShell reporter; ADR index and CHANGELOG updated.
Verified: 323 tests pass, naming/style green, frontend builds, plugin
migration dry-run green on scratch MySQL.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
End-of-pipeline cleanup. No structural changes; documents what is
done, what is left, and the discipline for future cleanup commits.
Skill:
- simplifying-python: end-of-session cleanup discipline. Inspired by
Anthropic's open-sourced code-simplifier. Targets duplication, dead
code, voodoo constants, stale comments, misnamed identifiers,
unnecessary abstraction. Anti-targets: architecture, public API
surface, schema, sweeping rewrites. Behavior preservation enforced
by running pytest before and after.
Simplify pass on shopdb/utils/responses.py:
- error_response docstring claimed the error info lives at top level
`error`. Implementation puts it under `data.error` (consistent with
the success envelope). Implementation is correct; docstring updated.
- paginated_response docstring used snake_case keys (`per_page`,
`total_pages`, etc). Implementation uses lowercase concatenated per
CONTRIBUTING.md. Docstring updated to match.
Documentation:
- docs/PLUGINS.md: bundled plugins (six, with what they track and
caveats per ADR), planned plugins (measuringtools as the scaffold
canary per ADR-005), distribution conventions for sister-site
plugins per ADR-003, naming policy.
- docs/ROADMAP.md: phase status table (0-5 done, 6 in progress),
must-have work for 1.0 (Asset.mapx/mapy, equipment migration,
printers retirement, frontend hook contract, per-plugin Alembic
chains), nice-to-have (measuringtools plugin, frontend scaffolding,
marketplace listing, surface-diff tooling), deferred (multi-tenancy,
pip-installable plugins, event bus). Defines what 1.0.0 means as a
contract.
Test count unchanged: 101 passing. Naming/style check green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>