Skip to content

feat: add atomeam-stack unified dashboard - #39

Merged
atomeam merged 3 commits into
mainfrom
feature/atomeam-stack
May 18, 2026
Merged

feat: add atomeam-stack unified dashboard#39
atomeam merged 3 commits into
mainfrom
feature/atomeam-stack

Conversation

@atomeam

@atomeam atomeam commented May 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • Created unified-app/ - a simple Node.js Express dashboard
  • Shows status of repos, logs, and tools
  • API endpoints: /api/status, /api/repos, /api/tools, /api/logs
  • Simple dark UI dashboard

To Run

cd unified-app
npm install
npm start
# Opens at http://localhost:3000

@atomeam can click here to continue refining the PR

Summary by CodeRabbit

  • New Features

    • Launched a unified dark-themed dashboard showing status, repositories, and tools with auto-refresh every 10s and visual repo availability indicators.
    • Added a backend API powering the dashboard, including an optional external-logs endpoint to surface recent log entries when configured.
  • Chores

    • Project ignores common development artifacts (node_modules, macOS .DS_Store, and log files).

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds a new unified-app: project metadata and .gitignore, an ES-module Express server with read-only endpoints (status, repos, tools, logs, optional Notion-backed /api/notion/logs), static public SPA, and a dark-themed frontend that polls APIs every 10 seconds.

Changes

Unified App Dashboard

Layer / File(s) Summary
Project configuration and dependencies
\.gitignore, unified-app/package.json
Adds git ignore patterns and a new ES-module package.json with express, cors, dotenv, and @notionhq/client plus start/dev scripts.
Express server and API endpoints
unified-app/server.js
Creates Express app with CORS and JSON middleware, hardcoded CONFIG, endpoints /api/status, /api/repos, /api/tools, /api/logs, conditional Notion client and /api/notion/logs query, static public/ serving, and server listen on port 3000.
Frontend dashboard UI
unified-app/public/index.html
Adds dark-themed SPA that asynchronously fetches /api/status, /api/repos, /api/tools, updates DOM (#timestamp, #status, #repos, #tools), and refreshes data every 10 seconds.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 In cozy code a dashboard wakes,
Polling every ten for status updates,
Server whispers logs when keys align,
Frontend paints the counts in midnight shine,
A tiny rabbit cheers — all systems fine.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a unified dashboard for the atomeam-stack project with relevant functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/atomeam-stack

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
unified-app/package.json (1)

2-4: ⚡ Quick win

Mark the app as private to avoid accidental publication.

This repo looks like an internal app, so setting "private": true is a safer default.

Suggested patch
 {
   "name": "atomeam-stack",
+  "private": true,
   "version": "1.0.0",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@unified-app/package.json` around lines 2 - 4, Set the npm package to private
by adding the "private": true field to package.json so the internal app ("name":
"atomeam-stack", "version": "1.0.0", "description": "Unified dashboard for
atomeam") cannot be accidentally published; insert the "private": true property
at the top-level of package.json alongside the existing name/version/description
entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.gitignore:
- Around line 1-3: Add patterns to .gitignore to exclude dotenv files so secrets
aren't committed; update the existing .gitignore (which already contains
node_modules, .DS_Store, *.log) to include entries for .env and any
environment-file variants such as .env.* (e.g., ".env" and ".env.*") so all
dotenv files are ignored across environments and local overrides.

In `@unified-app/public/index.html`:
- Around line 46-64: The loadData function should guard against fetch failures
and run the three API calls in parallel: change the sequential fetches
(fetch('/api/status'), fetch('/api/repos'), fetch('/api/tools')) to run
concurrently (using Promise.all or Promise.allSettled) and update the DOM only
from successful responses; wrap the whole loadData body in a try/catch so any
thrown error is caught, log the error and update UI with a safe fallback (e.g.,
empty values or an error message) without allowing an unhandled rejection to
stop future polling, and ensure the polling mechanism (setInterval or a
self-scheduling setTimeout inside loadData) continues regardless of individual
request failures.

In `@unified-app/server.js`:
- Around line 42-43: The route handler for app.get('/api/repos') (and the
similar handler around lines 50-51) returns exists: true for every item; change
it to compute the real existence by checking the filesystem or the authoritative
source for each repo/resource. Update the handler(s) to be async, use
fs.promises.access or fs.existsSync (or your configured repo-check function) to
determine existence for each CONFIG.repos entry, build the response objects with
the actual boolean in the exists field, and await Promise.all when mapping async
checks so the response contains real existence states for both endpoints.
- Line 11: The app is enabling unrestricted CORS via the current app.use(cors())
call; replace that call so CORS is restricted to same-origin frontend requests
by configuring the cors middleware with origin set to "http://localhost:3000"
and methods limited to ["GET"] (i.e., update the app.use(cors()) invocation in
server.js to pass the options object restricting origin and methods).

---

Nitpick comments:
In `@unified-app/package.json`:
- Around line 2-4: Set the npm package to private by adding the "private": true
field to package.json so the internal app ("name": "atomeam-stack", "version":
"1.0.0", "description": "Unified dashboard for atomeam") cannot be accidentally
published; insert the "private": true property at the top-level of package.json
alongside the existing name/version/description entries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 17f1230c-f762-45e3-9995-3c3230190cc5

📥 Commits

Reviewing files that changed from the base of the PR and between 27e1c18 and 9df8ca6.

📒 Files selected for processing (4)
  • .gitignore
  • unified-app/package.json
  • unified-app/public/index.html
  • unified-app/server.js

Comment thread .gitignore
Comment on lines +1 to +3
node_modules/
.DS_Store
*.log

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Ignore dotenv files to prevent accidental secret commits.

.env files are currently not ignored, so local credentials can be committed by mistake.

Suggested patch
 node_modules/
 .DS_Store
 *.log
+.env
+.env.*
+!.env.example
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
node_modules/
.DS_Store
*.log
node_modules/
.DS_Store
*.log
.env
.env.*
!.env.example
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.gitignore around lines 1 - 3, Add patterns to .gitignore to exclude dotenv
files so secrets aren't committed; update the existing .gitignore (which already
contains node_modules, .DS_Store, *.log) to include entries for .env and any
environment-file variants such as .env.* (e.g., ".env" and ".env.*") so all
dotenv files are ignored across environments and local overrides.

Comment on lines +46 to +64
async function loadData() {
const status = await fetch('/api/status').then(r => r.json());
document.getElementById('timestamp').textContent = new Date(status.timestamp).toLocaleString();
document.getElementById('status').innerHTML = `
<div class="stat"><span class="stat-name">Repos</span><span class="stat-value">${status.summary.totalRepos}</span></div>
<div class="stat"><span class="stat-name">Logs</span><span class="stat-value">${status.summary.totalLogs}</span></div>
<div class="stat"><span class="stat-name">Tools</span><span class="stat-value">${status.summary.totalTools}</span></div>
`;
const repos = await fetch('/api/repos').then(r => r.json());
document.getElementById('repos').innerHTML = repos.map(r => `
<div class="stat"><span class="stat-name">${r.name}</span><span class="stat-value status-active">${r.exists ? '✓' : '✗'}</span></div>
`).join('');
const tools = await fetch('/api/tools').then(r => r.json());
document.getElementById('tools').innerHTML = tools.map(t => `
<div class="stat"><span class="stat-name">${t.name}</span><span class="stat-value">${t.cmd}</span></div>
`).join('');
}
loadData();
setInterval(loadData, 10000);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify presence of error handling around loadData and parallel fetch usage.
rg -n "async function loadData|try\\s*\\{|catch\\s*\\(|Promise\\.all\\(" unified-app/public/index.html

Repository: atomeam/atomarcade-bridge

Length of output: 104


Handle fetch failures to prevent unhandled rejections and broken polling.

loadData lacks error handling, so any API failure will throw an unhandled rejection and break the 10-second refresh cycle. Additionally, the three fetch calls are sequential when they could execute in parallel.

Suggested patch
 async function loadData() {
-  const status = await fetch('/api/status').then(r => r.json());
-  document.getElementById('timestamp').textContent = new Date(status.timestamp).toLocaleString();
-  document.getElementById('status').innerHTML = `
-    <div class="stat"><span class="stat-name">Repos</span><span class="stat-value">${status.summary.totalRepos}</span></div>
-    <div class="stat"><span class="stat-name">Logs</span><span class="stat-value">${status.summary.totalLogs}</span></div>
-    <div class="stat"><span class="stat-name">Tools</span><span class="stat-value">${status.summary.totalTools}</span></div>
-  `;
-  const repos = await fetch('/api/repos').then(r => r.json());
-  document.getElementById('repos').innerHTML = repos.map(r => `
-    <div class="stat"><span class="stat-name">${r.name}</span><span class="stat-value status-active">${r.exists ? '✓' : '✗'}</span></div>
-  `).join('');
-  const tools = await fetch('/api/tools').then(r => r.json());
-  document.getElementById('tools').innerHTML = tools.map(t => `
-    <div class="stat"><span class="stat-name">${t.name}</span><span class="stat-value">${t.cmd}</span></div>
-  `).join('');
+  try {
+    const [status, repos, tools] = await Promise.all([
+      fetch('/api/status').then(r => r.json()),
+      fetch('/api/repos').then(r => r.json()),
+      fetch('/api/tools').then(r => r.json())
+    ]);
+    document.getElementById('timestamp').textContent = new Date(status.timestamp).toLocaleString();
+    document.getElementById('status').innerHTML = `
+      <div class="stat"><span class="stat-name">Repos</span><span class="stat-value">${status.summary.totalRepos}</span></div>
+      <div class="stat"><span class="stat-name">Logs</span><span class="stat-value">${status.summary.totalLogs}</span></div>
+      <div class="stat"><span class="stat-name">Tools</span><span class="stat-value">${status.summary.totalTools}</span></div>
+    `;
+    document.getElementById('repos').innerHTML = repos.map(r => `
+      <div class="stat"><span class="stat-name">${r.name}</span><span class="stat-value status-active">${r.exists ? '✓' : '✗'}</span></div>
+    `).join('');
+    document.getElementById('tools').innerHTML = tools.map(t => `
+      <div class="stat"><span class="stat-name">${t.name}</span><span class="stat-value">${t.cmd}</span></div>
+    `).join('');
+  } catch (err) {
+    document.getElementById('status').textContent = 'Failed to load dashboard data.';
+  }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@unified-app/public/index.html` around lines 46 - 64, The loadData function
should guard against fetch failures and run the three API calls in parallel:
change the sequential fetches (fetch('/api/status'), fetch('/api/repos'),
fetch('/api/tools')) to run concurrently (using Promise.all or
Promise.allSettled) and update the DOM only from successful responses; wrap the
whole loadData body in a try/catch so any thrown error is caught, log the error
and update UI with a safe fallback (e.g., empty values or an error message)
without allowing an unhandled rejection to stop future polling, and ensure the
polling mechanism (setInterval or a self-scheduling setTimeout inside loadData)
continues regardless of individual request failures.

Comment thread unified-app/server.js
const app = express();
const PORT = 3000;

app.use(cors());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether frontend uses cross-origin API calls and whether open CORS is present.
rg -n "fetch\(['\"]https?://" unified-app/public/index.html
rg -n "app.use\\(cors\\(" unified-app/server.js

Repository: atomeam/atomarcade-bridge

Length of output: 89


🏁 Script executed:

# Search for all API calls in the frontend, not just cross-origin ones
rg -n "fetch\|XMLHttpRequest\|api/repos\|api/logs" unified-app/public/ -t js -t html

Repository: atomeam/atomarcade-bridge

Length of output: 51


🏁 Script executed:

# Check the server.js file to understand the full API setup
cat -n unified-app/server.js | head -50

Repository: atomeam/atomarcade-bridge

Length of output: 1790


🏁 Script executed:

# Check if there's any frontend JavaScript code outside of index.html
find unified-app/public -type f -name "*.js" -o -name "*.html" | head -20

Repository: atomeam/atomarcade-bridge

Length of output: 99


🏁 Script executed:

# Read the frontend HTML to see how it calls APIs
cat -n unified-app/public/index.html

Repository: atomeam/atomarcade-bridge

Length of output: 3665


Restrict CORS to same-origin requests only.

The frontend makes only same-origin API calls (relative paths like /api/status, /api/repos, /api/tools), so unrestricted CORS is unnecessary and weakens security. Restrict it to localhost:3000 and GET methods only.

Suggested patch
-app.use(cors());
+app.use(cors({
+  origin: ['http://localhost:3000'],
+  methods: ['GET']
+}));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
app.use(cors());
app.use(cors({
origin: ['http://localhost:3000'],
methods: ['GET']
}));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@unified-app/server.js` at line 11, The app is enabling unrestricted CORS via
the current app.use(cors()) call; replace that call so CORS is restricted to
same-origin frontend requests by configuring the cors middleware with origin set
to "http://localhost:3000" and methods limited to ["GET"] (i.e., update the
app.use(cors()) invocation in server.js to pass the options object restricting
origin and methods).

Comment thread unified-app/server.js
Comment on lines +42 to +43
app.get('/api/repos', (req, res) => {
res.json(CONFIG.repos.map(r => ({ name: r.name, exists: true })));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Return real existence state instead of hardcoded true.

Lines 43 and 51 always report resources as existing, so dashboard health is misleading.

Suggested patch
-import { readFileSync } from 'fs';
-import { join } from 'path';
+import { existsSync } from 'fs';
+import { join, resolve } from 'path';
@@
 app.get('/api/repos', (req, res) => {
-  res.json(CONFIG.repos.map(r => ({ name: r.name, exists: true })));
+  res.json(
+    CONFIG.repos.map(r => ({
+      name: r.name,
+      exists: existsSync(resolve(__dirname, r.path))
+    }))
+  );
 });
@@
 app.get('/api/logs', (req, res) => {
-  res.json(CONFIG.logs.map(l => ({ name: l.name, exists: true })));
+  res.json(
+    CONFIG.logs.map(l => ({
+      name: l.name,
+      exists: existsSync(resolve(__dirname, l.path))
+    }))
+  );
 });

Also applies to: 50-51

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@unified-app/server.js` around lines 42 - 43, The route handler for
app.get('/api/repos') (and the similar handler around lines 50-51) returns
exists: true for every item; change it to compute the real existence by checking
the filesystem or the authoritative source for each repo/resource. Update the
handler(s) to be async, use fs.promises.access or fs.existsSync (or your
configured repo-check function) to determine existence for each CONFIG.repos
entry, build the response objects with the actual boolean in the exists field,
and await Promise.all when mapping async checks so the response contains real
existence states for both endpoints.

@atomeam
atomeam merged commit 27f3c2d into main May 18, 2026
1 of 2 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@unified-app/server.js`:
- Around line 15-21: The code incorrectly falls back to
process.env.GEMINI_API_KEY when building NOTION_KEY causing false "connected"
state; update the NOTION_KEY assignment to use only process.env.NOTION_API_KEY,
remove any use of process.env.GEMINI_API_KEY in this file, and ensure the Notion
client is only instantiated when NOTION_KEY is truthy (affecting the notion
variable/Client creation and any connection/status checks like the status
endpoint that reads notion). Locate the NOTION_KEY constant, the notion = new
Client({ auth: NOTION_KEY }) instantiation, and any checks that infer connection
status to make this change.
- Around line 68-86: The /api/notion/logs route currently returns 200 on errors
and exposes raw upstream errors; update the handler
(app.get('/api/notion/logs')) so that if notion is not configured (the notion
variable) it responds with res.status(503).json({ error: 'Notion service
unavailable', logs: [] }); and in the catch block for the notion.databases.query
call respond with res.status(502).json({ error: 'Failed to fetch Notion logs',
logs: [] }); while logging the real error server-side (e.g., console.error or
existing logger) instead of returning e.message to the client; keep the
successful response unchanged (res.status(200).json({ logs })).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 886b13c3-177f-4aac-b0e5-91df645bfac6

📥 Commits

Reviewing files that changed from the base of the PR and between 9df8ca6 and 50e2e88.

⛔ Files ignored due to path filters (1)
  • unified-app/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • unified-app/package.json
  • unified-app/server.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • unified-app/package.json

Comment thread unified-app/server.js
Comment on lines +15 to +21
const NOTION_KEY = process.env.NOTION_API_KEY || process.env.GEMINI_API_KEY;
const LOGS_DB_ID = '4ee3980e-62fa-4abe-a716-c7d6656011ba';

let notion;
if (NOTION_KEY) {
notion = new Client({ auth: NOTION_KEY });
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

find . -name "server.js" -type f | head -20

Repository: atomeam/atomarcade-bridge

Length of output: 93


🏁 Script executed:

cat -n ./unified-app/server.js | head -60

Repository: atomeam/atomarcade-bridge

Length of output: 2095


🏁 Script executed:

cat -n ./unified-app/server.js | grep -A 5 -B 5 "notion\."

Repository: atomeam/atomarcade-bridge

Length of output: 519


🏁 Script executed:

grep -n "GEMINI_API_KEY" ./unified-app/server.js

Repository: atomeam/atomarcade-bridge

Length of output: 149


🏁 Script executed:

wc -l ./unified-app/server.js && grep -c "process.env" ./unified-app/server.js

Repository: atomeam/atomarcade-bridge

Length of output: 98


Remove fallback to GEMINI_API_KEY for Notion authentication.

Using an unrelated API key causes a false "connected" state. The status endpoint reports connected: true (line 49), but subsequent Notion API calls at line 73 fail with invalid credentials. Keep Notion authentication bound to NOTION_API_KEY only.

Suggested patch
-const NOTION_KEY = process.env.NOTION_API_KEY || process.env.GEMINI_API_KEY;
+const NOTION_KEY = process.env.NOTION_API_KEY;

Also applies to: 48-50

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@unified-app/server.js` around lines 15 - 21, The code incorrectly falls back
to process.env.GEMINI_API_KEY when building NOTION_KEY causing false "connected"
state; update the NOTION_KEY assignment to use only process.env.NOTION_API_KEY,
remove any use of process.env.GEMINI_API_KEY in this file, and ensure the Notion
client is only instantiated when NOTION_KEY is truthy (affecting the notion
variable/Client creation and any connection/status checks like the status
endpoint that reads notion). Locate the NOTION_KEY constant, the notion = new
Client({ auth: NOTION_KEY }) instantiation, and any checks that infer connection
status to make this change.

Comment thread unified-app/server.js
Comment on lines +68 to +86
app.get('/api/notion/logs', async (req, res) => {
if (!notion) {
return res.json({ error: 'No Notion API key', logs: [] });
}
try {
const response = await notion.databases.query({
database_id: LOGS_DB_ID,
sorts: [{ timestamp: 'created_time', direction: 'descending' }],
page_size: 10
});
const logs = response.results.map(page => ({
id: page.id,
created: page.created_time,
properties: page.properties
}));
res.json({ logs });
} catch (e) {
res.json({ error: e.message, logs: [] });
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

find . -name "server.js" -o -name "servers.js" | head -20

Repository: atomeam/atomarcade-bridge

Length of output: 93


🏁 Script executed:

git ls-files | grep -i server | head -20

Repository: atomeam/atomarcade-bridge

Length of output: 91


🏁 Script executed:

sed -n '68,86p' unified-app/server.js

Repository: atomeam/atomarcade-bridge

Length of output: 628


🏁 Script executed:

wc -l unified-app/server.js

Repository: atomeam/atomarcade-bridge

Length of output: 94


🏁 Script executed:

grep -n "res.json\|res.status" unified-app/server.js | head -30

Repository: atomeam/atomarcade-bridge

Length of output: 399


🏁 Script executed:

cat -n unified-app/server.js

Repository: atomeam/atomarcade-bridge

Length of output: 3178


Return proper HTTP error codes and avoid leaking raw upstream errors.

Lines 70 and 85 respond with HTTP 200 even on failures. Missing Notion configuration should return 503, and Notion API exceptions should return 502 with a sanitized error message (raw e.message leaks internal details to clients).

Suggested patch
 app.get('/api/notion/logs', async (req, res) => {
   if (!notion) {
-    return res.json({ error: 'No Notion API key', logs: [] });
+    return res.status(503).json({ error: 'Notion integration is not configured', logs: [] });
   }
   try {
     const response = await notion.databases.query({
       database_id: LOGS_DB_ID,
       sorts: [{ timestamp: 'created_time', direction: 'descending' }],
       page_size: 10
     });
     const logs = response.results.map(page => ({
       id: page.id,
       created: page.created_time,
       properties: page.properties
     }));
     res.json({ logs });
   } catch (e) {
-    res.json({ error: e.message, logs: [] });
+    console.error('Failed to fetch Notion logs:', e);
+    res.status(502).json({ error: 'Failed to fetch Notion logs', logs: [] });
   }
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@unified-app/server.js` around lines 68 - 86, The /api/notion/logs route
currently returns 200 on errors and exposes raw upstream errors; update the
handler (app.get('/api/notion/logs')) so that if notion is not configured (the
notion variable) it responds with res.status(503).json({ error: 'Notion service
unavailable', logs: [] }); and in the catch block for the notion.databases.query
call respond with res.status(502).json({ error: 'Failed to fetch Notion logs',
logs: [] }); while logging the real error server-side (e.g., console.error or
existing logger) instead of returning e.message to the client; keep the
successful response unchanged (res.status(200).json({ logs })).

@atomeam
atomeam deleted the feature/atomeam-stack branch May 18, 2026 09:01
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.

1 participant