192 lines
8.7 KiB
Markdown
192 lines
8.7 KiB
Markdown
# Aether Development SOP (Frontend)
|
|
> **Version:** 1.2 (2026-03-17)
|
|
> **Location:** documentation/GUIDE__Development.md
|
|
|
|
## 1. Verification (The "Test-First" Mandate)
|
|
**Rule:** No code is to be committed unless it has passed local verification.
|
|
|
|
### Required Checks
|
|
1. **Svelte Integrity:** `npx svelte-check`
|
|
- **Zero Tolerance:** If a task introduces even a single svelte-check warning or error, it must not be merged. Resolve all warnings before committing.
|
|
2. **Type Safety:** Ensure interfaces in `src/lib/types/ae_types.ts` match backend schemas.
|
|
3. **Reactivity Check:** Verify Svelte 5 runes (`$state`, `$derived`) are not creating race conditions with Dexie `liveQuery`.
|
|
4. **Build Check:** For major changes, run `npm run build:dev` to ensure no SSR or build-time failures.
|
|
5. **Integration Tests:** For changes to badge print, event layouts, or auth/store logic, run the relevant Playwright test file(s):
|
|
```bash
|
|
npx playwright test tests/event_badge_render.test.ts tests/event_badge_attendee_workflow.test.ts
|
|
```
|
|
Run the full suite with `npm run test:integration`. The badge tests (`event_badge_*.test.ts`) are the canonical integration test template.
|
|
|
|
## 2. Commit Policy
|
|
- **Atomic Commits:** One component or one logic fix per commit. Do not batch unrelated changes.
|
|
- **Safety:** Use `~/tmp/agents_trash` for file removal; never use `rm` directly on source files.
|
|
- **Secrets:** Never commit `.env`, API keys, or passwords.
|
|
|
|
## 3. Coordination (The Handshake)
|
|
You are not working in a vacuum. Coordinate with the Backend Agent via MCP tools.
|
|
|
|
### Mandatory Messaging Triggers
|
|
- **Data Requirements:** When a UI feature requires a new field or endpoint.
|
|
- **API Failures:** When a V3 endpoint returns unexpected data or errors.
|
|
- **Blocked:** If stuck in a loop or lacking information, use `ae_send_message` to ask the Backend Agent, or flag for Scott.
|
|
|
|
### Tools
|
|
- `ae_send_message` / `ae_inbox` — agent-to-agent messaging
|
|
- `ae_task_list` / `ae_task_add` / `ae_task_complete` — shared Kanban board
|
|
- `ae_log_work` — log activity to daily journal
|
|
|
|
## 4. Continuity (Before Starting Work)
|
|
1. Review `documentation/TODO__Agents.md` for active tasks.
|
|
2. Check `~/agents_sync/README.md` for fleet status and cross-agent tasks.
|
|
3. Describe your plan before making code changes across multiple files.
|
|
|
|
## 5. Key Documentation
|
|
|
|
| File | Purpose |
|
|
| --- | --- |
|
|
| `documentation/TODO__Agents.md` | Active task list — read first |
|
|
| `documentation/GUIDE__AE_API_V3_for_Frontend.md` | V3 API reference (authoritative) |
|
|
| `documentation/GUIDE__SvelteKit2_Svelte5_DexieJS.md` | Dexie + liveQuery patterns |
|
|
| `documentation/GEMINI__Svelte_and_Me.md` | Svelte 5 runes patterns |
|
|
| `documentation/AE__Architecture.md` | System architecture overview |
|
|
| `documentation/AE__Naming_Conventions.md` | Naming rules |
|
|
| `documentation/PROJECT__AE_Events_Launcher_Native_integration.md` | Electron/Launcher reference |
|
|
| `tests/README.md` | Playwright test guide — shared helpers, hard-won lessons, demo IDs |
|
|
|
|
## 6. Inline Field Editing — `element_ae_obj_field_editor`
|
|
|
|
The standard component for single-field inline editing throughout the platform. Wraps a `PATCH /v3/crud/{obj_type}/{obj_id}` call behind a click-to-edit UI that respects `$ae_loc.edit_mode`.
|
|
|
|
```svelte
|
|
import Element_ae_obj_field_editor from '$lib/elements/element_ae_obj_field_editor.svelte';
|
|
```
|
|
|
|
### Basic usage — text field with custom display
|
|
|
|
Wrap the display content in the default snippet. The component renders it in view mode and swaps in the input on edit.
|
|
|
|
```svelte
|
|
<Element_ae_obj_field_editor
|
|
object_type={'event_session'}
|
|
object_id={session.id}
|
|
field_name={'name'}
|
|
field_type={'text'}
|
|
current_value={session.name}
|
|
on_success={() => events_func.load_ae_obj_id__event_session({ api_cfg: $ae_api, event_session_id: session.id })}
|
|
>
|
|
<h1 class="text-2xl font-bold">{session.name}</h1>
|
|
</Element_ae_obj_field_editor>
|
|
```
|
|
|
|
### Field types
|
|
|
|
| `field_type` | Input rendered |
|
|
| --- | --- |
|
|
| `text` (default) | `<input type="text">` — Enter key saves |
|
|
| `textarea` | `<textarea>` — use `textarea_rows` prop |
|
|
| `select` | `<select>` — pass `select_options={{ value: 'Label' }}` |
|
|
| `checkbox` | `<input type="checkbox">` — shows Enabled/Disabled |
|
|
| `tiptap` | TipTap rich-text editor |
|
|
| `date` | `<input type="date">` |
|
|
| `datetime` | `<input type="datetime-local">` |
|
|
| `number` | `<input type="number">` — Enter key saves |
|
|
|
|
### Select with nullable FK
|
|
|
|
```svelte
|
|
<Element_ae_obj_field_editor
|
|
object_type={'event_presenter'}
|
|
object_id={presenter.event_presenter_id}
|
|
field_name={'person_id'}
|
|
field_type={'select'}
|
|
current_value={presenter.person_id}
|
|
select_options={$slct.person_obj_kv}
|
|
allow_null={$ae_loc.administrator_access}
|
|
on_success={() => events_func.load_ae_obj_id__event_presenter({ api_cfg: $ae_api, event_presenter_id: presenter.event_presenter_id })}
|
|
>
|
|
{presenter.person_id ?? 'Not linked'}
|
|
</Element_ae_obj_field_editor>
|
|
```
|
|
|
|
### Key props
|
|
|
|
| Prop | Default | Notes |
|
|
| --- | --- | --- |
|
|
| `current_value` | — | Required. Bound with `$bindable` — liveQuery updates flow through automatically |
|
|
| `allow_null` | `false` | Shows a "Set Null" button in edit mode |
|
|
| `display_block` | `false` | Makes the wrapper `display: block` instead of `inline-block` |
|
|
| `on_success` | — | Callback after successful PATCH — use to trigger SWR cache refresh |
|
|
| `object_reload` | `true` | Triggers internal SWR reload after patch (in addition to `on_success`) |
|
|
|
|
### Behavior notes
|
|
- The edit trigger button is `visibility: hidden` (not `display: none`) when `$ae_loc.edit_mode` is off — this preserves layout so the page doesn't shift when edit mode toggles.
|
|
- Optimistic display: draft value is shown immediately after save; cleared once liveQuery confirms the update came back from the DB.
|
|
- `on_success` should always call the relevant `load_ae_obj_id__*` function to keep Dexie in sync.
|
|
|
|
---
|
|
|
|
## 7. URL Parameters
|
|
|
|
URL params consumed by the app. Params are read by layouts and applied on mount.
|
|
|
|
### Global (active on all routes — read by `src/routes/+layout.svelte`)
|
|
|
|
| Param | Values | Effect |
|
|
| --- | --- | --- |
|
|
| `iframe` | `true` / `false` | Enables iframe mode — hides the AE system bar for all users by default, suppresses sign-in/passcode UI |
|
|
| `show_menu` | `true` | Override: show the AE system bar inside an iframe. Intended for admins/trusted users who need menu access while testing an embed. |
|
|
| `hide_menu` | `true` | Explicitly hide the AE system bar outside of iframe mode (e.g. fullscreen kiosk pages). |
|
|
| `theme` | theme name | Applies a theme on load, then removes param from URL (no history entry) |
|
|
| `theme_mode` | `light` / `dark` | Applies theme mode on load, then removes param from URL |
|
|
|
|
### IDAA Module (`/idaa/` routes)
|
|
|
|
| Param | Values | Consumed by | Effect |
|
|
| --- | --- | --- | --- |
|
|
| `iframe` | `true` | `idaa/+layout.svelte` | Hides IDAA nav chrome |
|
|
| `uuid` | Novi UUID | `idaa/(idaa)/+layout.svelte` | Sets Novi UUID → triggers member auth lookup |
|
|
|
|
### IDAA Video Conferences (`/idaa/video_conferences`)
|
|
|
|
| Param | Values | Effect |
|
|
| --- | --- | --- |
|
|
| `uuid` | Novi UUID | Member identity for Jitsi JWT |
|
|
| `key` | site key string | Site auth key |
|
|
| `room` | room name | Jitsi room name |
|
|
| `moderator` | `true` | Grants moderator role + JWT, enables lobby and activity logging |
|
|
| `domain` | hostname | Jitsi server (default: `jitsi.dgrzone.com`) |
|
|
| `start_muted` | `true` | Start audio muted |
|
|
| `start_hidden` | `true` | Start video off |
|
|
| `incoming_msg_sound` | `true` | Disable incoming message sound |
|
|
| `participant_joined_sound` | `true` | Disable participant joined sound |
|
|
| `participant_left_sound` | `true` | Disable participant left sound |
|
|
| `reaction_sound` | `true` | Disable reaction sound |
|
|
| `raise_hand_sound` | `true` | Disable raise hand sound |
|
|
|
|
### Events Launcher (`/events/[id]/launcher`)
|
|
|
|
| Param | Values | Effect |
|
|
| --- | --- | --- |
|
|
| `session_id` | session ID | Pre-selects a session on load |
|
|
| `iframe` | `true` | Iframe mode flag |
|
|
| `launcher_menu` | show/hide | Show/hide launcher menu chrome |
|
|
| `launcher_header` | show/hide | Show/hide launcher header |
|
|
| `launcher_footer` | show/hide | Show/hide launcher footer |
|
|
|
|
### Events Sign-In (`/events/[id]/sign_in_out`)
|
|
|
|
| Param | Values | Effect |
|
|
| --- | --- | --- |
|
|
| `person_id` | person ID | Pre-fill attendee |
|
|
| `person_pass` | passphrase | Auto-authenticate attendee |
|
|
| `presentation_id` | ID | Pre-select presentation |
|
|
| `presenter_id` | ID | Pre-select presenter |
|
|
| `session_id` | ID | Pre-select session |
|
|
|
|
### Badges (`/events/[id]/badges/print_list`)
|
|
|
|
| Param | Values | Effect |
|
|
| --- | --- | --- |
|
|
| `printed_status` | filter value | Filter badge list by print status |
|
|
| `badge_type_code` | code string | Filter badge list by type |
|