Initial import: shopdb-flask multi-site asset platform

Flask + Vue rewrite of the classic-ASP shopdb, built as a plugin
framework so sister GE Aerospace sites can adopt it. Product version
0.7.0-pre-0.8.0, plugin contract 0.11.0, 966 backend tests.

Key entry points:
- docs/INSTALL-WINDOWS-IIS.md - tested Windows + IIS install runbook
  (own-site and subpath deployment methods)
- docs/PILOT-DEPLOY.md - production pilot: stand up + import + verify
- docs/IMPORT-API.md - schema-agnostic legacy data import contract
- scripts/site_imports/wjf/ - West Jefferson reference import loader
- docs/adr/ - twelve accepted architecture decision records
This commit is contained in:
2026-07-14 07:58:51 -04:00
commit a9d0dfff4a
599 changed files with 88557 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
// Enabled-plugin gating for the router. Fetches the enabled plugin-name list
// ONCE (cached promise) so a disabled backend plugin's frontend routes become
// unreachable by direct URL. Fail-open: any fetch error treats every plugin as
// enabled, so an API blip can never brick navigation.
import { pluginsApi } from '../api'
let enabledPromise = null
let enabledSet = null // resolved Set<string>, or null while pending / on failure
// Kick off (or reuse) the single fetch. The endpoint is jwt-optional so this
// works on unauthenticated kiosk routes (e.g. /tv) too.
export function loadEnabledPlugins() {
if (!enabledPromise) {
enabledPromise = pluginsApi.enabled()
.then(response => {
const names = response?.data?.data
// Only trust a real array; anything else -> fail open (null).
enabledSet = Array.isArray(names) ? new Set(names) : null
return enabledSet
})
.catch(() => {
// Fail open: leave enabledSet null so isPluginEnabled returns true.
enabledSet = null
return null
})
}
return enabledPromise
}
// True if the plugin is enabled OR the list is unknown (fail-open). A null
// enabledSet means we never got a trustworthy answer, so allow everything.
export function isPluginEnabled(name) {
if (!name) return true
if (enabledSet === null) return true
return enabledSet.has(name)
}
// Test/hot-reload hook: forget the cached result so the next call refetches.
export function resetEnabledPlugins() {
enabledPromise = null
enabledSet = null
}