feat(ui): add structured JSON logging for Loki observability - #331
Conversation
Wire logError() to emit structured JSON for Loki/Promtail ingestion: - Add StructuredLogEntry interface for consistent log format - Add emitStructuredLog() helper for env-aware output - Production: JSON to stdout (Promtail picks up via docker logs) - Development: Colorized console output for debugging - Remove Sentry TODO comment (using self-hosted Loki instead) Log format includes: timestamp, level, message, error details, component, action, and full context for searchability in Grafana. No new infrastructure needed - uses existing Loki/Promtail stack. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
WalkthroughThe changes enhance error logging in Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
pmoves/ui/lib/errorUtils.ts (1)
83-95: Consider avoiding duplication ofcomponentandactionin context.Lines 92-93 extract
componentandactionto top-level fields, while line 94 spreads the entirecontextobject. This means ifcontextcontainscomponentoractionproperties, they'll appear in both the top-level and nestedcontextfield.If this duplication is intentional for Loki query flexibility, consider adding a comment to clarify. Otherwise, consider excluding these fields from the nested context:
🔎 Apply this diff to avoid duplication:
const entry: StructuredLogEntry = { timestamp: new Date().toISOString(), level: severity, message, error: { name: errorObj.name, message: errorObj.message, stack: errorObj.stack, }, component: context?.component, action: context?.action, - context: context ? { ...context } : undefined, + context: context ? Object.fromEntries( + Object.entries(context).filter(([key]) => key !== 'component' && key !== 'action') + ) : undefined, };
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
pmoves/ui/lib/errorUtils.ts(3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
pmoves/ui/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (pmoves/AGENTS.md)
UI updates: run
make -C pmoves notebook-workbench-smoke ARGS="--thread=<uuid>"to lint the Next.js bundle and validate Supabase connectivity; referencepmoves/docs/UI_NOTEBOOK_WORKBENCH.md
Files:
pmoves/ui/lib/errorUtils.ts
🔇 Additional comments (3)
pmoves/ui/lib/errorUtils.ts (3)
15-31: LGTM! Well-structured log entry type.The
StructuredLogEntryinterface is well-designed for Loki ingestion with appropriate optional fields and clear typing.
57-69: LGTM! Good addition of debug flag.The updated comment accurately reflects the function's behavior, and the addition of
NEXT_PUBLIC_DEBUG_LOGGINGflag provides a useful mechanism for enabling debug logs in production when needed.
1-138: Verify changes with notebook-workbench-smoke test.As per coding guidelines, please run the following command to lint the Next.js bundle and validate Supabase connectivity:
#!/bin/bash # Generate a UUID for the test thread TEST_UUID=$(uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || python3 -c "import uuid; print(uuid.uuid4())") echo "Running notebook-workbench-smoke test with thread: $TEST_UUID" make -C pmoves notebook-workbench-smoke ARGS="--thread=$TEST_UUID"This validates that the logging changes don't break the Next.js bundle or runtime behavior.
| function emitStructuredLog(entry: StructuredLogEntry): void { | ||
| if (process.env.NODE_ENV === 'production') { | ||
| // JSON format for Promtail to parse and send to Loki | ||
| console.log(JSON.stringify(entry)); | ||
| } else { | ||
| // Pretty output for development | ||
| const levelColors: Record<ErrorSeverity, string> = { | ||
| debug: '\x1b[90m', // gray | ||
| info: '\x1b[36m', // cyan | ||
| warning: '\x1b[33m', // yellow | ||
| error: '\x1b[31m', // red | ||
| critical: '\x1b[35m' // magenta | ||
| }; | ||
| const reset = '\x1b[0m'; | ||
| const color = levelColors[entry.level] || ''; | ||
| console.log(`${color}[${entry.level.toUpperCase()}]${reset} ${entry.message}`, entry); | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
fd errorUtils pmoves/ui -type fRepository: POWERFULMOVES/PMOVES.AI
Length of output: 237
🏁 Script executed:
cat -n pmoves/ui/lib/errorUtils.ts | head -100Repository: POWERFULMOVES/PMOVES.AI
Length of output: 3443
🏁 Script executed:
rg -n "StructuredLogEntry" pmoves/ui/lib/errorUtils.tsRepository: POWERFULMOVES/PMOVES.AI
Length of output: 206
🏁 Script executed:
rg -n "emitStructuredLog" pmoves/ui/ -A 3 -B 3Repository: POWERFULMOVES/PMOVES.AI
Length of output: 919
🏁 Script executed:
# First, let's find and read the errorUtils file
find pmoves/ui -name "errorUtils.ts" -type f 2>/dev/null | head -1 | xargs catRepository: POWERFULMOVES/PMOVES.AI
Length of output: 3859
Add error handling for JSON serialization failures in production logging.
Line 41 should handle serialization errors. The StructuredLogEntry interface accepts context?: Record<string, unknown>, which allows arbitrary objects to be passed. If the context contains circular references or non-serializable values (functions, symbols, DOM nodes), JSON.stringify(entry) will throw a TypeError, breaking production logging.
Implement a try-catch block to gracefully handle serialization failures:
function emitStructuredLog(entry: StructuredLogEntry): void {
if (process.env.NODE_ENV === 'production') {
// JSON format for Promtail to parse and send to Loki
- console.log(JSON.stringify(entry));
+ try {
+ console.log(JSON.stringify(entry));
+ } catch (error) {
+ // Fallback serialization on failure
+ console.log(JSON.stringify({
+ timestamp: entry.timestamp,
+ level: entry.level,
+ message: entry.message,
+ error: entry.error,
+ serializationError: 'Failed to serialize full entry context'
+ }));
+ }
} else {🤖 Prompt for AI Agents
In pmoves/ui/lib/errorUtils.ts around lines 38 to 55, the production path calls
JSON.stringify(entry) directly which can throw if entry.context contains
circular or non-serializable values; wrap the JSON.stringify call in a
try-catch, and on success keep console.log(JSON.stringify(entry)), but on
failure catch the error, console.error a short message including the
serialization error, and output a safe fallback log (for example a minimal JSON
with entry.level, entry.message and a note that serialization failed, plus a
string describing the context type or entry keys). Ensure the catch does not
rethrow so production logging never crashes.
- Add IDOR vulnerability details with affected routes (PR #329) - Expand JWT base64url decoding with RFC 4648 details (PR #330) - Add structured logging for Loki/Promtail integration (PR #331) - Add post-refactoring cleanup pattern - Add Observability checklist section - Mark completed action items with PR/commit references 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Wire logError() to emit structured JSON for Loki/Promtail ingestion: - Add StructuredLogEntry interface for consistent log format - Add emitStructuredLog() helper for env-aware output - Production: JSON to stdout (Promtail picks up via docker logs) - Development: Colorized console output for debugging - Remove Sentry TODO comment (using self-hosted Loki instead) Log format includes: timestamp, level, message, error details, component, action, and full context for searchability in Grafana. No new infrastructure needed - uses existing Loki/Promtail stack. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat(ui): implement cohesive design system for console (#324) * feat(ui): implement cohesive design system for console - Add card-brutal and card-glass component styles - Implement Cataclysm color palette (cyan, forest, ember, violet, gold) - Introduce DashboardShell layout component - Update login page with split branding layout - Modernize dashboard pages with consistent typography - Fix JSX conditional rendering in ingestion-queue - Add CSS variables and utility classes in globals.css - Extend Tailwind config with design tokens 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): add missing heading-serif class and improve focus accessibility - Add heading-serif CSS class used in login page - Add focus:ring-2 focus:ring-cata-cyan/30 to form inputs for WCAG 2.1 AA compliance - Add focus ring to OAuth provider buttons Addresses critical issues from PR #324 code review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * feat(ui): add error boundaries and error utilities (#325) * feat(ui): add error boundaries and error utilities - Add root error boundary (app/error.tsx) for global error handling - Add dashboard error boundary (app/dashboard/error.tsx) - Add errorUtils.ts with logError, logForDebugging, Result type - Provides consistent error handling patterns for the UI 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address PR review feedback for error boundaries - Use logError() instead of console.error() for production visibility - Remove html/body tags from root error boundary (not global-error.tsx) - Add role="alert" and aria-live for accessibility - Add aria-hidden="true" to decorative icon - Add error context (component, digest) to log calls 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): resolve ESLint set-state-in-effect error in chat page Move setStatus('connecting') inside async function to avoid calling setState synchronously in useEffect body. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test(ui): update tests for new design system - Add usePathname mock to services-pages Jest test - Use getAllByRole for multiple service links in Jest - Use .first() locator in Playwright E2E tests - Update ingest test to look for "ingest" instead of "ingestion dashboard" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): accessibility improvements and Tailwind JIT compliance (#327) * fix(ui): accessibility improvements and Tailwind JIT compliance - Add skip link for keyboard navigation (WCAG 2.1 AA) - Add id="main-content" to DashboardShell main element - Fix dynamic Tailwind class generation in services/page.tsx: - Replace `tag tag-${color}` with TAG_CLASSES lookup - Replace complex ternary bg class with ICON_BG_CLASSES lookup - Extract colorClasses to module-level BORDER_CLASSES constant - Fix misleading comment in globals.css (heading-serif uses sans-serif font) Fixes accessibility and design consistency issues from PR #324 review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: remove focus:outline-none for WCAG 2.4.7 compliance Skip link now has visible focus outline (focus:outline-2) instead of hiding it. The cyan background provides primary feedback, but the outline ensures compliance with WCAG 2.4.7 Focus Visible requirement. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(a11y): improve skip link accessibility compliance - Add focus:outline-void for visible outline against cyan background - Add tabIndex={-1} to main-content for proper skip link focus - Correct WCAG reference: SC 2.4.1 Bypass Blocks is Level A, not AA - Add cross-reference comment linking skip target to layout.tsx 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui/chat): eliminate silent failures and preserve input on error (#326) * fix(ui/chat): eliminate silent failures and preserve input on error - API routes: Return 401 with error message instead of empty array on auth failure - API routes: Add JWT parsing error logging for debugging - fetchMessages: Return {data, error} pattern instead of silent empty array - sendMessage: Check response status and return {ok, error} - handleSend: Only clear input after successful send (preserve on failure) - Add error banner UI to show API errors to users - Add sending state with disabled UI during request Fixes silent failure issues identified in PR #324 review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address PR review feedback for chat error handling - Use logError() instead of logForDebugging() in JWT catch blocks - Add explicit JSON parsing error handling with logging - Add database error logging with sanitized client messages - Fix field name mismatch: agent_id → agent 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): add defensive error handling to client-side chat code - Replace `.catch(() => ({}))` with explicit try-catch blocks in fetchMessages and sendMessage for proper error logging - Wrap realtime subscription callbacks (onInsert/onUpdate/onDelete) in try-catch to prevent silent failures - Replace console.error with logForDebugging for consistent logging - Add component and context metadata to all error logs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(api): use consistent 401 status for authentication failures Changed missing owner ID response from 400 to 401 in /api/chat/send to match /api/chat/messages behavior. Both endpoints now return 401 Unauthorized when authentication is required. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * refactor(ui): extract ownerFromJwt to shared lib/jwtUtils.ts (#330) DRY fix - extracts duplicate JWT parsing logic to shared utility: - Create lib/jwtUtils.ts with proper base64url decoding (RFC 4648) - Update chat/send/route.ts to use shared ownerFromJwt - Update chat/messages/route.ts to use shared ownerFromJwt - Add component parameter for contextual error logging The shared implementation fixes base64url encoding by replacing '-' with '+' and '_' with '/' before decoding, and handles padding correctly per RFC 4648. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * feat(ui): add structured JSON logging for Loki observability (#331) Wire logError() to emit structured JSON for Loki/Promtail ingestion: - Add StructuredLogEntry interface for consistent log format - Add emitStructuredLog() helper for env-aware output - Production: JSON to stdout (Promtail picks up via docker logs) - Development: Colorized console output for debugging - Remove Sentry TODO comment (using self-hosted Loki instead) Log format includes: timestamp, level, message, error details, component, action, and full context for searchability in Grafana. No new infrastructure needed - uses existing Loki/Promtail stack. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix(security): remove client-provided ownerId bypass in API routes (#329) * fix(security): remove client-provided ownerId bypass in API routes CRITICAL SECURITY FIX - Removes authentication bypass vulnerabilities: - uploads/presign: Remove body.ownerId fallback, require session auth - uploads/persist: Remove body.ownerId fallback, require session auth - chat/send: Remove body.ownerId fallback, use JWT only - chat/messages: Remove query param ownerId fallback, use JWT only User identity must now come exclusively from authenticated JWT tokens, preventing IDOR (Insecure Direct Object Reference) attacks where attackers could access or modify resources by supplying arbitrary owner IDs in request bodies or query parameters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: remove unused logForDebugging import 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * docs: add UI development checklist and patterns from CodeRabbit review - Add UI Development Checklist section to CLAUDE.md with security, privacy, accessibility, and code quality guidelines - Create ui-patterns.md context doc with error handling, authentication, and accessibility patterns from PRs #325, #326, #327 - Document CodeRabbit review learnings for future reference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address CodeRabbit review nitpicks from PR #321 - deepresearch/worker.py: Use _env_bool helper for CGP_PUBLISH_ENABLED, move datetime import to module level - supaserch/app.py: Replace nested ternary with status_proj_map dict - publisher-discord/main.py: Add _safe_format_number helper for defensive numeric formatting in CHIT event handlers - geometry-nats-subjects.md: Add 'text' language identifier to code block 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat(ui): implement cohesive design system for console (#324) * feat(ui): implement cohesive design system for console - Add card-brutal and card-glass component styles - Implement Cataclysm color palette (cyan, forest, ember, violet, gold) - Introduce DashboardShell layout component - Update login page with split branding layout - Modernize dashboard pages with consistent typography - Fix JSX conditional rendering in ingestion-queue - Add CSS variables and utility classes in globals.css - Extend Tailwind config with design tokens 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): add missing heading-serif class and improve focus accessibility - Add heading-serif CSS class used in login page - Add focus:ring-2 focus:ring-cata-cyan/30 to form inputs for WCAG 2.1 AA compliance - Add focus ring to OAuth provider buttons Addresses critical issues from PR #324 code review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * feat(ui): add error boundaries and error utilities (#325) * feat(ui): add error boundaries and error utilities - Add root error boundary (app/error.tsx) for global error handling - Add dashboard error boundary (app/dashboard/error.tsx) - Add errorUtils.ts with logError, logForDebugging, Result type - Provides consistent error handling patterns for the UI 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address PR review feedback for error boundaries - Use logError() instead of console.error() for production visibility - Remove html/body tags from root error boundary (not global-error.tsx) - Add role="alert" and aria-live for accessibility - Add aria-hidden="true" to decorative icon - Add error context (component, digest) to log calls 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): resolve ESLint set-state-in-effect error in chat page Move setStatus('connecting') inside async function to avoid calling setState synchronously in useEffect body. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test(ui): update tests for new design system - Add usePathname mock to services-pages Jest test - Use getAllByRole for multiple service links in Jest - Use .first() locator in Playwright E2E tests - Update ingest test to look for "ingest" instead of "ingestion dashboard" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): accessibility improvements and Tailwind JIT compliance (#327) * fix(ui): accessibility improvements and Tailwind JIT compliance - Add skip link for keyboard navigation (WCAG 2.1 AA) - Add id="main-content" to DashboardShell main element - Fix dynamic Tailwind class generation in services/page.tsx: - Replace `tag tag-${color}` with TAG_CLASSES lookup - Replace complex ternary bg class with ICON_BG_CLASSES lookup - Extract colorClasses to module-level BORDER_CLASSES constant - Fix misleading comment in globals.css (heading-serif uses sans-serif font) Fixes accessibility and design consistency issues from PR #324 review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: remove focus:outline-none for WCAG 2.4.7 compliance Skip link now has visible focus outline (focus:outline-2) instead of hiding it. The cyan background provides primary feedback, but the outline ensures compliance with WCAG 2.4.7 Focus Visible requirement. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(a11y): improve skip link accessibility compliance - Add focus:outline-void for visible outline against cyan background - Add tabIndex={-1} to main-content for proper skip link focus - Correct WCAG reference: SC 2.4.1 Bypass Blocks is Level A, not AA - Add cross-reference comment linking skip target to layout.tsx 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui/chat): eliminate silent failures and preserve input on error (#326) * fix(ui/chat): eliminate silent failures and preserve input on error - API routes: Return 401 with error message instead of empty array on auth failure - API routes: Add JWT parsing error logging for debugging - fetchMessages: Return {data, error} pattern instead of silent empty array - sendMessage: Check response status and return {ok, error} - handleSend: Only clear input after successful send (preserve on failure) - Add error banner UI to show API errors to users - Add sending state with disabled UI during request Fixes silent failure issues identified in PR #324 review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address PR review feedback for chat error handling - Use logError() instead of logForDebugging() in JWT catch blocks - Add explicit JSON parsing error handling with logging - Add database error logging with sanitized client messages - Fix field name mismatch: agent_id → agent 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(ui): add defensive error handling to client-side chat code - Replace `.catch(() => ({}))` with explicit try-catch blocks in fetchMessages and sendMessage for proper error logging - Wrap realtime subscription callbacks (onInsert/onUpdate/onDelete) in try-catch to prevent silent failures - Replace console.error with logForDebugging for consistent logging - Add component and context metadata to all error logs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(api): use consistent 401 status for authentication failures Changed missing owner ID response from 400 to 401 in /api/chat/send to match /api/chat/messages behavior. Both endpoints now return 401 Unauthorized when authentication is required. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * refactor(ui): extract ownerFromJwt to shared lib/jwtUtils.ts (#330) DRY fix - extracts duplicate JWT parsing logic to shared utility: - Create lib/jwtUtils.ts with proper base64url decoding (RFC 4648) - Update chat/send/route.ts to use shared ownerFromJwt - Update chat/messages/route.ts to use shared ownerFromJwt - Add component parameter for contextual error logging The shared implementation fixes base64url encoding by replacing '-' with '+' and '_' with '/' before decoding, and handles padding correctly per RFC 4648. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * feat(ui): add structured JSON logging for Loki observability (#331) Wire logError() to emit structured JSON for Loki/Promtail ingestion: - Add StructuredLogEntry interface for consistent log format - Add emitStructuredLog() helper for env-aware output - Production: JSON to stdout (Promtail picks up via docker logs) - Development: Colorized console output for debugging - Remove Sentry TODO comment (using self-hosted Loki instead) Log format includes: timestamp, level, message, error details, component, action, and full context for searchability in Grafana. No new infrastructure needed - uses existing Loki/Promtail stack. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * fix(security): remove client-provided ownerId bypass in API routes (#329) * fix(security): remove client-provided ownerId bypass in API routes CRITICAL SECURITY FIX - Removes authentication bypass vulnerabilities: - uploads/presign: Remove body.ownerId fallback, require session auth - uploads/persist: Remove body.ownerId fallback, require session auth - chat/send: Remove body.ownerId fallback, use JWT only - chat/messages: Remove query param ownerId fallback, use JWT only User identity must now come exclusively from authenticated JWT tokens, preventing IDOR (Insecure Direct Object Reference) attacks where attackers could access or modify resources by supplying arbitrary owner IDs in request bodies or query parameters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: remove unused logForDebugging import 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * docs: add UI development checklist and patterns from CodeRabbit review - Add UI Development Checklist section to CLAUDE.md with security, privacy, accessibility, and code quality guidelines - Create ui-patterns.md context doc with error handling, authentication, and accessibility patterns from PRs #325, #326, #327 - Document CodeRabbit review learnings for future reference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address CodeRabbit review nitpicks from PR #321 - deepresearch/worker.py: Use _env_bool helper for CGP_PUBLISH_ENABLED, move datetime import to module level - supaserch/app.py: Replace nested ternary with status_proj_map dict - publisher-discord/main.py: Add _safe_format_number helper for defensive numeric formatting in CHIT event handlers - geometry-nats-subjects.md: Add 'text' language identifier to code block 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Wire logError() to emit structured JSON for Loki/Promtail ingestion: - Add StructuredLogEntry interface for consistent log format - Add emitStructuredLog() helper for env-aware output - Production: JSON to stdout (Promtail picks up via docker logs) - Development: Colorized console output for debugging - Remove Sentry TODO comment (using self-hosted Loki instead) Log format includes: timestamp, level, message, error details, component, action, and full context for searchability in Grafana. No new infrastructure needed - uses existing Loki/Promtail stack. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Codex Agent <codex-agent@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Add IDOR vulnerability details with affected routes (PR #329) - Expand JWT base64url decoding with RFC 4648 details (PR #330) - Add structured logging for Loki/Promtail integration (PR #331) - Add post-refactoring cleanup pattern - Add Observability checklist section - Mark completed action items with PR/commit references 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary
logError()to emit structured JSON for Loki/Promtail ingestionLog Format
{ "timestamp": "2025-12-18T...", "level": "error", "message": "Failed to send chat message", "error": { "name": "Error", "message": "...", "stack": "..." }, "component": "chat/send", "action": "insert" }Changes
pmoves/ui/lib/errorUtils.tsStructuredLogEntryinterfaceemitStructuredLog()helperlogError()to use structured loggingTest Plan
NODE_ENV=production)🤖 Generated with Claude Code
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.