docs: clarify Electron scope, update badge test lessons, all badge tests passing

- AE__Architecture.md: Add section 7 -- Runtime Environment: Browser vs Electron.
  Electron is ONLY for Events Pres Mgmt Launcher. Badge printing (and everything
  else) works via standard browser window.print(), no Electron needed.
- MODULE__AE_Events_Badges.md rev 3: Update print section to browser-first approach,
  remove Electron from print workflow, add two new test lessons (flat API URLs,
  CSS attribute vs DOM property), mark all tests passing.
- TODO__Agents.md: Add completed data integrity test fixes item, add window.print()
  wiring to upcoming tasks, expand input field audit note.
This commit is contained in:
Scott Idem
2026-02-26 18:10:08 -05:00
parent f5e98b8c0d
commit 7c6f264266
3 changed files with 115 additions and 19 deletions

View File

@@ -135,7 +135,34 @@ A list of potential future standard fields, often prefixed with `obj_`. These ar
- `obj_id`, `obj_ext_uid`, `obj_ext_id`, `obj_import_id`, `obj_code`, `obj_account_id`, `obj_passcode`, `obj_type`, `obj_type_ver_id`, `obj_name`, `obj_summary`, `obj_outline`, `obj_description`, `obj_enable`, `obj_enable_on`, `obj_archive_on`, `obj_hide`, `obj_priority`, `obj_sort`, `obj_group`, `obj_cfg_json`, `obj_notes`, `obj_created_on`, `obj_updated_on`.
## 7. IndexedDB LiveQuery Usage
## 7. Runtime Environment: Browser vs Electron
The Aether SvelteKit frontend runs in a standard web browser in almost all cases. The Electron native app is a **very specialized exception** with a narrow, specific purpose.
### 7.1. Standard Browser (Default)
All Aether modules run in a regular browser (Chrome, Chromium, Firefox, Safari). This includes:
- Badge printing — `window.print()` works well across Chrome, Chromium, and Firefox. Chrome is recommended for onsite badge printing stations.
- All CRUD operations, event management, journals, IDAA, reports, etc.
- No special browser configuration required.
### 7.2. Electron Native App (Specialized — Pres Mgmt Launcher Only)
The Electron app (`aether_app_native_electron/`) exists **solely** to support the **Events Presentation Management Launcher**. It provides OS-level capabilities that a browser sandbox cannot:
- Control of third-party presentation software (PowerPoint, Keynote, LibreOffice Impress)
- Local filesystem access for slide file management
- Hardware telemetry for connected devices
**What Electron is NOT used for:**
- Badge printing (browser works fine)
- Any other Aether module
- Any general-purpose Aether functionality
The bridge is exposed as `window.aetherNative` (set by Electron's preload script). All code that calls `window.aetherNative` should degrade gracefully when it is `undefined` (i.e., in a normal browser). See: `src/lib/electron/electron_relay.ts`.
**When to assume Electron is available:** Only inside the `/events/[event_id]/(launcher)/` route group, and only when the page was loaded from the native app.
## 8. IndexedDB LiveQuery Usage
- `lq__xyz_obj`: Used for general read-only access to liveQuery results.
- `lqw__xyz_obj`: Used for forms and binding values, representing a writable snapshot of liveQuery results.

View File

@@ -3,7 +3,7 @@
**Module Path:** `src/routes/events/[event_id]/(badges)/badges/`
**API Module:** `src/lib/ae_events/ae_events__event_badge.ts`
**Database:** `db_events.badge` (Dexie IndexedDB table)
**Last Updated:** 2026-02-26
**Last Updated:** 2026-02-26 (rev 3)
---
@@ -208,6 +208,18 @@ editable_badge_type_code: string | null
### Search Component
**File:** `ae_comp__badge_search.svelte`
### Multi-Word Search Fix (2026-02-26)
Fulltext search now correctly handles multi-word queries by splitting on whitespace and applying AND logic per word:
```typescript
// "scott idem" → LIKE '%scott%' AND LIKE '%idem%'
// Previously: LIKE '%scott idem%' (failed to match)
const words = qry.split(/\s+/).filter(w => w.length > 0);
for (const word of words) {
search_query.and.push({ field: 'default_qry_str', op: 'like', value: `%${word}%` });
}
```
**Committed:** dc0f3066
### Available Filters
**Fulltext Search** (All Users)
@@ -345,13 +357,34 @@ print_first_datetime: string // ISO datetime of first print
print_last_datetime: string // ISO datetime of most recent print
```
### Print Workflow (Future)
### Print Button (Implemented 2026-02-26)
The `handle_print_badge()` function in `ae_comp__badge_obj_view.svelte` increments the count and records timestamps:
```typescript
async function handle_print_badge() {
const now = new Date().toISOString();
const current_print_count = $lq__event_badge_obj.print_count ?? 0;
const data_to_update = {
print_count: current_print_count + 1,
print_last_datetime: now
};
if (current_print_count === 0) {
data_to_update.print_first_datetime = now; // Only set on first print
}
await events_func.update_ae_obj__event_badge({ ... });
}
```
Button has `data-testid="badge-print-btn"` and shows loading/done/error states with icon feedback.
### Print Workflow
1. **Pre-Print:** Check `print_count` to warn if already printed
2. **Print:** Send to printer via Electron native bridge or browser print
3. **Post-Print:** Increment `print_count`, update `print_last_datetime`
2. **Print:** `window.print()` — standard browser print dialog. Works well in Chrome, Chromium, and Firefox. Chrome is the recommended browser for onsite badge printing (most stable in production).
3. **Post-Print:** Handled by `handle_print_badge()` — count + timestamps updated
4. **Audit:** Print history available for staff review
**Current Status:** UI placeholder for print button, tracking fields exist in database, print functionality pending.
**Browser vs Electron:** Badge printing does NOT require the Electron native app. The standard browser print dialog works well across Chrome, Chromium, and Firefox. The Electron native app is specialized for the **Events Pres Mgmt Launcher only** and should not be assumed available for badge stations.
**Current Status:** Button records print event and updates IDB. The `window.print()` call still needs to be wired to the button — see Future Enhancements.
---
@@ -483,32 +516,61 @@ delete_ae_obj_id__event_badge({ event_badge_id, event_id, method })
- **Metadata:** ID, created/updated timestamps (edit mode only)
**Badge Detail View** (`ae_comp__badge_obj_view.svelte`)
- **Edit Mode:** Activated by `#review` URL hash or edit button
- **Edit Mode:** Activated by edit button (or `#review` URL hash for future self-service)
- **Condition:** Renders only when BOTH `$lq__event_badge_obj` AND `$lq__event_badge_template_obj` are non-null
- **Form Binding:** Direct `bind:value` on editable fields
- **Dynamic Sizing:** Font size adjusts based on text length
- **Print Preview:** Full badge layout with template
- **Save Handler:** Only sends changed fields to API
- **`data-testid` attributes:** `badge-edit-btn`, `badge-save-btn`, `badge-cancel-btn`, `badge-print-btn`, `badge-professional-title-input` — use these in tests
---
## Testing Status
### Current Test Coverage
- Badge list cold-start (failing — mock API issue)
- Badge data integrity (failing — mock API issue)
- Badge template list (failing — route mismatch)
- Badge list loads (all 6 data integrity tests passing)
- Badge template list loads and displays
- Badge template form renders and populates correctly
- ✅ Badge template values persist in edit form
- ✅ Electron bridge compatibility (graceful degradation in browser)
- ✅ Badge field processor handles missing optional fields
- ✅ Badge type filter tests
- ✅ Badge template relationship tests
-Electron bridge compatibility (graceful degradation)
-**Attendee workflow test** — navigate → edit professional title → print → return (d1ded2d4)
### Test Issues
**Root Cause:** Mock API routes not matching actual request patterns. Tests provide correct mock data but page shows "No badges found".
### Key Test Lessons Learned
**Browser Error:** `Object is missing a valid ID for table "badge"` — Mock data reaching IDB with only `{tmp_sort_1, tmp_sort_2, event_id}`, all other fields stripped.
**Search API path is FLAT, not nested.** `search_ae_obj_v3` builds `/v3/crud/{obj_type}/search` — always flat regardless of the parent relationship. Mocks must match this:
```typescript
// CORRECT — flat path
url.includes('/v3/crud/event_badge/search') && method === 'POST'
// WRONG — nested path, mock will never fire
url.includes(`/v3/crud/event/${event_id}/event_badge/search`) && method === 'POST'
```
**Fix Required:** Debug actual API request URLs, adjust mock route patterns.
**List API (GET) is also FLAT with query params.** `get_ae_obj_li_v3` builds `/v3/crud/{obj_type}/?for_obj_id=...` — always flat. Mocks must check `url.includes('/v3/crud/event_badge_template/') && url.includes('for_obj_id')`.
**Manual Testing Recommended:** Navigate to `/events/{event_id}/badges` in browser to verify actual functionality before fixing test infrastructure.
**CSS `input[value*=...]` selectors don't work with Svelte bind:value.** The CSS selector checks the HTML *attribute*; Svelte's `bind:value` sets the DOM *property* only. In Playwright tests, use `page.getByLabel()` or `locator.inputValue()` instead.
**Dexie requires `_random` ID fields.** Badge objects saved to IDB must include:
```typescript
event_badge_id_random: string // Must be present or Dexie skips the object
id_random: string // Also checked
// Error: "Object is missing a valid ID for table 'badge'"
```
All API mock responses in tests need these fields.
**Badge view requires both badge AND template.** `ae_comp__badge_obj_view.svelte` wraps everything in `{#if $lq__event_badge_obj && $lq__event_badge_template_obj}` — if the template isn't loaded, edit/print buttons and the badge itself don't render. Tests must mock the badge template endpoint.
**Badge GET endpoint (single object):** `/v3/crud/event_badge/{id}` (NOT nested under event). Matches `api.get_ae_obj_v3()` which uses the flat path.
**Badge PATCH endpoint (update):** `/v3/crud/event/${event_id}/event_badge/${badge_id}` (nested under event). Matches `api.patch_ae_obj_v3()` which uses the nested path.
**Use `data-testid` for test selectors.** Key buttons have targets: `badge-edit-btn`, `badge-save-btn`, `badge-cancel-btn`, `badge-print-btn`, `badge-professional-title-input`.
### Remaining Test Issues
None — all current badge tests passing as of 2026-02-26 (f5e98b8c).
---
@@ -521,7 +583,7 @@ delete_ae_obj_id__event_badge({ event_badge_id, event_id, method })
### Future Enhancements
1. **Access-Based Edit Permissions:** Implement JSON config for field-level access control
2. **Print Functionality:** Wire up print button to Electron native print or browser print API
2. **Print Functionality:** Wire up `window.print()` to the print button. Standard browser print API — works well in Chrome/Chromium/Firefox for badge label printing. Electron is NOT needed.
3. **Batch Operations:** Bulk update, bulk print, bulk export
4. **Audit Log:** Track who edited which fields and when
5. **Photo Badges:** Support badge photo upload and display
@@ -585,5 +647,5 @@ db_events.badge.toArray().then(console.log)
---
**Document Status:** ✅ Complete
**Last Verified:** 2026-02-26
**Verified Against:** Code commit b28595da (badge data fixes)
**Last Verified:** 2026-02-26 (rev 3 — all badge tests passing)
**Verified Against:** Code commit f5e98b8c (all data integrity tests passing)

View File

@@ -10,6 +10,8 @@
## 🚧 Upcoming High Priority
- **CRUD v2 Refactor:** Finalize retirement of `Element_ae_crud_v2.svelte` in favor of V3 Editor.
- **Temp Cleanup:** Auto-removal of native `.tmp` files older than 24h.
- **`window.print()` for badge print button:** Wire the existing `handle_print_badge()` to trigger `window.print()`. Browser print works well across Chrome/Chromium/Firefox — no Electron needed.
- **Input Field Audit:** Several input fields are missing `name`/`id` attributes or `data-testid`. Known examples: badge override fields in `ae_comp__badge_obj_view.svelte`; template name input in `ae_comp__badge_template_form.svelte`. Matters for: accessibility, autofill, label associations, and test targeting. (For tests, use `getByLabel()` rather than `input[value*=...]` which only checks the HTML attribute, not the Svelte-bound DOM property.)
## ✅ Completed Recently
- [x] **[API]** **V3 Lookup System Integration:** Implemented standardized `/v3/lookup/` endpoints for Countries, Subdivisions, and Time Zones. Added support for `only_priority` filtering in IDAA editors.
@@ -23,3 +25,8 @@
- [x] **[API]** Unified all CRUD helpers to standard V3 `/v3/crud/...` paths.
- [x] **[Framework]** Implemented `AE_Obj_Field_Editor_V3` with Svelte 5 Runes.
- [x] **[IDAA]** Verify Bulletin Board and Recovery Meetings functionality.
- [x] **[Badges]** **Multi-word fulltext search fix:** Split query on whitespace, apply AND logic per word. `"scott idem"` now matches records containing both words. (dc0f3066)
- [x] **[Badges]** **Print button implemented:** `handle_print_badge()` increments `print_count`, records `print_first_datetime`/`print_last_datetime`. Button has loading/done/error states. (d1ded2d4)
- [x] **[Badges]** **`data-testid` attributes added** to badge view interactive elements (`badge-edit-btn`, `badge-save-btn`, `badge-cancel-btn`, `badge-print-btn`, `badge-professional-title-input`) for reliable test targeting.
- [x] **[Tests]** **Attendee badge workflow test passing:** `event_badge_attendee_workflow.test.ts` — navigate → edit professional title → save (verify PATCH body) → print (verify count/timestamps) → return to search. (d1ded2d4)
- [x] **[Tests]** **All badge data integrity tests fixed:** All 6 tests in `event_badge_data_integrity.test.ts` now pass. Root causes: (1) search mock used nested URL instead of flat `/v3/crud/event_badge/search`, (2) template list mock used nested URL instead of flat with `for_obj_id`, (3) missing `_random` ID fields in mock badge objects, (4) CSS `input[value*=...]` selector doesnt work for Svelte-bound inputs — fixed to `getByLabel()`. (f5e98b8c)