diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 491809b..80ed250 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -79,6 +79,16 @@ packages/ (`./config`, not `./config.js`). Cross-package imports use the package name (`@notes/shared`). - **Functional React components**; hooks for state. Global app state via **React Context + reducers**; heavy widgets (editor, canvas, table) may own encapsulated local stores. +- **Avoid `useEffect` for app logic**. Use it only for true external synchronization + boundaries (for example: registering/unregistering message/event handlers, imperative API + wiring, timers, subscriptions). Derive UI state from props/state/query data instead of + effect-driven state syncing. +- **Discourage `useRef` unless truly required** (DOM handles, stable imperative instances, + mutable escape hatches that must not trigger renders). Prefer regular state, memoization, + and pure data flow when possible. +- **Use `@tanstack/react-query` for all new data fetching and mutations** (already wired in + this repo; board note types are a reference implementation). For new query surfaces, define + and use **query key factories** rather than ad-hoc inline keys. - **Strict TypeScript** — no implicit `any`, handle `null`/`undefined`, keep functions typed. - **Desktop-safe interactions only** — never use `window.prompt` dialogs (they fail in desktop). Use in-app modal/popover UI components for user input instead. @@ -86,12 +96,15 @@ packages/ ## Testing & Verification -- Run `npm run typecheck && npm test` after each task; fix errors before moving on. +- After completing work, run formatting, linting, tests (unit/integration and e2e), and + compilation/type checks, then fix any linting errors before considering the task complete. - Add Vitest unit tests for logic (`*.test.ts` beside the code) and Playwright specs in `e2e/`. - First e2e run needs browsers: `npx playwright install chromium`. ## Git Conventions +- For new work, explicitly create/switch to a feature branch before making implementation + changes. - **Conventional commits:** `feat:`, `fix:`, `refactor:`, `chore:`, `test:`, `docs:`. - **Targeted commits only** — never `git add -A`. Stage specific files/hunks and verify with `git diff --cached --stat` before committing. diff --git a/.github/skills/create-note-type/SKILL.md b/.github/skills/create-note-type/SKILL.md new file mode 100644 index 0000000..f3ad20a --- /dev/null +++ b/.github/skills/create-note-type/SKILL.md @@ -0,0 +1,106 @@ +--- +name: create-note-type +description: Create a new first-party note type package using the current note registry patterns. Use when asked to add a note type (board/canvas-style), including parser/serializer, rendered/editor modes, and TanStack Query data hooks. +--- + +# Create Note Type (Repository Skill) + +Use this skill when implementing a new first-party note type in this repository. + +## Required outcome + +Create a complete note-type implementation that matches the existing package patterns (`note-boards`, `note-canvas`, `note-calendar`, `note-grid`, `note-tables`) and the current note registry wiring on this branch. + +## Implementation workflow + +1. Confirm work is happening on a feature branch for new work. +2. Study current note-type registration and mirror it (do not invent a parallel registration path). +3. Create or update a package under `packages/note-/`. +4. Wire data model + serialization + UI + registry + tests together end-to-end. + +## Required file pattern + +Create these files (names adjusted for ``): + +- `packages/note-/src/-note-type.ts` +- `packages/note-/src/-view.tsx` +- `packages/note-/src/-format.ts` +- `packages/note-/src/-format.test.ts` +- `packages/note-/src/-query-keys.ts` +- `packages/note-/src/use-get-.ts` (query hook) +- `packages/note-/src/use-create-.ts` (mutation hook as needed) +- `packages/note-/src/use-update-.ts` (mutation hook as needed) +- `packages/note-/src/use-delete-.ts` (mutation hook as needed) +- `packages/note-/src/index.ts` (named exports only) + +If the note type does not need remote data, still create `-query-keys.ts` and keep future query keys centralized there. + +## Note type provider contract + +In `-note-type.ts`, export: + +- `TYPE_NOTE_TYPE_ID` constant +- `typeNoteType: NoteTypeProvider` +- `registerBuiltinNoteView(registry: NoteViewRegistry): NoteViewDisposer` + +Detection rules must be explicit and deterministic (`.canvas` extension or `.md` + frontmatter `type`). + +Set mode capabilities intentionally: + +- `supportedModes: ["edit", "split", "rendered"]` when true source editing is supported. +- `supportedModes: ["rendered"]` for structured notes where source should be protected. +- `sourceProtected` and `supportsScrollSync` must match UX behavior. + +## UI state requirements + +The note UI must correctly handle: + +- loading state (`Loading…` UI or equivalent) +- edit/split/render mode compatibility via `supportedModes` +- external file-change sync +- undo/redo integration where existing patterns require it + +Do not use `window.prompt`; use repository prompt/modal components. + +## Serialization and model rules + +In `-format.ts`: + +- define model types and interfaces +- implement parse function with safe fallback on malformed input +- implement serialize function with stable output +- provide `empty()` or equivalent factory for new files + +In `-format.test.ts`: + +- parse/serialize round-trip coverage +- malformed input fallback behavior +- key schema edge cases for the type + +## TanStack Query requirements (mandatory for new data-fetching/mutation) + +Use `@tanstack/react-query` for new fetching and mutations. Do not use ad-hoc `fetch` state wiring inside components. + +### Query key factory (required) + +Create `-query-keys.ts` and define typed factory helpers, for example: + +```ts +export const typeQueryKeys = { + all: ["type"] as const, + byPath: (path: string) => [...typeQueryKeys.all, path] as const, + list: (path: string) => [...typeQueryKeys.byPath(path), "list"] as const, + detail: (path: string, id: string) => [...typeQueryKeys.byPath(path), "detail", id] as const, +}; +``` + +Hooks must consume these factories for `queryKey`, `invalidateQueries`, and related cache operations. + +Prefer `invalidateQueries` for mutation follow-up unless the feature specifically requires eager refetch semantics. + +## Registration and integration checklist + +1. Export all public APIs from `packages/note-/src/index.ts`. +2. Register builtin note view in the current app registry wiring (follow the active pattern on this branch). +3. Ensure provider `id` and frontmatter/file detection rules match creation templates and server behavior. +4. Keep core contracts in `@notes/core` React-free.