Validate channel name exists on the instance when creating a channel #114

Closed
opened 2026-08-01 08:47:27 +02:00 by myrmidex · 0 comments
Owner

Summary

When creating a channel, the name is typed free-hand and only validated for format — not for whether the community actually exists on the selected instance. A typo produces a channel that looks fine in the UI but fails at publish time.

Current state

app/Livewire/Channels.php::createChannel() validates:

'newName' => [
    'required', 'string', 'max:255',
    'regex:/^[a-z0-9_]+$/',
    Rule::unique('platform_channels', 'name')
        ->where('platform_instance_id', $this->newPlatformInstanceId),
],

So regex catches malformed slugs and unique catches duplicates — but a well-formed name for a community that does not exist passes validation.

The name doubles as the Lemmy community slug: CreateChannelAction copies name into channel_id, which is used verbatim for community lookup at publish time (see the comment in createChannel()).

Failure mode

  1. User types a slug with a typo
  2. Channel is created successfully, appears active in the UI
  3. Publishing fails later when LemmyApiService::resolveCommunityId() cannot resolve it
  4. The failure surfaces in a queue job, not at the point of the mistake

Existing building block

app/Modules/Lemmy/Services/LemmyApiService.php already has what is needed:

  • getCommunityId(string $communityName, string $token): int — queries the instance's community endpoint by name and throws if not found
  • resolveCommunityId(string $channelId, string $token): int — handles the slug-vs-numeric case

So existence checking is a matter of calling the existing method at create time, not writing new API code.

Two possible approaches

A. Validate on submit — keep the text input, call getCommunityId() during createChannel(), and surface a field error if the community is not found.

  • Smaller change, fits the existing addError() pattern already used for RuntimeException
  • Still requires the user to type the slug correctly
  • One API call per submit

B. Replace the input with a select — fetch the instance's communities and let the user pick.

  • Eliminates typos entirely, better UX
  • Needs a way to list communities (the current service only looks up one by name — check whether the Lemmy API list endpoint is available and paginated)
  • Requires the instance to be chosen first, so the select must repopulate reactively via updatedNewPlatformInstanceId()
  • Instances can host thousands of communities — a plain select may not scale, and a searchable/autocomplete control may be needed
  • Needs a fallback when the instance is unreachable, otherwise channel creation is blocked entirely

Recommendation

Worth considering A first, B second. A closes the correctness gap immediately with a small, well-tested change; B is the better experience but carries open questions (listing endpoint, pagination, scale, offline fallback) that deserve their own scoping.

Happy to be overruled if the select is wanted outright — noting the trade-off rather than deciding it.

Acceptance criteria

  • Creating a channel with a non-existent community name is rejected
  • The error is surfaced as a field-scoped form error, not a 500
  • Instance unreachable / API failure does not produce an unhandled exception — decide whether it blocks creation or warns
  • Existing ChannelsTest coverage still passes
  • New tests cover: valid community accepted, invalid rejected, API failure handled
  • API calls are mocked in tests — see the LemmyApiService mocking notes in .claude/PLATFORM.md, since it takes a per-instance URL and cannot be container-resolved

Same create path hardened in #106 (channel_id integrity).

## Summary When creating a channel, the name is typed free-hand and only validated for **format** — not for whether the community actually exists on the selected instance. A typo produces a channel that looks fine in the UI but fails at publish time. ## Current state `app/Livewire/Channels.php::createChannel()` validates: ```php 'newName' => [ 'required', 'string', 'max:255', 'regex:/^[a-z0-9_]+$/', Rule::unique('platform_channels', 'name') ->where('platform_instance_id', $this->newPlatformInstanceId), ], ``` So `regex` catches malformed slugs and `unique` catches duplicates — but a well-formed name for a community that does not exist passes validation. The name doubles as the Lemmy community slug: `CreateChannelAction` copies `name` into `channel_id`, which is used verbatim for community lookup at publish time (see the comment in `createChannel()`). ## Failure mode 1. User types a slug with a typo 2. Channel is created successfully, appears active in the UI 3. Publishing fails later when `LemmyApiService::resolveCommunityId()` cannot resolve it 4. The failure surfaces in a queue job, not at the point of the mistake ## Existing building block `app/Modules/Lemmy/Services/LemmyApiService.php` already has what is needed: - `getCommunityId(string $communityName, string $token): int` — queries the instance's `community` endpoint by name and throws if not found - `resolveCommunityId(string $channelId, string $token): int` — handles the slug-vs-numeric case So existence checking is a matter of calling the existing method at create time, not writing new API code. ## Two possible approaches **A. Validate on submit** — keep the text input, call `getCommunityId()` during `createChannel()`, and surface a field error if the community is not found. - Smaller change, fits the existing `addError()` pattern already used for `RuntimeException` - Still requires the user to type the slug correctly - One API call per submit **B. Replace the input with a select** — fetch the instance's communities and let the user pick. - Eliminates typos entirely, better UX - Needs a way to list communities (the current service only looks up one by name — check whether the Lemmy API list endpoint is available and paginated) - Requires the instance to be chosen first, so the select must repopulate reactively via `updatedNewPlatformInstanceId()` - Instances can host thousands of communities — a plain select may not scale, and a searchable/autocomplete control may be needed - Needs a fallback when the instance is unreachable, otherwise channel creation is blocked entirely ## Recommendation Worth considering **A first, B second**. A closes the correctness gap immediately with a small, well-tested change; B is the better experience but carries open questions (listing endpoint, pagination, scale, offline fallback) that deserve their own scoping. Happy to be overruled if the select is wanted outright — noting the trade-off rather than deciding it. ## Acceptance criteria - [ ] Creating a channel with a non-existent community name is rejected - [ ] The error is surfaced as a field-scoped form error, not a 500 - [ ] Instance unreachable / API failure does not produce an unhandled exception — decide whether it blocks creation or warns - [ ] Existing `ChannelsTest` coverage still passes - [ ] New tests cover: valid community accepted, invalid rejected, API failure handled - [ ] API calls are mocked in tests — see the `LemmyApiService` mocking notes in `.claude/PLATFORM.md`, since it takes a per-instance URL and cannot be container-resolved ## Related Same create path hardened in #106 (channel_id integrity).
myrmidex added this to the v1.4.0 milestone 2026-08-01 08:47:27 +02:00
myrmidex added the
enhancement
label 2026-08-01 08:47:27 +02:00
myrmidex self-assigned this 2026-08-01 08:47:28 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lvl0/fedi-feed-router#114
No description provided.