Add migration handoff doc with review status and next steps.

Documents Levkin paths, manifest progress, triage order, and
prepare-export/mmetl TODOs for the next session.
This commit is contained in:
2026-05-29 14:02:18 -04:00
parent 1ce803fc9c
commit e513d2a045
2 changed files with 169 additions and 0 deletions
+165
View File
@@ -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.