diff --git a/.claude/commands/push.md b/.claude/commands/push.md index 92fe2f650..812508ca9 100644 --- a/.claude/commands/push.md +++ b/.claude/commands/push.md @@ -3,20 +3,15 @@ name: push description: Run pre-push checks including typecheck and tests --- -Run the following pre-push checks to ensure code quality before pushing to remote: +Run pre-push checks before pushing to remote: -1. **Type checking**: Run `yarn typecheck` to check for TypeScript errors -2. if you find any errors. fix them. -3. comment this lines in "dev" file: -``` -run("node scripts/cleanup-desktop.js") -run("./scripts/cleanup-frontend.sh") -``` -4. **Tests**: Run `./dev build-desktop && yarn web:prod` to ensure the apps build properly and tests pass -5. uncomment the lines in the "dev" file. -6. if there are any changes you made to fix the typecheck, commit with `--amend` the changes keeping the same message code. no need to change the commit message, just add the new changed files. -7. git pull -8. git push -9. **Report results**: Provide a summary of which checks passed or failed +1. **Type checking**: run `pnpm typecheck` from the repo root. +2. **Tests**: run `pnpm test` from the repo root. +3. **Build smoke checks**: run `./dev build-desktop` and `pnpm web:prod` when the changed files can affect desktop or + web builds. +4. **Formatting**: run `pnpm format:write` if the checks or edits touched formatted files. +5. If a check fails, fix it in place and rerun the failed command. +6. Report which checks passed or failed and include any remaining errors. -If any checks fails and you cannot fix it, describe that in the report, provide details about the errors so they can be fixed before pushing. \ No newline at end of file +Do not edit `dev` just to run these checks. Do not amend, pull, or push unless the user explicitly asked for git +changes. diff --git a/.cursor/rules/web.mdc b/.cursor/rules/web.mdc index 81019eb93..09891a100 100644 --- a/.cursor/rules/web.mdc +++ b/.cursor/rules/web.mdc @@ -1,14 +1,19 @@ --- -description: -globs: +description: +globs: alwaysApply: true --- -This mostly includes details about `frontend/apps/web` + +This mostly includes details about `frontend/apps/web`. # Tests -Run tests for things in the `frontend/apps/web`, if there is a test file present. Do this automatically without me asking you! +Run tests for things in `frontend/apps/web` automatically when there is a relevant test file. + +Use pnpm from the repo root: -Run the tests by running `yarn web:test run ` in the repo root. If you forget to include `run`, you will be stuck in watch mode! Orjust `yarn web:test run` to run all web test. Also you can run `yarn workspace @shm/shared test run` for tests in `frontend/packages/shared` +- `pnpm --filter @shm/web test -- ` for one web test file. +- `pnpm web:test` for all web tests. +- `pnpm --filter @shm/shared test -- ` for relevant shared package tests. -If you are working on something that is easily tested, you can offer to create a test \ No newline at end of file +If you are working on something that is easily tested, offer to create or update a test. diff --git a/AGENTS.md b/AGENTS.md index 2612e4475..7101c2c44 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,6 +28,8 @@ ## Workflow +- For cross-subsystem work, read `docs/README.md`, `docs/code-map.md`, and the relevant glossary or architecture doc + before planning or making changes. - Ask clarifying questions when ambiguity matters. - Use OS temp dir for scratch files. Clean up after you're done. - Ask for elevated permissions instead of working around sandboxing issues (if you can run in a sandbox). diff --git a/README.md b/README.md index a8bf87469..2f7c531cd 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,13 @@ # Seed -Seed is a decentralized knowledge collaboration application for open -communities powered by a knowledge graph. +Seed is a decentralized knowledge collaboration application for open communities powered by a knowledge graph. You can read more about the product and why we are here on our website: https://seed.hyper.media. ### Hypermedia Protocol -Seed Hypermedia is powered by the new [Hypermedia Web Protocol](https://hyper.media). This -open protocol provides secure identities, version control, semantic documents, multimedia, -and groups/organizations. +Seed Hypermedia is powered by the new [Hypermedia Web Protocol](https://hyper.media). This open protocol provides secure +identities, version control, semantic documents, multimedia, and groups/organizations. ### Desktop App + Web Server @@ -20,32 +18,39 @@ This repo includes: ## ⚠️ Stability -This is software is being actively developed, and may contain bugs and rough edges. -We appreciate any feedback and bug reports, so if you find any, please open an issue. +This is software is being actively developed, and may contain bugs and rough edges. We appreciate any feedback and bug +reports, so if you find any, please open an issue. -The permanent data format has been declared stable, and we don't expect any breaking changes there. -Documentation is still missing though, but it will come. +The permanent data format has been declared stable, and we don't expect any breaking changes there. Documentation is +still missing though, but it will come. -We still recommend you to have a copy of anything valuable you put into the app, while we are polishing it, -and improving the overall stability. +We still recommend you to have a copy of anything valuable you put into the app, while we are polishing it, and +improving the overall stability. ## Dev Environment -See the [developer setup](./docs/docs/dev-setup.md) page for detailed instructions. +See the [developer setup](./docs/dev-setup.md) page for detailed instructions. -The dev environment on macOS+Linux uses the [Mise](https://mise.jdx.dev), -and [Direnv](https://direnv.net). +## Contributor orientation -The bare minimum required for compilation is to have Go, and NodeJS toolchains -installed. +Start with the [Seed Builder Guide](./docs/README.md) when building or fixing across subsystems. Useful entry points: + +- [Domain glossary](./docs/domain/glossary.md) for account/key/vault/document/resource terminology. +- [Architecture overview](./docs/architecture/overview.md) for runtime boundaries and sources of truth. +- [Code map](./docs/code-map.md) for "if touching X, start here" file lists. +- [Frontend map](./frontend/README.md) and [backend map](./backend/README.md) for subsystem-specific orientation. + +The dev environment on macOS+Linux uses the [Mise](https://mise.jdx.dev), and [Direnv](https://direnv.net). + +The bare minimum required for compilation is to have Go, and NodeJS toolchains installed. [./dev](./dev) is the main dev CLI. Run `./dev` to list commands, including: - `./dev run-desktop` - `./dev run-desktop-mainnet` - `./dev build-desktop` -- `./dev run-site` -- `./dev build-site` +- `./dev run-web` +- `./dev build-web` To run the dev build with the production network, use the following command: @@ -58,22 +63,20 @@ SEED_P2P_TESTNET_NAME="" ./dev run-desktop ```bash pnpm test # test all the packages pnpm desktop:test # test desktop app (e2e only now) -pnpm site:test # test only site code (WIP) +pnpm web:test # test only web app code ``` ## Web Build ## Group sites -Group sites need two programs to run. The daemon which includes the P2P node (go app) -and the frontend that renders documents (nextjs app). However for a production -deployment everything is orchestrated by docker compose. Read next sections for how to -either deploy a site on a production server or run it locally in dev mode +Group sites need two programs to run. The daemon which includes the P2P node (go app) and the frontend that renders +documents (Remix app). However for a production deployment everything is orchestrated by docker compose. Read next +sections for how to either deploy a site on a production server or run it locally in dev mode ### Deploy a Group Site -To deploy a group into a site, make sure you have a domain name and -a server with the following requirements: +To deploy a group into a site, make sure you have a domain name and a server with the following requirements: 1. At least 2GB RAM 2. Al least 512MB free space in root partition. @@ -85,16 +88,15 @@ After checking that, run the following command in the server: sh <(curl -sL https://raw.githubusercontent.com/seed-hypermedia/seed/main/website_deployment.sh) https://example.com ``` -replacing `https://example.com` by your <`address`> If everything went well, -after some seconds, you should be watching a final output line like -`https://example.com/secret-invite/XXXX`. You should paste that link back into -the owner's application to register the newly created site and start publihing. -The site deployment workspace will default to `~/.seed-site`. +replacing `https://example.com` by your <`address`> If everything went well, after some seconds, you should be watching +a final output line like `https://example.com/secret-invite/XXXX`. You should paste that link back into the owner's +application to register the newly created site and start publishing. The site deployment workspace will default to +`~/.seed-site`. #### Auto-Update a Site -If you want the site to auto update to latest stable images when they are pushed, -just execute the installation command with the `--auto-update` flag. Ex: +If you want the site to auto update to latest stable images when they are pushed, just execute the installation command +with the `--auto-update` flag. Ex: ```shell sh <(curl -sL https://raw.githubusercontent.com/seed-hypermedia/seed/main/website_deployment.sh) https://example.com --auto-update @@ -102,9 +104,9 @@ sh <(curl -sL https://raw.githubusercontent.com/seed-hypermedia/seed/main/websit #### Replace Site -If you want to replace an old site with a new site in a different domain in the same machine, -you need to redeploy the site from scratch. Note that old content will be available as long as -the owner of the site is synced with the site at the moment of the replacement. On the server: +If you want to replace an old site with a new site in a different domain in the same machine, you need to redeploy the +site from scratch. Note that old content will be available as long as the owner of the site is synced with the site at +the moment of the replacement. On the server: ```shell docker stop seed-web @@ -112,8 +114,7 @@ mv ~/.seed-site ~/.seed-site.bak docker start seed-web ``` -Get the new secret link from the command line after starting the `seed-web` container -Now in the Seed App, the Owner of the site can go to the group he/she wants to (re)deploy -and click on the three dots, and publish group to site. Enter the new secret and the old content -should be now available in the new site. If there is no new content (A completely new group), then -the site will be empty ready to accept documents +Get the new secret link from the command line after starting the `seed-web` container Now in the Seed App, the Owner of +the site can go to the group he/she wants to (re)deploy and click on the three dots, and publish group to site. Enter +the new secret and the old content should be now available in the new site. If there is no new content (A completely new +group), then the site will be empty ready to accept documents diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 000000000..2afae1e8b --- /dev/null +++ b/backend/README.md @@ -0,0 +1,47 @@ +# Backend + +Status: current. + +The backend is the Go runtime for Seed. It contains the daemon, API implementations, blob formats/indexing, SQLite +storage, P2P networking, and backend tests. + +## Package map + +| Path | Ownership | +| -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| [`api`](./api) | gRPC service implementations and API test helpers. Mirrors `proto/**` service areas. | +| [`api/documents/v3alpha`](./api/documents/v3alpha) | Documents, resources, comments, contacts, access control, document history. | +| [`api/entities/v1alpha`](./api/entities/v1alpha) | Entity timeline, search, delete/undelete, discovery entry points. | +| [`api/activity/v1alpha`](./api/activity/v1alpha) | Activity feed and subscription APIs. | +| [`api/daemon/v1alpha`](./api/daemon/v1alpha) | Daemon admin/key/vault/domain APIs. | +| [`blob`](./blob) | Signed blob formats (`Change`, `Ref`, `Comment`, `Capability`, profile/contact), blob store/indexing, visibility propagation. | +| [`storage`](./storage) | SQLite store, schema source of truth, migrations, local vault storage. Read [`storage/AGENTS.md`](./storage/AGENTS.md) before editing. | +| [`hmnet`](./hmnet) | libp2p node, Bitswap/file serving, peer/debug endpoints, P2P client/server plumbing. | +| [`hmnet/syncing`](./hmnet/syncing) | Authorized sync, discovery, scheduling, sync server. | +| [`daemon`](./daemon) | App composition: storage, index, network, sync, gRPC, HTTP, metrics, reindexing, LLM embedding. | +| [`cmd/seed-daemon`](./cmd/seed-daemon) | CLI entry point for the daemon binary. | +| [`core`](./core) | Cryptography, principals, key pairs, keystores, mnemonics. | +| [`config`](./config) | Daemon configuration and defaults. | +| [`llm`](./llm) | Embedding backends and llama.cpp/Ollama integration. | +| [`util`](./util) | Shared Go utilities; keep new helpers small and justified. | + +## Sources of truth + +- Proto contracts: [`../proto`](../proto). +- DB schema: [`storage/schema.sql`](./storage/schema.sql). +- DB migrations: [`storage/storage_migrations.go`](./storage/storage_migrations.go). +- Blob formats: [`blob/blob_*.go`](./blob). +- Daemon composition: [`daemon/daemon.go`](./daemon/daemon.go). + +## Common commands + +```bash +go test ./backend/... +golangci-lint run --new-from-merge-base origin/main ./backend/... +go install ./backend/... # compile-only check +./dev run-backend -- -http.port=53001 -grpc.port=53002 -p2p.port=53000 +./dev gen //backend/... # after generated schema/proto-affecting changes +``` + +For local CI parity before pushing, use the backend workflows from +[`../docs/local-ci-with-agent-ci.md`](../docs/local-ci-with-agent-ci.md). diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..5784e72ca --- /dev/null +++ b/docs/README.md @@ -0,0 +1,85 @@ +# Seed Builder Guide + +Status: current. + +This is the canonical docs index for people and agents building or fixing Seed. Start here when the work crosses +subsystem boundaries or when you are not sure where a behavior is owned. + +## Read order + +1. [`AGENTS.md`](../AGENTS.md) for repo-wide rules and validation expectations. +2. [`docs/domain/glossary.md`](./domain/glossary.md) for shared product/protocol language. +3. [`docs/architecture/overview.md`](./architecture/overview.md) for runtime boundaries and sources of truth. +4. [`docs/code-map.md`](./code-map.md) for "if touching X, start in these files" maps. +5. The relevant subsystem README or doc listed below. + +## Repo map + +| Path | What lives here | +| ------------------------------------------------------------------- | --------------------------------------------------------------------------------- | +| [`backend/**`](../backend/README.md) | Go daemon, gRPC/HTTP APIs, blob/index/storage, P2P, local vault storage, tests. | +| [`frontend/apps/web`](../frontend/apps/web/README.md) | Remix public/site web app, SSR loaders, web editing, daemon HTTP integration. | +| [`frontend/apps/desktop`](../frontend/apps/desktop/README.md) | Electron shell, main/preload/renderer wiring, local daemon lifecycle, desktop UI. | +| [`frontend/apps/notify`](../frontend/apps/notify/README.md) | Notification service routes, email verification, inbox/config/read-state APIs. | +| [`frontend/packages/shared`](../frontend/packages/shared/README.md) | Shared TS API adapters, routes, models, document machine, query ownership. | +| [`frontend/packages/client`](../frontend/packages/client/README.md) | Low-level Hypermedia client: signing, blob payloads, import/export helpers. | +| [`frontend/packages/editor`](../frontend/packages/editor/README.md) | TipTap/BlockNote editor, readonly viewer, comment editor, editor extensions. | +| [`frontend/packages/ui`](../frontend/packages/ui) | Shared React UI components and document/resource surfaces. | +| [`proto/**`](../proto/README.md) | Protobuf service contracts and generated Go/TS API source. | +| [`vault/**`](../vault/README.md) | Remote identity vault service and SPA; use Bun here, not pnpm. | +| [`ops/**`](../ops) | Deployment tooling; uses pinned Bun version from `ops/package.json`. | +| [`docs/plans/**`](./plans) | Planning documents. Treat as proposals unless the status index says otherwise. | + +## Doc status convention + +Use these labels in indexes and new docs: + +| Status | Meaning | +| ------------ | ------------------------------------------------------------------------------------- | +| `current` | Intended to describe the present system or current workflow. | +| `plan` | Proposed or in-progress work. Do not treat as shipped behavior without checking code. | +| `historical` | Useful context about previous decisions or shipped changes; may be stale in details. | +| `superseded` | Replaced by another doc; keep only for traceability. | + +## Current docs index + +| Doc | Status | Notes | +| ----------------------------------------------------------------------------------------------------------------- | ---------- | -------------------------------------------------------------------------- | +| [`docs/dev-setup.md`](./dev-setup.md) | current | Concise local setup and common commands. | +| [`docs/domain/glossary.md`](./domain/glossary.md) | current | Canonical domain vocabulary. | +| [`docs/architecture/overview.md`](./architecture/overview.md) | current | Runtime/component map and source-of-truth table. | +| [`docs/code-map.md`](./code-map.md) | current | Starting points by feature area. | +| [`docs/templates/feature-brief.md`](./templates/feature-brief.md) | current | Template for non-trivial feature/fix briefs. | +| [`docs/local-ci-with-agent-ci.md`](./local-ci-with-agent-ci.md) | current | Local GitHub Actions parity workflow before pushing. | +| [`docs/vault-session-key-delegation.md`](./vault-session-key-delegation.md) | current | Vault delegation protocol explanation. | +| [`docs/document-lifecycle-explained.md`](./document-lifecycle-explained.md) | current | User-facing document lifecycle explanation. | +| [`docs/notifications/local-first-read-state-edge-cases.md`](./notifications/local-first-read-state-edge-cases.md) | current | Notification read-state edge cases and policy. | +| [`docs/sentry-dashboard-setup.md`](./sentry-dashboard-setup.md) | current | Sentry project/token setup checklist. | +| [`docs/all-documents-page-spec.md`](./all-documents-page-spec.md) | plan | Implementation spec; verify against code before assuming shipped behavior. | +| [`docs/copy-link-submenu.md`](./copy-link-submenu.md) | historical | Records copy-link submenu changes. | +| [`docs/draft-context-unification.md`](./draft-context-unification.md) | plan | Draft context cleanup proposal. | +| [`docs/subscriptions-master-plan.md`](./subscriptions-master-plan.md) | plan | Performance/subscription architecture proposal. | + +## Plan docs index + +All docs in `docs/plans/**` are status `plan` unless this table is updated. + +| Plan doc | Status | Notes | +| ----------------------------------------------------------------------------------------- | ------ | -------------------------------------------------------------- | +| [`docs/plans/editor-big-plan.md`](./plans/editor-big-plan.md) | plan | Unified document lifecycle/editor target design. | +| [`docs/plans/editor-macro-plan.md`](./plans/editor-macro-plan.md) | plan | Macro migration plan for the editor renderer. | +| [`docs/plans/plan-comment-performance.md`](./plans/plan-comment-performance.md) | plan | Web comment performance instrumentation and optimization plan. | +| [`docs/plans/plan-editor-document-features.md`](./plans/plan-editor-document-features.md) | plan | Editor extension migration proposal. | +| [`docs/plans/plan-editor-migration-steps.md`](./plans/plan-editor-migration-steps.md) | plan | Incremental editor migration steps. | +| [`docs/plans/plan-web-desktop-sharing.md`](./plans/plan-web-desktop-sharing.md) | plan | Web/desktop document sharing refactor plan and ledger. | +| [`docs/plans/reactions-plan.md`](./plans/reactions-plan.md) | plan | Proposed reactions model. | + +## Common workflows + +| Workflow | Start with | +| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Add proto/API field | [`proto/README.md`](../proto/README.md), [`docs/code-map.md#protocodegen`](./code-map.md#protocodegen). | +| Change storage schema | [`backend/storage/AGENTS.md`](../backend/storage/AGENTS.md), [`docs/code-map.md#storage-migrations`](./code-map.md#storage-migrations). | +| Change document UI | [`frontend/README.md`](../frontend/README.md), [`docs/code-map.md#document-publishediting`](./code-map.md#document-publishediting). | +| Change notification behavior | [`docs/code-map.md#notifications`](./code-map.md#notifications), notification architecture docs linked there. | +| Change vault/identity behavior | [`docs/domain/glossary.md#vault-vs-account-hierarchy`](./domain/glossary.md#vault-vs-account-hierarchy), [`docs/code-map.md#identityvaultdelegation`](./code-map.md#identityvaultdelegation). | diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md new file mode 100644 index 000000000..e1d34d054 --- /dev/null +++ b/docs/architecture/overview.md @@ -0,0 +1,100 @@ +# Architecture overview + +Status: current. + +Seed is a decentralized knowledge collaboration system with desktop and web clients, a local Go daemon, signed +content-addressed blobs, SQLite indexes, P2P sync/discovery, a remote identity Vault, and notification services. + +```text +Desktop UI / Web UI / Vault UI / Notify UI + | + v + gRPC, gRPC-web, HTTP APIs + | + v + Daemon + / | \ + Blob Storage P2P / HMNet + formats SQLite Sync / Discovery + | | | + +--------+--------------+ + | + Indexes +``` + +## Runtime components + +| Component | Runtime | Responsibility | Start here | +| --------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- | +| Desktop app | Electron + React | Local app shell, renderer UI, daemon lifecycle, IPC/tRPC bridge, desktop-only draft and settings stores. | [`frontend/apps/desktop/README.md`](../../frontend/apps/desktop/README.md) | +| Web app | Remix + React | Public/read site, SSR loaders, web editing/drafts, daemon HTTP integration, gateway/custom-domain behavior. | [`frontend/apps/web/README.md`](../../frontend/apps/web/README.md) | +| Notify app | Remix + server runtime | Notification inbox/config/read-state API, email verification, notification email delivery. | [`frontend/apps/notify`](../../frontend/apps/notify) | +| Vault | Bun + React SPA | Zero-knowledge identity vault, auth methods, encrypted vault data, delegation consent. | [`vault/README.md`](../../vault/README.md) | +| Daemon | Go | gRPC/HTTP API server, blob index, SQLite store, P2P node, sync service, key access, LLM embeddings. | [`backend/README.md`](../../backend/README.md) | +| P2P / HMNet | Go/libp2p | Peer connectivity, Bitswap/file transfer, sync protocol, discovery status, debug network pages. | [`backend/hmnet`](../../backend/hmnet), [`backend/hmnet/syncing`](../../backend/hmnet/syncing) | +| Storage / index | Go + SQLite | Durable local database, schema/migrations, blob storage, structural indexes and search-ish aggregate tables. | [`backend/storage`](../../backend/storage), [`backend/blob`](../../backend/blob) | + +## API surfaces + +| Surface | Used by | Defined in | Implemented in | +| ------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Documents/Comments/AccessControl gRPC | Desktop, web server, shared TS adapters | [`proto/documents/v3alpha`](../../proto/documents/v3alpha) | [`backend/api/documents/v3alpha`](../../backend/api/documents/v3alpha) | +| Entities and discovery gRPC | Desktop discovery/subscription flows, web API routes | [`proto/entities/v1alpha`](../../proto/entities/v1alpha) | [`backend/api/entities/v1alpha`](../../backend/api/entities/v1alpha) | +| Activity/subscriptions gRPC | Desktop subscriptions and activity feed | [`proto/activity/v1alpha`](../../proto/activity/v1alpha) | [`backend/api/activity/v1alpha`](../../backend/api/activity/v1alpha) | +| Daemon admin/key/vault gRPC | Desktop settings/onboarding, local dev tooling | [`proto/daemon/v1alpha`](../../proto/daemon/v1alpha) | [`backend/api/daemon/v1alpha`](../../backend/api/daemon/v1alpha) | +| Daemon HTTP/file/debug | Web app, desktop/web local clients, debug pages | Go handlers | [`backend/daemon/http.go`](../../backend/daemon/http.go), [`backend/hmnet/http_debug*.go`](../../backend/hmnet) | +| Web Remix routes | Browsers and gateway integrations | Remix route files | [`frontend/apps/web/app/routes`](../../frontend/apps/web/app/routes) | +| Notify Remix routes | Desktop/web notification clients and email links | Remix route files | [`frontend/apps/notify/app/routes`](../../frontend/apps/notify/app/routes) | +| Desktop IPC/tRPC | Electron renderers | TypeScript routers/bridges | [`frontend/apps/desktop/src/app-trpc.ts`](../../frontend/apps/desktop/src/app-trpc.ts), [`frontend/apps/desktop/src/app-ipc.tsx`](../../frontend/apps/desktop/src/app-ipc.tsx) | + +## Storage and indexing responsibility + +- `backend/storage/schema.sql` is the SQLite schema source of truth. +- `backend/storage/storage_migrations.go` owns migration steps when schema changes. +- `backend/blob/*` owns signed blob formats, decoding, validation, indexing hooks, and visibility propagation. +- `backend/blob/index*.go` and related schema tables turn content-addressed blobs into queryable + document/resource/comment/capability state. + +## Sync and discovery responsibility + +- `backend/hmnet` owns libp2p node setup, Bitswap/file transport, peer metadata, relays, debug endpoints, and P2P + service registration. +- `backend/hmnet/syncing` owns authorized blob sync, discovery scheduling, and sync server behavior. +- `proto/entities/v1alpha/entities.proto` defines discovery request/response semantics used by clients. +- Desktop subscriptions and resource discovery streams are coordinated in `frontend/apps/desktop/src/models/entities.ts` + and `frontend/apps/desktop/src/app-sync.ts`. + +## Identity and vault responsibility + +- Account/private key generation, import/export, and daemon key listing live behind the daemon API. +- The local daemon key store and local vault storage live under `backend/core/keystore` and `backend/storage/vault`. +- The remote Vault service under `vault/**` handles zero-knowledge auth, encrypted data, and delegation consent. +- Web delegation/session flows live in `frontend/apps/web/app/auth*`, + `frontend/apps/web/app/routes/hm.api.delegate-device.tsx`, and the Vault app. + +## Notifications responsibility + +- Shared notification classification, payloads, titles, and read-state merge logic live under + `frontend/packages/shared/src/models/notification-*`. +- Desktop local notification sync/read/config state lives under `frontend/apps/desktop/src/app-notification*.ts` and + `frontend/apps/desktop/src/app-notifications.ts`. +- Web notification UI and API integration live in `frontend/apps/web/app/web-notifications.ts`, + `frontend/apps/web/app/notifications-page-content.tsx`, and `frontend/apps/web/app/routes/hm.notifications.tsx`. +- The notification service API and persistence live under `frontend/apps/notify/app`. + +## Sources of truth + +| Concern | Source of truth | +| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Proto service contracts | [`proto/**`](../../proto) | +| Generated Go API types | [`backend/genproto/**`](../../backend/genproto) | +| Generated TS API types | Generated package outputs referenced by frontend imports; refresh with [`./dev gen`](../../dev). | +| DB schema | [`backend/storage/schema.sql`](../../backend/storage/schema.sql) | +| DB migrations | [`backend/storage/storage_migrations.go`](../../backend/storage/storage_migrations.go) | +| Blob formats | [`backend/blob/blob_*.go`](../../backend/blob) | +| Blob visibility/indexing | [`backend/blob/index*.go`](../../backend/blob), [`backend/storage/schema.sql`](../../backend/storage/schema.sql) | +| TS shared models | [`frontend/packages/shared/src/**`](../../frontend/packages/shared/src) | +| Low-level Hypermedia TS client | [`frontend/packages/client/src/**`](../../frontend/packages/client/src) | +| Desktop shell/runtime | [`frontend/apps/desktop/src/main.ts`](../../frontend/apps/desktop/src/main.ts), [`frontend/apps/desktop/src/app-*.ts`](../../frontend/apps/desktop/src) | +| Web SSR and routes | [`frontend/apps/web/app/routes`](../../frontend/apps/web/app/routes), [`frontend/apps/web/app/loaders.ts`](../../frontend/apps/web/app/loaders.ts) | +| Vault auth/encryption | [`vault/src`](../../vault/src) | diff --git a/docs/code-map.md b/docs/code-map.md new file mode 100644 index 000000000..3bba04a45 --- /dev/null +++ b/docs/code-map.md @@ -0,0 +1,129 @@ +# Code map + +Status: current. + +Use this map to find the first files to read before changing a behavior. It is intentionally concrete and biased toward +entry points, tests, and sources of truth. + +## Document publish/editing + +Start here: + +| Layer | Files | +| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Proto | [`proto/documents/v3alpha/documents.proto`](../proto/documents/v3alpha/documents.proto), [`proto/documents/v3alpha/resources.proto`](../proto/documents/v3alpha/resources.proto), [`proto/documents/v3alpha/access_control.proto`](../proto/documents/v3alpha/access_control.proto) | +| Go API | [`backend/api/documents/v3alpha/documents.go`](../backend/api/documents/v3alpha/documents.go), [`backend/api/documents/v3alpha/resources.go`](../backend/api/documents/v3alpha/resources.go), [`backend/api/documents/v3alpha/dochistory.go`](../backend/api/documents/v3alpha/dochistory.go) | +| Blob model | [`backend/blob/blob_change.go`](../backend/blob/blob_change.go), [`backend/blob/blob_ref.go`](../backend/blob/blob_ref.go), [`backend/blob/blob_profile.go`](../backend/blob/blob_profile.go) | +| Storage/index | [`backend/storage/schema.sql`](../backend/storage/schema.sql), [`backend/blob/index_sql.go`](../backend/blob/index_sql.go), [`backend/blob/index_visibility.go`](../backend/blob/index_visibility.go) | +| Low-level TS client | [`frontend/packages/client/src/change.ts`](../frontend/packages/client/src/change.ts), [`frontend/packages/client/src/ref.ts`](../frontend/packages/client/src/ref.ts), [`frontend/packages/client/src/client.ts`](../frontend/packages/client/src/client.ts), [`frontend/packages/client/src/signing.ts`](../frontend/packages/client/src/signing.ts) | +| Shared TS | [`frontend/packages/shared/src/models/document-machine.ts`](../frontend/packages/shared/src/models/document-machine.ts), [`frontend/packages/shared/src/models/use-document-machine.ts`](../frontend/packages/shared/src/models/use-document-machine.ts), [`frontend/packages/shared/src/models/post-publish-cache.ts`](../frontend/packages/shared/src/models/post-publish-cache.ts), [`frontend/packages/shared/src/utils/document-changes.ts`](../frontend/packages/shared/src/utils/document-changes.ts), [`frontend/packages/shared/src/routes.ts`](../frontend/packages/shared/src/routes.ts) | +| Editor/UI | [`frontend/packages/editor/src/document-editor.tsx`](../frontend/packages/editor/src/document-editor.tsx), [`frontend/packages/editor/src/readonly-viewer.tsx`](../frontend/packages/editor/src/readonly-viewer.tsx), [`frontend/packages/ui/src/resource-page-common.tsx`](../frontend/packages/ui/src/resource-page-common.tsx), [`frontend/packages/ui/src/document-tools.tsx`](../frontend/packages/ui/src/document-tools.tsx) | +| Desktop | [`frontend/apps/desktop/src/pages/desktop-resource.tsx`](../frontend/apps/desktop/src/pages/desktop-resource.tsx), [`frontend/apps/desktop/src/app-drafts.ts`](../frontend/apps/desktop/src/app-drafts.ts), [`frontend/apps/desktop/src/components/publish-draft-button.tsx`](../frontend/apps/desktop/src/components/publish-draft-button.tsx), [`frontend/apps/desktop/src/utils/publish-document.ts`](../frontend/apps/desktop/src/utils/publish-document.ts) | +| Web | [`frontend/apps/web/app/web-resource-page.tsx`](../frontend/apps/web/app/web-resource-page.tsx), [`frontend/apps/web/app/document-edit`](../frontend/apps/web/app/document-edit), [`frontend/apps/web/app/routes/hm.api.document-update.tsx`](../frontend/apps/web/app/routes/hm.api.document-update.tsx), [`frontend/apps/web/app/draft-media-db.ts`](../frontend/apps/web/app/draft-media-db.ts) | +| Tests | [`backend/api/documents/v3alpha/*_test.go`](../backend/api/documents/v3alpha), [`backend/blob/blob_change_test.go`](../backend/blob/blob_change_test.go), [`frontend/apps/web/app/document-edit/*.test.ts`](../frontend/apps/web/app/document-edit), [`frontend/packages/shared/src/utils/document-changes*.test.ts`](../frontend/packages/shared/src/utils) | + +## Comments/discussions + +Start here: + +| Layer | Files | +| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Proto/API | [`proto/documents/v3alpha/comments.proto`](../proto/documents/v3alpha/comments.proto), [`backend/api/documents/v3alpha/comments.go`](../backend/api/documents/v3alpha/comments.go) | +| Blob/index | [`backend/blob/blob_comment.go`](../backend/blob/blob_comment.go), [`backend/blob/index_sql.go`](../backend/blob/index_sql.go), [`backend/storage/schema.sql`](../backend/storage/schema.sql) | +| Low-level TS client | [`frontend/packages/client/src/comment.ts`](../frontend/packages/client/src/comment.ts), [`frontend/packages/client/src/hm-types.ts`](../frontend/packages/client/src/hm-types.ts) | +| Shared TS | [`frontend/packages/shared/src/api-comments.ts`](../frontend/packages/shared/src/api-comments.ts), [`frontend/packages/shared/src/comments-service-provider.tsx`](../frontend/packages/shared/src/comments-service-provider.tsx), [`frontend/packages/shared/src/models/comments.ts`](../frontend/packages/shared/src/models/comments.ts), [`frontend/packages/shared/src/optimistic-comment.ts`](../frontend/packages/shared/src/optimistic-comment.ts) | +| Editor/UI | [`frontend/packages/editor/src/comment-editor.tsx`](../frontend/packages/editor/src/comment-editor.tsx), [`frontend/packages/ui/src/comments.tsx`](../frontend/packages/ui/src/comments.tsx), [`frontend/packages/ui/src/discussions-page.tsx`](../frontend/packages/ui/src/discussions-page.tsx) | +| Desktop | [`frontend/apps/desktop/src/app-comments.ts`](../frontend/apps/desktop/src/app-comments.ts), [`frontend/apps/desktop/src/components/commenting.tsx`](../frontend/apps/desktop/src/components/commenting.tsx), [`frontend/apps/desktop/src/models/comments.ts`](../frontend/apps/desktop/src/models/comments.ts) | +| Web | [`frontend/apps/web/app/commenting.tsx`](../frontend/apps/web/app/commenting.tsx), [`frontend/apps/web/app/comment-draft-utils.ts`](../frontend/apps/web/app/comment-draft-utils.ts), [`frontend/apps/web/app/routes/hm.api.resource.$.tsx`](../frontend/apps/web/app/routes/hm.api.resource.$.tsx) | +| Tests | [`backend/api/documents/v3alpha/comments_test.go`](../backend/api/documents/v3alpha/comments_test.go), [`backend/blob/blob_comment_test.go`](../backend/blob/blob_comment_test.go), [`frontend/packages/shared/src/__tests__/comment-*.test.ts`](../frontend/packages/shared/src/__tests__), [`frontend/apps/web/app/__tests__`](../frontend/apps/web/app/__tests__) | + +## Notifications + +Start here: + +| Layer | Files | +| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Architecture docs | [`frontend/apps/desktop/src/NOTIFICATIONS_DESKTOP_ARCHITECTURE.md`](../frontend/apps/desktop/src/NOTIFICATIONS_DESKTOP_ARCHITECTURE.md), [`frontend/apps/web/app/NOTIFICATIONS_WEB_ARCHITECTURE.md`](../frontend/apps/web/app/NOTIFICATIONS_WEB_ARCHITECTURE.md), [`frontend/apps/notify/app/NOTIFICATIONS_SERVICE_ARCHITECTURE.md`](../frontend/apps/notify/app/NOTIFICATIONS_SERVICE_ARCHITECTURE.md), [`docs/notifications/local-first-read-state-edge-cases.md`](./notifications/local-first-read-state-edge-cases.md) | +| Shared TS | [`frontend/packages/shared/src/models/notification-service.ts`](../frontend/packages/shared/src/models/notification-service.ts), [`frontend/packages/shared/src/models/notification-state.ts`](../frontend/packages/shared/src/models/notification-state.ts), [`frontend/packages/shared/src/models/notification-read-logic.ts`](../frontend/packages/shared/src/models/notification-read-logic.ts), [`frontend/packages/shared/src/models/notification-payload.ts`](../frontend/packages/shared/src/models/notification-payload.ts), [`frontend/packages/shared/src/models/notification-titles.ts`](../frontend/packages/shared/src/models/notification-titles.ts) | +| Desktop | [`frontend/apps/desktop/src/app-notifications.ts`](../frontend/apps/desktop/src/app-notifications.ts), [`frontend/apps/desktop/src/app-notification-config.ts`](../frontend/apps/desktop/src/app-notification-config.ts), [`frontend/apps/desktop/src/app-notification-inbox.ts`](../frontend/apps/desktop/src/app-notification-inbox.ts), [`frontend/apps/desktop/src/app-notification-read-state.ts`](../frontend/apps/desktop/src/app-notification-read-state.ts), [`frontend/apps/desktop/src/pages/notifications.tsx`](../frontend/apps/desktop/src/pages/notifications.tsx) | +| Web | [`frontend/apps/web/app/web-notifications.ts`](../frontend/apps/web/app/web-notifications.ts), [`frontend/apps/web/app/notifications-page-content.tsx`](../frontend/apps/web/app/notifications-page-content.tsx), [`frontend/apps/web/app/routes/hm.notifications.tsx`](../frontend/apps/web/app/routes/hm.notifications.tsx), [`frontend/apps/web/app/routes/hm.api.config.tsx`](../frontend/apps/web/app/routes/hm.api.config.tsx) | +| Notify service | [`frontend/apps/notify/app/routes/hm.api.notifications.tsx`](../frontend/apps/notify/app/routes/hm.api.notifications.tsx), [`frontend/apps/notify/app/routes/hm.api.notification-inbox.tsx`](../frontend/apps/notify/app/routes/hm.api.notification-inbox.tsx), [`frontend/apps/notify/app/routes/hm.api.notification-config.tsx`](../frontend/apps/notify/app/routes/hm.api.notification-config.tsx), [`frontend/apps/notify/app/routes/hm.api.notification-read-state.tsx`](../frontend/apps/notify/app/routes/hm.api.notification-read-state.tsx), [`frontend/apps/notify/app/notification-state.ts`](../frontend/apps/notify/app/notification-state.ts), [`frontend/apps/notify/app/email-notifier.ts`](../frontend/apps/notify/app/email-notifier.ts) | +| Tests | [`frontend/apps/desktop/src/__tests__/app-notification*.test.ts`](../frontend/apps/desktop/src/__tests__), [`frontend/apps/web/app/__tests__/hm.notifications*.test.tsx`](../frontend/apps/web/app/__tests__), [`frontend/apps/notify/app/*notification*.test.ts`](../frontend/apps/notify/app) | + +## Identity/vault/delegation + +Start here: + +| Layer | Files | +| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Domain docs | [`docs/domain/glossary.md#vault-vs-account-hierarchy`](./domain/glossary.md#vault-vs-account-hierarchy), [`docs/vault-session-key-delegation.md`](./vault-session-key-delegation.md) | +| Proto/API | [`proto/daemon/v1alpha/daemon.proto`](../proto/daemon/v1alpha/daemon.proto), [`proto/documents/v3alpha/access_control.proto`](../proto/documents/v3alpha/access_control.proto), [`backend/api/daemon/v1alpha/daemon.go`](../backend/api/daemon/v1alpha/daemon.go), [`backend/api/documents/v3alpha/access_control.go`](../backend/api/documents/v3alpha/access_control.go) | +| Keys/vault storage | [`backend/core`](../backend/core), [`backend/core/keystore`](../backend/core/keystore), [`backend/storage/vault`](../backend/storage/vault) | +| Remote Vault | [`vault/src/api.ts`](../vault/src/api.ts), [`vault/src/api-service.ts`](../vault/src/api-service.ts), [`vault/src/session.ts`](../vault/src/session.ts), [`vault/src/frontend/vault.ts`](../vault/src/frontend/vault.ts), [`vault/src/frontend/router.tsx`](../vault/src/frontend/router.tsx) | +| Desktop | [`frontend/apps/desktop/src/models/daemon.ts`](../frontend/apps/desktop/src/models/daemon.ts), [`frontend/apps/desktop/src/components/remote-vault-reminder.tsx`](../frontend/apps/desktop/src/components/remote-vault-reminder.tsx), [`frontend/apps/desktop/src/components/edit-profile-dialog.tsx`](../frontend/apps/desktop/src/components/edit-profile-dialog.tsx), [`frontend/apps/desktop/src/utils/vault-connection.ts`](../frontend/apps/desktop/src/utils/vault-connection.ts) | +| Web | [`frontend/apps/web/app/auth.tsx`](../frontend/apps/web/app/auth.tsx), [`frontend/apps/web/app/auth-session.ts`](../frontend/apps/web/app/auth-session.ts), [`frontend/apps/web/app/routes/hm.api.delegate-device.tsx`](../frontend/apps/web/app/routes/hm.api.delegate-device.tsx), [`frontend/apps/web/app/vault-links.ts`](../frontend/apps/web/app/vault-links.ts) | +| Tests | [`backend/core/*_test.go`](../backend/core), [`backend/storage/vault/*_test.go`](../backend/storage/vault), [`frontend/apps/desktop/src/__tests__/vault-*.test.tsx`](../frontend/apps/desktop/src/__tests__), [`vault/src/*.test.ts`](../vault/src) | + +## Sync/discovery + +Start here: + +| Layer | Files | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Proto/API | [`proto/entities/v1alpha/entities.proto`](../proto/entities/v1alpha/entities.proto), [`proto/networking/v1alpha/networking.proto`](../proto/networking/v1alpha/networking.proto), [`proto/p2p/v1alpha/syncing.proto`](../proto/p2p/v1alpha/syncing.proto), [`backend/api/entities/v1alpha/entities.go`](../backend/api/entities/v1alpha/entities.go), [`backend/api/networking/v1alpha/networking.go`](../backend/api/networking/v1alpha/networking.go) | +| P2P/sync | [`backend/hmnet/hmnet.go`](../backend/hmnet/hmnet.go), [`backend/hmnet/syncing`](../backend/hmnet/syncing), [`backend/hmnet/filemanager.go`](../backend/hmnet/filemanager.go), [`backend/hmnet/list_blobs.go`](../backend/hmnet/list_blobs.go) | +| Activity/subscriptions | [`proto/activity/v1alpha/subscriptions.proto`](../proto/activity/v1alpha/subscriptions.proto), [`backend/api/activity/v1alpha/subscriptions.go`](../backend/api/activity/v1alpha/subscriptions.go), [`frontend/apps/desktop/src/derived-subscriptions.ts`](../frontend/apps/desktop/src/derived-subscriptions.ts) | +| Desktop | [`frontend/apps/desktop/src/app-sync.ts`](../frontend/apps/desktop/src/app-sync.ts), [`frontend/apps/desktop/src/models/entities.ts`](../frontend/apps/desktop/src/models/entities.ts), [`frontend/apps/desktop/src/models/library.ts`](../frontend/apps/desktop/src/models/library.ts), [`frontend/apps/desktop/src/network-debug.ts`](../frontend/apps/desktop/src/network-debug.ts) | +| Shared/Web | [`frontend/packages/shared/src/discovery.ts`](../frontend/packages/shared/src/discovery.ts), [`frontend/apps/web/app/routes/hm.api.discover.tsx`](../frontend/apps/web/app/routes/hm.api.discover.tsx), [`frontend/apps/web/app/utils/discovery.ts`](../frontend/apps/web/app/utils/discovery.ts) | +| Tests | [`backend/hmnet/**/*_test.go`](../backend/hmnet), [`backend/api/entities/v1alpha/*_test.go`](../backend/api/entities/v1alpha), [`frontend/packages/shared/src/discovery.test.ts`](../frontend/packages/shared/src/discovery.test.ts) | + +## Web SSR loading + +Start here: + +| Layer | Files | +| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Web docs | [`frontend/apps/web/docs/ssr-loading-architecture.md`](../frontend/apps/web/docs/ssr-loading-architecture.md), [`frontend/apps/web/docs/ssr-loading-refactor.md`](../frontend/apps/web/docs/ssr-loading-refactor.md) | +| Remix entry/root | [`frontend/apps/web/app/root.tsx`](../frontend/apps/web/app/root.tsx), [`frontend/apps/web/app/entry.server.tsx`](../frontend/apps/web/app/entry.server.tsx), [`frontend/apps/web/app/entry.client.tsx`](../frontend/apps/web/app/entry.client.tsx) | +| Routes/loaders | [`frontend/apps/web/app/routes/$.tsx`](../frontend/apps/web/app/routes/$.tsx), [`frontend/apps/web/app/routes/_index.tsx`](../frontend/apps/web/app/routes/_index.tsx), [`frontend/apps/web/app/loaders.ts`](../frontend/apps/web/app/loaders.ts), [`frontend/apps/web/app/queries.server.ts`](../frontend/apps/web/app/queries.server.ts), [`frontend/apps/web/app/client.server.ts`](../frontend/apps/web/app/client.server.ts) | +| Client/runtime | [`frontend/apps/web/app/providers.tsx`](../frontend/apps/web/app/providers.tsx), [`frontend/apps/web/app/universal-client.tsx`](../frontend/apps/web/app/universal-client.tsx), [`frontend/apps/web/app/server-universal-client.ts`](../frontend/apps/web/app/server-universal-client.ts), [`frontend/apps/web/app/web-resource-page.tsx`](../frontend/apps/web/app/web-resource-page.tsx) | +| Tests | [`frontend/apps/web/app/ssr-document.integration.test.ts`](../frontend/apps/web/app/ssr-document.integration.test.ts), [`frontend/apps/web/app/local-db*.test.ts`](../frontend/apps/web/app), [`frontend/apps/web/app/validated-links.test.tsx`](../frontend/apps/web/app/validated-links.test.tsx) | + +## Desktop shell/navigation + +Start here: + +| Layer | Files | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Electron entry | [`frontend/apps/desktop/src/main.ts`](../frontend/apps/desktop/src/main.ts), [`frontend/apps/desktop/src/preload.ts`](../frontend/apps/desktop/src/preload.ts), [`frontend/apps/desktop/src/renderer.ts`](../frontend/apps/desktop/src/renderer.ts), [`frontend/apps/desktop/src/root.tsx`](../frontend/apps/desktop/src/root.tsx) | +| Shell services | [`frontend/apps/desktop/src/app-windows.ts`](../frontend/apps/desktop/src/app-windows.ts), [`frontend/apps/desktop/src/app-menu.ts`](../frontend/apps/desktop/src/app-menu.ts), [`frontend/apps/desktop/src/app-ipc.tsx`](../frontend/apps/desktop/src/app-ipc.tsx), [`frontend/apps/desktop/src/app-trpc.ts`](../frontend/apps/desktop/src/app-trpc.ts), [`frontend/apps/desktop/src/daemon.ts`](../frontend/apps/desktop/src/daemon.ts) | +| Navigation | [`frontend/apps/desktop/src/models/navigation.ts`](../frontend/apps/desktop/src/models/navigation.ts), [`frontend/apps/desktop/src/assistant-navigation.ts`](../frontend/apps/desktop/src/assistant-navigation.ts), [`frontend/apps/desktop/src/utils/navigation-container.tsx`](../frontend/apps/desktop/src/utils/navigation-container.tsx), [`frontend/apps/desktop/src/pages/main.tsx`](../frontend/apps/desktop/src/pages/main.tsx) | +| Pages/UI | [`frontend/apps/desktop/src/pages`](../frontend/apps/desktop/src/pages), [`frontend/apps/desktop/src/components/sidebar.tsx`](../frontend/apps/desktop/src/components/sidebar.tsx), [`frontend/apps/desktop/src/components/main-wrapper.tsx`](../frontend/apps/desktop/src/components/main-wrapper.tsx), [`frontend/apps/desktop/src/components/titlebar.tsx`](../frontend/apps/desktop/src/components/titlebar.tsx) | +| Tests | [`frontend/apps/desktop/src/__tests__/assistant-navigation.test.ts`](../frontend/apps/desktop/src/__tests__/assistant-navigation.test.ts), [`frontend/apps/desktop/src/__tests__/open-url.test.tsx`](../frontend/apps/desktop/src/__tests__/open-url.test.tsx), [`frontend/apps/desktop/tests`](../frontend/apps/desktop/tests) | + +## Storage migrations + +Start here: + +| Layer | Files | +| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Rules | [`backend/storage/AGENTS.md`](../backend/storage/AGENTS.md) | +| Schema/migrations | [`backend/storage/schema.sql`](../backend/storage/schema.sql), [`backend/storage/storage_migrations.go`](../backend/storage/storage_migrations.go), [`backend/storage/schema.go`](../backend/storage/schema.go), [`backend/storage/schema.gen.go`](../backend/storage/schema.gen.go) | +| Store/opening | [`backend/storage/storage.go`](../backend/storage/storage.go), [`backend/storage/sqlite.go`](../backend/storage/sqlite.go), [`backend/daemon/daemon.go`](../backend/daemon/daemon.go) | +| Index consumers | [`backend/blob/index_sql.go`](../backend/blob/index_sql.go), [`backend/blob/reindex.go`](../backend/blob/reindex.go), [`backend/daemon/reindexing`](../backend/daemon/reindexing) | +| Tests | [`backend/storage/schema_test.go`](../backend/storage/schema_test.go), [`backend/storage/storage_migrations_test.go`](../backend/storage/storage_migrations_test.go), [`backend/daemon/sqlite_queries_test.go`](../backend/daemon/sqlite_queries_test.go), affected API/blob tests | + +After schema changes, update migrations and run `./dev gen //backend/...`. + +## Proto/codegen + +Start here: + +| Layer | Files | +| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Rules | [`proto/AGENTS.md`](../proto/AGENTS.md), [`proto/README.md`](../proto/README.md) | +| Proto sources | [`proto/documents/v3alpha`](../proto/documents/v3alpha), [`proto/entities/v1alpha`](../proto/entities/v1alpha), [`proto/activity/v1alpha`](../proto/activity/v1alpha), [`proto/daemon/v1alpha`](../proto/daemon/v1alpha), [`proto/networking/v1alpha`](../proto/networking/v1alpha), [`proto/p2p/v1alpha`](../proto/p2p/v1alpha) | +| Generated Go | [`backend/genproto`](../backend/genproto) | +| Implementations | [`backend/api`](../backend/api), plus affected frontend shared/client adapters | +| Commands | `./dev gen`, or targeted `./dev gen //proto/...` / `./dev gen //backend/...` | +| Tests | Affected backend API tests and frontend package tests that consume the generated TS types | diff --git a/docs/dev-setup.md b/docs/dev-setup.md new file mode 100644 index 000000000..2c2da7b03 --- /dev/null +++ b/docs/dev-setup.md @@ -0,0 +1,120 @@ +# Developer setup + +Status: current. + +This repo uses `pnpm` for the main workspace and `bun` only inside `vault/**`. The root [`./dev`](../dev) script is the +main entrypoint for day-to-day commands. + +## Prerequisites + +- macOS or Linux. +- [`mise`](https://mise.jdx.dev/) for pinned toolchains from [`mise.toml`](../mise.toml). +- [`direnv`](https://direnv.net/) so entering the repo activates those tools. +- Docker Desktop if you plan to run local CI with agent-ci. + +`mise.toml` pins Go, Node, pnpm, Bun, Please (`plz`), protoc, CMake, and golangci-lint. Let `direnv` install and +activate them instead of manually mixing system versions. + +## First-time setup + +```bash +# from the repo root +direnv allow . +pnpm install +./dev +``` + +`direnv allow .` may take several minutes the first time because it initializes the `llama-go` submodule, builds local +llama.cpp libraries, and downloads the embedding model used by the daemon. + +If `./dev` says direnv is not enabled, open a new shell in the repo or run `direnv reload`. + +## Common commands + +```bash +./dev run-desktop # desktop app in dev mode +./dev run-desktop-mainnet # desktop dev build pointed at mainnet +./dev build-desktop # package desktop for the current platform +./dev run-web # web app dev server +./dev build-web # production web build +./dev run-backend -- -http.port=53001 -grpc.port=53002 -p2p.port=53000 +./dev gen # check and refresh generated code +``` + +Useful direct pnpm commands: + +```bash +pnpm test +pnpm typecheck +pnpm format:write +pnpm web:test +pnpm shared:test +pnpm desktop:test:unit +pnpm web:standalone # backend + web together on local ports +pnpm notify:standalone # backend + notify together on local ports +``` + +## Web app local run notes + +The web app talks to a Seed daemon over HTTP/gRPC-web-compatible endpoints. The simplest path is usually: + +```bash +pnpm web:standalone +``` + +For separate processes, run a daemon first and then the web app with matching environment variables: + +```bash +./dev run-backend -- -http.port=58001 -grpc.port=58002 -p2p.port=58000 -data-dir="$PWD/.dev-data/web" +pnpm web +``` + +See [`frontend/apps/web/README.md`](../frontend/apps/web/README.md) for route and SSR details. + +## Backend checks + +```bash +go test ./backend/... +golangci-lint run --new-from-merge-base origin/main ./backend/... +go install ./backend/... # compile-only check +``` + +When changing `backend/storage/schema.sql`, also update migrations and run: + +```bash +./dev gen //backend/... +``` + +## Frontend checks + +```bash +pnpm typecheck +pnpm test +pnpm audit +pnpm format:write +``` + +For targeted packages, use filters, for example: + +```bash +pnpm --filter @shm/web test +pnpm --filter @shm/shared typecheck +pnpm --filter @seed-hypermedia/client test +``` + +## Vault checks + +`vault/**` uses Bun and has its own lockfile: + +```bash +cd vault +bun install +bun run check +bun test +bun run build +``` + +## Local CI before pushing + +Use agent-ci for workflow parity before pushing, especially after backend, frontend, vault, or ops changes. See +[`docs/local-ci-with-agent-ci.md`](./local-ci-with-agent-ci.md) for setup and retry commands. diff --git a/docs/domain/glossary.md b/docs/domain/glossary.md new file mode 100644 index 000000000..da830a341 --- /dev/null +++ b/docs/domain/glossary.md @@ -0,0 +1,50 @@ +# Domain glossary + +Status: current. + +Use this glossary to keep product, protocol, backend, and UI language aligned. When a term has legacy names in code, +prefer the term documented here in new docs and explain aliases at system boundaries. + +## Core terms + +| Term | Meaning | Common confusion | Source files | +| ----------------------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Account | A Hypermedia identity/profile owner. In document APIs, an account owns paths and signs profile/document/comment activity. | Not the same as a Vault. Older comments sometimes say this should be renamed to space/site. | [`proto/documents/v3alpha/documents.proto`](../../proto/documents/v3alpha/documents.proto), [`backend/core`](../../backend/core), [`frontend/packages/shared/src/account-metadata.ts`](../../frontend/packages/shared/src/account-metadata.ts) | +| Space | Blob/indexing term for the account/identity whose resource namespace a signed object belongs to. | Often the same principal as the signer, but delegated writes can target another space/account. | [`backend/blob/blob_ref.go`](../../backend/blob/blob_ref.go), [`backend/blob/blob_comment.go`](../../backend/blob/blob_comment.go), [`backend/storage/schema.sql`](../../backend/storage/schema.sql) | +| Site / Gateway | Public web presentation of Hypermedia resources. A site can use a custom domain or the gateway host. | A site is not the account key itself; it is a hosting/viewing surface for account content. | [`frontend/apps/web`](../../frontend/apps/web), [`backend/api/daemon/v1alpha/daemon_domains.go`](../../backend/api/daemon/v1alpha/daemon_domains.go), [`backend/blob/domain_store.go`](../../backend/blob/domain_store.go) | +| Vault | Secure identity/key storage and sync. The remote Vault is zero-knowledge; local daemon vault files hold local secure state. | Not per-account UI settings. One vault can protect multiple account keys. | [`vault/**`](../../vault/README.md), [`backend/storage/vault`](../../backend/storage/vault), [`proto/daemon/v1alpha/daemon.proto`](../../proto/daemon/v1alpha/daemon.proto) | +| Key | Private signing material used to create or control an account identity. In the daemon API, keys have local names/labels. | UI may call the public identity an "Account ID"; the key is secret/private material. | [`proto/daemon/v1alpha/daemon.proto`](../../proto/daemon/v1alpha/daemon.proto), [`backend/core/crypto.go`](../../backend/core/crypto.go), [`backend/core/keystore.go`](../../backend/core/keystore.go) | +| Principal | Packed, typed public key representation; string form is base58btc DID-key-style encoding. | A principal is public identity material, not a private key. | [`backend/core/principal.go`](../../backend/core/principal.go), [`frontend/packages/client/src/hm-types.ts`](../../frontend/packages/client/src/hm-types.ts) | +| Daemon | Local Go process that owns storage, indexing, P2P sync/discovery, gRPC/HTTP APIs, and key access for desktop/web dev flows. | Not the desktop UI. Desktop launches/talks to it, but the daemon is the backend runtime. | [`backend/daemon`](../../backend/daemon), [`backend/cmd/seed-daemon`](../../backend/cmd/seed-daemon), [`proto/daemon/v1alpha/daemon.proto`](../../proto/daemon/v1alpha/daemon.proto) | +| Document | Renderable knowledge object addressed by account + path and represented by refs/changes over time. | Not every entity is a document; comments, profiles, contacts, and capabilities are also signed objects. | [`proto/documents/v3alpha/documents.proto`](../../proto/documents/v3alpha/documents.proto), [`backend/api/documents/v3alpha/documents.go`](../../backend/api/documents/v3alpha/documents.go), [`frontend/packages/shared/src/models/document-machine.ts`](../../frontend/packages/shared/src/models/document-machine.ts) | +| Resource | Indexed addressable object, usually represented internally by an IRI (`hm://...`) and owner/genesis metadata. | Broader than document UI pages; resources can represent other addressable protocol objects. | [`backend/storage/schema.sql`](../../backend/storage/schema.sql), [`backend/blob/blob_ref.go`](../../backend/blob/blob_ref.go), [`frontend/packages/shared/src/api-resource.ts`](../../frontend/packages/shared/src/api-resource.ts) | +| Entity | Network-synced timeline/object with a DAG of changes and discovery status. | Broader than document and used by discovery/search/timeline APIs. | [`proto/entities/v1alpha/entities.proto`](../../proto/entities/v1alpha/entities.proto), [`backend/api/entities/v1alpha/entities.go`](../../backend/api/entities/v1alpha/entities.go), [`frontend/apps/desktop/src/models/entities.ts`](../../frontend/apps/desktop/src/models/entities.ts) | +| Blob | Signed or raw content-addressed unit stored by CID/multihash and indexed when understood. | Not the same as a document. Documents are reconstructed from Change/Ref blobs and attached content blobs. | [`backend/blob`](../../backend/blob), [`backend/storage/schema.sql`](../../backend/storage/schema.sql), [`frontend/packages/shared/src/blobs.ts`](../../frontend/packages/shared/src/blobs.ts) | +| Change | Signed blob containing document operations. A linked DAG of changes represents document content over time. | A change is one input to a document version; a document version may have multiple heads. | [`backend/blob/blob_change.go`](../../backend/blob/blob_change.go), [`proto/documents/v3alpha/documents.proto`](../../proto/documents/v3alpha/documents.proto), [`frontend/packages/client/src/change.ts`](../../frontend/packages/client/src/change.ts) | +| Ref | Signed blob that claims a path in a space/account points at document change heads, redirects, tombstones, and visibility. | Similar to a Git ref but signed and content-addressed. | [`backend/blob/blob_ref.go`](../../backend/blob/blob_ref.go), [`backend/api/documents/v3alpha/documents.go`](../../backend/api/documents/v3alpha/documents.go), [`frontend/packages/client/src/ref.ts`](../../frontend/packages/client/src/ref.ts) | +| Draft | Local unpublished edit state used before publishing signed blobs/refs. Desktop and web store drafts differently. | Not network-synced published state. Do not assume a draft exists on other devices. | [`frontend/apps/desktop/src/app-drafts.ts`](../../frontend/apps/desktop/src/app-drafts.ts), [`frontend/apps/web/app/document-edit/web-draft-db.ts`](../../frontend/apps/web/app/document-edit/web-draft-db.ts), [`frontend/packages/shared/src/models/document-machine.ts`](../../frontend/packages/shared/src/models/document-machine.ts) | +| Capability | Signed permission grant for a delegate to act on an account/path with a role. | Not the same as a browser session key, although a delegated session may rely on a capability. | [`proto/documents/v3alpha/access_control.proto`](../../proto/documents/v3alpha/access_control.proto), [`backend/blob/blob_capability.go`](../../backend/blob/blob_capability.go), [`frontend/packages/shared/src/models/capabilities.ts`](../../frontend/packages/shared/src/models/capabilities.ts) | +| Delegation | Flow where an account key authorizes another key/session to act within a scope. | Delegation is authorization; it is not transfer of the long-lived private account key. | [`docs/vault-session-key-delegation.md`](../vault-session-key-delegation.md), [`frontend/apps/web/app/routes/hm.api.delegate-device.tsx`](../../frontend/apps/web/app/routes/hm.api.delegate-device.tsx), [`vault/src`](../../vault/src) | +| Comment | Signed discussion unit targeting a document path/version; replies form threads. | Comments are blobs and API objects, not document changes. | [`proto/documents/v3alpha/comments.proto`](../../proto/documents/v3alpha/comments.proto), [`backend/blob/blob_comment.go`](../../backend/blob/blob_comment.go), [`frontend/packages/shared/src/models/comments.ts`](../../frontend/packages/shared/src/models/comments.ts) | +| Subscription | User interest in a document/account path, optionally recursive; used to sync and surface activity. | Not the same as notification email settings, though notification state may depend on subscriptions. | [`proto/activity/v1alpha/subscriptions.proto`](../../proto/activity/v1alpha/subscriptions.proto), [`backend/api/activity/v1alpha/subscriptions.go`](../../backend/api/activity/v1alpha/subscriptions.go), [`frontend/apps/desktop/src/derived-subscriptions.ts`](../../frontend/apps/desktop/src/derived-subscriptions.ts) | +| Discovery | Best-effort process of finding peers/blobs for an `hm://` resource or account/path scope. | Discovery status can be in progress even if cached content already exists. | [`proto/entities/v1alpha/entities.proto`](../../proto/entities/v1alpha/entities.proto), [`backend/hmnet/syncing/discovery.go`](../../backend/hmnet/syncing/discovery.go), [`frontend/apps/desktop/src/models/entities.ts`](../../frontend/apps/desktop/src/models/entities.ts) | +| Notification read state | Local-first state describing which notification events are read/unread and the mark-all-read watermark. | Separate from whether the event exists in the feed or whether email notifications are configured. | [`frontend/packages/shared/src/models/notification-read-logic.ts`](../../frontend/packages/shared/src/models/notification-read-logic.ts), [`frontend/apps/desktop/src/app-notification-read-state.ts`](../../frontend/apps/desktop/src/app-notification-read-state.ts), [`docs/notifications/local-first-read-state-edge-cases.md`](../notifications/local-first-read-state-edge-cases.md) | + +## Vault vs Account hierarchy + +- Vault-level concerns apply to the entire vault: biometric login, master password, email address, remote vault + connection, and vault encryption state. +- Account-level concerns apply to one Hypermedia account/key: profile, account ID, connected sites, backup/export, and + delete account. +- Do not show backup status badges unless the system can prove that specific account backup state. The current lesson is + that we do **not** know whether an account has been backed up. +- Backup/restore is a per-account action, not a vault-wide action. + +## Naming guidance + +- At API boundaries, preserve field names from existing protos (`account`, `path`, `signing_key_name`, etc.). +- In new prose, prefer "account" for user-facing identity/profile ownership and "principal" for public-key-level + identity. +- Use "space" only when describing backend blob/index internals or existing code that names the resource namespace that + way. +- Use "vault" only for secure key/identity storage and sync, not for account profile settings. diff --git a/docs/templates/feature-brief.md b/docs/templates/feature-brief.md new file mode 100644 index 000000000..287003fb4 --- /dev/null +++ b/docs/templates/feature-brief.md @@ -0,0 +1,30 @@ +# Feature/Fix Brief + +Status: current (template). + +## Problem + +## Desired behavior + +## Affected subsystems + +- [ ] proto +- [ ] backend API +- [ ] storage +- [ ] desktop +- [ ] web +- [ ] vault +- [ ] notify +- [ ] docs + +## Current code path + +## Domain terms / invariants + +## Proposed approach + +## Tests + +## Open questions + +## Docs to update diff --git a/frontend/README.md b/frontend/README.md index 9971d72be..0d8088879 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,5 +1,49 @@ -# Seed Hypermedia Frontend monorepo +# Seed Hypermedia frontend monorepo + +Status: current. + +The frontend workspace contains Electron, Remix apps, shared product models, editor/UI packages, and the low-level +TypeScript Hypermedia client. Use `pnpm` from the repo root for this subtree. + +## App and package map + +| Path | Package | Purpose | +| ------------------------------------------------ | ------------------------- | ------------------------------------------------------------------------------------------ | +| [`apps/web`](./apps/web/README.md) | `@shm/web` | Remix public/site web app, SSR loaders, web editing, daemon HTTP integration. | +| [`apps/desktop`](./apps/desktop/README.md) | `@shm/desktop` | Electron desktop app, daemon lifecycle, main/preload/renderer shell, desktop-only storage. | +| [`apps/notify`](./apps/notify/README.md) | `@shm/notify` | Notification service routes, email verification, inbox/config/read state. | +| [`packages/shared`](./packages/shared/README.md) | `@shm/shared` | Shared API adapters, routes, query models, document machine, notification/domain models. | +| [`packages/client`](./packages/client/README.md) | `@seed-hypermedia/client` | Low-level Hypermedia signing, imports, blob payload helpers, type schemas. | +| [`packages/editor`](./packages/editor/README.md) | `@shm/editor` | TipTap/BlockNote document editor, readonly viewer, comment editor, editor extensions. | +| [`packages/ui`](./packages/ui) | `@shm/ui` | Shared React UI components and resource/document surfaces. | ## Development -- [run sites locally](./apps/web/README.md) +```bash +pnpm install +pnpm web # web app dev server only +pnpm web:standalone # local daemon + web app +pnpm desktop # Electron app; ./dev run-desktop is usually preferred +pnpm notify:standalone +``` + +Prefer root `./dev` commands when they exist because they build required generated artifacts and daemon binaries first: + +```bash +./dev run-desktop +./dev run-web +./dev build-desktop +./dev build-web +``` + +## Checks + +```bash +pnpm typecheck +pnpm test +pnpm audit +pnpm format:write +``` + +For targeted work, use package filters, for example `pnpm --filter @shm/web test` or +`pnpm --filter @shm/shared typecheck`. diff --git a/frontend/apps/desktop/README.md b/frontend/apps/desktop/README.md new file mode 100644 index 000000000..aeb4bbdb8 --- /dev/null +++ b/frontend/apps/desktop/README.md @@ -0,0 +1,48 @@ +# Desktop app + +Status: current. + +`@shm/desktop` is the Electron app for local reading, editing, publishing, syncing, and account management. It starts a +local daemon unless configured otherwise, then exposes app-specific services to renderer windows through preload, IPC, +and tRPC. + +## Architecture + +| Area | Files | Notes | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------- | +| Main process entry | [`src/main.ts`](./src/main.ts) | Boots Electron, daemon, stores, windows, menus, notification sync, and app services. | +| Daemon lifecycle | [`src/daemon.ts`](./src/daemon.ts), [`src/daemon-path.ts`](./src/daemon-path.ts), [`src/grpc-client.ts`](./src/grpc-client.ts) | Builds/locates/runs `seed-daemon` and creates gRPC clients for renderer-facing models. | +| Preload | [`src/preload.ts`](./src/preload.ts), related `preload-*.ts` files | Safe bridge from isolated renderers to Electron APIs. | +| Renderer entry | [`src/renderer.ts`](./src/renderer.ts), [`src/root.tsx`](./src/root.tsx) | React app root and renderer initialization. | +| App services | [`src/app-*.ts`](./src) | Main-process services and stores. Prefer extending an existing `app-*.ts` by domain. | +| IPC/tRPC | [`src/app-ipc.tsx`](./src/app-ipc.tsx), [`src/app-trpc.ts`](./src/app-trpc.ts), [`src/trpc.ts`](./src/trpc.ts) | Renderer-to-main typed bridge. Keep payloads serializable. | +| Models | [`src/models`](./src/models) | Renderer hooks and data models around gRPC/tRPC/shared package APIs. | +| Pages | [`src/pages`](./src/pages) | Top-level route/page components. | +| Components | [`src/components`](./src/components) | Desktop-specific UI pieces; shared UI should live in `@shm/ui` when reusable. | +| Navigation | [`src/models/navigation.ts`](./src/models/navigation.ts), [`src/utils/navigation-container.tsx`](./src/utils/navigation-container.tsx), [`src/assistant-navigation.ts`](./src/assistant-navigation.ts) | Route state, navigation helpers, assistant-aware navigation. | + +## Conventions + +- `app-*.ts` files are main-process service boundaries for stores, background jobs, IPC/tRPC routers, and OS + integration. +- `models/*.ts` files are renderer-facing hooks/models; keep direct Electron/main process usage out of React components + unless bridged. +- Desktop draft state lives in [`src/app-drafts.ts`](./src/app-drafts.ts); web drafts use a different IndexedDB path. +- Notification architecture has a dedicated map in + [`src/NOTIFICATIONS_DESKTOP_ARCHITECTURE.md`](./src/NOTIFICATIONS_DESKTOP_ARCHITECTURE.md). +- Prefer shared code in `frontend/packages/shared`, `frontend/packages/ui`, or `frontend/packages/editor` only when web + and desktop genuinely share behavior. + +## Commands + +From the repo root: + +```bash +./dev run-desktop +./dev run-desktop-mainnet +./dev build-desktop +pnpm desktop:test:unit +pnpm desktop:test +pnpm --filter @shm/desktop typecheck +pnpm --filter @shm/desktop format:write +``` diff --git a/frontend/apps/web/README.md b/frontend/apps/web/README.md index 6114e0c22..a506a62d9 100644 --- a/frontend/apps/web/README.md +++ b/frontend/apps/web/README.md @@ -1,31 +1,79 @@ -## Dev +# Web app -To run the dev site service: +Status: current. -``` -yarn dev -``` +`@shm/web` is the Remix app that renders public Hypermedia sites, gateway routes, registration/device-link flows, web +notifications, and browser-based document editing. -To run the site daemon: +## Run locally -``` -SEED_P2P_TESTNET_NAME="dev" go run ./backend/cmd/seed-daemon -data-dir="$HOME/.seed-site" -p2p.port=59000 -grpc.port=59002 -http.port=59001 +The easiest local setup runs a daemon and web app together: + +```bash +pnpm web:standalone ``` -set `config.json` to: +To run only the web app against an already-running daemon: -``` -{"availableRegistrationSecret": "abc"} +```bash +pnpm web ``` -then go into the app and publish your account with this URL: +`pnpm web` sets the default dev daemon ports used by the root script. If you run your own daemon, use those ports or run +the Remix binary directly with custom environment variables: -``` -http://localhost:5175/hm/register?secret=abc +```bash +./dev run-backend -- -data-dir="$PWD/.dev-data/web" -p2p.port=58000 -http.port=58001 -grpc.port=58002 +pnpm web ``` -For web deployment in production +For custom daemon ports, bypass the root `pnpm web` script so its default port assignments do not override your +environment: +```bash +cd frontend/apps/web +SEED_BASE_URL="http://localhost:3099" PORT=3099 DAEMON_HTTP_URL="http://localhost:53001" DAEMON_FILE_URL="http://localhost:53001/ipfs" pnpm exec remix vite:dev ``` -sh <(curl -sL https://raw.githubusercontent.com/seed-hypermedia/seed/main/website_deployment.sh) https://seed.verse.link --tag main --auto-update + +## Remix structure + +| Area | Files | +| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Root/entries | [`app/root.tsx`](./app/root.tsx), [`app/entry.server.tsx`](./app/entry.server.tsx), [`app/entry.client.tsx`](./app/entry.client.tsx) | +| Catch-all site route | [`app/routes/$.tsx`](./app/routes/$.tsx) | +| API routes | [`app/routes/hm.api.*.tsx`](./app/routes) | +| Resource rendering | [`app/web-resource-page.tsx`](./app/web-resource-page.tsx), [`app/web-feed-page.tsx`](./app/web-feed-page.tsx) | +| SSR loading | [`app/loaders.ts`](./app/loaders.ts), [`app/queries.server.ts`](./app/queries.server.ts), [`app/client.server.ts`](./app/client.server.ts) | +| Universal clients | [`app/universal-client.tsx`](./app/universal-client.tsx), [`app/server-universal-client.ts`](./app/server-universal-client.ts) | +| Web editing | [`app/document-edit`](./app/document-edit), [`app/draft-media-db.ts`](./app/draft-media-db.ts) | +| Auth/vault | [`app/auth.tsx`](./app/auth.tsx), [`app/auth-session.ts`](./app/auth-session.ts), [`app/routes/hm.api.delegate-device.tsx`](./app/routes/hm.api.delegate-device.tsx), [`app/vault-links.ts`](./app/vault-links.ts) | +| Notifications | [`app/web-notifications.ts`](./app/web-notifications.ts), [`app/notifications-page-content.tsx`](./app/notifications-page-content.tsx), [`app/routes/hm.notifications.tsx`](./app/routes/hm.notifications.tsx) | + +See [`docs/ssr-loading-architecture.md`](./docs/ssr-loading-architecture.md) for SSR loader details. + +## Daemon connection + +The web server talks to a Seed daemon for document/resource data, blob files, discovery, and API operations. Important +environment variables include: + +| Variable | Purpose | +| ----------------------- | --------------------------------------------------------------------------------------- | +| `DAEMON_HTTP_URL` | Base URL for daemon HTTP APIs when not using only port-based defaults. | +| `DAEMON_HTTP_PORT` | Local daemon HTTP port used by the package `dev`/`start` scripts. | +| `DAEMON_FILE_URL` | URL prefix for daemon-served file/blob content, usually `http://localhost:/ipfs`. | +| `SEED_BASE_URL` | Public base URL for canonical links and auth/delegation flows. | +| `PORT` | Remix server port. | +| `SEED_IDENTITY_ENABLED` | Enables identity/delegation flows in standalone web runs. | +| `SEED_SIGNING_ENABLED` | Enables signing behavior where supported. | + +## Tests and checks + +```bash +pnpm --filter @shm/web test +pnpm --filter @shm/web typecheck +pnpm --filter @shm/web format:write +pnpm web:prod ``` + +For production deployment, use the root deployment scripts and Docker workflow documented from the root +[`README.md`](../../../README.md). diff --git a/frontend/packages/client/README.md b/frontend/packages/client/README.md new file mode 100644 index 000000000..ca187eba1 --- /dev/null +++ b/frontend/packages/client/README.md @@ -0,0 +1,33 @@ +# @seed-hypermedia/client + +Status: current. + +`@seed-hypermedia/client` is the low-level TypeScript Hypermedia client. It owns protocol-shaped payload construction, +signing helpers, import/export helpers, and schema/types that are useful outside a specific app shell. + +## Ownership map + +| Area | Files | Notes | +| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | +| Public exports | [`src/index.ts`](./src/index.ts) | Keep exports deliberate; app-level models should usually live in `@shm/shared`. | +| Client facade | [`src/client.ts`](./src/client.ts) | Low-level client operations around Hypermedia objects and daemon/web APIs. | +| Signing and capabilities | [`src/signing.ts`](./src/signing.ts), [`src/capability.ts`](./src/capability.ts), [`src/keyfile.ts`](./src/keyfile.ts), [`src/encryption.ts`](./src/encryption.ts) | Cryptographic signing, keyfile handling, encryption helpers. | +| Blob payloads | [`src/change.ts`](./src/change.ts), [`src/ref.ts`](./src/ref.ts), [`src/comment.ts`](./src/comment.ts), [`src/contact.ts`](./src/contact.ts), [`src/document-state.ts`](./src/document-state.ts) | Build and interpret Hypermedia document/comment/contact/ref state. | +| Imports/conversion | [`src/markdown-to-blocks.ts`](./src/markdown-to-blocks.ts), [`src/blocks-to-markdown.ts`](./src/blocks-to-markdown.ts), [`src/pdf-to-blocks.ts`](./src/pdf-to-blocks.ts), [`src/tei-to-blocks.ts`](./src/tei-to-blocks.ts), [`src/file-to-ipfs.ts`](./src/file-to-ipfs.ts) | Import helpers and block conversions. | +| Types/schemas | [`src/hm-types.ts`](./src/hm-types.ts), [`src/editor-types.ts`](./src/editor-types.ts) | Runtime schemas and shared TS types close to protocol payloads. | +| Resolver/URLs | [`src/hm-resolver.ts`](./src/hm-resolver.ts), [`src/auto-link.ts`](./src/auto-link.ts), [`src/base64.ts`](./src/base64.ts) | Hypermedia URL/ID helper logic. | + +## Guidelines + +- Keep this package app-agnostic: no Electron, Remix loader, React query, or UI dependencies. +- Prefer `@shm/shared` for higher-level product models and app-facing hooks. +- Add tests next to protocol/signing/import helpers; many files already have colocated `*.test.ts` coverage. + +## Commands + +```bash +pnpm --filter @seed-hypermedia/client test +pnpm --filter @seed-hypermedia/client typecheck +pnpm --filter @seed-hypermedia/client build +pnpm --filter @seed-hypermedia/client format:write +``` diff --git a/frontend/packages/shared/README.md b/frontend/packages/shared/README.md new file mode 100644 index 000000000..2e6f5a792 --- /dev/null +++ b/frontend/packages/shared/README.md @@ -0,0 +1,37 @@ +# @shm/shared + +Status: current. + +`@shm/shared` owns TypeScript behavior shared by desktop, web, notify, editor, and UI packages. Put code here when it +represents product/domain logic used across app surfaces, not app-specific shell behavior. + +## Ownership map + +| Area | Files | Notes | +| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | +| API adapters | [`src/api-*.ts`](./src) | Typed wrappers and transformations around daemon/web API responses. | +| Universal client | [`src/universal-client.ts`](./src/universal-client.ts), [`src/create-web-universal-client.ts`](./src/create-web-universal-client.ts), [`src/grpc-client.ts`](./src/grpc-client.ts) | Cross-runtime client abstractions consumed by web/desktop/shared models. | +| Routes and navigation types | [`src/routes.ts`](./src/routes.ts), [`src/routing.tsx`](./src/routing.tsx), [`src/validated-route-link.tsx`](./src/validated-route-link.tsx) | Shared route shapes, parsing, validated links. | +| Document machine | [`src/models/document-machine.ts`](./src/models/document-machine.ts), [`src/models/use-document-machine.ts`](./src/models/use-document-machine.ts), [`src/models/document-machine-inspect.ts`](./src/models/document-machine-inspect.ts) | Shared document lifecycle state machine and React bindings. | +| Query ownership | [`src/models/query-client.ts`](./src/models/query-client.ts), [`src/models/query-keys.ts`](./src/models/query-keys.ts), [`src/request-cache.ts`](./src/request-cache.ts) | Query key conventions, cache helpers, SSR/client request caching. | +| Document/content helpers | [`src/document-utils.ts`](./src/document-utils.ts), [`src/document-to-text.ts`](./src/document-to-text.ts), [`src/html-to-blocks.ts`](./src/html-to-blocks.ts), [`src/utils/document-changes.ts`](./src/utils/document-changes.ts), [`src/blobs.ts`](./src/blobs.ts) | Transformations shared by editor, web, desktop, and tests. | +| Comments | [`src/comments-service-provider.tsx`](./src/comments-service-provider.tsx), [`src/models/comments.ts`](./src/models/comments.ts), [`src/optimistic-comment.ts`](./src/optimistic-comment.ts) | Shared comment fetching, optimistic state, navigation behavior. | +| Notifications | [`src/models/notification-*.ts`](./src/models) | Notification payloads, event classification, titles, read-state merge logic. | +| Discovery/search | [`src/discovery.ts`](./src/discovery.ts), [`src/models/search.ts`](./src/models/search.ts), [`src/api-search.ts`](./src/api-search.ts) | Shared discovery helpers and search models. | + +## Guidelines + +- Keep app shell concerns out of this package. Electron main process code belongs in `frontend/apps/desktop`; Remix + server-only behavior belongs in `frontend/apps/web` or `frontend/apps/notify`. +- Prefer tests for domain logic in `src/__tests__` or colocated `*.test.ts` files. +- Do not duplicate normalization deep inside models; system-boundary code should pass canonical values into shared + internals. + +## Commands + +```bash +pnpm --filter @shm/shared test +pnpm --filter @shm/shared typecheck +pnpm --filter @shm/shared build:types +pnpm --filter @shm/shared format:write +```