Skip to content

[dashboards] Link Next.js dashboard to open-brain-rest dependency#130

Open
alanshurafa wants to merge 3 commits intoNateBJones-Projects:mainfrom
alanshurafa:contrib/alanshurafa/dashboard-rest-link
Open

[dashboards] Link Next.js dashboard to open-brain-rest dependency#130
alanshurafa wants to merge 3 commits intoNateBJones-Projects:mainfrom
alanshurafa:contrib/alanshurafa/dashboard-rest-link

Conversation

@alanshurafa
Copy link
Copy Markdown
Contributor

Contribution Type

  • Recipe (/recipes)
  • Schema (/schemas)
  • Dashboard (/dashboards)
  • Integration (/integrations)
  • Repo improvement (docs, CI, templates)

What does this do?

Updates the Next.js dashboard to explicitly reference the new open-brain-rest integration as its required backend:

  • Adds a cross-reference link to ../../integrations/open-brain-rest/README.md in prerequisites
  • Fixes a path typo in Step 1 (open-brain-dashboardopen-brain-dashboard-next)
  • Declares open-brain-rest Edge Function in metadata.json services

Dependency: This PR depends on #129 ([integrations] Add open-brain-rest Edge Function). Merge #129 first — this PR's cross-reference link (../../integrations/open-brain-rest/README.md) only resolves after the integration exists in the repo.

Requirements

No additional requirements — this is a docs-only update to an existing dashboard contribution.

Checklist

  • I've read CONTRIBUTING.md
  • My contribution has a README.md with prerequisites, step-by-step instructions, and expected outcome
  • My metadata.json has all required fields
  • I tested this on my own Open Brain instance
  • No credentials, API keys, or secrets are included

Companion to #129. Together they close #124.

alanshurafa and others added 3 commits March 27, 2026 16:58
REST API gateway providing 12+ endpoints for the Open Brain thoughts
database. Required backend for the Next.js dashboard (issue NateBJones-Projects#124).

Includes:
- Deno/Hono Edge Function with search, capture, browse, CRUD, stats,
  reflections, duplicates, and ingest endpoints
- 5 SQL migrations: schema extensions with serial_id surrogate key
  (supports both UUID and BIGSERIAL base schemas), reflections table,
  ingestion tables, 8 RPCs, and full-text search index
- Utility modules for embedding, classification, and sensitivity detection
- README with step badges, credential tracker, and troubleshooting

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds the Deno/Hono REST API handler (index.ts) and shared utility
modules for embedding, classification, and sensitivity detection.

Files placed under function/ (not supabase/) to avoid the root
.gitignore rule that excludes supabase/ directories.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add cross-reference link to ../../integrations/open-brain-rest/ as
  the required backend in prerequisites
- Fix cd path typo (open-brain-dashboard → open-brain-dashboard-next)
- Declare open-brain-rest Edge Function in metadata.json services

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@shansen3
Copy link
Copy Markdown

Code review

Found 4 issues:

  1. PR title is [dashboards] but the primary content is 2,500+ lines of new integrations/open-brain-rest/ code. CLAUDE.md requires title format [category] Short description matching the contribution type. This should be [integrations] or split into two PRs.

https://github.com/NateBJones-Projects/OB1/blob/db21166d02f3e956e470fc97717c5d32508f7b11/CLAUDE.md#L36-L37

  1. upsert_thought returns action "created" but TypeScript checks for "inserted" -- every new capture displays "Updated" instead of "Captured new". Same mismatch exists for upsert_reflection.

SQL:

v_action := 'created';
END IF;

TypeScript:
content_fingerprint: result.content_fingerprint,
message: `${result.action === "inserted" ? "Captured new" : "Updated"} thought #${result.thought_id} as ${prepared.type}`,
});

  1. get_thought_connections RPC RETURNS TABLE has no preview or overlap_type columns, but the TypeScript handler reads both -- they will always be undefined.

SQL:

RETURNS TABLE (
id BIGINT,
content TEXT,
type TEXT,
importance SMALLINT,
created_at TIMESTAMPTZ,
shared_topics JSONB,
shared_people JSONB,
overlap_count INT,
similarity FLOAT,
score FLOAT
) AS $$

TypeScript:
importance: row.importance,
preview: row.preview,
created_at: row.created_at,
shared_topics: row.shared_topics ?? [],
shared_people: row.shared_people ?? [],
overlap_count: row.overlap_count ?? 0,
score: row.score,
overlap_type: row.overlap_type,
}));

  1. Auth bypass when MCP_ACCESS_KEY is unset: if (MCP_ACCESS_KEY && !isAuthorized(req)) skips the check when the key is empty string. Combined with --no-verify-jwt in the deploy command, a misconfigured deployment is fully unauthenticated.

// Auth check
if (MCP_ACCESS_KEY && !isAuthorized(req)) {
return json({ error: "Unauthorized" }, 401);

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@matthallett1
Copy link
Copy Markdown
Collaborator

@claude review this PR

1 similar comment
@matthallett1
Copy link
Copy Markdown
Collaborator

@claude review this PR

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 30, 2026

Claude finished @matthallett1's task in 2m 5s —— View job


PR Review

  • Gather context and read changed files
  • Review alignment, clarity, completeness, safety, design patterns
  • Post final review

Thanks for this contribution. The integration is well-structured and the README is clear and followable. @shansen3 already caught four real issues — I'll confirm those and add a few more I found while reading through the files.

Confirmed Issues (from @shansen3's review)

1. PR title is misclassified ([dashboards][integrations])

The 2,500+ lines of new code are all under integrations/open-brain-rest/. The dashboard changes are 4 lines. Per CLAUDE.md the title format must match the contribution type. Please rename to [integrations] Add open-brain-rest Edge Function (or split into two PRs, though a single [integrations] title is simpler given the dashboard change is trivially small).


2. upsert_thought / upsert_reflection action string mismatch — captures always display "Updated"

Both SQL functions return "created", but the TypeScript handlers check for "inserted":

Fix: change the SQL to return "inserted" instead of "created" on the new-row path (or change the TypeScript checks to "created" — either is fine, just needs to match). Fix this →


3. get_thought_connectionspreview and overlap_type are always undefined

The SQL RETURNS TABLE at sql/04-rpcs.sql:251-262 has no preview or overlap_type columns, but the TypeScript handler at function/index.ts:643-649 reads both. Every connections response will have preview: undefined and overlap_type: undefined.

The SQL does return content (truncated to 200 chars) which could serve as preview. overlap_type could be derived from whether overlap is primarily topics, people, or embedding similarity. Fix this →


4. Auth bypass when MCP_ACCESS_KEY is unset

function/index.ts:59:

if (MCP_ACCESS_KEY && !isAuthorized(req)) {

When MCP_ACCESS_KEY is empty string (unset env var), the condition short-circuits and skips auth entirely. Combined with --no-verify-jwt in the deploy command (which disables Supabase's own JWT check), a misconfigured deployment is fully unauthenticated and publicly accessible.

The fix is to require the key to be set and reject all requests if it isn't:

if (!MCP_ACCESS_KEY) {
  return json({ error: "Service misconfigured: MCP_ACCESS_KEY not set" }, 503);
}
if (!isAuthorized(req)) {
  return json({ error: "Unauthorized" }, 401);
}

Fix this →


Additional Issues Found

5. brain_stats_aggregate key mismatch — /stats always returns empty types and topics

The SQL function returns keys types and topics (sql/04-rpcs.sql:236-240):

RETURN jsonb_build_object('total_count', v_total, 'types', v_types, 'topics', v_topics);

But the TypeScript handler reads aggregate.top_types and aggregate.top_topics (function/index.ts:461-466):

parseAggregateCounts(aggregate.top_types, "type")  // always undefined → []
parseAggregateCounts(aggregate.top_topics, "topic") // always undefined → []

The /stats endpoint always returns types: {} and top_topics: [] regardless of what's in the database. Fix by changing aggregate.top_typesaggregate.types and aggregate.top_topicsaggregate.topics. Fix this →


6. No Row Level Security on new tables

The reflections, ingestion_jobs, and ingestion_items tables are created without enabling RLS. OB1's pattern requires RLS on new tables. Each migration should include:

ALTER TABLE reflections ENABLE ROW LEVEL SECURITY;
-- and a policy allowing service_role full access

Without RLS, these tables are accessible to anon role depending on Supabase project settings. Fix this →


Minor Nit

The brain_stats_aggregate SQL returns a key total_count but the TypeScript in handleStats never reads it — it uses a separate Supabase count query. Harmless but slightly wasteful. Not a blocker.


Overall Assessment

The integration is well thought-out, clearly documented, and OB1-aligned. It's a legitimate REST gateway over the thoughts table and follows the Edge Function deployment pattern correctly. The README is the best I've seen in this repo — the credential tracker, expandable SQL blocks, and troubleshooting section are great touches.

However, issues 2–6 above are blocking: two produce silent data bugs (stats always empty, captures always say "Updated"), one is a schema/security gap (no RLS), and the auth bypass (issue 4) is a real security concern. Please fix these before merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[dashboards] Next.js dashboard missing open-brain-rest Edge Function dependency

3 participants