Version 3.8.0 ยท All versions

All pages

These are the docs as released with Solid Memo 3.8.0. Read the latest docs.

Architecture

Solid Memo is structured as hexagonal (ports & adapters) layers, and each layer is its own npm workspace package in a Turborepo monorepo. A package's package.json names what it may import, and npm run check:boundaries holds every import to that (boundaries.md). The composition root is the one place where the layers meet.

Packages

PackageFolderResponsibility
@solid-memo/webapps/web/The site's one page: its entry point (src/main.tsx), which renders the app over the use cases composition wires, the page (src/App.tsx) that shows Solid Memo, or the Studio at its routes, loaded lazily, and the Vite build that also publishes ns/ (the vocabulary and shapes), decks/ (the deck library) and these docs, rendered by markdown's tooling, with the app (deployment.md).
@solid-memo/studioapps/studio/Solid Memo Studio (studio.md): its screens and router (src/ui/), and its entry point, StudioWorkspace, which the site's page loads as a chunk of its own at the hashes under #/studio.
@solid-memo/compositionpackages/composition/The composition root (createAppUseCases in src/appUseCases.ts): every adapter behind its port, the guest's pod, the write fence, the site's documents read from where it is served, and the use cases over them, a Studio trial's sandbox among them (createTrialUseCases in src/trialUseCases.ts, studio.md). An app passes what is its own: its name, where it is served, the build's values.
@solid-memo/uipackages/ui/The Preact UI: the components and the router (src/ui/), the messages in each language (src/i18n/), the theme and the styles (src/style.css). It receives UseCases and knows no adapter.
@solid-memo/applicationpackages/application/Use cases (what the app does) and ports (what the app needs).
@solid-memo/domainpackages/domain/Pure types and pure functions: the app's vocabulary, SRS, migrations.
@solid-memo/vocabpackages/vocab/The data contract: the TypeScript generated (src/*.generated.ts) from the RDF vocabulary and SHACL shapes in the repository's ns/ (vocab.md, shapes.md), with the generator (tooling/); vendored profiles (vendor/) and fixtures.
@solid-memo/solidpackages/solid/Adapters for Solid pods (Inrupt): repositories, the type index, the instance copier, the write fence, the pod-reading shape validator, the deck archive (decks as Turtle or JSON-LD files, data-model.md), the drafts of releases and the Turtle a release is written in (data-model.md), and the guest's pod kept in the browser (guest-mode.md).
@solid-memo/shaclpackages/shacl/The SHACL engine (rdf-validate-shacl, loaded lazily), profiles and shape loading (src/); node-side validation of Turtle files and the deck library's index and checks, its Markdown rules among them (node/, npm run library).
@solid-memo/browserpackages/browser/Adapters for the browser: the update journal, the language, the guest's pod's store (IndexedDB), and files saved as downloads and opened from the user's disk (FileExchange).
@solid-memo/turtlepackages/turtle/Node-only Turtle tooling (n3): parsing and the house-style formatter.
@solid-memo/markdownpackages/markdown/Markdown in data, read into a tree of its own, folded to what the app shows and bounded at every entry point, derived as plain text, and checked by the rules for a release; and the repository's own docs, read in the same dialect with their headings kept and rendered by its node tooling (tooling/) to static pages, their links checked and their Mermaid diagrams drawn to SVG in Chromium, with the Vite plugin that publishes them (markdown.md), their pages listed from their index, docs/docs.ttl. Imports nothing of the app's but turtle, from tooling/ only, to read that index.
@solid-memo/e2e-pode2e/pod/End-to-end tests of the app's use cases and Solid adapters against real Solid servers, started in Docker (testing.md).
@solid-memo/e2e-journeyse2e/journeys/The user journeys: whole flows a user takes through the built app, driven in Chromium with Playwright against a Community Solid Server in Docker (testing.md). It imports nothing of the app's but its messages, to find text on screen by.

Each package's folder has a README.md: what the package is, what it exports, what it may import and who may import it, and how to test it. Its package.json has a one-line description.

Dependency rule

A package may depend only on packages below it in this graph. Adapters implement application ports (dependency inversion): the application owns the interfaces, adapters conform to them.

Package dependencies
Which packages import which, with a dotted arrow where an import is allowed only from certain files.
The diagram's source
graph TD
    accTitle: Package dependencies
    accDescr: Which packages import which, with a dotted arrow where an import is allowed only from certain files.
    web["apps/web<br/>the page"] --> ui["ui<br/>the components"]
    web -. "main.tsx only, lazily" .-> studio["apps/studio<br/>its screens"]
    studio --> ui
    ui --> application
    web -. "main.tsx only" .-> composition["composition<br/>the composition root"]
    composition --> application & solid & browser
    ui -. src/ui/ only .-> markdown
    web -. "vite.config.ts and its test only" .-> markdown
    application --> domain --> vocab["vocab<br/>the data contract"]
    solid -. implements ports .-> application
    solid --> domain & vocab & shacl
    browser -. implements ports .-> application
    shacl --> domain & vocab
    shacl -. node/ only .-> turtle & markdown
    vocab -. tooling/ only .-> turtle
    markdown -. tooling/ only .-> turtle
    e2e["e2e/pod"] --> application & solid
    journeys["e2e/journeys"] -. "harness/strings.ts only" .-> ui

Packages are consumed as TypeScript source (exports maps @solid-memo/<package>/<module> to src/<module>.ts): there is no build step between packages, and Vite bundles the app from source. ui maps @solid-memo/ui/<module> to src/ui/<module>.tsx, lists its few .ts modules one by one, and exports style.css and the message files (i18n/<locale>.json).

Tasks

turbo.json runs each package's typecheck, test, test:roundtrip (solid's, every library release through a draft, testing.md), generate:check, format:turtle:check, library:check and build in dependency order, cached by input. A task's inputs are its package's files and those of the packages it depends on; the few that also read ns/ or decks/ add them in their package's own turbo.json (vocab, shacl, solid, composition, apps/web and apps/studio), so a deck edit reruns only the tasks that read the library. The Studio has no build of its own: Solid Memo's bundles it (studio.md).

npm run check     # Biome's lint, markdownlint, cspell; then every package: typecheck, tests (100% coverage), the round trip, drift, Turtle formatting, the deck library; then boundaries
npm run build     # the site, the Studio and the docs included, into apps/web/dist/
npm run browsers  # once: Chromium, which npm run check and npm run build draw the docs' diagrams in (markdown.md)
npm run dev       # the site, from source; the Studio at #/studio
npm start         # the site as deployed: built, then served at http://localhost:4173
npm run test:unit # every package's tests in one run, without coverage (a file or two: `-- <path>`)
npm run test:watch # the same, in watch mode
npm run test:pod  # e2e/pod against the Solid servers it starts in Docker (testing.md)
npm run pod       # a Community Solid Server at http://127.0.0.1:3999/, to poke at by hand
npm run pod:clean # take down the servers an interrupted run left
npm run generate  # the vocab package's generated TypeScript, from ns/
npm run format:turtle  # every Turtle file in the house style
npm run library   # the deck library's index, decks/index.ttl
npm run crosscheck # the pySHACL cross-check CI runs (Python, scripts/requirements-ci.txt)

Key objects

Why