Files
app/docs/fixes/surrealdb-cache-fix.md
Albert 0ed2d6c0b3 feat: Improve UI layout and navigation
- Increase logo size (48x48 desktop, 56x56 mobile) for better visibility
- Add logo as favicon
- Add logo to mobile header
- Move user menu to navigation bars (sidebar on desktop, bottom bar on mobile)
- Fix desktop chat layout - container structure prevents voice controls cutoff
- Fix mobile bottom bar - use icon-only ActionIcons instead of truncated text buttons
- Hide Create Node/New Conversation buttons on mobile to save header space
- Make fixed header and voice controls work properly with containers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 14:43:11 +00:00

3.4 KiB

SurrealDB Cache Authentication Fix

Problem

Node publishing was showing a yellow warning notification:

Node published to Bluesky, but cache update failed. Advanced features may be unavailable.

Server logs showed:

[POST /api/nodes] ⚠ SurrealDB cache write failed (non-critical):
Error [ResponseError]: There was a problem with the database: There was a problem with authentication

Root Cause

The connectToDB() function in lib/db.ts was attempting to authenticate with SurrealDB using our application's custom JWT token:

await db.authenticate(token);

However, SurrealDB doesn't know how to validate our custom JWT tokens. The db.authenticate() method is for SurrealDB's own token-based authentication system, not for validating external JWTs.

Solution

Changed connectToDB() to use root credentials instead:

Before:

export async function connectToDB(token: string): Promise<Surreal> {
  const db = new Surreal();
  await db.connect(SURREALDB_URL);
  await db.authenticate(token); // ❌ This fails
  await db.use({ namespace, database });
  return db;
}

After:

export async function connectToDB(): Promise<Surreal> {
  const db = new Surreal();
  await db.connect(SURREALDB_URL);
  await db.signin({
    username: SURREALDB_USER, // ✅ Use root credentials
    password: SURREALDB_PASS,
  });
  await db.use({ namespace, database });
  return db;
}

Data Security

Since we're now using root credentials instead of JWT-based authentication, we maintain data isolation by:

  1. Extracting user_did from the verified JWT in API routes
  2. Filtering all queries by user_did to ensure users only access their own data

Example from /app/api/nodes/route.ts:

// Verify JWT to get user's DID
const userSession = verifySurrealJwt(surrealJwt);
const { did: userDid } = userSession;

// Create node with user_did field
const nodeData = {
  user_did: userDid, // ✅ Enforces data ownership
  atp_uri: atp_uri,
  title: title,
  body: body,
  embedding: embedding,
};
await db.create('node', nodeData);

Example from /app/api/suggest-links/route.ts:

// Query filtered by user_did
const query = `
  SELECT * FROM node
  WHERE user_did = $user_did  // ✅ Only user's own nodes
  ORDER BY score DESC
  LIMIT 5;
`;
await db.query(query, { user_did: userDid });

Files Changed

  1. /lib/db.ts - Changed authentication method
  2. /app/api/nodes/route.ts - Removed JWT parameter from connectToDB() call
  3. /app/api/suggest-links/route.ts - Updated to use root credentials and filter by user_did

Test

Created /tests/magnitude/cache-success.mag.ts to verify:

  • Node publishes successfully
  • GREEN success notification (not yellow warning)
  • No "cache update failed" message

Verification

After the fix, server logs show:

[POST /api/nodes] ✓ Published to ATproto PDS
[POST /api/nodes] ✓ Generated embedding vector
[POST /api/nodes] ✓ Cached node in SurrealDB
POST /api/nodes 200 in 1078ms

No more authentication errors! 🎉

Architecture Note

This implements the "App View Cache" pattern where:

  • ATproto PDS is the source of truth (decentralized, user-owned)
  • SurrealDB is a performance cache (centralized, app-managed)

The cache uses root credentials but enforces data isolation through user_did filtering in application code, similar to how the OAuth session store works (lib/auth/oauth-session-store.ts).