diff --git a/CLAUDE.md b/CLAUDE.md index 4a86513..79024e2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -37,26 +37,19 @@ actor-scoped route gets a name in the same spirit, agreed with the owner, and a | Thing | Route | |---|---| -| Actor | `/peasants/{name}` (`/users/{name}` 301-redirects here) | +| Actor | `/peasants/{name}` (`/users/{name}` 301-redirects here; browsers are sent to `/@{name}`) | | Inbox | `/peasants/{name}/mouth` | -| Outbox | `/peasants/{name}/anus` | +| Outbox | `/peasants/{name}/anus` (`?page=true[&max_id=]` for pages) | | Shared inbox | `/human-centipede` (also `/peasants/{name}/human-centipede`) | +| Followers | `/peasants/{name}/groupies` | +| Following | `/peasants/{name}/stalking` | +| Notes | `/peasants/{name}/scribbles/{id}` | +| Activities | `/peasants/{name}/grunts/{id}` (`create-{postId}` resolves) | +| DM context | `/peasants/{name}/whispers/{id}` | | Token refresh | `/clientapi/user/sniff/again` | -These are agreed for the roadmap and replace the conventional names still in the code today: - -| Thing | Route | Replaces | -|---|---|---| -| Followers | `/groupies` | `/followers` | -| Following | `/stalking` | `/following` | -| Notes | `/scribbles/{id}` | `/posts/{id}` | -| Activities | `/grunts/{id}` | `/activities/{id}` | -| Replies, likes, shares | `/gossip`, `/drool`, `/echoes` | | -| Featured | `/trophies` | | -| Featured tags | `/tattoos` | | -| Group members | `/flock` | | -| Group moderators | `/wardens` | | -| DM context | `/whispers/{id}` | | +Agreed for later phases: `/gossip`, `/drool`, `/echoes` (replies, likes, shares), `/trophies` (featured), `/tattoos` +(featured tags), `/flock` and `/wardens` (group members and moderators). Routes other software looks up by name stay conventional: - `/.well-known/*` and `/nodeinfo/*`; @@ -75,6 +68,8 @@ PrivaPub/ ASP.NET Core Web API, net10.0 Group, Post (posts + DMs), Admin, Data Infrastructure/ Http/ FederationHttp + SafeHttpHandlerFactory + IpRangeGuard: the only way out + Jobs/ JobQueue (leases), JobWorker, Backoff, HostCircuitBreaker + Ids/ PrivacyIds (day-only ids for personas and groups, published-time ids for remote posts) Data/ Indexes (created at start), EntityMaps.Warm, Migrations/_NNN_*.cs Cli/ AdminCommands (`PrivaPub admin promote|demote `) RateLimiting.cs accounts (per client address) and inbox (per sending origin) policies @@ -83,13 +78,18 @@ PrivaPub/ ASP.NET Core Web API, net10.0 WellKnownController (webfinger, nodeinfo), UsersController (redirect) Actors/ LocalActorService (LocalActor, Keys, ReservedName), RemoteActorService (authoritative fetch, key verification, WebFinger), ActorDocument (parser) - Objects/ Origin (same-origin rules), ContentSanitizer (HtmlSanitizer, Mastodon allowlist) + Objects/ Origin, ActivityJson, NoteParser, Addressing, ContentSanitizer + Moderation/ DomainBlocks (suspend / silence / reject media) Signing/ HttpSignatures (draft-cavage sign/verify) - Inbox/ InboxService (Follow/Undo/Create/Delete/Update) - Outbox/ DeliveryService + DeliveryWorker - Rendering/ ActivityPubRenderer (JsonObject builders) + Inbox/ InboxReceiver (verify, queue, 202) → InboxProcessor (job) → Handlers/{Follow,Undo,Create,Update,Delete} + Outbox/ DeliveryService (queues jobs) + DeliveryJobHandler + Rendering/ ActivityPubRenderer (Mastodon @context, actors, notes, collections) + Domain/ + Content/ ContentRenderer (Markdown or plain text → HTML with h-card mentions and hashtags) + Privacy/ VisibilityPolicy (IsPublic expression, CanSee) + Web/Pages/ Razor: /@{user}, /@{user}/{id} (public posts only, strict CSP, noindex) Services/ RootUsersService, GroupUsersService, PostsService, AppConfigurationService, … - Models/ Mongo entities: User/, Group/, Post/, Federation/, AppConfiguration + Models/ Mongo entities: User/, Group/, Post/, Federation/, Jobs/, AppConfiguration StaticServices/ DbEntities (Find accessors), AuthTokenManager (JWT), PasswordHasher Data/InitDb.cs first-run seeding (languages) PrivaPub.ClientModels/ DTOs + validation resources shared with clients @@ -157,8 +157,13 @@ cd /var/www/privapub.thepra.dev && sudo -u www-data ASPNETCORE_ENVIRONMENT=Produ 8. **Circles never federate.** A circle's actor, collections, WebFinger and inbox answer 404, and its posts are `IsLocalOnly`. Only communities are Group actors. 9. **A DM joins a conversation only by `DmGroup.ParticipantsKey`**, the exact set of its participants; a remote - `context` decides nothing. -10. **Durable delivery:** activities go out through the delivery queue, never inline in a request. + `context` decides nothing. DMs are `Post`s with `Visibility = Direct` and a `ConversationId` (`DmPost` is legacy). +10. **Nothing slow happens inside a request.** Deliveries and inbox processing are `Job`s (`Infrastructure/Jobs`): + leased, retried on Mastodon's curve, at most two per host, paused per host by `RemoteInstance`. The inbox answers + 202 once it has verified and queued; a handler must be idempotent (unique `ObjectURI`, job `DedupeKey`). +11. **Every "may anyone see this" goes through `VisibilityPolicy.IsPublic`;** a persona-specific read uses `CanSee`. +12. **Remote content is stored only when someone here asked for it:** a local persona addressed or mentioned, a reply to + a local post, or a community the author follows. Followers-only is detected by the author's stored `followers` URL. ## Privacy invariants