# Deep-Dive Analysis — Rethink! EAM 2026 Vortragsportal

- **Project:** `rethink_dump`
- **Analyst:** Mary (BMAD Business Analyst persona), BMM v6.10.0
- **Date:** 2026-07-07
- **Scope:** Full project deep dive + offline-hardening plan and execution
- **Method:** Minto Pyramid (answer-first), evidence grounded in the repository files

---

## 1. Answer first (executive summary)

`rethink_dump` is a **single-purpose, dependency-free, static offline web portal** that renders
sessions of the *Rethink! EAM 2026* conference as filterable cards. Data originates from a
manual browser DOM capture of the [hubs101](https://app.hubs101.com) agenda app, stored as a raw
text dump, transformed by one Python script into a JSON manifest, and rendered client-side by a
single `app.js`. BMAD tooling (`_bmad/`, `.claude/skills/`) is installed but had produced no
artifacts yet.

The project's stated purpose is **100 % offline availability of all sessions, downloads, and
videos**. Before this pass it was *mostly* offline but had three concrete gaps that broke that
promise. All three are now closed (see §6).

---

## 2. System overview

```
Browser (hubs101 agenda)  ──manual capture──►  output/hubs101_agenda_dump.txt   (source of truth: raw)
                                                        │
                                              scripts/parse_sessions.py          (transform)
                                                        ▼
                                data/sessions.json  +  data/sessions.js          (manifest + file:// fallback)
                                downloads/attachments/<slug>.md                  (offline note per session)
                                downloads/videos/<slug>.html                     (offline video page per session)
                                                        │
                                       index.html + app.js + styles.css          (render layer)
                                                        ▼
                                            Filterable session-card UI
```

### Component inventory

| Component | File | Role |
|---|---|---|
| Raw agenda dump | `output/hubs101_agenda_dump.txt` | Human-captured source; 6 sessions, block format `=== Session N ===` |
| Parser | `scripts/parse_sessions.py` | Single reproducible transform → all generated artifacts |
| Session manifest | `data/sessions.json` | Machine-read data consumed by the UI |
| file:// fallback | `data/sessions.js` | Same data as `window.__SESSIONS__` so the app runs without a server |
| Offline notes | `downloads/attachments/<slug>.md` | Self-contained per-session archive (full text) |
| Offline video pages | `downloads/videos/<slug>.html` | Self-contained per-session player + drop-in slot for a real `.mp4` |
| App shell | `index.html` | Layout, hero, toolbar, script wiring |
| Renderer | `app.js` | Fetch/fallback data, search + type + date filters, card render |
| Styling | `styles.css` | Dark theme, responsive grid, no external fonts/CSS |

---

## 3. Data model

A session object (manifest schema):

| Field | Type | Notes |
|---|---|---|
| `id` | string | `session-<n>`, positional |
| `type` | enum | `NETWORKING` \| `OPENING` \| `PRESENTATION` (fallback `PRESENTATION`) |
| `date` / `time` / `timezone` | string | As captured, German locale |
| `location` | string | Room / area |
| `title` / `description` | string | `description` is bullet-flattened to one line for card display |
| `speaker` / `role` / `company` | string | May be empty (networking/track blocks) |
| `source` | string | Provenance pointer to the raw dump |
| `attachments[]` | array | `{label, file, kind, type}` — raw export, offline note, offline video |

**Captured content (updated 2026-07-07):** the **full agenda of both conference days — 62 sessions**
(35 on `Mo, 29.06.2026`, 27 on `Di, 30.06.2026`), pulled from the live we.CONECT/hubs101 API, not a
hand capture. Types: 27 PRESENTATION, 18 WORKSHOP, 10 NETWORKING, 2 OPENING, 2 CLOSING, 1 KEYNOTE,
1 DISCUSSION, 1 DEMO. Full descriptions and speaker biographies included. Source of truth is
`output/hubs101_agenda_full.json` (raw API response); the parser regenerates everything else from it.

> **Provenance:** the hubs101 app (`app.hubs101.com`) is a login-gated SPA and cannot be scraped
> headless. The same agenda is served publicly by the marketing backend at
> `https://api.we-conect.com/events/63507a6a-605d-411e-ba21-38c97fa6a768/agenda` (event UUID resolved
> from `api.we-conect.com/events`). That JSON is the authoritative offline capture.

---

## 4. Architecture assessment

**Strengths**
- **Zero runtime dependencies** — pure HTML/CSS/JS + one stdlib-only Python script. Nothing to
  install, nothing to break, trivially archivable.
- **Clean separation** raw → transform → manifest → view. Provenance is explicit (`source`).
- **XSS-safe render** — `escapeHtml()` applied to every interpolated field in `app.js`.
- **Deterministic parser** — regex block split, tolerant key/value parsing, safe type fallback.

**Risks / limitations (pre-pass)**
1. **`file://` breakage** — `fetch('./data/sessions.json')` fails under `file://` (CORS), so
   "just open index.html" did *not* work; a server was mandatory. → **fixed** via `sessions.js`.
2. **Parser drift** — `sessions.json` was hand-enriched with offline-note attachments the parser
   did not generate. Re-running the parser would have *deleted* that enrichment. → **fixed**: the
   parser is now the single source of truth for every attachment and offline file.
3. **Thin offline archive** — notes were metadata stubs without the session description, so the
   "offline note" did not actually preserve the session content. → **fixed**: notes now embed the
   full description and bullet list.
4. **No video layer** — the goal names videos, but no video structure existed. → **fixed**: a
   self-contained offline video page per session with a drop-in `.mp4` slot.
5. **Coverage** — *resolved.* The prior pass held only 6 hand-captured sessions. The full agenda for
   both days (62 sessions) is now captured from the public we.CONECT API and integrated. See §7 for
   the one remaining refresh caveat.

---

## 5. BMAD context

- Install: BMAD **v6.10.0**, module **bmm** (`software-development` team), languages English,
  user `Deltatree`, skill level intermediate.
- Agents available: Analyst (Mary), Tech Writer (Paige), PM (John), UX (Sally), Architect
  (Winston), Dev (Amelia).
- `_bmad-output/` (planning + implementation artifacts) and `docs/` were **empty** — this document
  is the first project-knowledge artifact.

---

## 6. Offline-hardening — what changed this pass

1. **Parser is now the single source of truth.** `scripts/parse_sessions.py` regenerates, from the
   one raw dump: `data/sessions.json`, `data/sessions.js`, every `downloads/attachments/<slug>.md`,
   and every `downloads/videos/<slug>.html`. One command reproduces the entire offline archive.
2. **Enriched offline notes** — each note now contains the full metadata *and* the complete
   description with bullet points preserved: a genuinely self-contained offline record.
3. **Offline video pages** — one self-contained HTML page per session, dark-themed, no external
   assets, with a `<video controls>` pointing at a local `./<slug>.mp4` drop-in slot and clear
   instructions. Linked from the manifest as an `Offline-Video` attachment.
4. **`file://` support** — `data/sessions.js` sets `window.__SESSIONS__`; `app.js` tries `fetch`
   first and falls back to the embedded global, so the portal works by double-clicking
   `index.html` with **no server required**. 100 % offline, zero network, zero dependencies.

---

## 7. Known limitations (explicit, not hidden)

- **The offline archive is a snapshot (captured 2026-07-07).** All 62 sessions of both days are
  present, but the live agenda can still change (added talks, room swaps). Changes are picked up only
  by re-pulling `output/hubs101_agenda_full.json` from the API and re-running the parser — see §8.
- **Speaker photos & company logos** — 178 real images (~6.3 MB) in `downloads/media/`, wired into
  cards (avatars) and notes.
- **Recordings & slide PDFs — obtained via authenticated hubs101 login (RPA).** The *public* agenda
  JSON has no media, but the logged-in API (`api.we-conect.com/api/v1`) exposes
  `/users/on-demand-videos` (10 recordings) and `/events/{id}/documents` (19 PDFs). Login was done
  with a real browser (Playwright/Chromium) because the API sits behind a WAF + JS SPA; the captured
  Bearer token then read the two lists (saved to `output/hubs101_on_demand_videos.json` and
  `output/hubs101_documents.json`).
  - **Videos** turned out to be **public/unlisted YouTube** links (we.CONECT channel), verified via
    oEmbed — reachable without an account. They are therefore linked (card badge + embedded player),
    not re-hosted. Real offline still supported via the `<slug>.mp4` drop-in slot.
  - **PDFs** are served *unauthenticated* on the media CDN, so `scripts/fetch_documents.py`
    re-downloads all 19 (~58 MB) with no login — fully reproducible.

---

## 8. How to reproduce / extend

```bash
# refresh the capture (offline snapshot of the live agenda)
EVENT=63507a6a-605d-411e-ba21-38c97fa6a768
curl -s -H "Origin: https://www.we-conect.com" -H "Referer: https://www.we-conect.com/" \
  "https://api.we-conect.com/events/$EVENT/agenda" > /tmp/agenda.json
# wrap into output/hubs101_agenda_full.json ({_meta, sessions, tracks}), then:

# regenerate the whole offline archive from the full JSON capture
python3 scripts/parse_sessions.py

# serve (optional — file:// also works)
python3 -m http.server 8000    # → http://127.0.0.1:8000/
```

The parser rebuilds the text dump, manifest, `file://` fallback, and one offline note + video page
per session. To add a real recording: copy `downloads/videos/<slug>.mp4` — the video page picks it
up with no code change.
</content>
