This document serves as the primary onboarding guide and reference for developers working on NotterPad. It outlines the core architectural principles, directory structure, data flow, and development guidelines.
The codebase follows a modular, feature-based architecture to maintain separation of concerns:
src/components/: Reusable UI components (React).src/lib/storage/: IndexedDB storage layer and repository pattern implementation.src/lib/ai/: Bring Your Own Key (BYOK) AI integrations, extraction logic, and prompt handling.src/lib/store/: Global state management and data stores.src/lib/models/: TypeScript interfaces and data models for entities.src/lib/engines/: Complex business logic engines (Canon Engine, Merge Engine).docs/: Technical documentation detailing specific system areas.
- Local-First / Offline-First: All data is stored locally in IndexedDB by default. The application must function without an internet connection (excluding AI features).
- Bring Your Own Key (BYOK): User privacy and cost management are handled by requiring users to provide their own API keys for AI services.
- Strict Typings: TypeScript is used extensively to define entities and API boundaries, reducing runtime errors.
- Separation of Concerns: The UI layer should be decoupled from the storage and AI layers. Repositories handle data access, stores handle state, and components render the view.
- IndexedDB: The fundamental storage mechanism. 12 object stores house entities, chapters, blobs, etc.
- Repositories (
src/lib/storage/repositories/): Abstract the IndexedDB API. They provide CRUD operations and specific queries for entities. - State Management (
src/lib/store/): Subscribes to changes or fetches data from repositories and exposes it to the React application via hooks or store subscriptions. - React UI: Consumes the state. Actions dispatched from the UI flow back through the store to the repositories, updating the IndexedDB and triggering state refreshes.
- Define Model: Create the TypeScript interface in
src/lib/models/. - Update Schema: Add a new object store definition in the IndexedDB initialization logic (
src/lib/storage/schema.tsor equivalent). Ensure versioning is handled correctly. - Create Repository: Implement a new repository class extending the base repository to handle CRUD for the new entity.
- Update State: Add state management logic in
src/lib/store/to expose the new entity to the UI. - Build UI: Create components to display and edit the entity.
- Implement Provider Interface: Create a new class implementing the core AI provider interface (e.g.,
IAIProvider) insrc/lib/ai/providers/. - Handle Authentication: Implement logic to securely store and retrieve the provider's API key.
- Map Schemas: Ensure the provider's output can be mapped to the expected JSON schema for extractions.
- Register Provider: Add the new provider to the provider registry/factory so it can be selected by the user in settings.
- Storage: Handled by IndexedDB. Blob storage is used for large assets (images).
- Merges: The Merge Engine handles conflict resolution when entities have overlapping data or when importing. It uses intelligent heuristics to suggest merges.
- Backups: Workspaces can be exported as full JSON objects. Novels can be exported individually. The import/export logic serializes and deserializes the IndexedDB state.
- Strict Mode: TypeScript strict mode is enabled and must be adhered to. No
anytypes unless absolutely necessary (and documented). - JSDoc: All exported functions, classes, and module headers must contain complete JSDoc annotations.
- No UI in Logic: Business logic (
lib/) must not import UI components. - Formatting: Use standard formatting (Prettier/ESLint) as configured in the project root.