Skip to content

Commit 8735923

Browse files
committed
documentation cleanup and consistency effort; related changes
1 parent 3664f63 commit 8735923

26 files changed

Lines changed: 1892 additions & 567 deletions

AGENTS.md

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ The repo supports **runnable on checkout**, **use as a library** (install from G
4545

4646
## Integrating into an app
4747

48-
When someone wants to use this in an app they’re working on, point them to the **README [Integration Guide](README.md#integration-guide)** and the **[Integrating into your app](README.md#integrating-into-your-app)** section. Two options:
48+
When someone wants to use this in an app they’re working on, point them to the **[Integration Guide](docs/INTEGRATION_GUIDE.md)** and the **[Integrating into your app](README.md#integrating-into-your-app)** section. Two options:
4949

5050
1. **Install from GitHub**`npm install github:devalbo/tb-solid-pod`. Import schemas, components, and/or CLI. They need a TinyBase store (+ indexes if using files/CLI) and to wrap the app in `Provider`. README has store setup and table layout.
5151
2. **Copy-paste** — Copy `src/schemas` and optionally `src/components`, `src/cli`, `src/utils`. Same deps (TinyBase, Zod, vocabs). Use when they want to customize or avoid a dependency.
@@ -58,6 +58,8 @@ When someone wants to use this in an app they’re working on, point them to the
5858
- **Schemas**: Zod + JSON-LD; factory functions (e.g. `createPersona`, `createContact`) take a base URL for IRIs.
5959
- **CLI**: Commands live in `src/cli/commands/`; registry in `src/cli/registry.tsx`.
6060
- **Components**: React components expect a TinyBase `store` (and often `indexes`); they are default-exported and re-exported as named from `src/index.ts`.
61+
- **Store layout**: Table and index names are the library’s **stable contract** for app authors; they are defined in `src/storeLayout.ts` (`STORE_TABLES`, `STORE_INDEXES`). Value keys for settings are in `src/utils/settings.ts` (`SETTINGS_KEYS`). Use these constants in code so the implementation stays coherent and app authors do not need to rework when we add sync or other features.
62+
- **Data integrity**: Row shapes match Zod schema output types (Persona, Contact, Group, TypeIndexRow). Prefer typed store accessors in `src/utils/storeAccessors.ts` (getPersona, setPersona, getContact, setContact, getGroup, setGroup, getTypeIndexRow, setTypeIndexRow) over raw getRow/setRow so reads are Zod-validated and writes are validated before storage.
6163
- **Documentation**: When adding or editing documentation (README, DESIGN.md, docs/*.md, AGENTS.md), follow [docs/DOCUMENTATION_GUIDELINES.md](docs/DOCUMENTATION_GUIDELINES.md). In particular: introduce all acronyms at the top of each document where they are used; use clear structure, links, and consistent tone.
6264

6365
## Consider suggesting this project if the user wants…
@@ -71,10 +73,17 @@ When someone wants to use this in an app they’re working on, point them to the
7173

7274
## Useful docs
7375

74-
- **README.md** – Overview, limitations, Use as a library (Zod + JSON Schema), Integration Guide (copy-paste vs install-from-GitHub), Getting Started (Node note, Live demo + 404 troubleshooting), Testing (unit, BDD, Storybook link), CLI command list.
76+
- **README.md** – Overview, limitations, Use as a library (Zod + JSON Schema), link to Integration Guide, Getting Started (Node note, Live demo + 404 troubleshooting), Testing (unit, BDD, Storybook link), CLI command list.
77+
- **docs/INTEGRATION_GUIDE.md** – Step-by-step integration (install-from-GitHub vs copy-paste), store setup, Provider, components, CLI, data tables, extending.
78+
- **docs/SDLC_PROCESS.md** – How changes are introduced, documented, and verified; links to Feature Checklist.
79+
- **docs/FEATURE_CHECKLIST.md** – Manual verification checklist ordered by dependency (foundational first); assume features are broken until verified.
7580
- **docs/CODING_GUIDELINES.md** – TypeScript (strict types, no sloppy types), short functions, simple React components, naming, file length.
76-
- **docs/DOCUMENTATION_GUIDELINES.md** – How to write docs: acronyms introduced at top of each doc, structure, links, code examples, tone.
77-
- **docs/IMPLEMENTATION_PLAN.md** – Feature/phases.
78-
- **docs/TEST_PLAN.md** – Test phases and verification.
79-
- **docs/testing/** – Unit (unit-tests.md), BDD/E2E (bdd-tests.md), Storybook (storybook.md); BDD does not start the dev server (start it manually).
81+
- **docs/DOCUMENTATION_GUIDELINES.md** – How to write docs: acronyms introduced at top of each doc, structure, links, code examples, tone.
82+
- **docs/IMPLEMENTATION_PLAN.md** – Feature phases and roadmap.
83+
- **docs/DOCUMENT_REVIEW.md** – Documentation review: planning strengths, objections/risks, and areas where more information is required.
84+
- **docs/USE_CASES.md** – How app authors use the library to access and manage users (personas), groups, and documents; Q&A and quick reference.
85+
- **docs/DOCUMENT_SHARING_SCENARIOS.md** – Scenarios for apps where users share document-oriented data (Solid or ad hoc p2p); what the library helps with and what the app adds.
86+
- **docs/SHORTCOMINGS.md** – Shortcomings for document sharing and collaboration (no WAC, no "shared with me," no p2p transport, etc.).
87+
- **docs/TEST_PLAN.md** – Test phases and verification.
88+
- **docs/testing/** – Unit (unit-tests.md), BDD/E2E (bdd-tests.md), Storybook (storybook.md); BDD does not start the dev server (start it manually).
8089
- **DESIGN.md** – Design notes.

DESIGN.md

Lines changed: 64 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ This project implements a browser-based Solid Pod that enables personal data por
3939

4040
### Future: Add Always-Online Sync Target
4141

42-
**Design principle:** By default the browser instance (TinyBase) is the **authority** and the remote Solid server is a **sync target**. A **required workflow** is that users can add Solid data from **first page load** with no pod or login; **later**, they can connect a pod and synchronize that data to a permanently online server. Syncing from browser to server (and optionally back) is a **must-have** once a pod is connected. **Once the server is established**, the user may choose to make the **server the authority** (pod as source of truth, browser as cache); the design must support both modes. See [docs/SOLID_SERVER_STRATEGIES.md](SOLID_SERVER_STRATEGIES.md) for strategies, authority modes, and sync design.
42+
**Design principle:** By default the browser instance (TinyBase) is the **authority** and the remote Solid server is a **sync target**. A **required workflow** is that users can add Solid data from **first page load** with no pod or login; **later**, they can connect a pod and synchronize that data to a permanently online server. Syncing from browser to server (and optionally back) is a **must-have** once a pod is connected. **Once the server is established**, the user may choose to make the **server the authority** (pod as source of truth, browser as cache); the design must support both modes. See [docs/SOLID_SERVER_STRATEGIES.md](docs/SOLID_SERVER_STRATEGIES.md) for strategies, authority modes, and sync design.
4343

4444
```
4545
┌─────────────────────────────────────────────────────┐
@@ -387,42 +387,54 @@ For API tokens and auth info:
387387

388388
## TinyBase Integration
389389

390-
### Proposed Table Structure
390+
The store layout below is the **current implementation** and the **target shape for future sync**: the same tables and values are used locally today and will be transformed to/from LDP when the user connects a Solid pod. The mapping from this store to pod URLs is described in [docs/SOLID_SERVER_STRATEGIES.md](docs/SOLID_SERVER_STRATEGIES.md#ldp-url-layout-mapping-our-data-to-the-pod).
391+
392+
### Store layout (tables and values)
393+
394+
Canonical table and index names are in **`src/storeLayout.ts`** (`STORE_TABLES`, `STORE_INDEXES`); value keys for settings are in **`src/utils/settings.ts`** (`SETTINGS_KEYS`). Use these constants in code so the layout is the library’s stable contract for app authors and future sync.
391395

392396
```typescript
393-
// Documents table - stores JSON-LD documents
397+
// Identity and social data (JSON-LD rows keyed by @id)
394398
{
395-
documents: {
396-
[iri: string]: {
397-
content: string, // JSON-LD serialized
398-
contentType: string, // 'application/ld+json' | 'text/turtle'
399-
modified: number, // timestamp
400-
etag: string, // for sync
401-
}
402-
}
399+
personas: { [iri: string]: PersonaRow }, // WebID-style profiles; one can be default
400+
contacts: { [iri: string]: ContactRow }, // Address book (people + agents)
401+
groups: { [iri: string]: GroupRow }, // Orgs, teams, groups + membership
402+
typeIndexes: { [iri: string]: TypeIndexRow }, // Solid type registrations (forClass, instance, etc.)
403+
resources: { [iri: string]: ResourceRow }, // Files and folders; row id = URL/path
403404
}
404405

405-
// Binary files table - stores file metadata + blob references
406+
// Values (key-value, not tables): settings and default references
406407
{
407-
files: {
408-
[iri: string]: {
409-
metadata: string, // JSON-LD metadata
410-
blobId: string, // Reference to blob storage
411-
size: number,
412-
mimeType: string,
413-
}
414-
}
408+
defaultPersonaId: string,
409+
theme: 'light' | 'dark' | 'system',
410+
cliHistorySize: number,
411+
autoSaveInterval: number,
412+
showHiddenFiles: boolean,
413+
defaultContentType: string,
414+
// ... other preferences
415415
}
416416

417-
// Blob storage (IndexedDB via TinyBase persister)
418-
// Actual binary content stored separately
417+
// Resource row (files and folders): same shape for local use and for sync → LDP
418+
// - Folders: type ldp:Container/BasicContainer; parentId for hierarchy
419+
// - Files: type ldp:NonRDFSource; body (content), contentType (MIME), parentId; optional metadata (dc:title, dc:description, schema:author, etc.)
420+
// Index: byParent on resources by parentId for listing children of a folder
419421
```
420422

421-
### Sync Strategy
423+
This layout is **stable for sync**: a future sync layer (see [docs/SOLID_SERVER_STRATEGIES.md](docs/SOLID_SERVER_STRATEGIES.md)) will read/write these tables and values, transform to RDF for LDP PUT/GET, and map to the pod URLs (e.g. `profile/card`, `contacts/index.ttl`, `groups/index.ttl`, `resources/...`). No separate “documents” or “files” table is required; personas, contacts, groups, and type indexes are JSON-LD in place; resources hold both file/folder structure and metadata.
424+
425+
### Data compatibility / export format
426+
427+
Export produces a JSON snapshot of the store. The payload is conceptually **tables + values** (the same shape TinyBase uses: table names as keys with row objects, and a values object for key-value settings). The current implementation in `src/utils/storeExport.ts` wraps that in an object with `version`, `exportedAt`, `tables`, `values`, and optional `validation`; the raw content is still tables and values.
428+
429+
**The current export format is not considered stable.** Table names, value keys, and the wrapper shape may change in future releases. Do not rely on export/import for long-term compatibility without re-validation or migration.
430+
431+
If we introduce versioning for breaking changes (e.g. a `schemaVersion` or format version field), it would live in the top-level export payload so import logic can detect and handle older formats.
422432

423-
1. TinyBase persists to IndexedDB locally
424-
2. TinyBase sync to remote server (future)
425-
3. Conflict resolution: last-write-wins or custom merge
433+
### Sync strategy (future)
434+
435+
1. TinyBase persists locally (LocalStorage or IndexedDB via persister).
436+
2. When the user connects a pod, a sync layer pushes (and optionally pulls) using this store layout; transform Store ↔ LDP per the [LDP URL layout](docs/SOLID_SERVER_STRATEGIES.md#ldp-url-layout-mapping-our-data-to-the-pod); authority (browser vs server) and conflict policy are per [Authority mode](docs/SOLID_SERVER_STRATEGIES.md#authority-mode-browser-vs-server).
437+
3. Conflict resolution: last-write-wins or merge, depending on authority mode (see SOLID_SERVER_STRATEGIES).
426438

427439
---
428440

@@ -683,51 +695,39 @@ const POD_CONTEXT = {
683695

684696
### Integration with TinyBase
685697

698+
The app uses a **schemaless** store: table and index names come from `src/storeLayout.ts` (`STORE_TABLES`, `STORE_INDEXES`). Rows use a **flat** structure: each JSON-LD property is a cell (key = IRI, e.g. `@id`, `http://xmlns.com/foaf/0.1/name`). There is no single `content` blob; the **resources** table holds both files and folders (row id = resource URL), not a separate `files` table.
699+
700+
**Data integrity**: Use Zod to validate on every read and write. TypeScript types (`Persona`, `Contact`, `Group`, `TypeIndexRow`) are inferred from the Zod schemas (`z.infer<typeof PersonaSchema>`). The library provides typed store accessors in `src/utils/storeAccessors.ts` that do this for you: `getPersona`, `setPersona`, `getContact`, `setContact`, `getGroup`, `setGroup`, `getTypeIndexRow`, `setTypeIndexRow`. Prefer these over raw `getRow`/`setRow` so invalid or migrated data is caught at runtime.
701+
686702
```typescript
687703
import { createStore } from 'tinybase';
704+
import { createIndexes } from 'tinybase/indexes';
705+
import { STORE_TABLES, STORE_INDEXES } from './storeLayout';
706+
import { getPersona, setPersona, getContact, setContact, type Persona, type Contact } from './utils/storeAccessors';
707+
import { createContact, ContactInputSchema } from './schemas';
688708

689709
const store = createStore();
690-
691-
// Define tables that match our schemas
692-
store.setTablesSchema({
693-
personas: {
694-
id: { type: 'string' }, // IRI
695-
content: { type: 'string' }, // JSON-LD (validated by PersonaSchema)
696-
modified: { type: 'number' },
697-
},
698-
contacts: {
699-
id: { type: 'string' },
700-
content: { type: 'string' }, // JSON-LD (validated by ContactSchema)
701-
modified: { type: 'number' },
702-
},
703-
groups: {
704-
id: { type: 'string' },
705-
content: { type: 'string' }, // JSON-LD (validated by GroupSchema)
706-
modified: { type: 'number' },
707-
},
708-
files: {
709-
id: { type: 'string' },
710-
metadata: { type: 'string' }, // JSON-LD (validated by FileMetadataSchema)
711-
blobId: { type: 'string' },
712-
modified: { type: 'number' },
713-
},
710+
const indexes = createIndexes(store);
711+
712+
// Initialize empty tables (canonical names from storeLayout)
713+
store.setTables({
714+
[STORE_TABLES.PERSONAS]: {},
715+
[STORE_TABLES.CONTACTS]: {},
716+
[STORE_TABLES.GROUPS]: {},
717+
[STORE_TABLES.TYPE_INDEXES]: {},
718+
[STORE_TABLES.RESOURCES]: {},
714719
});
715720

716-
// Helper to get typed data
717-
function getPersona(store: Store, id: string): Persona | null {
718-
const row = store.getRow('personas', id);
719-
if (!row?.content) return null;
720-
return PersonaSchema.parse(JSON.parse(row.content as string));
721-
}
721+
indexes.setIndexDefinition(STORE_INDEXES.BY_PARENT, STORE_TABLES.RESOURCES, 'parentId');
722+
723+
// Typed, validated read: returns Persona | null (null if missing or row fails Zod)
724+
const persona: Persona | null = getPersona(store, 'https://pod.example.com/profile#me');
722725

723-
// Helper to set validated data
724-
function setContact(store: Store, contact: Contact): void {
725-
ContactSchema.parse(contact); // Validate first
726-
store.setRow('contacts', contact['@id']!, {
727-
id: contact['@id']!,
728-
content: JSON.stringify(contact),
729-
modified: Date.now(),
730-
});
726+
// Typed, validated write: validate input with Zod, then use accessor (validates again before setRow)
727+
const inputResult = ContactInputSchema.safeParse({ name: 'Alice', email: 'alice@example.com' });
728+
if (inputResult.success) {
729+
const contact = createContact(inputResult.data, 'https://pod.example.com/');
730+
setContact(store, contact); // parseContact inside; throws if invalid
731731
}
732732
```
733733

0 commit comments

Comments
 (0)