---
path: /messaging/telegram-channels
surface: admin
domain: cross-product
auth: signed-in (admin)
source: apps/oshun/admin/src/app/messaging/telegram-channels/page.tsx
status: drafted
last_walked: '—'
---

# Cross-product · Telegram channels

## Purpose

Operator-only registry for public Telegram channels bound to editorial
pipelines, takedowns, disclosure copy, and crisis suppression. Cross-product
surface: pairs editorial domain content (Veritas / Nyx / Tara / Arete / Nisaba)
with the Telegram channel boundary policy from `@oshun/messaging-channels`.

## Entry points

- Direct URL — `/messaging/telegram-channels` (the `/messaging` parent has no
  index page)
- External runbooks / deep links
- Not in canonical admin IA — no sidebar entry from `AdminSidebar`

## Layout regions

Page does NOT wrap the body in `AdminShell`. Renders a plain
`<main className="adminPage">`:

- **adminHeader** — eyebrow "Messaging"; h1 "Telegram channels"; copy describing
  the operator registry; when a `telegramChannelBoundary()` exists, a
  `<dl className="boundaryStrip">` surfaces Residency, Retention, Consent,
  Disclosure values from `CHANNEL_BOUNDARIES` (filtered to
  `channelId === 'telegram-channel'`)
- **adminTable** — six columns: Channel / Domain / Pipeline / Owner role /
  Crisis suppression / Actions. Rows from `SEED_BINDINGS` (five hardcoded
  channels: `@oshun_veritas`, `@oshun_nyx`, `@oshun_tara`, `@oshun_arete`,
  `@oshun_nisaba`)
- **adminSection (bind form)** — h2 "Bind a Telegram channel"; form fields
  Channel handle (pattern `@.+`), Domain select (5 options), Editorial pipeline
  select, Owner role input, Locale input, Audited rationale textarea, "Bind
  channel" submit
- **adminFootnote** — explanation of how `takedownTelegramChannelPost` edits or
  publishes a correction notice

## States

- [ ] Anonymous → global middleware redirects
- [ ] Boundary present (default true; `CHANNEL_BOUNDARIES` includes
      `telegram-channel`) → boundary strip renders
- [ ] Boundary missing → `boundaryStrip` omitted (`boundary !==     undefined`
      guard)
- [ ] Table populated from `SEED_BINDINGS` constant — always 5 rows
- [ ] Crisis suppression toggle on each row reflects
      `binding.crisisSuppressionEnabled` (all `true` in seed data)
- [ ] Post preview `<details>` element collapsed by default; opens to show
      `synthesizeTelegramChannelPost` output

## Interactions

- [ ] **Crisis suppression toggle** (per row)
  - Function: `<form action={toggleCrisisSuppression}>` with hidden `handle`
    input; submit dispatches the server action
  - `aria-pressed={binding.crisisSuppressionEnabled}`
- [ ] **Takedown form** (per row)
  - Hidden `handle` input; **Rationale** input (default
    `Takedown <handle> — audited reason`); **Takedown** submit; calls
    `takedownTelegramChannel` server action
- [ ] **Post preview** (`<details>` / `<summary>`)
  - Summary: "Post preview"; pre-formatted body from `previewPost(binding)`
    (uses `synthesizeTelegramChannelPost`)
- [ ] **Bind channel form** (bottom)
  - **Channel handle** input — required, pattern `@.+`, default `@oshun_metis`
  - **Domain select** — 5 options (tara / arete / veritas / nyx / nisaba);
    default `tara`
  - **Editorial pipeline select** — 5 options from `PIPELINES`; default
    `arete-weekly-reflection`
  - **Owner role** input — required; default `Editor`
  - **Locale** input — required; default `en-US`
  - **Audited rationale** textarea — required; default copy
  - **Bind channel** (submit) — calls `bindTelegramChannel` server action

## Data & contracts

- **Reads**:
  - `CHANNEL_BOUNDARIES` from `@oshun/messaging-channels` (module constant)
  - `SEED_BINDINGS` — 5 hardcoded channel bindings in the page file
  - `PIPELINES` — 5 hardcoded pipeline id/label pairs
- **Writes**: three server actions from
  `apps/oshun/admin/src/app/messaging/telegram-channels/actions.ts`:
  - `bindTelegramChannel` (form action)
  - `takedownTelegramChannel` (form action)
  - `toggleCrisisSuppression` (form action)
- **Helpers used at render**:
  - `synthesizeTelegramChannelPost(channel, content)` produces the preview body
  - `takedownTelegramChannelPost(message)` produces the action (`edit` vs
    `correction-notice`) — surfaced in the footnote
- **Realtime**: _None._
- **Auth/role check**: only the global middleware (no session fetch in the page;
  no scope check)

## Cross-references

- Shell: `shell/02-routing-layouts.md`
- Not in canonical IA — `/messaging` parent has no index page
- Library: `@oshun/messaging-channels` — `CHANNEL_BOUNDARIES`,
  `synthesizeTelegramChannelPost`, `takedownTelegramChannelPost`,
  `EditorialDomain`
- Server actions:
  `apps/oshun/admin/src/app/messaging/telegram-channels/actions.ts`
- Related canonical workspace: `../workspaces/content/editorial.md` (editorial
  pipelines are the upstream source of channel posts)
- V1 PWA relationship: Telegram bot CTA appears on the V1 PWA home
  (`WALKTHROUGH/customer/02-home-discovery/home.md` companion bridge rail); the
  admin side governs the channel registry

## Open questions / known gaps

- [ ] `SEED_BINDINGS` is hardcoded in the page file; document where the
      production registry lives and how it replaces the seed data
- [ ] No session / scope check — the page uses server actions but relies
      entirely on middleware to gate access. Consider promoting to the canonical
      workspace pattern
- [ ] Form fields have minimal client-side validation; document the
      server-action validation contracts (handle pattern, locale format,
      rationale length)
