diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index da7c2dc..69f2e4f 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -6,7 +6,8 @@ This document captures current architectural intent. It is a planning artifact a Primary system responsibilities: -- Host and render DIY project content. +- Expose a stable HTTP API as the primary interface for all clients. +- Host and render DIY project content through a bundled web UI that consumes the public API. - Manage local accounts and authorization. - Federate selected objects and activities using ActivityPub. - Enforce local moderation policy for both local and remote content. @@ -24,13 +25,42 @@ Out of scope for early phases: - Moderation and trust policy. - Search and discovery. +## Client and Front-End Strategy + +The server exposes a stable, documented HTTP API as its primary interface. The bundled web UI is a first-party client of that same API — it receives no privileged server-side access that a third-party client could not also use. + +Principles: + +- **API-first**: every user-facing capability is reachable through the public API before the bundled UI uses it. +- **No server-side rendering shortcuts**: the bundled UI must not depend on server-internal state or bypass the API layer. +- **Third-party clients are first-class**: authentication, content negotiation, and capability negotiation must work the same way for any client origin. +- **Content negotiation**: the server responds to `Accept: application/activity+json` (or `application/ld+json`) for federation endpoints, and `Accept: application/json` for the API, allowing a single URL namespace to serve both. +- **CORS**: cross-origin API access is supported for read-only public resources, with authenticated endpoints requiring explicit opt-in by the instance operator. +- **Bundled UI is optional at deploy time**: an instance operator should be able to run the backend and serve their own front-end without modifying server code. + +API surface areas: + +- Public read API: browse projects, actors, and search without authentication. +- Authenticated user API: authoring, account management, preferences. +- Moderation API: moderation actions and audit review, scoped by role. +- Federation endpoints: ActivityPub inbox/outbox per the ActivityPub specification. +- Well-known endpoints: WebFinger, NodeInfo, and instance metadata. + +Bundled web UI: + +- Delivered as static assets served from the same origin. +- Communicates only through the public API. +- Treated as the reference client for API usability validation. +- Should degrade gracefully where JavaScript is unavailable where practical. + ## Logical Components -- API and web delivery layer. +- Public HTTP API layer (routing, auth middleware, content negotiation, CORS). - Domain service layer for project and account workflows. - Federation layer (inbox/outbox, signing, verification, retries). - Persistence layer for local and federated records. - Moderation policy engine and audit log. +- Bundled web UI (static asset delivery). - Background workers for delivery, indexing, and maintenance tasks. ## Data and Object Strategy @@ -56,11 +86,13 @@ Out of scope for early phases: ## Non-Functional Requirements - Reliability: resilient delivery and retry strategy for federated traffic. -- Security: signature verification, key management, least-privilege defaults. +- Security: signature verification, key management, least-privilege defaults, and safe CORS policy. - Performance: predictable latency for local reads and bounded queues for remote events. - Operability: metrics, logs, and runbooks for incident response. +- API stability: public API changes follow a deprecation policy; breaking changes require a version increment. ## Architecture Decision Practice -- Capture major decisions with lightweight ADRs in a future docs/adrs directory. -- Each ADR should include context, options considered, decision, and consequences. +- Decisions are captured as ADRs in [docs/adrs/](adrs/). +- Each ADR includes: context, options considered, decision, and consequences. +- See [ADR 0001: API-First with Bundled Web UI](adrs/0001-api-first-bundled-ui.md). diff --git a/docs/OPEN_QUESTIONS.md b/docs/OPEN_QUESTIONS.md new file mode 100644 index 0000000..d81ae9c --- /dev/null +++ b/docs/OPEN_QUESTIONS.md @@ -0,0 +1,237 @@ +# FeDIY Open Questions + +A living document of unresolved design and product questions. When a question is resolved, record the decision as an ADR and remove or archive the entry here. + +Each question is tagged with the phase it blocks or most affects: [P0], [P1], [P2], [P3], [P4]. + +--- + +## Domain Model + +**Q1 [P1]** What is the canonical structure of a "project"? + +- Is it steps + materials + media, or does it also include file attachments (patterns, templates, cut files)? +- Are steps ordered (sequential instructions) or unordered (reference material)? +- Do projects have explicit versioning/revision history, or only an updated timestamp? + +**Q2 [P1]** How are materials modelled? + +- Free-text only, or linked to a shared taxonomy/catalog? +- Do quantities and units need to be structured (for search/filtering), or is prose sufficient for MVP? + +**Q3 [P1]** What is the tag and category strategy? + +- Folksonomy (free-form user tags), curated taxonomy, or both? +- Is there a category hierarchy (craft type → technique → material)? +- Who controls the taxonomy on a given instance? + +**Q4 [P1]** What licences can a project carry? + +- Does the platform enforce a licence selection, or is it free-text? +- Does the platform's own CC BY-SA 4.0 licence apply to user content by default, or is that a separate question? + +**Q5 [P3/P4]** What are the rules for project forks and remixes? + +- Can a user fork another user's project (including from a remote instance)? +- Does a fork maintain a reference/attribution link to the original? +- What licence constraints apply to remixing? + +--- + +## Identity and Authentication + +**Q6 [P1]** What is the authentication mechanism? + +- Local username/password (with secure hashing), passkeys, OAuth2/OIDC third-party providers, magic-link email, or a combination? +- Is email verification required for account creation? + +**Q7 [P1]** What account fields are required beyond the ActivityPub actor minimum? + +- Display name, bio, avatar, location — which are required, optional, or omitted entirely? +- Are there craft-specific profile fields (preferred crafts, skill level)? + +**Q8 [P2]** Can remote ActivityPub actors interact without a local account? + +- Can a remote actor follow a local user, like a project, or comment, without registering locally? +- What local data is persisted for a remote actor who interacts? + +**Q9 [P1]** What is the session and token strategy for the API? + +- Short-lived JWTs, opaque bearer tokens with a refresh flow, or server-side sessions? +- How are tokens invalidated (logout, account suspension)? + +--- + +## API Design + +**Q10 [P1]** What API style? + +- REST with JSON, or something else (GraphQL, JSON:API)? +- Is there value in JSON:API's sparse fieldsets and relationship includes for a project-browsing use case? + +**Q11 [P1]** What is the API versioning strategy? + +- URL path prefix (`/api/v1/`), `Accept` header versioning, or no versioning until a breaking change forces it? + +**Q12 [P1]** What is the pagination strategy? + +- Cursor-based (stable under concurrent inserts), offset-based, or keyset pagination? +- What is the default and maximum page size? + +**Q13 [P1]** What rate-limiting and abuse-prevention strategy applies to the API? + +- Per-IP, per-authenticated-user, or both? +- Does this apply equally to federation endpoints? + +--- + +## Front-End / Bundled UI + +**Q14 [P1]** What technology powers the bundled web UI? + +- Vanilla JS / progressive enhancement (HTMX or similar), a Rust WASM front-end framework, or a JS framework (e.g. Svelte, Vue)? +- Does the choice live in the same Cargo workspace or a separate directory with its own build tooling? + +**Q15 [P1]** What is the no-JavaScript fallback scope? + +- Read-only browsing (project pages, search results) without JS is desirable. +- Authoring without JS is probably out of scope — is that an explicit decision? + +**Q16 [P1]** What is the accessibility baseline? + +- WCAG 2.1 AA as a minimum? +- Are there specific craft-community accessibility concerns (screen reader support for step-by-step instructions, colour contrast for pattern images)? + +--- + +## Federation and ActivityPub + +**Q17 [P2]** How do FeDIY project objects map to ActivityPub types? + +- Use `Note` or `Article` for broad compatibility, or define a custom `FeDIYProject` type? +- If custom, what fallback representation do we provide for clients that don't understand it? + +**Q18 [P2]** What ActivityPub activity types does FeDIY support in phase 2? + +- Minimum set: `Create`, `Update`, `Delete`, `Follow`, `Accept`, `Reject`, `Undo`. +- Phase 2 or later: `Like`, `Announce` (boost), `Flag` (report)? + +**Q19 [P2]** What is the media federation strategy? + +- Do media attachments (images, files) federate as links to the canonical origin, or are they replicated locally? +- How are broken/unavailable remote media handled in the UI? + +**Q20 [P2]** What is the HTTP Signatures key lifecycle? + +- Per-actor keypairs (standard), or instance-level signing with `keyId` delegation? +- Key rotation: when and how are keys rotated, and how are remote instances notified? + +**Q21 [P2]** Which well-known endpoints are in scope for phase 2? + +- WebFinger (required for actor discovery). +- NodeInfo (instance metadata for compatibility and listing services). +- `/.well-known/oauth-authorization-server` if OIDC is supported. + +**Q22 [P2]** How is WebFinger structured for FeDIY entities? + +- Actors are users: `acct:user@instance` — standard. +- Do projects also have addressable AP identities, or do they belong to the author actor? + +--- + +## Search and Discovery + +**Q23 [P1]** What is the full-text search implementation? + +- PostgreSQL full-text search (zero extra infra), an embedded engine (Tantivy via Rust), or an external service (Meilisearch, Elasticsearch)? +- What fields are indexed: title, description, steps, tags, materials? + +**Q24 [P2]** Does search span federated content? + +- Phase 1: local content only. +- Phase 2+: do we query remote instances, or build a local index of federated objects we've received? + +--- + +## Media Storage + +**Q25 [P1]** How are user-uploaded media assets stored? + +- Local filesystem, S3-compatible object storage, or both with a configurable backend? +- What is the maximum file size and permitted formats for MVP? + +**Q26 [P1]** Is image processing (resize, thumbnail, format conversion) in-process or delegated? + +- In-process with a Rust image library, or delegated to an external service/worker? + +--- + +## Persistence + +**Q27 [P0/P1]** What is the database? + +- PostgreSQL is the obvious choice given full-text search, JSONB for flexible AP object storage, and broad hosting support — is this confirmed? +- Is SQLite a supported option for lightweight self-hosting, or is that complexity not worth it? + +**Q28 [P1]** What is the database migration strategy? + +- A Rust migration library (sqlx migrate, refinery), or a standalone tool (Flyway, Liquibase)? + +--- + +## Moderation + +**Q29 [P1]** How are moderator roles assigned and scoped? + +- Instance admin assigns moderators manually; no self-service promotion. +- Are there multiple moderation tiers (e.g. content moderator vs instance admin)? + +**Q30 [P3]** Do we participate in shared blocklists (e.g. FIRES, Oliphant tiers)? + +- Subscribe to external block lists automatically, or manual import only? +- Is this a phase 3 concern or deferred entirely? + +**Q31 [P3]** What is the user-facing report and appeals workflow? + +- Can a user see the status of their own report? +- Is there a formal appeals process, or at moderator discretion? + +--- + +## Deployment and Operations + +**Q32 [P0/P1]** What is the primary deployment target? + +- Single static binary + external PostgreSQL (simplest self-hosting). +- OCI/Docker container image. +- NixOS module. +- All three, or a prioritised subset? + +**Q33 [P1]** What are the minimum self-hosting requirements? + +- RAM, CPU, disk, and network minimums for a small instance. +- Is there a single-binary mode with embedded SQLite for hobbyist hosting (see Q27)? + +**Q34 [P1]** What is the configuration strategy? + +- Environment variables only, a config file (TOML), or both? +- What must be configurable per-instance (instance name, federation policy, storage backend, SMTP, etc.)? + +**Q35 [P4]** What observability stack is expected? + +- Structured logging to stdout (12-factor), Prometheus metrics endpoint, OpenTelemetry traces? +- Are these required at launch or added progressively? + +--- + +## Content and Community Policy + +**Q36 [P0]** Does the platform define baseline content guidelines beyond what moderation tooling enforces? + +- What categories of content are prohibited regardless of instance policy? +- CSAM must be prohibited and reported — is there a mechanism planned? + +**Q37 [P4]** Are collaborative/co-authorship workflows in scope? + +- Can multiple accounts be listed as co-authors of a project? +- Is there a contribution workflow (pull-request style) or trust-based co-author invite? diff --git a/docs/README.md b/docs/README.md index b1a6685..7979d49 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,5 +5,7 @@ This directory contains product and technical planning documents for FeDIY. - [Roadmap](ROADMAP.md): phased milestones from MVP to broader federation support. - [Architecture](ARCHITECTURE.md): system boundaries, components, and design constraints. - [Workflow](WORKFLOW.md): Red-Green TDD/BDD delivery model and GitHub Flow branching policy. +- [Open Questions](OPEN_QUESTIONS.md): unresolved design and product decisions, tagged by phase. +- [ADRs](adrs/): architecture decision records. These docs are intended to evolve as priorities change. diff --git a/docs/adrs/0001-api-first-bundled-ui.md b/docs/adrs/0001-api-first-bundled-ui.md new file mode 100644 index 0000000..ebea54e --- /dev/null +++ b/docs/adrs/0001-api-first-bundled-ui.md @@ -0,0 +1,28 @@ +# ADR 0001: API-First Architecture with Bundled Web UI + +## Status + +Accepted + +## Context + +FeDIY needs to serve both a usable web interface for end users and the ActivityPub federation protocol for other instances. It must also not create barriers to third-party clients or alternative front-ends. Without an explicit policy, it is easy to accumulate shortcuts where the bundled UI is given privileged access to server internals, making it progressively harder for external clients to reach parity. + +## Options Considered + +1. **Server-side rendering only** — simpler initial delivery but couples the front-end tightly to server internals, making third-party clients second-class. +2. **Separate front-end service** — clean decoupling but adds operational complexity and a cross-origin story from day one. +3. **API-first with bundled UI as first-party client** — the server exposes a stable public API; the bundled UI is a client of that API, co-deployed as static assets from the same origin. + +## Decision + +Option 3. The server exposes a stable HTTP API as its primary interface. The bundled web UI is a first-party client of that API and receives no privileged access unavailable to third-party clients. The UI is delivered as static assets from the same origin and is optional at deploy time. + +## Consequences + +- Every capability must be reachable through the public API before the bundled UI uses it. This creates a useful constraint that keeps the API complete. +- Content negotiation (ActivityPub vs JSON API) is required at the same URL namespace. +- CORS policy must be explicit and safe by default. +- Third-party clients and alternative front-ends are supported without server changes. +- The bundled UI serves as the reference implementation for API usability validation. +- The API surface must be versioned and changes must follow a deprecation policy.