Files
Marcos Paulo 77d538dd97
ci / ci (macos-latest) (push) Has been cancelled
ci / ci (ubuntu-latest) (push) Has been cancelled
ci / ci (windows-latest) (push) Has been cancelled
feat: Bases Cards, List, embeds, Map view, Maps settings and inline cell editing
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 04:45:32 -03:00

56 lines
7.6 KiB
Markdown

# Code map: where to edit (for agents)
Read this instead of exploring. `docs/ARCHITECTURE.md` has the crate-level design and status; this file says which FILE to open for which change. Rules: `AGENTS.md`, `.claude/rules/*.md`, `specs/agents/minimax-m3-1-flash.md`. Verified against the tree on 2026-10-20: if a path below is gone, `git grep` the symbol, then fix this file.
## Layers and crates (`cargo xtask layers` enforces)
L0 `vault` `markdown` | L1 `index` `canvas` `diagrams` `whiteboard` `annotate` `sync` `collab` `blocks` `pdf` | L2 `backlinks` `graph` `templates` `lint` `knowledge` | L3 `plugins` `themes` `calendar` | L4 `engine` | L5 `editor` `mcp` `i18n` | L6 `ui-egui`. Apps: `apps/notescraft` (desktop shell, launcher host), `apps/notescraft-cli`, `apps/notescraft-sync-server` (axum + rusqlite, exempt from layers). Nothing below L5 may use egui.
## Engine (`crates/engine/src`, package `notescraft-engine`)
Everything user-visible is a command (id, label, params, enabled, run) in a `Registry<Session>`.
| Want | Open |
|---|---|
| Register a command group | the group's `specs()`/`register_x(reg)`; add ONE call in `commands.rs::register_core` (list near the top, `register_*` calls after the loop) |
| Command shape, params validation | `spec.rs`, `params.rs`, a finished group to copy: `capture/`, `viewers/`, `share/commands.rs`, `review/commands.rs` |
| Which commands an AI assistant may call | `ai/assistant_gate.rs` (READ list vs WRITE list: add every new id) |
| Command list test | `tests/core_commands.rs` (`CORE_IDS`) |
| Errors | `error.rs` (one `Error` enum, add variants there; `thiserror`) |
| Session, buffers, open files | `vault/` (`session.rs`, `buffers.rs`, `attachments.rs`, `pdf_preview.rs`) |
| Settings (add a key) | `prefs/*_config.rs` (struct + defaults + validation), `prefs/catalog/` (listing), test like `tests/files_config_viewers.rs` |
| Server account, share, publish, invites | `share/` (`client.rs` = blocking `ServerClient`, `commands.rs`, `publish.rs`, `history.rs`, `bind.rs`) |
| Sync client, queue, conflicts | `sync/` (`worker.rs`, `commands.rs`, `conflicts.rs`) |
| Live co-editing | `live/` |
| Comments, suggestions, mentions | `review/` (`model`, `sidecar`, `anchor`, `suggestion`, `store`, `commands`, `merge`) |
| File viewers backend | `viewers/` (`file.info`, `file.hash`, `file.neighbours`, `image.annotations.*`) |
| Capture (`note.capture`) | `capture/` |
Engine tests: `crates/engine/tests/*.rs`, fixtures in `tests/common/mod.rs` (`TempVault`), drive the registry, not internals. Test servers: see `tests/versions_server.rs` pattern in `crates/ui-egui/tests/` and `tests/publish_stub/` in engine.
## UI (`crates/ui-egui/src`, package `notescraft-ui-egui`)
| Want | Open |
|---|---|
| A tab/view kind (file type -> view) | `widgets/tabs/kind.rs` (`TabKind::of`, tables, `icon()`), the dispatch in `shell/app/window/views.rs::show` (one arm per kind), the view in `views/<name>/` |
| An existing view | `views/`: `note_view`, `canvas_view`, `diagram_view`, `whiteboard_view`, `graph_view`, `calendar_view`, `settings_view`, `image_view` (+ `annotate/`), `media_view` (`video`, `pdf`, `audio/` = tab, embed card, waveform, live spectrum, own FFT, `ffplay` player; `bar.rs` = shared bar card/buttons), `code_view`, `file_card.rs` (info card), `folder_view.rs`, `share_dialog/` (members, invites, `publish.rs`), `versions_view/`, `trash_view/` |
| Bases (`.base` files) | pure crate `crates/bases` (`yaml/`, `expr/`, `eval/`, `query/`, `map/`), engine `crates/engine/src/bases/` (`base.*`, `maps.*`, `tiles/` fetcher and cache), the tab `views/base_view/` (`state.rs` queues engine calls and `BaseView::pump` runs them after the frame, `table/`, `menus/`) |
| Map view and Maps settings | `views/base_view/map/` (`camera` pan/zoom ease, `tiles` bounded texture cache fed by `maps.tile`, `markers` pins and clusters, `popup` card, placeholder and enable notice, `grid` fallback, zoom buttons and attribution), card `views/settings_view/categories/maps.rs`, copy `text/views/maps.rs` (`[ui.maps]`), tests `tests/base_map.rs` |
| Side panels | `panels/` (`tree*` = Explorer, `sidebar*`, `right*`, `search_panel`, `sync_*`) |
| Shared widgets | `widgets/` (`tabs/`, `context_menu.rs`, `palette.rs`, `bottom_sheet.rs`...) |
| App state and frame loop | `shell/app/` (`window/frame.rs` frame, `window/commands.rs` UI commands and `engine_command(id, &params)`, `window/views.rs` view state, `window/menus.rs`, `vault/` open/index, `sync.rs`, `live/`, `editor/` (paste/drop in `editor/attachments.rs`), `video.rs` ffmpeg player, audio player ticks from `vault/explorer.rs`) |
| Keyboard shortcuts, tab/panel focus hotkeys, shortcut text in tooltips | `shell/hotkeys/`: one table `defaults.rs` (add a chord there), `dispatch.rs` (consumes it once per frame), `commands.rs` (bodies, palette entries), `focus.rs` (panel landmarks); tooltips call `hotkeys::on_hover_hotkey(response, label, id)` / `hotkeys::tooltip`; `cargo test -p notescraft-ui-egui --lib hotkeys` checks the table for conflicts |
| Attachment paste and drop | `shell/attachment_drop/` (`collect` returns `Request`s; the app runs the engine command, no vault IO while painting) |
| Compact (phone) layout | `shell/compact/`, tokens in `design/style/compact*` |
| Icons | Lucide SVGs in `assets/icons/*.svg`, registered in `design/icons.rs` (`icon!("name")`), drawn with `crate::icons::paint(ui, "name", rect, colour)`; interactive controls use `design/lottie_icon.rs` |
| Colours, radii, spacing | theme tokens: `tokens.theme.colors.*` (`surface`, `surface_2`, `text`, `text_muted`, `accent`, `danger`...), `design/style.rs`; NEVER hex |
| Strings | every string goes through a table: `text/<area>.rs` or `text/views/<view>/mod.rs` with `table! { name = "ui.area.key"; }`, and the key in `crates/i18n/locales/en.toml` under `[ui.area]`. New table = append at the END of the `[ui.*]` tables; never between keys of another table. Check: `python3 -c "import tomllib;tomllib.load(open('crates/i18n/locales/en.toml','rb'))"`, `cargo xtask i18n`. Lib tests print raw keys? the i18n crate cached an old `en.toml`: `touch crates/i18n/src/i18n.rs` |
| Jobs that must not block the UI | worker thread + `std::sync::mpsc`, polled each frame, `ctx.request_repaint_after` (copy `share_dialog/mod.rs`) |
| UI tests | `crates/ui-egui/tests/*.rs` (egui_kittest, real events through frames; copy `share_ui.rs`, `image_view.rs`), unit tests next to the code, helpers `testsupport.rs` |
| Render a screen to PNG | `cargo run -p notescraft-ui-egui --example snapshot -- --vault <v> --out ui.png --size 1440x900 --open "note.md"` and READ the PNG |
Designs: `design/files/*.png` (viewers), `design/mobile/*.png`; PaperCraft project `NotesCraft`.
## Server (`apps/notescraft-sync-server/src`)
`api/routes.rs` (route table), `api/*` (accounts, vaults, members, invites), `store/` (rusqlite schema + queries), `history/`, `chunks/`, `live/`, `publish/` (pages, links, render), `activity/` (feed), `roles.rs`, `limits.rs`. HTTP tests: `apps/notescraft-sync-server/tests/*.rs` against a real in-process server.
## Gates (run only what you changed, then the whole set before claiming done)
`cargo test -p <crate>` | `cargo clippy -p <crate> --all-targets -- -D warnings` | `rustfmt --edition 2024 <your files>` (never `cargo fmt --all` in the shared tree) | `cargo xtask layers` | `cargo xtask tree` (max 12 loose `.rs` per dir) | `cargo xtask i18n` | `cargo xtask ci` (everything).
## Shared tree
Several agents and the owner work in one tree. Edit only the files your brief lists. Uncommitted files of others (check `git status`) are NOT yours and not part of your build: never depend on them, never fix them, say so in the report.