docs: split-domain handles idea + interop constraint for the trails check
Prompted by Hollo's split-domain setup. Two parts:
- docs/ideas/split-domain-handles.md: offering split handle/server
domains to self-hosters is config-level work — Fedify's origin
option natively accepts { handleHost, webOrigin } — and handles are
permanent identity, so apex handles matter. Single-domain stays the
default (Decision #18); post-launch polish.
- Interop constraint pinned in social-federation task 6.1 and
route-federation's gating decision: the trails-to-trails NodeInfo
check must run against the actor IRI's host after WebFinger
resolution, never the handle's domain — split-domain remote
instances would otherwise be wrongly refused.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
76b468d422
commit
bf907976c4
4 changed files with 62 additions and 0 deletions
55
docs/ideas/split-domain-handles.md
Normal file
55
docs/ideas/split-domain-handles.md
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# Split-domain handles for self-hosters
|
||||
|
||||
Pre-spec exploration (2026-06-07), prompted by Hollo's split-domain
|
||||
setup (https://docs.hollo.social/install/split-domain/).
|
||||
|
||||
## What it is
|
||||
|
||||
Letting the **handle domain** differ from the **server domain**:
|
||||
`@bob@example.com` while the journal runs at `trails.example.com`.
|
||||
The apex only has to serve (or redirect) `/.well-known/webfinger`;
|
||||
actor IRIs, inbox/outbox, and the web UI all live on the server
|
||||
domain. Mastodon (`WEB_DOMAIN`/`LOCAL_DOMAIN`), GoToSocial
|
||||
(host/account-domain), and Hollo all support this.
|
||||
|
||||
## Why it matters for trails.cool specifically
|
||||
|
||||
- Fediverse handles are **permanent identity** — you cannot migrate
|
||||
`@bob@trails.example.com` to `@bob@example.com` later. Self-hosters
|
||||
who care about their handle want the apex in it from day one.
|
||||
- Most apexes are taken (a website, an existing service): the operator
|
||||
case in this very project — `social.ullrich.is` exists because
|
||||
`ullrich.is` was occupied; split-domain would have allowed
|
||||
`@ullrich@ullrich.is`.
|
||||
- A self-hosting-first platform that forces "handle = wherever you can
|
||||
host a Node app" is leaving its best identity feature on the table.
|
||||
|
||||
## Why it's cheap for us
|
||||
|
||||
Architecture Resolved Decision #18 (single domain) was justified as
|
||||
"avoids WebFinger complexity" — but Fedify natively supports the split:
|
||||
the `origin` option we already pass to `createFederation` accepts
|
||||
`{ handleHost, webOrigin }` instead of a string (since Fedify 1.5).
|
||||
Our side would be roughly:
|
||||
|
||||
1. Optional `HANDLE_DOMAIN` env (defaults to `DOMAIN` — Decision #18
|
||||
stays the default)
|
||||
2. Pass `origin: { handleHost: HANDLE_DOMAIN, webOrigin: ORIGIN }`
|
||||
3. Audit the places that build handles vs URLs (`localActorIri` builds
|
||||
URLs — already correct; acct: construction, `users.domain` column
|
||||
semantics, profile `@user@domain` rendering)
|
||||
4. Self-hoster docs: one redirect rule on the apex
|
||||
(`/.well-known/webfinger` → server domain), like Hollo's guide
|
||||
|
||||
## Interop direction (already a constraint, not an idea)
|
||||
|
||||
Regardless of whether WE offer split domains, remote instances use
|
||||
them — the trails-to-trails check must run against the **actor IRI's
|
||||
host** after WebFinger resolution, never the handle's domain. Pinned in
|
||||
`social-federation` task 6.1 and `route-federation`'s gating decision.
|
||||
|
||||
## Scope guess
|
||||
|
||||
Config + audit + docs + a two-domain test in the (future) two-instance
|
||||
integration environment. Post-launch self-hosting polish; pairs with
|
||||
the broader self-host packaging story.
|
||||
|
|
@ -89,3 +89,4 @@ See `docs/ideas/` for pre-spec explorations:
|
|||
- `activity-participants.md` — tag co-riders on shared activities, confirm/decline, federated mentions
|
||||
- `multi-day-collections.md` — activity collections for multi-day trips (architecture open question #1)
|
||||
- `fediverse-enhancements.md` — post-v1 federation: map images in Notes, fediverse kudos, comments, Events/Mobilizon, Wanderer interop, federated explore
|
||||
- `split-domain-handles.md` — `@bob@example.com` handles while the journal runs on a subdomain (Hollo/Mastodon-style; Fedify supports it natively)
|
||||
|
|
|
|||
|
|
@ -71,6 +71,11 @@ activities are neither delivered to nor accepted from non-trails
|
|||
instances. (The Wanderer-interop idea would widen this allowlist —
|
||||
explicitly out of scope here.)
|
||||
|
||||
Split-domain interop: the check runs against the **actor IRI's host**
|
||||
(server domain) after WebFinger resolution, never the handle's domain —
|
||||
remote instances may run Hollo/Mastodon-style split domains. See
|
||||
`docs/ideas/split-domain-handles.md`.
|
||||
|
||||
### Decision: Sync check is a pg-boss cron, owner-driven re-fetch
|
||||
|
||||
Daily job on the *mirror-holding* instance: for each mirror whose
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
## 6. Outbound follow + trails-to-trails check
|
||||
|
||||
- [ ] 6.1 Update `followUser` to allow remote IRIs; before creating, fetch the remote actor object and inspect `software`/discovery endpoint
|
||||
> Split-domain interop constraint (2026-06-07): resolve the handle via WebFinger first, then run the NodeInfo/`software` check against the **actor IRI's host** (the server domain), never the handle's domain — Hollo/Mastodon-style split-domain instances (`@user@example.com` served from `social.example.com`) would otherwise be wrongly refused. See `docs/ideas/split-domain-handles.md`.
|
||||
- [ ] 6.2 Implement `/.well-known/trails-cool` endpoint on our side (publishes our software identity) so other trails instances recognize us
|
||||
- [ ] 6.3 If the discovery check fails, return 4xx with a clear "outbound federation to non-trails instances isn't supported yet" message + docs link
|
||||
- [ ] 6.4 If the check passes, write follow row with `accepted_at = NULL`, push `Follow` activity to remote inbox
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue