# Getting Started How to navigate the codebase, run the app, and find what you need. ## Prerequisites - **Node.js** 18+ and **pnpm** - **Rust** 1.77.2+ (for the Tauri backend) - **git** CLI (required by the git integration features) ## Quick Start ```bash # Install dependencies pnpm install # Run in browser (no Rust needed — uses mock data) pnpm dev # Open http://localhost:5173 # Run with Tauri (full app, requires Rust) pnpm tauri dev # Run tests pnpm test # Vitest unit tests cargo test # Rust tests (from src-tauri/) pnpm test:e2e # Playwright E2E tests ``` ## Directory Structure ``` laputa-app/ ├── src/ # React frontend │ ├── main.tsx # Entry point (renders ) │ ├── App.tsx # Root component — orchestrates 4-panel layout │ ├── App.css # App shell layout styles │ ├── types.ts # Shared TS types (VaultEntry, GitCommit, etc.) │ ├── mock-tauri.ts # Mock Tauri layer for browser testing │ ├── theme.json # Editor theme configuration │ ├── index.css # Global CSS variables + Tailwind setup │ │ │ ├── components/ # UI components │ │ ├── Sidebar.tsx # Left panel: filters + section groups │ │ ├── NoteList.tsx # Second panel: filtered note list │ │ ├── Editor.tsx # Third panel: tabs + BlockNote + diff │ │ ├── Inspector.tsx # Fourth panel: metadata + relationships │ │ ├── DynamicPropertiesPanel.tsx # Editable frontmatter properties │ │ ├── EditableValue.tsx # Inline value editor component │ │ ├── DiffView.tsx # Git diff viewer │ │ ├── ResizeHandle.tsx # Draggable panel divider │ │ ├── StatusBar.tsx # Bottom status bar │ │ ├── QuickOpenPalette.tsx # Cmd+P command palette │ │ ├── CreateNoteDialog.tsx # New note modal │ │ ├── CommitDialog.tsx # Git commit modal │ │ ├── Toast.tsx # Toast notifications │ │ ├── Editor.css # Editor layout styles │ │ ├── EditorTheme.css # BlockNote theme overrides │ │ └── ui/ # shadcn/ui primitives (button, dialog, etc.) │ │ │ ├── hooks/ # Custom React hooks │ │ ├── useVaultLoader.ts # Loads vault entries, git status, content │ │ ├── useNoteActions.ts # Tab management, frontmatter CRUD, navigation │ │ └── useTheme.ts # Flattens theme.json into CSS variables │ │ │ ├── utils/ # Pure utility functions │ │ ├── frontmatter.ts # TypeScript YAML frontmatter parser │ │ └── wikilinks.ts # Wikilink preprocessing + word count │ │ │ ├── lib/ │ │ └── utils.ts # Tailwind merge + cn() helper │ │ │ └── test/ │ └── setup.ts # Vitest test environment setup │ ├── src-tauri/ # Rust backend │ ├── Cargo.toml # Rust dependencies │ ├── build.rs # Tauri build script │ ├── tauri.conf.json # Tauri app configuration │ ├── capabilities/ # Tauri v2 security capabilities │ │ └── default.json │ ├── src/ │ │ ├── main.rs # Entry point (calls lib::run()) │ │ ├── lib.rs # Tauri command registration (9 commands) │ │ ├── vault.rs # Vault scanning + markdown parsing │ │ ├── frontmatter.rs # YAML frontmatter manipulation │ │ └── git.rs # Git CLI operations │ └── icons/ # App icons │ ├── e2e/ # Playwright E2E tests │ ├── app.spec.ts # App loading tests │ ├── core-flows.spec.ts # Main user workflows │ ├── keyboard-shortcuts.spec.ts │ ├── quick-open.spec.ts │ ├── screenshot.spec.ts # Visual regression screenshots │ └── ... │ ├── package.json # Frontend dependencies + scripts ├── vite.config.ts # Vite bundler config ├── tsconfig.json # TypeScript config ├── playwright.config.ts # E2E test config ├── CLAUDE.md # Project instructions for Claude └── docs/ # This documentation ``` ## Key Files to Know ### Start here | File | Why it matters | |------|---------------| | `src/App.tsx` | The root component. Shows how the 4-panel layout is assembled and how state flows between components. | | `src/types.ts` | All shared TypeScript types. Read this first to understand the data model. | | `src-tauri/src/lib.rs` | All 9 Tauri commands in one place. This is the frontend-backend API surface. | ### Data layer | File | Why it matters | |------|---------------| | `src/hooks/useVaultLoader.ts` | How vault data is loaded and managed. The Tauri/mock branching pattern. | | `src/hooks/useNoteActions.ts` | Tab management, wikilink navigation, frontmatter CRUD. The biggest hook. | | `src/mock-tauri.ts` | Mock data for browser testing. Shows the shape of all Tauri responses. | ### Backend | File | Why it matters | |------|---------------| | `src-tauri/src/vault.rs` | Vault scanning, frontmatter parsing, entity type inference. The core backend logic. | | `src-tauri/src/frontmatter.rs` | YAML manipulation — how properties are updated/deleted in files. | | `src-tauri/src/git.rs` | All git operations. Shells out to git CLI. | ### Editor | File | Why it matters | |------|---------------| | `src/components/Editor.tsx` | BlockNote setup, custom wikilink schema, tab bar, breadcrumb bar, diff toggle. | | `src/utils/wikilinks.ts` | The wikilink preprocessing pipeline (markdown → BlockNote blocks with wikilinks). | | `src/components/EditorTheme.css` | BlockNote CSS overrides for typography and styling. | ### Styling | File | Why it matters | |------|---------------| | `src/index.css` | All CSS custom properties (colors, spacing). The design token source of truth. | | `src/theme.json` | Editor-specific theme (fonts, headings, lists, code blocks). | | `src/hooks/useTheme.ts` | Converts theme.json into CSS variables for the editor. | ## Architecture Patterns ### Tauri/Mock Branching Every data-fetching operation checks `isTauri()` and branches: ```typescript if (isTauri()) { result = await invoke('command', { args }) } else { result = await mockInvoke('command', { args }) } ``` This lives in `useVaultLoader.ts` and `useNoteActions.ts`. Components never call Tauri directly. ### Props-Down, Callbacks-Up No global state management (no Redux, no Context). `App.tsx` owns the state and passes it down as props. Child-to-parent communication uses callback props (`onSelectNote`, `onCloseTab`, etc.). ### Discriminated Unions for Selection State ```typescript type SidebarSelection = | { kind: 'filter'; filter: 'all' | 'favorites' } | { kind: 'sectionGroup'; type: string } | { kind: 'entity'; entry: VaultEntry } | { kind: 'topic'; entry: VaultEntry } ``` This pattern makes it easy to handle all selection states exhaustively. ## Running Tests ```bash # Unit tests (fast, no browser) pnpm test # Rust tests cd src-tauri && cargo test # E2E tests (requires dev server) pnpm test:e2e # Single Playwright test npx playwright test e2e/screenshot.spec.ts # Visual verification screenshots npx playwright test e2e/screenshot.spec.ts # Screenshots saved to test-results/ ``` ## Common Tasks ### Add a new Tauri command 1. Write the Rust function in `vault.rs`, `git.rs`, or a new module 2. Add `#[tauri::command]` wrapper in `lib.rs` 3. Register it in the `generate_handler![]` macro in `lib.rs` 4. Call it from the frontend via `invoke()` in the appropriate hook 5. Add a mock handler in `mock-tauri.ts` ### Add a new component 1. Create `src/components/MyComponent.tsx` 2. If it needs vault data, receive it as props from the parent 3. Wire it into `App.tsx` or the relevant parent component 4. Add a test file `src/components/MyComponent.test.tsx` ### Add a new entity type 1. Create the folder in the vault (e.g., `~/Laputa/mytype/`) 2. Add the folder → type mapping in `vault.rs:parse_md_file()` (the `match` on folder names) 3. The sidebar section groups are defined as `SECTION_GROUPS` in `Sidebar.tsx` — add it there 4. Update `CreateNoteDialog.tsx` type options if users should be able to create it