Skip to content

feat: add peer connections system with requests, accept/decline, and dashboard UI#29

Open
ayesha1145 wants to merge 3 commits intoalphaonelabs:mainfrom
ayesha1145:feat/peer-connections
Open

feat: add peer connections system with requests, accept/decline, and dashboard UI#29
ayesha1145 wants to merge 3 commits intoalphaonelabs:mainfrom
ayesha1145:feat/peer-connections

Conversation

@ayesha1145
Copy link
Copy Markdown
Contributor

@ayesha1145 ayesha1145 commented Mar 28, 2026

Adds a peer connections feature allowing students to connect with each other based on shared learning activities.

Changes

schema.sql + src/worker.py DDL:

  • New peer_connections table: requester_id, addressee_id, status (pending/accepted/declined), optional message, timestamps
  • UNIQUE constraint prevents duplicate connection requests
  • ON DELETE CASCADE on both user FKs
  • 3 indexes for performance (requester, addressee, status)

src/worker.py — 5 new API endpoints:

  • GET /api/peers — list accepted connections for current user
  • GET /api/peers/requests — list incoming pending requests
  • POST /api/peers/request/:id — send connection request with optional message
  • POST /api/peers/:id/accept — accept a pending request
  • POST /api/peers/:id/decline — decline a pending request
  • DELETE /api/peers/:id — remove an accepted connection

public/dashboard.html:

  • New Peers section with 3 tabs: My Peers, Requests, Find Peers
  • Incoming request badge with count
  • Accept/Decline buttons on request cards
  • Find Peers tab shows people from your joined activities
  • XSS-safe rendering via escP()

Security

  • All endpoints require authentication
  • Users can only accept/decline requests addressed to them
  • Users can only remove connections they are part of
  • Input validation: isinstance() check on message, 200 char limit
  • Duplicate request detection (pending or accepted)

Peer Connections System

This PR adds a peer connections feature so students can discover and connect with peers who share learning activities, manage incoming requests, and view suggestions.

Database Changes

  • New peer_connections table:
    • id, requester_id, addressee_id, status (pending|accepted|declined), optional message, created_at, updated_at
    • FOREIGN KEYs to users(id) with ON DELETE CASCADE
    • UNIQUE(requester_id, addressee_id) to prevent duplicates
    • Indexes on requester_id, addressee_id, and status
    • Message limited/handled to 200 chars

API Endpoints (authentication required)

  • GET /api/peers — list accepted connections for the authenticated user
  • GET /api/peers/requests — list incoming pending requests (includes message)
  • GET /api/peers/suggestions — suggest users from shared active enrollments (excludes existing connections)
  • POST /api/peers/request/:id — send a connection request (validates self-requests, shared enrollment, message type/length; returns 409 for existing/declined/accepted conflicts)
  • POST /api/peers/:id/accept — accept a pending request (only addressee; enforces pending state)
  • POST /api/peers/:id/decline — decline a pending request (only addressee; enforces pending state; explicit declined handling with 409)
  • DELETE /api/peers/:id — remove an accepted connection (only participants)

Server-side improvements:

  • Comprehensive validation and permission checks
  • Sanitization/truncation of message input
  • Explicit handling for declined status and clearer 409 responses instead of relying on UNIQUE constraint failures
  • Additional error logging/context (req/env) in critical failure paths
  • Try/except around update operations for consistent error responses

Frontend/UI (public/dashboard.html)

  • New "Peers" section with three accessible tabs: My Peers, Requests, Find Peers
    • Requests tab shows incoming requests with a badge count and Accept/Decline actions
    • Find Peers shows suggestions from shared activities and allows sending requests
  • Implemented JS functions for loading/rendering peers, requests, suggestions, and performing mutations (send/accept/decline/remove)
  • Fixed markup/JS placement (peers moved inside , scripts inside a proper <script> block) to resolve ReferenceError
  • XSS-safe rendering via escP(), and ARIA attributes for tab accessibility
  • UI refreshes lists on mutations and surfaces alerts/errors to the user

Impact

  • Enables peer discovery and controlled connection workflows based on shared enrollments
  • Prevents duplicate/unauthorized requests and preserves referential integrity through cascade deletes
  • Adds UX/accessibility improvements and more robust server-side error handling and messaging

A1L13N and others added 2 commits March 26, 2026 12:17
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 28, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a peer-connections feature: dashboard UI and client JS for tabbed peer lists and actions, a new peer_connections table with indexes, and authenticated API endpoints to suggest, list, request, accept, decline, and remove peer connections. All server handlers enforce auth and business rules.

Changes

Cohort / File(s) Summary
Dashboard UI
public/dashboard.html
New "Peer Connections" section and tabbed panels; client-side JS to load/render peers, incoming requests, and suggestions; DOM-escaped strings; handlers for send/accept/decline/remove actions; refreshes and alerts on outcomes.
Database Schema
schema.sql, src/worker.py (DDL)
Added peer_connections table (id, requester_id, addressee_id, status DEFAULT 'pending', message, created_at, updated_at), UNIQUE(requester_id, addressee_id), FK constraints to users(id) ON DELETE CASCADE, and indexes idx_pc_requester, idx_pc_addressee, idx_pc_status.
Backend API & Logic
src/worker.py
New /api/peers namespace with endpoints: GET /api/peers/suggestions, GET /api/peers, GET /api/peers/requests, POST /api/peers/request/:id, POST /api/peers/:id/accept, POST /api/peers/:id/decline, DELETE /api/peers/:id. Implemented JWT auth checks, decrypting user names, suggestion logic based on shared active enrollments, request validation (no self-requests, shared activity required), conflict detection for existing rows (either direction), message sanitization/truncation, updates for accept/decline, and deletion for removals; includes DB error handling and logging.
Misc
src/worker.py (on_fetch)
Adjusted on_fetch newline handling while preserving 500 behavior on unhandled exceptions.

Sequence Diagram

sequenceDiagram
    participant Browser as Browser
    participant Server as Server (worker.py)
    participant DB as Database (SQLite)

    Browser->>Server: GET /api/peers/requests + Authorization: Bearer <JWT>
    Server->>Server: Verify JWT -> user_id
    Server->>DB: SELECT peer_connections WHERE addressee_id=? AND status='pending'
    DB-->>Server: pending request rows
    Server->>DB: SELECT user details for requester_ids
    DB-->>Server: requester user rows
    Server-->>Browser: 200 { ok:true, requests:[...] }
Loading
sequenceDiagram
    participant Browser as Browser
    participant Server as Server (worker.py)
    participant DB as Database (SQLite)

    Browser->>Server: POST /api/peers/request/{addressee_id} + body {message} + Authorization: Bearer <JWT>
    Server->>Server: Verify JWT -> requester_id
    Server->>DB: SELECT shared active enrollments AND existing peer_connections (either direction)
    DB-->>Server: enrollments / existing rows
    Server->>Server: Validate (not self, has shared enrollment, no conflicting row)
    Server->>DB: INSERT peer_connections (status='pending', message...)
    DB-->>Server: Insert OK / error
    Server-->>Browser: 200 { ok:true, connection_id } or error code
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately and comprehensively describes the main change: adding a complete peer connections system with request handling and UI integration.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@public/dashboard.html`:
- Around line 186-190: The tab group is missing ARIA roles and attributes and
the JS does not update them; add role="tablist" and aria-label on the container
and set role="tab", aria-selected and aria-controls on the three buttons (ids:
tab-connections, tab-requests, tab-find) and add corresponding tabpanel elements
with ids peers-connections, peers-requests, peers-find and role="tabpanel" +
aria-labelledby; then update the showPeerTab(tab) function to toggle the visible
panel classes and set aria-selected="true"/"false" on the buttons and update
each panel's aria-hidden (or equivalent) so screen readers reflect the active
tab.
- Around line 178-179: The peers section (the div with id="peers-section") is
currently located after the footer; move that entire element so it becomes a
sibling of the element with id="joined-section" inside the <main> container,
ensuring it appears before the footer in the DOM and preserves its classes and
content, so semantic structure and accessibility are corrected.
- Around line 178-207: Define the missing UI and data functions referenced by
the peer section: implement showPeerTab(tabName) to switch visible panels and
active tab classes for IDs tab-connections/tab-requests/tab-find and panels
peers-connections/peers-requests/peers-find; add async loader functions
loadPeers(), loadPeerRequests(), loadSuggestions() that fetch data and call
render helpers renderPeers(data), renderRequests(data), renderSuggestions(data)
to populate the containers peers-list, requests-list, suggestions-list; add
escP() (or rename uses to esc() if intended) to match the PR objective; ensure
these functions are registered before the HTML buttons run (put them in the page
<script> and call initializers like loadPeers() on DOMContentLoaded); finally,
move the peer connections block into the <main> element for semantic
correctness.

In `@src/worker.py`:
- Around line 1445-1447: Wrap the UPDATE calls that use
env.DB.prepare(...).bind(connection_id).run() inside a try/except and handle DB
errors consistently with other write operations (e.g., in
api_accept_peer_request and api_decline_peer_request): catch the exception
around the env.DB.prepare(...) call, call processLogger.error or the existing
logger with a descriptive message that includes the exception details and the
connection_id, and return/raise an appropriate error response so the caller
knows the update failed; mirror the same pattern for the UPDATE at the other
location referenced.
- Around line 1407-1429: Existing declined requests fall through to the INSERT
and trigger a UNIQUE constraint error; update the logic in the handler around
the existing lookup (the existing variable and the peer_connections queries) to
handle existing["status"] == "declined" explicitly: either return a clear client
error (e.g., err("Previous request was declined", 409)) or perform an UPDATE on
the existing row (use env.DB.prepare(...) to UPDATE peer_connections SET
requester_id=?, addressee_id=?, message=?, status='pending' WHERE id=? using
existing["id"] and the new message) instead of INSERT so resends succeed; adjust
conn_id usage accordingly and keep capture_exception("api_send_peer_request") in
the exception path as before.
- Around line 1362-1368: The loop building peers uses dict-style access
(r["id"], r["peer_id"], etc.) which is inconsistent with other handlers; change
to attribute-style access (e.g., r.id, r.peer_id, r.peer_name_enc, r.created_at)
when constructing the peer dict in the same loop, but keep the current
async-await pattern for decrypt_aes (do not convert to a list comprehension).
Update the keys in the constructed dict to use these attribute accesses
(connection_id: r.id, peer_id: r.peer_id, peer_name: await
decrypt_aes(r.peer_name_enc or "", enc), connected_at: r.created_at) to match
the codebase style.
- Around line 1427-1428: The exception handler inside api_send_peer_request
currently calls capture_exception(exc, where="api_send_peer_request") without
request context; update the call to pass the current req and env objects (e.g.,
capture_exception(exc, where="api_send_peer_request", req=req, env=env)) so logs
include the same request/environment context other handlers provide; locate the
except block in api_send_peer_request and add the req and env kwargs when
calling capture_exception.
🪄 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: Repository: alphaonelabs/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a347f21c-22de-4e94-88b2-c4fa210ef7f5

📥 Commits

Reviewing files that changed from the base of the PR and between d6e1a9c and 580d267.

📒 Files selected for processing (3)
  • public/dashboard.html
  • schema.sql
  • src/worker.py

@ayesha1145 ayesha1145 force-pushed the feat/peer-connections branch from 580d267 to 107e2f7 Compare March 28, 2026 23:57
@ayesha1145
Copy link
Copy Markdown
Contributor Author

Addressed CodeRabbit feedback:

  • Fixed critical: moved peers section inside and JS inside <script> tag — functions were present but outside the script block causing ReferenceError
  • Fixed minor: added explicit handling for declined status — returns 409 with clear message instead of failing silently on UNIQUE constraint
  • Fixed nitpick: added req/env context to capture_exception in api_send_peer_request
  • Fixed nitpick: added try/except to accept and decline UPDATE operations for consistent error handling
  • Fixed minor: added role="tab" and aria-selected attributes to tab buttons; showPeerTab() now updates aria-selected on tab switch

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (4)
src/worker.py (1)

1362-1368: 🧹 Nitpick | 🔵 Trivial

Inconsistent result access pattern — prefer attribute-style for consistency.

The code uses dictionary-style access (r["id"], r["peer_id"]) while other handlers in this file use attribute-style (r.id, row.title). Aligning with the codebase convention improves readability and maintainability.

♻️ Suggested fix
     for r in rows.results or []:
         peers.append({
-            "connection_id": r["id"],
-            "peer_id": r["peer_id"],
-            "peer_name": await decrypt_aes(r["peer_name_enc"] or "", enc),
-            "connected_at": r["created_at"],
+            "connection_id": r.id,
+            "peer_id": r.peer_id,
+            "peer_name": await decrypt_aes(r.peer_name_enc or "", enc),
+            "connected_at": r.created_at,
         })

Note: The static analysis hint about list comprehensions doesn't apply here since decrypt_aes is async, requiring the loop structure.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/worker.py` around lines 1362 - 1368, Change the dict-style field access
on rows.results to attribute-style to match the rest of the file: inside the
loop over rows.results use r.id, r.peer_id, r.peer_name_enc (or fallback empty
string) and r.created_at when building the dict appended to peers; keep the
async decrypt_aes(r.peer_name_enc or "", enc) call and the loop structure (do
not convert to a list comprehension) so behavior remains the same.
public/dashboard.html (3)

70-72: ⚠️ Potential issue | 🔴 Critical

Missing JavaScript implementation for peer connections UI.

The tab buttons call showPeerTab() (lines 70-72), but this function is not defined anywhere in the <script> block. Clicking any tab will throw ReferenceError: showPeerTab is not defined, making the peer connections feature non-functional.

The following functions need to be implemented:

  • showPeerTab(tabName) — switch visible panels and update aria-selected states
  • loadPeers() — fetch from /api/peers and populate #peers-list
  • loadPeerRequests() — fetch from /api/peers/requests and populate #requests-list
  • Functions to handle accept/decline/connect actions

Would you like me to help generate the JavaScript implementation for these functions?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@public/dashboard.html` around lines 70 - 72, Implement the missing peer UI
JavaScript by adding definitions for showPeerTab(tabName), loadPeers(),
loadPeerRequests(), and action handlers (acceptPeerRequest, declinePeerRequest,
connectToPeer): showPeerTab should toggle visibility of the tab panels (e.g.,
panels with ids like "connections", "requests", "find"), update the
aria-selected attribute and CSS classes on the tab buttons (ids tab-connections,
tab-requests, tab-find) to reflect the active tab; loadPeers() should fetch GET
/api/peers, render the results into the `#peers-list` container and attach connect
button handlers that call connectToPeer(id); loadPeerRequests() should fetch GET
/api/peers/requests, render into `#requests-list` and attach acceptPeerRequest(id)
and declinePeerRequest(id) handlers which POST/DELETE to the appropriate
endpoints and refresh lists on success; ensure all fetch calls handle errors and
update the UI state (disable buttons while pending, show simple error text), and
call loadPeers() and loadPeerRequests() on initial script run and after actions
to keep the UI in sync.

76-89: 🧹 Nitpick | 🔵 Trivial

Add role="tabpanel" and aria-labelledby to tab panels.

To complete the accessible tabs pattern, each panel should be marked as a tabpanel and linked to its controlling tab button. This helps screen readers understand the relationship between tabs and their content.

♿ Suggested enhancement
     <!-- My Connections -->
-    <div id="peers-connections" class="peer-panel">
+    <div id="peers-connections" class="peer-panel" role="tabpanel" aria-labelledby="tab-connections">
       <div id="peers-list" class="space-y-3"></div>
     </div>

     <!-- Incoming Requests -->
-    <div id="peers-requests" class="peer-panel hidden">
+    <div id="peers-requests" class="peer-panel hidden" role="tabpanel" aria-labelledby="tab-requests">
       <div id="requests-list" class="space-y-3"></div>
     </div>

     <!-- Find Peers -->
-    <div id="peers-find" class="peer-panel hidden">
+    <div id="peers-find" class="peer-panel hidden" role="tabpanel" aria-labelledby="tab-find">
       <p class="text-sm text-slate-500 mb-3">Connect with other learners from your activities.</p>
       <div id="suggestions-list" class="space-y-3"></div>
     </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@public/dashboard.html` around lines 76 - 89, Add role="tabpanel" and an
aria-labelledby that points to the controlling tab button for each panel div
(peers-connections, peers-requests, peers-find); for example set
aria-labelledby="peers-connections-tab", "peers-requests-tab", and
"peers-find-tab" respectively, and make sure the corresponding tab buttons use
those IDs so the relationship is valid; also keep the existing hidden toggling
(e.g., class "hidden") in sync with the tab logic (update aria-hidden as you
toggle if your tab script manages visibility).

69-73: 🧹 Nitpick | 🔵 Trivial

Enhance tab container with role="tablist" for full accessibility compliance.

The individual tab buttons correctly include role="tab" and aria-selected, which is great progress! However, the container <div> on line 69 should have role="tablist" and an aria-label to complete the accessible tabs pattern. Additionally, each button would benefit from aria-controls pointing to its corresponding panel.

♿ Suggested enhancement
-    <div class="flex gap-2 mb-4 border-b border-slate-100">
-      <button type="button" role="tab" aria-selected="true" onclick="showPeerTab('connections')" id="tab-connections" class="peer-tab px-4 py-2 text-sm font-semibold text-indigo-600 border-b-2 border-indigo-600">My Peers</button>
-      <button type="button" role="tab" aria-selected="false" onclick="showPeerTab('requests')" id="tab-requests" class="peer-tab px-4 py-2 text-sm font-semibold text-slate-400 border-b-2 border-transparent">Requests</button>
-      <button type="button" role="tab" aria-selected="false" onclick="showPeerTab('find')" id="tab-find" class="peer-tab px-4 py-2 text-sm font-semibold text-slate-400 border-b-2 border-transparent">Find Peers</button>
+    <div class="flex gap-2 mb-4 border-b border-slate-100" role="tablist" aria-label="Peer connection views">
+      <button type="button" role="tab" aria-selected="true" aria-controls="peers-connections" onclick="showPeerTab('connections')" id="tab-connections" class="peer-tab px-4 py-2 text-sm font-semibold text-indigo-600 border-b-2 border-indigo-600">My Peers</button>
+      <button type="button" role="tab" aria-selected="false" aria-controls="peers-requests" onclick="showPeerTab('requests')" id="tab-requests" class="peer-tab px-4 py-2 text-sm font-semibold text-slate-400 border-b-2 border-transparent">Requests</button>
+      <button type="button" role="tab" aria-selected="false" aria-controls="peers-find" onclick="showPeerTab('find')" id="tab-find" class="peer-tab px-4 py-2 text-sm font-semibold text-slate-400 border-b-2 border-transparent">Find Peers</button>

As per coding guidelines, "Review HTML templates for accessibility (ARIA attributes, semantic elements)".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@public/dashboard.html` around lines 69 - 73, Add accessibility attributes to
the tabs container and buttons: give the container div (the element wrapping the
three buttons) role="tablist" and an appropriate aria-label (e.g., "Peer tabs");
add aria-controls to each tab button (tab-connections, tab-requests, tab-find)
pointing to their corresponding panel IDs (use a consistent naming convention
such as panel-connections, panel-requests, panel-find); ensure the corresponding
panels exist and have role="tabpanel", the matching id (panel-...), and
aria-labelledby that references the controlling button id (tab-connections,
tab-requests, tab-find) so the showPeerTab function continues to toggle visible
panels while meeting ARIA tabs pattern.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@schema.sql`:
- Around line 110-112: Add a composite index to speed the common query in
api_list_peer_requests that filters WHERE addressee_id=? AND status='pending':
create an index on peer_connections covering (addressee_id, status) (e.g.,
idx_pc_addressee_status) so the planner can use a single index for that
predicate instead of two separate single-column indexes; add the CREATE INDEX IF
NOT EXISTS statement for idx_pc_addressee_status to schema.sql and keep or
remove the separate single-column indexes as you prefer.
- Around line 98-109: Add a CHECK constraint on the peer_connections.status
column to restrict values to 'pending', 'accepted', or 'declined': update the
CREATE TABLE peer_connections definition to include CHECK(status IN
('pending','accepted','declined')) for the status column (or add the same
constraint via ALTER TABLE for migrations) so the database enforces the allowed
states; reference the peer_connections table and the status column when applying
the change and ensure any migration scripts handle existing invalid rows before
adding the constraint.

In `@src/worker.py`:
- Around line 1386-1393: The loop building requests uses dict-style access on
the row object; switch to attribute access for consistency—change r["id"] ->
r.id, r["requester_id"] -> r.requester_id, r["requester_name_enc"] ->
r.requester_name_enc, r["message"] -> r.message, and r["created_at"] ->
r.created_at in the requests.append block (keeping the await
decrypt_aes(r.requester_name_enc or "", enc) call and the same keys
"connection_id", "requester_id", "requester_name", "message", "requested_at").
- Around line 1445-1446: The code uses dict-style access pc["status"] instead of
attribute-style access used elsewhere; update all occurrences (e.g., inside the
request handling where pc["status"] is checked and in the functions
api_send_peer_request and api_decline_peer_request) to use attribute access
pc.status, keeping the same comparison and behavior (e.g., if pc.status !=
"pending": return err(...)); ensure you replace every pc["status"] instance in
these functions with pc.status to maintain consistency.
- Line 1490: Wrap the await env.DB.prepare("DELETE FROM peer_connections WHERE
id=?").bind(connection_id).run() call in a try/except block to mirror the other
write operations: catch Exception as e, log a clear error message including the
connection_id and the exception (using the same logger used elsewhere in this
file), and then either re-raise or handle the error consistently with existing
write-operation error handling in this module.

---

Duplicate comments:
In `@public/dashboard.html`:
- Around line 70-72: Implement the missing peer UI JavaScript by adding
definitions for showPeerTab(tabName), loadPeers(), loadPeerRequests(), and
action handlers (acceptPeerRequest, declinePeerRequest, connectToPeer):
showPeerTab should toggle visibility of the tab panels (e.g., panels with ids
like "connections", "requests", "find"), update the aria-selected attribute and
CSS classes on the tab buttons (ids tab-connections, tab-requests, tab-find) to
reflect the active tab; loadPeers() should fetch GET /api/peers, render the
results into the `#peers-list` container and attach connect button handlers that
call connectToPeer(id); loadPeerRequests() should fetch GET /api/peers/requests,
render into `#requests-list` and attach acceptPeerRequest(id) and
declinePeerRequest(id) handlers which POST/DELETE to the appropriate endpoints
and refresh lists on success; ensure all fetch calls handle errors and update
the UI state (disable buttons while pending, show simple error text), and call
loadPeers() and loadPeerRequests() on initial script run and after actions to
keep the UI in sync.
- Around line 76-89: Add role="tabpanel" and an aria-labelledby that points to
the controlling tab button for each panel div (peers-connections,
peers-requests, peers-find); for example set
aria-labelledby="peers-connections-tab", "peers-requests-tab", and
"peers-find-tab" respectively, and make sure the corresponding tab buttons use
those IDs so the relationship is valid; also keep the existing hidden toggling
(e.g., class "hidden") in sync with the tab logic (update aria-hidden as you
toggle if your tab script manages visibility).
- Around line 69-73: Add accessibility attributes to the tabs container and
buttons: give the container div (the element wrapping the three buttons)
role="tablist" and an appropriate aria-label (e.g., "Peer tabs"); add
aria-controls to each tab button (tab-connections, tab-requests, tab-find)
pointing to their corresponding panel IDs (use a consistent naming convention
such as panel-connections, panel-requests, panel-find); ensure the corresponding
panels exist and have role="tabpanel", the matching id (panel-...), and
aria-labelledby that references the controlling button id (tab-connections,
tab-requests, tab-find) so the showPeerTab function continues to toggle visible
panels while meeting ARIA tabs pattern.

In `@src/worker.py`:
- Around line 1362-1368: Change the dict-style field access on rows.results to
attribute-style to match the rest of the file: inside the loop over rows.results
use r.id, r.peer_id, r.peer_name_enc (or fallback empty string) and r.created_at
when building the dict appended to peers; keep the async
decrypt_aes(r.peer_name_enc or "", enc) call and the loop structure (do not
convert to a list comprehension) so behavior remains the same.
🪄 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: Repository: alphaonelabs/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 65a1231d-9ddb-4808-8584-dd33b566ea65

📥 Commits

Reviewing files that changed from the base of the PR and between 580d267 and 107e2f7.

📒 Files selected for processing (3)
  • public/dashboard.html
  • schema.sql
  • src/worker.py

@ayesha1145 ayesha1145 force-pushed the feat/peer-connections branch from 107e2f7 to 07012fb Compare March 29, 2026 02:43
@ayesha1145
Copy link
Copy Markdown
Contributor Author

Fixed critical: JS functions (showPeerTab, loadPeers, renderPeers, renderRequests, acceptRequest, declineRequest, removePeer, loadSuggestions, escP) were missing from the script block — now properly added inside <script> tag. All peer connections UI functions are now fully implemented.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (2)
public/dashboard.html (2)

8-10: ⚠️ Potential issue | 🔴 Critical

Split the Tailwind CDN include from the peer script block.

Because Line 8 has a src attribute, browsers ignore the inline JavaScript inside this element. The peer functions in this block never get defined, so the runtime failure is still present. Keep the Tailwind include empty and move this logic into its own <script> tag.

In HTML, if a <script> element has a src attribute, does the inline JavaScript inside that same element execute or is it ignored by browsers?

Also applies to: 122-122

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@public/dashboard.html` around lines 8 - 10, The Tailwind <script> element
currently contains a src attribute and inline JS (the peer functions), which
browsers ignore; split them by leaving the Tailwind include as a single empty
<script src="https://cdn.tailwindcss.com"></script> and move all inline peer
functions into a separate <script> block immediately after it (i.e., relocate
the code currently inside the script with src into its own <script> so functions
are defined at runtime); apply the same change to the other occurrence noted
(line ~122).

65-77: ⚠️ Potential issue | 🟡 Minor

Finish wiring the tablist/panel relationships.

The buttons now expose role="tab" and aria-selected, but the group still lacks role="tablist", the tabs have no aria-controls, and the panels have no role="tabpanel" / aria-labelledby. Please also toggle aria-hidden alongside the visual hidden state in showPeerTab().

As per coding guidelines, **/*.html: Review HTML templates for accessibility (ARIA attributes, semantic elements).`

Also applies to: 181-200

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@public/dashboard.html` around lines 65 - 77, Add the missing ARIA
relationships and toggle aria-hidden in the tab logic: give the tabs container
role="tablist", add aria-controls on each tab button referencing its panel id
(e.g., tab buttons with id "tab-<name>" should have
aria-controls="peers-<name>"), add role="tabpanel" and aria-labelledby on each
panel (panels with id "peers-<name>" should have aria-labelledby="tab-<name>"),
and update showPeerTab() to set aria-hidden="true" on panels being hidden and
aria-hidden="false" on the visible panel in addition to adding/removing the CSS
"hidden" class; apply the same attribute fixes to the second tablist/panel block
referenced around lines 181-200.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@public/dashboard.html`:
- Around line 80-89: loadSuggestions currently only renders joined_activities
title/host_name and lacks any user identifier, connection state, or action to
call the peer-request endpoint; update the function to (1) expect and use a
candidate user_id from the API response (e.g., include user_id on each joined
activity), (2) render each candidate with a request/connect button (attach
data-user-id or id attribute) and a visual connection state element, and (3)
wire that button to an async handler that posts to POST /api/peers/request/:id
(use fetch with Authorization header) and updates the UI state on success/error;
reference loadSuggestions, joined_activities, escP and the suggestions-list
element when locating where to add the user_id rendering, the button, and the
click handler.

In `@schema.sql`:
- Around line 98-109: Change the one-direction UNIQUE on peer_connections to
enforce a canonical unordered pair by adding computed/stored columns that
normalize the pair and a UNIQUE constraint on those columns: in the CREATE TABLE
for peer_connections, add two generated columns (e.g., user_a and user_b) that
set user_a = CASE WHEN requester_id < addressee_id THEN requester_id ELSE
addressee_id END and user_b = CASE WHEN requester_id < addressee_id THEN
addressee_id ELSE requester_id END, then replace UNIQUE(requester_id,
addressee_id) with UNIQUE(user_a, user_b); also make the identical change in
src/worker.py’s _DDL definition so the same DDL is used by the worker. Ensure
foreign keys and other column definitions remain unchanged.

In `@src/worker.py`:
- Around line 1404-1410: The code currently only checks the addressee exists;
before checking/creating peer_connections you must enforce the shared-activity
rule by querying the DB (using env.DB.prepare and bind with addressee_id and
user["id"]) to confirm both users are members of at least one common learning
activity; insert this check immediately after the addressee lookup and before
the existing peer_connections query, and if the query finds no shared activity
return an error (e.g., err("Users do not share a learning activity", 403)).
- Around line 1418-1422: The handler currently rejects empty POST bodies because
parse_json_object returning a falsy/empty body leads to returning bad; instead,
treat an absent/empty body as an empty dict so message remains optional. Modify
the code around parse_json_object so that if parse_json_object yields a
None/empty body (or bad indicates an empty body) you set body = {} (and do not
return bad), then continue to extract raw_msg and compute message as you already
do; adjust logic that uses bad so only truly malformed JSON returns bad. Update
references to parse_json_object, body, bad, raw_msg and message accordingly.

---

Duplicate comments:
In `@public/dashboard.html`:
- Around line 8-10: The Tailwind <script> element currently contains a src
attribute and inline JS (the peer functions), which browsers ignore; split them
by leaving the Tailwind include as a single empty <script
src="https://cdn.tailwindcss.com"></script> and move all inline peer functions
into a separate <script> block immediately after it (i.e., relocate the code
currently inside the script with src into its own <script> so functions are
defined at runtime); apply the same change to the other occurrence noted (line
~122).
- Around line 65-77: Add the missing ARIA relationships and toggle aria-hidden
in the tab logic: give the tabs container role="tablist", add aria-controls on
each tab button referencing its panel id (e.g., tab buttons with id "tab-<name>"
should have aria-controls="peers-<name>"), add role="tabpanel" and
aria-labelledby on each panel (panels with id "peers-<name>" should have
aria-labelledby="tab-<name>"), and update showPeerTab() to set
aria-hidden="true" on panels being hidden and aria-hidden="false" on the visible
panel in addition to adding/removing the CSS "hidden" class; apply the same
attribute fixes to the second tablist/panel block referenced around lines
181-200.
🪄 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: Repository: alphaonelabs/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0a779800-2ac1-4908-9fb6-26f0c7dce1a2

📥 Commits

Reviewing files that changed from the base of the PR and between 107e2f7 and 07012fb.

📒 Files selected for processing (3)
  • public/dashboard.html
  • schema.sql
  • src/worker.py

@ayesha1145 ayesha1145 force-pushed the feat/peer-connections branch from 07012fb to 584f2ff Compare March 29, 2026 03:06
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (5)
schema.sql (2)

110-112: 🧹 Nitpick | 🔵 Trivial

Consider a composite index for the common pending-requests query.

The api_list_peer_requests handler filters by WHERE addressee_id=? AND status='pending'. A composite index would serve this pattern more efficiently:

CREATE INDEX IF NOT EXISTS idx_pc_addressee_status ON peer_connections(addressee_id, status);

This is an optional optimization — the current separate indexes will work fine for typical user volumes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@schema.sql` around lines 110 - 112, Add a composite index to speed up the
api_list_peer_requests pattern by creating an index on
peer_connections(addressee_id, status) (suggested name idx_pc_addressee_status)
so queries filtering WHERE addressee_id=? AND status='pending' can use a single
index instead of two separate indexes; add the CREATE INDEX IF NOT EXISTS
idx_pc_addressee_status ON peer_connections(addressee_id, status) statement
alongside the existing indexes.

98-109: ⚠️ Potential issue | 🟠 Major

Bidirectional uniqueness enforcement is still missing.

The UNIQUE (requester_id, addressee_id) constraint only prevents duplicate requests in one direction. Two concurrent requests could still create both A→B and B→A rows, leading to duplicate relationships that the API doesn't expect since connections are treated as undirected once accepted.

Consider enforcing canonical ordering at the database layer using generated columns:

user_a TEXT GENERATED ALWAYS AS (CASE WHEN requester_id < addressee_id THEN requester_id ELSE addressee_id END) STORED,
user_b TEXT GENERATED ALWAYS AS (CASE WHEN requester_id < addressee_id THEN addressee_id ELSE requester_id END) STORED,
UNIQUE(user_a, user_b)

Alternatively, the application layer in api_send_peer_request already checks both directions before inserting (lines 1447-1450 in worker.py), which mitigates this for non-concurrent requests. For full protection, the database constraint would be ideal.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@schema.sql` around lines 98 - 109, The peer_connections table allows A→B and
B→A rows because UNIQUE(requester_id, addressee_id) is directional; add
canonical ordering at the DB layer by introducing generated stored columns
(e.g., user_a and user_b computed from requester_id and addressee_id using CASE
to pick the lesser/greater) and then add UNIQUE(user_a, user_b) to enforce
bidirectional uniqueness for the peer_connections table; reference the
peer_connections table and the requester_id/addressee_id columns and add
user_a/user_b GENERATED ALWAYS AS (...) STORED plus UNIQUE(user_a, user_b) (or
alternatively implement an equivalent DB trigger) to prevent concurrent
opposite-direction inserts.
src/worker.py (2)

1369-1374: 🧹 Nitpick | 🔵 Trivial

Dictionary-style vs attribute-style access inconsistency.

The peer connection handlers use dictionary-style access (r["user_id"], r["id"]) while other handlers in this file use attribute-style access (row.id, r.title). Both work with D1 results, but consistency aids maintainability.

This applies throughout the new handlers (lines 1369-1374, 1393-1399, 1417-1423, 1452, 1488, 1510). Consider aligning with the existing codebase pattern using attribute access.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/worker.py` around lines 1369 - 1374, The loop building suggestions uses
dict-style access (r["user_id"], r["name_enc"], r["activity_title"]) which is
inconsistent with the rest of the file; change these to attribute-style access
(e.g., r.user_id, r.name_enc, r.activity_title) and keep the same None/empty
fallback for decrypt_aes (e.g., decrypt_aes(r.name_enc or "", enc)); apply the
same conversion in the other new handlers that build lists (the other
rows.results loops that call suggestions.append or similar) so all D1 result
access uses attribute access consistently.

1522-1534: 🧹 Nitpick | 🔵 Trivial

Authorization looks correct; consider optional error handling for consistency.

The api_remove_peer handler properly restricts deletion to participants of accepted connections only. The query on lines 1527-1530 correctly checks that the authenticated user is either the requester or addressee.

For consistency with the accept/decline handlers, you could wrap the DELETE in try/except:

🛡️ Optional enhancement
+    try:
         await env.DB.prepare("DELETE FROM peer_connections WHERE id=?").bind(connection_id).run()
+    except Exception as exc:
+        capture_exception(exc, req, env, "api_remove_peer.delete")
+        return err("Failed to remove connection", 500)
     return ok(msg="Connection removed")

This is a nice-to-have for consistency rather than critical.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/worker.py` around lines 1522 - 1534, The DELETE in api_remove_peer should
be wrapped in a try/except to mirror accept/decline handlers and surface DB
errors consistently; catch exceptions around the env.DB.prepare("DELETE FROM
peer_connections WHERE id=?").bind(connection_id).run() call, log or return a
500-style err with the error message, and ensure the handler still returns
ok(msg="Connection removed") on success while returning an err("Failed to remove
connection", 500) (including error details) on exception.
public/dashboard.html (1)

206-226: ⚠️ Potential issue | 🟡 Minor

Add role="tabpanel" and aria-labelledby to tab panels for complete accessibility.

The tab buttons correctly have role="tab" and aria-selected attributes, but the corresponding panels are missing their ARIA roles. This limits accessibility for screen reader users.

♿ Proposed accessibility enhancement
-    <div id="peers-connections" class="peer-panel">
+    <div id="peers-connections" class="peer-panel" role="tabpanel" aria-labelledby="tab-connections">

-    <div id="peers-requests" class="peer-panel hidden">
+    <div id="peers-requests" class="peer-panel hidden" role="tabpanel" aria-labelledby="tab-requests">

-    <div id="peers-find" class="peer-panel hidden">
+    <div id="peers-find" class="peer-panel hidden" role="tabpanel" aria-labelledby="tab-find">

As per coding guidelines, HTML templates should include ARIA attributes for accessibility.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@public/dashboard.html` around lines 206 - 226, Add proper ARIA semantics to
each tab panel by giving the elements with ids peers-connections,
peers-requests, and peers-find the attribute role="tabpanel" and an
aria-labelledby that references the corresponding tab button ids
(tab-connections, tab-requests, tab-find respectively); ensure the panels'
visibility toggling logic (showPeerTab) continues to manage the "hidden" class
and aria-hidden as needed so screen readers see the active tab panel via its
role and labelled-by relationship.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@public/dashboard.html`:
- Around line 8-146: The inline peer-connection functions (loadPeers,
renderPeers, renderRequests, escP, showPeerTab, loadSuggestions, sendRequest,
acceptRequest, declineRequest, removePeer) are currently inside a <script> tag
that has a src attribute so browsers ignore them; move all that inline JS into a
separate <script> block (or external file) so the functions are actually
defined, and ensure the token variable is defined before these functions run —
either place the new script after the script that sets token or wrap
initialization calls (e.g., loadPeers and any immediate usage of token) inside
DOMContentLoaded or a function that reads token at call-time to avoid
ReferenceError.

In `@src/worker.py`:
- Around line 453-469: The in-memory initialization constant _DDL contains the
CREATE TABLE for peer_connections and must match the updated schema.sql change
that enforces bidirectional uniqueness; update the peer_connections CREATE TABLE
string inside _DDL to use the same uniqueness constraint/logic you added in
schema.sql (e.g., replace UNIQUE (requester_id, addressee_id) with the
bidirectional uniqueness expression you used such as UNIQUE (least(requester_id,
addressee_id), greatest(requester_id, addressee_id)) or the equivalent
index-based approach), and ensure the related index names (idx_pc_requester,
idx_pc_addressee, idx_pc_status) remain consistent with the table definition.

---

Duplicate comments:
In `@public/dashboard.html`:
- Around line 206-226: Add proper ARIA semantics to each tab panel by giving the
elements with ids peers-connections, peers-requests, and peers-find the
attribute role="tabpanel" and an aria-labelledby that references the
corresponding tab button ids (tab-connections, tab-requests, tab-find
respectively); ensure the panels' visibility toggling logic (showPeerTab)
continues to manage the "hidden" class and aria-hidden as needed so screen
readers see the active tab panel via its role and labelled-by relationship.

In `@schema.sql`:
- Around line 110-112: Add a composite index to speed up the
api_list_peer_requests pattern by creating an index on
peer_connections(addressee_id, status) (suggested name idx_pc_addressee_status)
so queries filtering WHERE addressee_id=? AND status='pending' can use a single
index instead of two separate indexes; add the CREATE INDEX IF NOT EXISTS
idx_pc_addressee_status ON peer_connections(addressee_id, status) statement
alongside the existing indexes.
- Around line 98-109: The peer_connections table allows A→B and B→A rows because
UNIQUE(requester_id, addressee_id) is directional; add canonical ordering at the
DB layer by introducing generated stored columns (e.g., user_a and user_b
computed from requester_id and addressee_id using CASE to pick the
lesser/greater) and then add UNIQUE(user_a, user_b) to enforce bidirectional
uniqueness for the peer_connections table; reference the peer_connections table
and the requester_id/addressee_id columns and add user_a/user_b GENERATED ALWAYS
AS (...) STORED plus UNIQUE(user_a, user_b) (or alternatively implement an
equivalent DB trigger) to prevent concurrent opposite-direction inserts.

In `@src/worker.py`:
- Around line 1369-1374: The loop building suggestions uses dict-style access
(r["user_id"], r["name_enc"], r["activity_title"]) which is inconsistent with
the rest of the file; change these to attribute-style access (e.g., r.user_id,
r.name_enc, r.activity_title) and keep the same None/empty fallback for
decrypt_aes (e.g., decrypt_aes(r.name_enc or "", enc)); apply the same
conversion in the other new handlers that build lists (the other rows.results
loops that call suggestions.append or similar) so all D1 result access uses
attribute access consistently.
- Around line 1522-1534: The DELETE in api_remove_peer should be wrapped in a
try/except to mirror accept/decline handlers and surface DB errors consistently;
catch exceptions around the env.DB.prepare("DELETE FROM peer_connections WHERE
id=?").bind(connection_id).run() call, log or return a 500-style err with the
error message, and ensure the handler still returns ok(msg="Connection removed")
on success while returning an err("Failed to remove connection", 500) (including
error details) on exception.
🪄 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: Repository: alphaonelabs/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e841c69f-5961-49f2-8884-3e0f476eec62

📥 Commits

Reviewing files that changed from the base of the PR and between 07012fb and 584f2ff.

📒 Files selected for processing (3)
  • public/dashboard.html
  • schema.sql
  • src/worker.py

@ayesha1145 ayesha1145 force-pushed the feat/peer-connections branch from 584f2ff to 124ace8 Compare March 29, 2026 03:23
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
public/dashboard.html (1)

68-88: ⚠️ Potential issue | 🟡 Minor

Finish the tab semantics for screen readers.

The buttons now expose role="tab", but the container still has no role="tablist" and the panels are missing role="tabpanel" plus the aria-controls/aria-labelledby relationship. showPeerTab() only flips CSS classes and aria-selected, so assistive tech never gets the active panel state. Please wire the full tabs pattern here, including panel visibility state (aria-hidden or equivalent) when switching tabs.

As per coding guidelines, **/*.html: Review HTML templates for accessibility (ARIA attributes, semantic elements), XSS risks from unescaped user content, and proper use of template inheritance. Check that forms include CSRF protection tokens.

Also applies to: 266-279

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@public/dashboard.html` around lines 68 - 88, The tab container lacks
role="tablist" and the panels lack role="tabpanel" and ARIA relationships;
update the tab container div to include role="tablist", add aria-controls on
each button (tab-connections -> peers-connections, tab-requests ->
peers-requests, tab-find -> peers-find), and add role="tabpanel" and
aria-labelledby on each panel pointing back to its button id; then update the
showPeerTab(tabName) function to toggle aria-selected (true/false), set
tabindex=0 for the active button and -1 for others, and toggle panel visibility
via aria-hidden (false for active panel, true for others) in addition to the
existing CSS class changes so assistive tech receives correct active-tab and
active-panel state.
schema.sql (1)

98-109: ⚠️ Potential issue | 🟠 Major

Enforce uniqueness on the unordered user pair.

UNIQUE (requester_id, addressee_id) still allows concurrent A→B and B→A rows, even though the feature treats the relationship as undirected and already checks both directions in src/worker.py around Lines 1447-1450. That can leave duplicate connections the list/remove flows do not expect. Please canonicalize the pair at the database layer here, and apply the same DDL change in src/worker.py Lines 454-465.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@schema.sql` around lines 98 - 109, The peer_connections table allows both A→B
and B→A duplicates; modify the DDL to canonicalize the unordered pair and
enforce uniqueness on that canonical form by adding a generated/computed column
(e.g., canonical_pair computed from requester_id and addressee_id with a
deterministic ordering like min/max or lexicographic concatenation) and replace
UNIQUE(requester_id, addressee_id) with UNIQUE(canonical_pair); also update the
identical DDL string in src/worker.py (the table-creation SQL around the
peer_connections creation) so the runtime schema matches the DB constraint.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/worker.py`:
- Around line 1355-1367: The query built in env.DB.prepare selects a.title so
DISTINCT still returns the same user multiple times when they share multiple
activities; change the SQL to deduplicate by user (e.g., GROUP BY u.id,
u.name_enc) and pick or aggregate a representative activity label (e.g.,
MIN(a.title) or GROUP_CONCAT(a.title) AS activity_title) before applying LIMIT
20, then keep the same .bind(user["id"], user["id"], user["id"],
user["id"]).all() call so the dashboard rendering (which expects user_id,
name_enc, activity_title) receives at most 20 unique users.
- Around line 1458-1465: The current code swallows any JSON parse error or
non-object body and treats it as an empty request; change the parsing so that an
empty request body is allowed but malformed JSON or a non-object JSON returns a
400. Read the raw text first (e.g., await req.text()), treat empty/whitespace
text as body = {}, otherwise attempt json.loads/await req.json() inside a
try/except and on exception return a 400 response; after parsing, if body is not
a dict return 400; then continue using body.get("message"), raw_msg and message
as before. Ensure the error path uses the same handler for POST
/api/peers/request/:id and preserves the existing message trimming logic.

---

Duplicate comments:
In `@public/dashboard.html`:
- Around line 68-88: The tab container lacks role="tablist" and the panels lack
role="tabpanel" and ARIA relationships; update the tab container div to include
role="tablist", add aria-controls on each button (tab-connections ->
peers-connections, tab-requests -> peers-requests, tab-find -> peers-find), and
add role="tabpanel" and aria-labelledby on each panel pointing back to its
button id; then update the showPeerTab(tabName) function to toggle aria-selected
(true/false), set tabindex=0 for the active button and -1 for others, and toggle
panel visibility via aria-hidden (false for active panel, true for others) in
addition to the existing CSS class changes so assistive tech receives correct
active-tab and active-panel state.

In `@schema.sql`:
- Around line 98-109: The peer_connections table allows both A→B and B→A
duplicates; modify the DDL to canonicalize the unordered pair and enforce
uniqueness on that canonical form by adding a generated/computed column (e.g.,
canonical_pair computed from requester_id and addressee_id with a deterministic
ordering like min/max or lexicographic concatenation) and replace
UNIQUE(requester_id, addressee_id) with UNIQUE(canonical_pair); also update the
identical DDL string in src/worker.py (the table-creation SQL around the
peer_connections creation) so the runtime schema matches the DB constraint.
🪄 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: Repository: alphaonelabs/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ed1d6aca-21de-4f29-92ce-1d60c4227164

📥 Commits

Reviewing files that changed from the base of the PR and between 584f2ff and 124ace8.

📒 Files selected for processing (3)
  • public/dashboard.html
  • schema.sql
  • src/worker.py

@ayesha1145 ayesha1145 force-pushed the feat/peer-connections branch from 124ace8 to b6c7e16 Compare March 29, 2026 03:42
@ayesha1145
Copy link
Copy Markdown
Contributor Author

Addressed latest CodeRabbit feedback:

  • Fixed major: deduplicated suggestions query — replaced DISTINCT with GROUP BY u.id, u.name and MIN(a.title) so each suggested user appears once with one representative activity, preventing duplicate cards and wasted LIMIT slots
  • Fixed minor: malformed JSON now returns 400 — distinguishes between empty body (allowed, falls back to {}), valid JSON object (parsed normally), non-object JSON (400), and malformed JSON (400); empty body without Content-Type still accepted for message-free requests

@ayesha1145
Copy link
Copy Markdown
Contributor Author

@A1L13N this PR is ready for review — all CodeRabbit conversations resolved ✅

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.

2 participants