## Implementation Plan: `@note` Tag Feature **Approach:** Filter tab on existing saved page (Option B). The user sees a "Notes" tab alongside "All" on `/bookmarks/saved`. No separate `/notes` router. Keep UI changes minimal. ### Steps 1. **Database: add `source` column to `bookmarks` table** - File: `devplacepy/database/schema.py` - Add `create_column_by_example` call for `source` column with default `'manual'`. - The existing index `idx_bookmarks_source` will then succeed. - Ensure function `init_db()` calls this. 2. **Update `set_bookmark()` to accept `source` parameter** - File: `devplacepy/content.py`, function `set_bookmark()` (line ~433) - Add `source: str = "manual"` parameter. - In the insert/update DB call, explicitly set `source` value. - Update all existing call sites (there are 2: routes for manual bookmark toggle) to pass `source="manual"`. 3. **Add note detection in content creation chokepoints** - File: `devplacepy/content.py` - In `create_content_item()` (after line 196, before returning): ```python if has_note(content_text): set_bookmark(request, user, target_type, uid, saved=True, source="note") ``` Determine `target_type` from `table_name`: `'post'` (including rants), `'gist'`, `'project'`. - In `create_comment_record()` (after line 361): ```python if has_note(content): set_bookmark(request, user, parent_target_type, parent_target_uid, saved=True, source="note") ``` `parent_target_type` and `parent_target_uid` are already available in the function (they are parameters or derived from the comment record). 4. **Update saved listings endpoint to support `source` filter** - File: `devplacepy/routers/bookmarks.py` - In `GET /bookmarks/saved`, add optional query parameter `source: str = None`. - When `source` is provided, append `source=source` to the DB query. - Pass `source` to template context. 5. **Update saved page template with filter tab** - File: `devplacepy/templates/saved.html` - At top of listing, add two tabs: "All" (`?source=`) and "Notes" (`?source=note`). - Active tab based on current `source` query param. - Keep same pagination and item rendering. 6. **Add Devii agent action `list_notes`** - File: `devplacepy/services/devii/actions/catalog/engagement.py` - Add action definition that calls bookmarks listing with `source="note"`. - Register action in catalog. 7. **Update API docs** - File: `devplacepy/docs_api/groups/social_actions.py` - Add entry for notes listing (same schema as bookmarks, but filtered). 8. **Write tests** - Create `tests/api/notes/` with one test that verifies: - Creating a post with `@note` creates a bookmark with `source="note"`. - `GET /bookmarks/saved?source=note` returns that item. - `GET /bookmarks/saved` (no filter) returns all bookmarks including notes. - Create `tests/e2e/notes/` mirroring existing bookmark e2e pattern: - Use Playwright to sign up, create post with `@note`, navigate to saved page, click "Notes" tab, verify item appears. 9. **Lint and unit tests** - Run `ruff check .` – ensure zero new violations. - Run `pip install -e '.[dev]' -q && make test-unit` – ensure all tests pass. ### Definition of Done - [ ] Database migration adds `source` column (default `'manual'`) and index `idx_bookmarks_source`. - [ ] `set_bookmark()` accepts `source` parameter; all existing calls pass `source="manual"`. - [ ] Creating a post/gist/project/rant containing `@note` auto-creates a bookmark with `source="note"`. - [ ] Creating a comment containing `@note` auto-creates a bookmark for the parent content (not the comment). - [ ] `GET /bookmarks/saved?source=note` returns only notes; no `source` returns all. - [ ] Saved page template shows "All" and "Notes" tabs; "Notes" tab shows noted items. - [ ] Devii agent can list notes via `list_notes` action. - [ ] API docs include notes listing under social actions. - [ ] API tests and e2e tests for notes pass. - [ ] `ruff check .` passes with zero errors. - [ ] `make test-unit` passes (all existing + new tests).