Notes — Improvement & Growth Plan
Package: capell-app/notes · Kind: package · Tier: premium · Product group: Capell Collaboration · Bundle: collaboration · Status: Draft
1. Snapshot
Section titled “1. Snapshot”Notes is an admin-only collaboration package that attaches contextual notes to Capell admin records via a polymorphic subject morph (default subject: Capell\Core\Models\Page). It owns four tables (notes, note_assignments, note_mentions, note_reminders) and four models, all morph-based for both subject and participant (author, assignee, mentioned, assigned_by, mentioned_by). Surfaces include a Filament NotesInboxPage with attention tiles, a filterable note list, resolve/reopen/complete controls, a user-menu badge, and a “Add note” header action contributed onto the page EditPage via the admin ResourceHeaderActionExtender tag. Key Actions: CreateNoteAction, AssignNoteUsersAction, MentionNoteUsersAction, BuildUserAttentionCountsAction, BuildUserInboxNotesAction, MarkNoteMentionsReadAction; dep is capell-app/admin. Current marketplace summary is now honest about shipped scope: “Add private, assignable notes and @mentions to any Capell admin record so editors can leave context, hand off work, and never lose track of what needs attention.” — the 2026-06-06 runner pass exposed and fixed a populated-inbox Blade namespace bug, then recaptured and promoted Capell runner PNGs for populated inbox, attention counts, empty inbox, user-menu attention badge, and the record-level Add note modal. The screenshot runner now executes package setup/demo commands, and capell:notes-demo --force seeds deterministic assignment, mention, reminder, and resolved-note records before capture.
2. Improvements (existing functionality)
Section titled “2. Improvements (existing functionality)”Prioritized.
-
Done/Shipped: Surface actual notes in the inbox, not just counts —
NotesInboxPagerenders attention tiles plus a filterable note list that shows body excerpts, subject, author, assignments, and mentions. Displayed mentions are marked read after preserving the initial badge counts. Evidence:tests/Feature/Filament/NotesInboxPageTest.phpcovers render, private-note scoping, and status-filter mention reads. —src/Filament/Pages/NotesInboxPage.php,resources/views/filament/pages/notes-inbox.blade.php— L -
Done/Shipped: Wire resolve/reopen/complete into the UI — the inbox list now calls
ResolveNoteAction,ReopenNoteAction, andCompleteNoteAssignmentActionthrough current-user-scoped Livewire methods. Evidence:NotesInboxPageTestasserts the buttons render and the page delegates each lifecycle operation. —src/Filament/Pages/NotesInboxPage.php,resources/views/filament/pages/notes-inbox.blade.php— M -
Done/Shipped: Mark mentions read —
MarkNoteMentionsReadActionmarks only displayed notes for the current user, and the inbox calls it on mount/status-filter changes so the mention badge can clear. Evidence:tests/Integration/Actions/UserInboxNotesActionTest.phpandNotesInboxPageTest. —src/Actions/MarkNoteMentionsReadAction.php,src/Filament/Pages/NotesInboxPage.php— S -
Shipped 2026-06-06: attention counts share a request-scoped cache.
UserAttentionCountsCachenow owns per-user request memoization forBuildUserAttentionCountsAction, and both the admin user-menu badge andNotesInboxPageresolve counts through that cache. Inbox lifecycle actions clear the cached entry before re-rendering counts. —src/Support/UserAttentionCountsCache.php,src/Providers/AdminServiceProvider.php,src/Filament/Pages/NotesInboxPage.php— S -
Shipped 2026-06-06: note enums implement Filament labels.
NoteStatus,NoteVisibility, andNoteReminderRecurrencenow implementHasLabel, and the page header action derives visibility options from the enum instead of hand-building translated arrays. —src/Enums/NoteStatus.php,src/Enums/NoteVisibility.php,src/Enums/NoteReminderRecurrence.php,src/Filament/Extenders/Page/CreateNoteResourceHeaderActionExtender.php— S -
Shipped 2026-06-06: user dropdowns use lazy searchable queries. Assignee and mention selects now use
getSearchResultsUsing()andgetOptionLabelsUsing()so the Add note modal no longer eager-loads two separatelimit(100)user lists on open. Selected labels remain resolvable by key. —src/Filament/Extenders/Page/CreateNoteResourceHeaderActionExtender.php— S -
Shipped 2026-06-06: Add note can be opted into beyond page EditPage.
NotesManager::registerSubject()now accepts resource header page classes,CreateNoteResourceHeaderActionExtender::supports()reads that registry, and the action accepts any registered Eloquent subject that the current user can update. The package still registers CapellPage+EditPageby default, while host packages can register their own subject/edit-page pair throughCapellNotes. —src/Support/NotesManager.php,src/Filament/Extenders/Page/CreateNoteResourceHeaderActionExtender.php,src/Providers/NotesServiceProvider.php— M -
Tighten the health check label or implement real checks —
NotesHealthCheckonly declarescompatibleCapellApiVersion()(identical to sibling packages like comments/insights, so it is convention-correct, not a bug), but the manifest labels it “surfaces, providers, and install health are discoverable by Diagnostics” atseverity: critical. Either downgrade the label to match what the contract actually verifies, or extend it if the host contract grows assertion hooks. —src/Health/NotesHealthCheck.php,capell.jsonhealthChecks — S
3. Missing Features (gaps)
Section titled “3. Missing Features (gaps)”Manifest advertises capabilities: ["notes", "notes-admin"] and the summary now promises private notes, assignments, and mentions. Against that and internal-notes norms:
- Shipped 2026-06-06: reminders have a create/schedule/notify path. The Add note modal now accepts due time, recurrence, and timezone fields,
CreateNoteActionpersists them throughUpsertNoteReminderAction, andcapell:notes:send-due-remindersrunsSendDueNoteReminderNotificationsActionon a five-minute schedule. Due reminders notify active assignees, writelast_notified_at, and advancenext_due_atfor recurring reminders. —src/Filament/Extenders/Page/CreateNoteResourceHeaderActionExtender.php,src/Actions/UpsertNoteReminderAction.php,src/Actions/SendDueNoteReminderNotificationsAction.php,src/Console/SendDueNoteRemindersCommand.php - Rich text remains absent. Body is a plain
textcolumn and now renders as an escaped inbox excerpt, but there is no rich text, markdown, or @mention autocomplete inside the body (mentions are a separate multi-select, not inline). Table-stakes for a fuller “notes” product. - No activity feed / threaded replies / comments on a note. A note is a single immutable body with no follow-ups. Internal-notes norms expect a thread. Gap vs the sibling
commentspackage — consider cross-linking. - No attachments. No file/image attachment to a note despite “contextual notes” framing. Table-stakes.
- No pinning / ordering. No way to pin an important note to the top of a record. Table-stakes.
DismissedandArchivedstatuses +archived_atare dead. Defined inNoteStatusand the schema but never written or surfaced. Either implement archive/dismiss actions or trim the enum/column.- Shipped 2026-06-06: per-note visibility has record-editor semantics.
CanViewNoteActionallows authors, active assignees, and mentioned users to see their notes, keeps private notes restricted to those participants, and treatsRecordEditorsnotes as visible to users who canupdatethe subject record.BuildSubjectNotesActionexposes that policy-backed rule for future record-level note display. - Shipped 2026-06-06: assignment and mention notifications.
AssignNoteUsersActionandMentionNoteUsersActionnow send queuedNoteAttentionNotificationmessages after persistence, skipping self-notifications. Delivery channels are configurable throughcapell-notes.notifications.channelsand default to database notifications, with mail rendering available whenmailis enabled.assigned_by/mentioned_byactor metadata now drives notification suppression. - No roles/permissions.
capell.jsondeclarespermissions: []; note creation is gated only by the subject’supdatepolicy. No dedicated capability to view/manage notes, no admin override.
4. Issues / Risks
Section titled “4. Issues / Risks”- Advertised capability unreachable (dead feature). Reminders ship as schema + data + read-side aggregation with no producer — see §3. Highest-credibility risk for a paid tier. —
src/Actions/BuildUserAttentionCountsAction.php:63,src/Models/NoteReminder.php,capell.jsonmarketplace.summary. - Closed: lifecycle Actions now have a production caller.
ResolveNoteAction,ReopenNoteAction, andCompleteNoteAssignmentActionare reachable from the inbox list and covered byNotesInboxPageTest. Remaining lifecycle gaps are the unimplemented dismiss/archive statuses. —src/Filament/Pages/NotesInboxPage.php. - Admin-only visibility is partially test-proven. The inbox render is authenticated-admin-only through Filament and
NotesInboxPageTestproves another participant’s private note is not shown. Still add a public-output safety assertion if a future public route, frontend hook, or record-level rendered component is introduced. —docs/overview.md:38,resources/boost/guidelines/core.blade.php. - Closed for plain text: body length and escaped display.
CreateNoteActioncaps body length at 5,000 characters and the inbox renders escaped excerpts. If rich-text display lands, add sanitizer coverage at that boundary. —src/Actions/CreateNoteAction.php,resources/views/filament/pages/notes-inbox.blade.php. - Shipped 2026-06-06: polymorphic orphan cleanup. Registered note subjects now attach a deleting hook that deletes notes for the removed subject through
PruneNotesForDeletedSubjectAction. Registered participants attach a deleting hook that deletes authored notes, removes direct assignment/mention rows, and clears nullableassigned_by/mentioned_byactor references throughPruneNotesForDeletedParticipantAction. Note-owned child rows still cascade through the existingNote::deletinghook and database FKs. —src/Support/NotesManager.php,src/Actions/PruneNotesForDeletedSubjectAction.php,src/Actions/PruneNotesForDeletedParticipantAction.php. - Performance budget cited, partially at risk. Manifest
performance.adminQueryBudget: 40,frontendRenderBudgetMs: 0(admin-only, correct).cacheSafety.cacheable: false. The badge + page double-run the 4-count action (§2.4); once the inbox lists notes with morph eager-loads it must stay within budget — add a query-count assertion test. —capell.jsonperformance. - Test gaps. Covered: CreateNote (+rollback + max length), assign/mention upsert + reactivate, complete-assignment, resolve/reopen, attention counts, mention
read_atclearing, inbox page render/lifecycle delegation/private-note scoping, model casts/relations, migrations (guarded + cascade), manager registration, data objects, provider registration, the header-action extender. Not covered: reminder lifecycle (none exists), record-editor visibility semantics outside the attention inbox, public-output safety for any future public surface, orphaned-morph behavior. —tests/. - i18n.
note.php+navigation.php+package.phpexist forenonly; strings are translated (good), butclass_basenamefallback label inuserLabel()and the hard-coded'UTC'reminder timezone default are not localized/configurable. —resources/lang/en/,src/Filament/Extenders/Page/CreateNoteResourceHeaderActionExtender.php:148. php: ^8.3in composer vs PHP 8.4 house standard. Minor: package allows 8.3 while the platform targets 8.4; uses#[Override]and typed properties that are 8.3-safe, so fine, but confirm intended floor. —composer.json.
5. Marketplace & Selling
Section titled “5. Marketplace & Selling”Current summary: “Add private, assignable notes and @mentions to any Capell admin record so editors can leave context, hand off work, and never lose track of what needs attention.” This now matches the shipped notes/assignments/mentions scope and avoids the unbuilt reminder producer. Composer description: “Private, assignable notes and @mentions for any Capell admin record” — aligned in scope, intentionally shorter for package-manager listings.
Improved 1-sentence summary:
Add private, assignable notes and @mentions to any Capell admin record so editors can leave context, hand off work, and never lose track of what needs attention.
Improved 3–4 sentence description:
Notes turns Capell admin records into a collaboration surface: leave a contextual note on a page (or any opted-in record), assign it to teammates, and mention people who need to weigh in. A per-user inbox and user-menu badge surface what’s assigned to you and where you’ve been mentioned, so nothing slips between editors. Notes are strictly admin-internal with per-note visibility (record-editors or private) and are never exposed on the public site. Built the Capell way — domain logic in Actions, polymorphic attachment to any registered subject — so it extends cleanly into your own resources. (Drop “reminders” from copy until the reminder producer ships; then re-add with “scheduled reminders”.)
Screenshot/media status: capell.json now lists the extension card plus Capell runner captures for the populated Notes inbox, opened user-menu attention badge, record-level Add note modal, attention counts/lifecycle controls, empty inbox, and dark-mode workflow. capell:notes-demo --force seeds deterministic collaboration records before capture so the badge and inbox screenshots show real assigned, mentioned, overdue, and resolved note states.
Pricing / tier / bundle positioning: Correctly a utility within the collaboration bundle, premium tier, requires capell-app/admin. This is a bundled, not standalone play — its value compounds with admin breadth and the comments package. Standalone pricing is weak until reminders + record-level display land. Cross-sell: bundle with comments (public-facing discussion) as an “internal vs external conversation” pair; pair with any admin-heavy Extension Suite (editorial/workflow). Lead-in capability: once notes attach to arbitrary records, every other premium package’s resources become a notes surface.
Differentiators / value props / target buyer: Differentiator = admin-internal, per-record, per-note-visibility collaboration native to Capell (not a bolt-on). Target buyer = teams with multiple editors/reviewers doing editorial or content-ops handoffs. Value props: contextual handoff, mention-driven attention, zero public leakage.
Keywords/tags (8–12): notes, internal-notes, collaboration, mentions, assignments, admin, editorial-workflow, content-ops, team, filament, polymorphic.
6. Prioritized Roadmap
Section titled “6. Prioritized Roadmap”| Item | Bucket | Effort | Impact | Section ref |
|---|---|---|---|---|
| Render notes list in inbox (view/open notes) | Done | L | High | §2.1 |
| Wire resolve/reopen/complete actions into UI | Done | M | High | §2.2 |
| Mark mentions read (clear the badge) | Done | S | High | §2.3, §3 |
| Reconcile reminders: build producer before re-advertising reminders | Done | M–L | High | §3, §4, §5 |
| Add record-editor visibility semantics for future record-level note display | Done | M | High | §4 |
| Body rich-text sanitization if/when rich text ships | Later | S | Med | §4 |
| Consolidate/cache attention counts (badge + page) | Done | S | Med | §2.4 |
| Searchable user selects (drop limit(100)) | Done | S | Med | §2.6 |
| Adopt enum labels (status/visibility/recurrence) | Done | S | Med | §2.5 |
| Generalize “Add note” beyond page EditPage to any subject | Done | M | High | §2.7 |
| Notifications on assign/mention (database/email) | Done | M | Med | §3 |
| Orphaned-morph cleanup on subject/author delete | Done | M | Med | §4 |
| Promote dedicated user-menu badge and record-level Add note modal captures | Done | S | Med | §5 |
| Note threads/replies + attachments | Later | L | Med | §3 |
| Pinning + dismiss/archive lifecycle (use dead enum cases) | Later | M | Low | §3 |
| Per-note view/manage permissions (manifest permissions: []) | Later | M | Med | §3 |