The step was called "Starter Data" and offered to "seed the data a new site
needs", but seed_starter inserts eight vendor rows and nothing else: no assets,
locations, departments or statuses. An operator ran it, saw every dashboard
count stay at zero, and reasonably concluded the seed was broken.
Rename the step to Reference Data, describe what is actually seeded, and say
outright that no assets are created and that an empty dashboard is expected
here. Assets arrive later via the import API.
The uploaded-blueprint thumbnails on the map settings page and the
setup wizard used the raw setting value (/api/settings/map-blueprint/
...), which resolves at the server root and 404s under a subpath
mount - while the map itself resolves through blueprintUrlFor and
worked. Wrap the previews in withBase.
Plugins list now carries a displayname (manifest display_name, else the
machine name title-cased). Adds display_name to the four whose title-case
was wrong: GE-Enforce, USB, Measuring Tools, Knowledge Base. The setup
wizard Features step and Settings > Plugins render it, so "Geenforce"/"Usb"
are gone.
Finish step shows a pointer when GE-Enforce is enabled: it still needs a
scoped service token (Settings > API Tokens) and a share export root
(GE-Enforce page) before the fleet uses it - operational config the wizard
does not collect.
frontend build green; naming green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the app distributable to other GE Aerospace sites (one self-hosted
instance per site, ADR-004). GE values remain the shipped defaults; every
site-specific behavior is now a Setting an admin can change in the UI.
Settings-driven site config:
- Branding: site/QR/badge logos, favicon, primary color (upload endpoints
mirror the map-blueprint pattern; new Settings > Branding section).
- ServiceNow: search/incident/change URL templates ({ticket}), ticket
prefixes, enable toggle. Defaults point at the current
geaerospaceqa.service-now.com global search. Disabled = plain-text tickets.
- Employee-id regex (employeeid_pattern), printer hostname template,
QR label targets (qr_target_printer / qr_target_usb, blank = asset page,
else URL template with placeholders), usb_label_style (barcode|qr).
- West Jefferson floor-plan PNGs removed from the tree; generic placeholder
ships as the map default and sites upload their own blueprint.
Security closeout:
- dashboarddefaults writes now require admin.
- Collector: generic error messages (no str(exc) leak); API key accepted
via X-API-Key header only (BREAKING: querystring api_key removed).
- IP-based login rate limiting (AUTH_RATELIMIT_* knobs) atop account lockout.
- Setting.set() creation race fixed (IntegrityError retry).
Release engineering and docs:
- __version__ 0.5.0 (distinct from __contract_version__, ADR-007),
CHANGELOG.md, Gitea Actions CI config, frontend version aligned.
- One wizard-first install story across README/DEPLOY; new CONFIG.md,
UPGRADE.md, BACKUP-RESTORE.md; CLAUDE.md and ROADMAP de-staled.
- Dockerfile multi-stage build now bundles the frontend; compose binds
MySQL to 127.0.0.1; stale database/schema.sql and one-off SQL removed.
Debt and fixes:
- .query.get() -> db.session.get() sweep; datetime.utcnow() removed
(naive-UTC via timezone-aware now); users.py on authz decorators.
- Fixed 4 stale tests (slides feed shape, shopfloor splitperemployee,
plugin contract purity) and the USB label page field mapping (both usb
modes emit the cmmc shape: device_id/device_desc).
- Health endpoint reports the real version.
248 tests pass; naming/style check green; frontend builds; fresh-DB
flask db upgrade + seeds verified; QR targets verified by decoding
rendered codes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
No CLI needed for a UI-driven install.
- Login page: when the instance has no users yet (/setup/needs-admin), it shows
a "create the first admin" form instead of login. Submitting creates the admin
(admin role = full access / superadmin) via /setup/create-admin, logs in, and
goes to the setup wizard.
- Wizard Starter Data step: "Seed core reference data" button (statuses, types,
permissions, default settings via /setup/seed-reference) alongside the common
vendors, so a UI-first install gets the data the app needs.
- Add waitress to requirements.txt (the IIS web.config launches it but it was
missing - found while validating the Windows install).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Validated a clean install on MySQL 5.6 end to end and fixed the blockers.
- migrations/env.py: force alembic_version.version_num to VARCHAR(128) in its
own committed connection before running migrations. It was VARCHAR(32); the
revision id 7d02_widen_notification_employee_cols (37 chars) truncated, so the
next migration's version bump matched 0 rows and `flask db upgrade` died at
7d03 on a fresh DB. Now upgrades run clean to head.
- flask db-utils preflight: checks Python, required env, DB connectivity, and
the MySQL 5.6 utf8mb4 index flags (innodb_large_prefix/Barracuda) - the 767
prerequisite - and prints exact fixes. Exits non-zero on blockers.
- flask seed admin --username --email [--password]: real first-admin command
(generates + prints a password once). The docs referenced it but only the
dev-only test-user existed.
- setup endpoints for a UI-driven first run: /setup/needs-admin,
/setup/create-admin (guarded to zero-users), /setup/seed-reference.
- Wizard: drop the PC-access-domain question (always .device.geaerospace.net);
the setting keeps its default.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Answers the confusion of asking for a DB connection while also offering to
create the tables. Each self-host-capable plugin (employees, usb) now shows a
mode choice; the external connection fields appear only for "connect your own
database". Default is self-hosted (create tables here) - the external path is
the niche/our-site option.
- provisioning_note gains mode_setting; employee_directory_mode + usb_directory_
mode settings (both default 'selfhosted').
- Wizard renders the radio, shows the note for self-hosted and the config fields
for external, and saves the chosen mode.
Employees works fully in both modes. USB self-hosted ROUTING is still TODO - the
USB routes read the external cmmc_usb schema; wiring them to the app-owned
tables is the remaining work (tracked).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both plugins provision extra tables, so they now install disabled and explain
themselves before a site opts in.
- Plugin contract gains get_provisioning_note() -> {tables, note, docs}.
Employees and USB implement it (what tables get created in shopdb, how they
are referenced, link to the schema README; USB references the captured
DLP/reminder plans).
- Manifest default_enabled=false for employees + usb; the plugins list API
returns provisioning_note + default_enabled; install now registers a plugin
disabled when default_enabled is false.
- Setup wizard Features step renders the provisioning note the moment a plugin
with one is enabled.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Plugin contract gains get_config_schema(); the plugins list API returns it.
Employees plugin declares its directory-DB fields (host/name/user + password).
- employee_connection reads host/name/user settings-first (env fallback); the
password stays env-only.
- Setup wizard Features step renders each enabled plugin's config: non-secret
fields save to settings; secrets are never stored - the wizard emits .env
lines to paste. Fixed the plugins-list data path (data.plugins).
- Settings PUT now upserts (creates the row on first write) so plugin-config
keys can be saved without pre-seeding.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- setup_complete site setting; a fresh admin is steered to /setup until it is
finished (skippable for the session).
- SetupWizard.vue: Site (facility/base-url/access-domain), Features (plugin
enable/disable), Floor Map dimensions, Starter Data (seed common vendors),
Finish. Reuses the settings + plugins APIs.
- setup blueprint: POST /setup/seed-starter (idempotent common vendors) and
POST /setup/complete. setupState composable drives the router redirect.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>