diff --git a/docker-compose.yml b/docker-compose.yml index 05e3df7..d4fd4f2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -35,12 +35,22 @@ services: # default and enabled from the Admin console; this is the only email # secret and it is never stored in the DB. Leave unset until configured. SMTP_PASSWORD: ${SMTP_PASSWORD:-} + # Optional — read-only SQL Server connection to the Micron asset catalog, + # which backs the asset picker in the work package creator. Leave unset and + # the picker cleanly falls back to manual entry (see server/assets_db.py). + # Use a db_datareader login: the app only ever SELECTs. + MICRON_DB_URL: ${MICRON_DB_URL:-} restart: unless-stopped depends_on: db: condition: service_healthy # waits for postgres to accept connections networks: - internal + # Reaching the Micron database means leaving this compose project, and + # `internal` is deliberately egress-free. `outbound` is attached to the api + # container ONLY — the database and backup containers stay sealed. Detach it + # again if you are not using the Micron asset picker. + - outbound db: image: postgres:16-alpine @@ -98,4 +108,12 @@ networks: name: proxy external: true internal: - internal: true # no outbound internet access from api/db \ No newline at end of file + internal: true # no route off the host for anything on this network alone + outbound: + # An ordinary bridge network, i.e. one that HAS a default gateway. `internal` + # above removes the gateway entirely, which blocks not just the internet but + # the LAN and the VPN too — so the api container needs this second network to + # reach the Micron asset database. Attached to `api` alone: `db` and `backup` + # remain on `internal` only and still have no way off the host. + # Detach it from api if you are not using the Micron asset picker. + driver: bridge \ No newline at end of file diff --git a/docs/reference/completion.md b/docs/reference/completion.md index 91b92da..51a0c7c 100644 --- a/docs/reference/completion.md +++ b/docs/reference/completion.md @@ -67,6 +67,7 @@ name the probe that re-checks the item on every run. | D8 | built | T7.7 (5MB / PDF+image / 2GB, 80% warning) | | D9 | built | T7.6 (Field View text pill at 390px) | | D10 | built | T7.6 / reused T8.3 (stored setting, admin-only, audited, sink-verified) | +| D11 | built | merge of `origin/Micron-Assets` + integration, Aug 20 (`assets_check`); see `decisions-2026-08-20.md` | ## Out of scope, confirmed unbuilt @@ -74,8 +75,10 @@ name the probe that re-checks the item on every run. `materials_check` grep the model and the diff for stock/inventory/price fields on every run; none exist. D6's uploaded list is project-scoped data entry, not a catalog. -- **Asset database integration** — the assets section stays a CR-006 toggle - (off on the Micron sample); no integration code exists. +- **Asset database integration** — SUPERSEDED by D11 on Aug 20: Cody Schaefer's + Micron asset picker (read-only catalog lookup, `origin/Micron-Assets`) merged + and adapted to the R2 creator. The assets section stays a CR-006 toggle + (off on the Micron sample). This line was true when written. - **CxAlloy integration** — CR-014 is notification-only, as the task footnote ordered; the platforms block stores names and URLs, nothing calls them. - **P6 activity import** — CR-001 renders the two fields; nothing imports. diff --git a/docs/reference/file-map.md b/docs/reference/file-map.md index ad0250d..59c9e5f 100644 --- a/docs/reference/file-map.md +++ b/docs/reference/file-map.md @@ -305,7 +305,13 @@ python tests/icon_check.py # S6 - one icon system, no emoji, mapped python tests/helptip_check.py # C1/S8 - tips by keyboard+touch, audit greps 13 checks python tests/mobile_check.py # C2 - all 7 pages at 390px, targets + fit 24 checks python tests/archived_check.py # D7 - archived projects, admins only, frozen 15 checks -python tests/color_check.py # C4 - zero literals outside theme-light 4 checks +python tests/color_check.py # C4 - zero literals outside theme-light 5 checks +``` + +The August 20 integration adds: + +```bash +python tests/assets_check.py # D11 - Micron picker: read-only, degrades 27 checks ``` **Three probes were re-pointed at `T7.1`.** `sections_check.py` 5b drove the live diff --git a/docs/waves/decisions-2026-08-20.md b/docs/waves/decisions-2026-08-20.md new file mode 100644 index 0000000..3351819 --- /dev/null +++ b/docs/waves/decisions-2026-08-20.md @@ -0,0 +1,55 @@ +# Decisions — August 20, 2026 + +One item. Like the August 18 set, it is a **new item** with its own `D` id, not a +reinterpretation of an existing one. + +--- + +## D11 — The Micron asset picker merges into the R2 creator + +- **Arrived as:** `origin/Micron-Assets` (`7ef1fcd`, Cody Schaefer, Aug 18) — written + against pre-R2 `main`, integrated here by Nick's instruction on Aug 20. +- **Amends:** the R2 completion record's "Asset database integration — out of scope, + confirmed unbuilt" line, which was true when written and stops being true here. +- **Surface:** `html/` (creator), `server/` (`assets_db.py`, `/api/assets`), + `docker-compose.yml`, `requirements.txt`. + +### What the branch brought + +A read-only lookup onto the Micron asset catalog (a SQL Server instance outside this +repo): the whole catalog is fetched once per creator page load through `/api/assets` +and searched in memory; picked assets are stored on the package tagged +`source:'catalog'` with the DB's own casing; anything not in the catalog is added by +hand and visibly tagged manual. CSV import and Excel column paste bulk-add with the +same matching. Unconfigured (`MICRON_DB_URL` unset) and unreachable are first-class +states that degrade to manual entry — the suite runs without Micron wired up. + +### What integration changed (and why) + +The branch predates waves 5–9, so it used surfaces R2 replaced. Each adaptation keeps +Cody's behaviour and moves it onto the R2 idiom: + +1. **Six `alert()` calls → the T7.9 dialog kit and toast.** The creator ships zero + native dialogs (`creator_dialogs_check` pins the count). File-handling errors use + `toast(msg,'alert')` exactly as the drawings uploader and comment import do; + the instructional message and the import summary use the kit, which gained the + one-button `wpAlertDialog` shape it was always going to need (BL-024 wants it too). +2. **The export block** moved inside T9.1's sectioned `add('assets', …)` frame, so the + CR-006 assets toggle keeps governing it. Content is Cody's: two columns, Asset ID + + Note, no controls.dev link column. +3. **`initAssetPicker()`** joined the R2 `bootData()` loads rather than replacing them. +4. **`role="status"`** on the picker's source note, so loading → ready/absent/error + announces (C1, the login.html pattern). +5. Everything else landed as written: his `⤒` import glyph is already the S6-mapped + U+2912, `.material-actions` is the creator's own class, and the styles block + declares no colour literal (`color_check` re-verifies). + +### Recorded properties, restated as constraints + +- **Read-only, structurally.** `assets_db.py` contains one SELECT and no other + statement; there is no POST route. `assets_check` greps this on every run. +- **Credentials are env-only** (`MICRON_DB_URL`), matching the SMTP password rule. + Driver errors are logged server-side and never propagated to the browser, because + a malformed URL's error text can quote password fragments. +- **Unconfigured is not an error.** Local dev and the demo DB run with the picker in + manual mode; nothing in the suite requires the catalog to exist. diff --git a/html/help.js b/html/help.js index 1a67e50..0fbaf4d 100644 --- a/html/help.js +++ b/html/help.js @@ -244,7 +244,7 @@

Key fields