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
|
- `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)
|
- `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
|
- `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 —
|
instances. (The Wanderer-interop idea would widen this allowlist —
|
||||||
explicitly out of scope here.)
|
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
|
### Decision: Sync check is a pg-boss cron, owner-driven re-fetch
|
||||||
|
|
||||||
Daily job on the *mirror-holding* instance: for each mirror whose
|
Daily job on the *mirror-holding* instance: for each mirror whose
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@
|
||||||
## 6. Outbound follow + trails-to-trails check
|
## 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
|
- [ ] 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.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.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
|
- [ ] 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