[schemas] Add crm-person-tiers — relationship tier schema + dashboard page#18
[schemas] Add crm-person-tiers — relationship tier schema + dashboard page#18alanshurafa wants to merge 5 commits intomainfrom
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ab49c88f4d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const thoughtId = active.id as number; | ||
| const newStatus = over.id as string; | ||
|
|
There was a problem hiding this comment.
Derive drop target status from container, not
over.id
handleDragEnd treats over.id as the destination status, but in a SortableContext this is often the hovered card's id rather than the column id. In that common case, a drop over another card sends a numeric status to /api/kanban/update, fails server validation (new|planning|active|review|done|archived), and triggers the optimistic revert path, so drag-and-drop appears broken unless the user lands on empty column space. Resolve the target status from the droppable/sortable container metadata instead of over.id directly.
Useful? React with 👍 / 👎.
| for (const thoughtType of ["task", "idea"]) { | ||
| const sp = new URLSearchParams(); | ||
| sp.set("per_page", "100"); | ||
| sp.set("sort", "importance"); |
There was a problem hiding this comment.
Paginate kanban fetches beyond first 100 items per type
The kanban data loader fetches exactly one page per thought type with per_page=100 and never requests subsequent pages. Accounts with more than 100 task or more than 100 idea thoughts will silently miss the rest on the board, which means those items cannot be reviewed or updated from this workflow UI. Add paging (or loop until a short page) so the board reflects the full dataset.
Useful? React with 👍 / 👎.
…VOKER The public crm_person_tiers RPC was declared SECURITY DEFINER with EXECUTE granted to anon. An exposed Supabase anon key would let any caller dump every person's canonical_name, aliases, and metadata from crm_persons -- no RLS is enabled and SECURITY DEFINER bypasses table grants. Least-privilege fix: function is now SECURITY INVOKER and execute is granted to authenticated + service_role only. Added README "Security" section documenting the intended install path (server-side service_role or authenticated-with-RLS) and how to opt into anon access on purpose. Flagged by Claude gsd-code-reviewer + Codex review.
The crm_person_tiers RPC applied LIMIT/OFFSET inside person_page CTE before mention_count and effective_tier were computed. The final ORDER BY effective_tier priority then only re-sorted the preselected page -- for datasets above p_limit, page 1 could miss high-mention "connected" people that sort later by last_seen, contradicting the documented ordering contract (tier priority first). Restructured the CTE chain to: filter -> aggregate mention_counts -> compute effective_tier -> global ORDER BY -> LIMIT/OFFSET. Added an inline comment explaining why ordering must precede pagination. Flagged by Claude gsd-code-reviewer + Codex review.
Two dashboard snippet fixes: P2 - per-tier summary strip derived counts from the first 400 loaded rows while the adjacent caption showed total persons, making the strip look like a global breakdown. Caption now reads "N loaded (of M total -- per-tier counts above reflect loaded rows only, capped at 400)" when total > loaded. No aggregate RPC required. P3 - server component threw on RPC failure, triggering Next.js's default error surface for drop-in consumers that lack a route-level error boundary. fetchPersonTiers now returns a typed discriminated union; CrmPage renders an in-page rose error panel with a troubleshoot hint (run NOTIFY pgrst, 'reload schema') and logs detail server-side. Flagged by Claude gsd-code-reviewer + Codex review.
|
Refreshing checks after markdownlint cleanup merged into fork main. |
|
Refreshing checks after fork markdownlint workflow fix. |
Summary
Adds a new
schemas/crm-person-tiers/contribution, ported from Alan's ExoCortex repo (migration202604210007_crm_person_tiers.sql+web/extensions/crm/page.tsx), generalized for the public OB1 contract.crm_personstable — standalone person record with a four-valuerelationship_tierCHECK constraint (connected>contact>known>unknown), case-insensitive unique index oncanonical_name, and an auto-touchupdated_attrigger.crm_person_mentionsjoin table — links persons to corethoughtsrows without modifying thethoughtstable (OB1 contribution rule).crm_person_tiers(...)RPC — paginated view that returns each person's stored tier plus aneffective_tierthat promotes high-activity recent contacts toconnected. Knobs (p_promote_min_mentions,p_promote_within) are RPC parameters so callers can retune per request.dashboard-snippets/page.tsx+ README) — drop-in Next.js App Router page that renders the RPC output with tier badges. ExoCortex-specific imports (@/lib/api,@/lib/auth,@/lib/extensions/types) stripped; only a genericgetSupabaseServerClient()helper is assumed.Prereq assumption
The ExoCortex source is tightly coupled to a separate
entities+thought_entitiesgraph that OB1 doesn't have. Rather than drag that graph in, I made the schema standalone: acrm_personstable withrelationship_tier, plus acrm_person_mentionsjoin table that referencesthoughts.idas UUID (the default fromdocs/01-getting-started.md). README flags the BIGINT alternative.Safety
CREATE TABLE IF NOT EXISTS,CREATE INDEX IF NOT EXISTS,CREATE OR REPLACE FUNCTION.DROP TABLE,DROP DATABASE,TRUNCATE, or unqualifiedDELETE FROM.thoughtstable is untouched.Test plan
markdownlint-cli2 --config .github/.markdownlint.jsonc "schemas/crm-person-tiers/**/*.md"→ 0 errors)metadata.jsonparses and matches the required schema fieldsDROP\s+TABLE|DROP\s+DATABASE|TRUNCATE) matches zero lines inschema.sqlALTER thoughts ... COLUMNregex matches zero linesschema.sqlagainst a test Supabase database and confirm tables + RPC are createdcrm_person_tiers(p_limit := 5)to verify tier rollupdashboard-snippets/page.tsxintodashboards/open-brain-dashboard-nextand confirm the/crmroute rendersReview status
Fork PR only. Pre-review pending — will run
gsd-code-reviewer(Claude) +codex execreview (Codex) before considering an upstream PR toNateBJones-Projects/OB1, per Alan's cross-AI review pattern.