diff --git a/README.md b/README.md index 6dec16c..a3f4c17 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,10 @@ Docs: [Migrate from Slack](https://docs.mattermost.com/administration-guide/onbo - Python 3.10+ (stdlib only for server) - Official Slack export folder or enriched copy with `channels.json`, `users.json`, channel dirs +## Handoff + +Ongoing Levkin migration status, review order, and TODOs: **[docs/HANDOFF.md](docs/HANDOFF.md)** + ## Remote ```text diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md new file mode 100644 index 0000000..7c39d33 --- /dev/null +++ b/docs/HANDOFF.md @@ -0,0 +1,165 @@ +# slack-sieve — handoff + +**Repo:** https://git.levkin.ca/ilia/slack-sieve (public) +**Clone:** `git clone git@git.levkin.ca:ilia/slack-sieve.git` +**Last updated:** 2026-05-29 + +--- + +## What this is + +Local triage UI for migrating **Levkin** Slack (`levkine.slack.com`) → homelab Mattermost (`https://slack.levkin.ca`, VM `10.0.10.237`). + +Pipeline: + +```text +Official Slack export (JSON) + → make hydrate # __uploads/ via xoxe URLs in export + → make preset-skips # optional noise-channel skips + → make review # manifest.json (gitignored) + → prepare-export # TODO — filtered Slack-shaped folder/zip + → mmetl transform slack + → mmctl import +``` + +--- + +## Data on disk (Mac) + +| Path | Role | +|------|------| +| `~/Downloads/Levkin Slack export Sep 29 2016 - May 27 2026` | Raw official export (~27MB JSON only) | +| `~/Downloads/Levkin Slack export enriched` | **Use for review** — JSON + `__uploads/` (~1109 files) | +| `~/Documents/code/slack-sieve/manifest.json` | Triage decisions (local only, not in git) | + +Hydrate copied **1109 / 1122** attachments; **13** old files returned HTTP 401 (expired export token). + +--- + +## Commands + +```bash +cd ~/Documents/code/slack-sieve + +export SLACK_EXPORT_PATH="$HOME/Downloads/Levkin Slack export enriched" +make review # http://127.0.0.1:8765 + +make hydrate # re-download attachments if needed +make preset-skips # apply presets/levkin-skips.json (safe to re-run; keeps your channel decisions) +``` + +--- + +## Review progress (manifest snapshot) + +As of preset + partial manual review: + +| Status | Count | Channels | +|--------|-------|----------| +| **skip** (preset Tier A/B) | 22 | `#jewbottest`, `#meetings`, `#help`, `#baby`, `#garden`, `#recipes`, `#grants`, `#integromat`, `#clickup`, `#general`, `#after-school-activities`, `#cleaner`, `#medical`, `#purchase`, `#temp`, `#viewings`, `#moishe`, `#520steeles`, `#29wilson`, `#york`, `#jam`, Reading List | +| **import** | 1 | `#153niagara` | +| **partial** (cherry-pick) | 3 | `#122harmony`, `#6keefer`, `#zoey` | +| **undecided** | 14 | See review order below | + +Refresh counts after more review: + +```bash +python3 -c " +import json +from pathlib import Path +m = json.loads(Path('manifest.json').read_text()) +from collections import Counter +c = Counter(v.get('status','?') for v in m.get('channels',{}).values()) +print(dict(c)) +" +``` + +--- + +## Suggested review order + +1. `#284richmond` → `#45ritson` → finish `#122harmony`, `#6keefer`, `#zoey` (partial) +2. `#banking` → `#realestate` → `#airbnb` +3. `#izik` → `#levkin` +4. **Tier D (later):** `#random`, `#professional`, `#parenting`, `#adhd`, `#baking-biz`, `#standup`, `#zane` + +### Inside a channel + +- **Shift+S** — skip whole channel +- **Shift+I** — import whole channel +- **Cherry-pick mode** — only checked messages export (use **Import whole thread** on parent) +- **Skip:** join/leave noise, bot posts, bare “ok” / link-only +- **Keep:** attachments, leases, repairs, banking, decisions with dates/names + +--- + +## Presets + +`presets/levkin-skips.json` — Tier A/B channel names for `make preset-skips`. +Copy and edit for another workspace. + +--- + +## UI / server notes + +- **Port:** 8765 (`SLACK_IMPORT_PORT`) +- **Attachments:** served at `/uploads/…` and `/api/file-download?file_id=…` +- **DOCX preview:** server-side + browser mammoth; spaces in filenames need URL decode (fixed in server) +- Restart after code changes: `make review` (kill old process on 8765 if needed) + +--- + +## What not to use + +| Tool | Why | +|------|-----| +| `slack-advanced-exporter` + rotating `xoxe.xoxp` token | Token format rejected; enrich zip stayed ~4MB | +| `slackdump hydrate` | Rejects `?token=xoxe-…` URLs; use **this repo’s** `make hydrate` instead | +| `slackdump` browser login | Failed in headless/automated runs; not required if official export exists | + +--- + +## TODO (next implementer) + +1. **`scripts/prepare-export.py`** — read `manifest.json`, emit filtered Slack export dir/zip (`__uploads/` + selected JSON days, thread parents included). +2. **Pilot import** — one small channel through `mmetl` → `mmctl` on Mattermost VM; verify threads, files, users. +3. **User mapping** — optional `fetch-emails` or Slack ID → Mattermost username map for `mmetl`. +4. **Makefile** `make prepare-export` + doc section in README. + +### Mattermost / homelab + +- SSO: Authentik — see ansible `docs/guides/mattermost-authentik-gitlab-oauth.md` +- Import docs: https://docs.mattermost.com/administration-guide/onboard/migrate-from-slack.html + +--- + +## Repo layout + +```text +slack-sieve/ + server.py # HTTP API + static UI + slack_export.py # Parse export, file index, search + static/ # Review UI + scripts/ + hydrate-export.sh + preset-skips.py + presets/ + levkin-skips.json + manifest.json # gitignored — your work in progress + docs/ + HANDOFF.md # this file +``` + +--- + +## Moved from ansible + +Slack import tooling was removed from `git@git.levkin.ca:ilia/ansible.git` (2026-05-29). Ansible guide pointer: `docs/guides/slack-mattermost-import.md`. + +--- + +## Security + +- Do not commit `manifest.json` or Slack export folders. +- Rotate any Slack tokens/cookies pasted in chat during setup. +- `~/.config/hermes/gitea.env` used for Gitea API only — unrelated to Slack.