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>
This commit is contained in:
122
docs/fixes/surrealdb-cache-fix.md
Normal file
122
docs/fixes/surrealdb-cache-fix.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# 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:
|
||||
|
||||
```typescript
|
||||
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:
|
||||
```typescript
|
||||
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:
|
||||
```typescript
|
||||
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`:
|
||||
```typescript
|
||||
// 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`:
|
||||
```typescript
|
||||
// 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`).
|
||||
Reference in New Issue
Block a user