Skip to content

Mvp/issue49#50

Merged
aki91-g merged 4 commits intomainfrom
mvp/issue49
Mar 10, 2026
Merged

Mvp/issue49#50
aki91-g merged 4 commits intomainfrom
mvp/issue49

Conversation

@aki91-g
Copy link
Copy Markdown
Owner

@aki91-g aki91-g commented Mar 10, 2026

Summary by CodeRabbit

  • Refactor

    • Simplified server configuration; server now binds to all interfaces with dynamic port (default 10000) and updated startup logging.
    • Frontend item-creation API changed to accept a single payload object (parameter signature updated).
  • New Features

    • Added interactive scatter-plot visualization with responsive canvas and hover tooltips.
    • New graph utility and types powering the visualization.
    • Dashboard UI updated to include the scatter plot, richer item description input, and debug seed/fetch controls.
  • Chores

    • Removed hardcoded localhost fallback for the frontend API base URL.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 10, 2026

Warning

Rate limit exceeded

@aki91-g has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 9 minutes and 56 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ee5ba2c9-47d1-4b2b-b7d5-48be7a78092e

📥 Commits

Reviewing files that changed from the base of the PR and between b6d06e0 and 0d23d67.

📒 Files selected for processing (3)
  • apps/frontend/src/components/ScatterPlot.vue
  • apps/frontend/src/composables/useGraph.ts
  • apps/frontend/src/views/MainDashboard.vue
📝 Walkthrough

Walkthrough

Adds a canvas-based ScatterPlot UI with a new graph composable and types, updates item creation to use a payload object, removes a localhost fallback in the Hono client, and simplifies backend env loading while binding the server to 0.0.0.0 with a dynamic port.

Changes

Cohort / File(s) Summary
Server config
apps/backend/src/index.ts
Removed dotenv/path usage; use process.env.PORT (default 10000); pass port: Number(port) and hostname: '0.0.0.0' to server; updated startup log.
Frontend: graph feature
apps/frontend/src/components/ScatterPlot.vue, apps/frontend/src/composables/useGraph.ts, apps/frontend/src/types/graph.ts
Added ScatterPlot component, new useGraph composable, and Graph types. Implements DPR-aware canvas rendering, ResizeObserver, data mapping, grid and point drawing, and hover tooltip handling.
Frontend: item API & usage
apps/frontend/src/composables/useItems.ts, apps/frontend/src/views/MainDashboard.vue
Changed createItem to accept a single payload object; updated MainDashboard to include description field, call new payload API, reset fields after create, add debug seed/fetch helpers, and embed the ScatterPlot component.
Frontend: client config
apps/frontend/src/api/honoClient.ts
Removed hardcoded localhost fallback for baseUrl; constructor now relies solely on provided arg or import.meta.env.VITE_HONO_BASE_URL.
Frontend: minor
apps/frontend/src/App.vue
Whitespace/formatting-only edits (no functional changes).
sequenceDiagram
participant Main as MainDashboard
participant Scatter as ScatterPlot
participant Graph as useGraph
participant Canvas as HTMLCanvasElement

Main->>Scatter: pass items prop
Scatter->>Graph: init with canvasRef + config
Graph->>Canvas: measure DPR & size (on mount / resize)
Main->>Scatter: items change (watch)
Scatter->>Graph: updateData(rawItems)
Graph->>Graph: compute min/max time, map to GraphItem[]
Graph->>Canvas: draw() -> clear, drawGrid, drawPoints
Canvas-->>Scatter: mousemove events
Scatter->>Graph: hit-test -> find hovered item
Scatter->>Main: emit/select hovered item (show tooltip)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • feat: hono api #40 — Also modifies apps/backend/src/index.ts around dotenv and server binding; likely overlapping server env/host changes.
  • feat: repo for hono/rust #38 — Related to apps/frontend/src/api/honoClient.ts baseUrl handling; touches the same client fallback logic.

Poem

🐰 In my burrow I code and plot,

dots hop on canvas, a sprightly lot.
Payloads bundled, ports set free,
Host widened wide, come stare with me.
Hooray — a scatter and smoother tree! 🥕✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Mvp/issue49' is vague and generic, using a branch name format that does not clearly convey the actual changes made in the pull request. Replace the title with a clear, descriptive summary of the main changes, such as 'Add ScatterPlot visualization component and refactor item creation API' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mvp/issue49

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
Contributor

@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: 1

🧹 Nitpick comments (1)
apps/backend/src/index.ts (1)

9-9: Port type handling is acceptable but consider explicit parsing.

The current implementation works correctly since Number(port) handles both string and number types. However, if PORT is set to an empty string or non-numeric value, this will result in NaN being passed to serve.

🔧 Optional: More defensive port parsing
-const port = process.env.PORT || 10000;
+const port = parseInt(process.env.PORT || '', 10) || 10000;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/backend/src/index.ts` at line 9, The current top-level const port =
process.env.PORT || 10000 can yield NaN if PORT is an empty or non-numeric
string; update the parsing to defensively convert process.env.PORT to an integer
and fall back to 10000 when the result is NaN. Specifically, read
process.env.PORT (the PORT env var), parse it with Number.parseInt(..., 10) or
Number(...), check Number.isNaN(...) and set the exported/used port variable
(the const port) to 10000 when parsing fails so any downstream call that
consumes port (e.g., serve(...) or app.listen) always receives a valid numeric
port.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/backend/src/index.ts`:
- Around line 488-494: Frontend fallback base URL mismatches backend default
port 10000 causing failed local connections; update the frontend fallback in the
Hono client (look for the class/constructor that sets this.baseUrl in
apps/frontend/src/api/honoClient.ts) to use 'https://localhost:10000' when
VITE_HONO_BASE_URL is absent, and also update the port references in
apps/backend/README.md to mention port 10000 so docs match the backend's default
(the backend server is started via serve({... port: Number(port) ...}) which
defaults to 10000).

---

Nitpick comments:
In `@apps/backend/src/index.ts`:
- Line 9: The current top-level const port = process.env.PORT || 10000 can yield
NaN if PORT is an empty or non-numeric string; update the parsing to defensively
convert process.env.PORT to an integer and fall back to 10000 when the result is
NaN. Specifically, read process.env.PORT (the PORT env var), parse it with
Number.parseInt(..., 10) or Number(...), check Number.isNaN(...) and set the
exported/used port variable (the const port) to 10000 when parsing fails so any
downstream call that consumes port (e.g., serve(...) or app.listen) always
receives a valid numeric port.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b1ba9ab3-6282-4624-8622-52b5049762a4

📥 Commits

Reviewing files that changed from the base of the PR and between e6bb414 and 4218be5.

📒 Files selected for processing (1)
  • apps/backend/src/index.ts

Copy link
Copy Markdown
Contributor

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/frontend/src/composables/useItems.ts (1)

181-188: ⚠️ Potential issue | 🟠 Major

Don’t turn a successful create into a failed promise just because the refresh failed.

itemRepository.createItem() has already committed the write before fetchActiveItems() runs. If the refresh errors, this rejects the whole call and the UI will likely encourage a retry, which can create duplicate tasks.

Suggested fix
   async function createItem(payload: {
     title: string,
     description: string | null,
     motivation: number | null,
     due: string,
     durationMinutes?: number | null
   }): Promise<string> {
     error.value = null;
-  try {
-    const id = await itemRepository.createItem(payload);
-    await fetchActiveItems();
-    return id;
+    try {
+      const id = await itemRepository.createItem(payload);
+      try {
+        await fetchActiveItems();
+      } catch (refreshErr) {
+        console.error('Item created, but refresh failed:', refreshErr);
+      }
+      return id;
     } catch (err) {
       error.value = String(err);
       console.error('Failed to create item:', err);
       throw err;
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/composables/useItems.ts` around lines 181 - 188, The
current catch wraps both createItem and fetchActiveItems so a refresh failure
turns a successful create into an error; change the flow in useItems.ts so you
await itemRepository.createItem(payload) first, then call fetchActiveItems()
inside its own try/catch (do not rethrow on refresh failure), log or set
error.value for the refresh error (e.g., "Failed to refresh items after create")
but always return the created id from createItem; keep createItem,
fetchActiveItems and error.value references to locate the code.
🧹 Nitpick comments (2)
apps/frontend/src/components/ScatterPlot.vue (1)

24-26: Drop the duplicate props.items watcher.

Both watchers observe the same source with deep: true and immediate: true, so every change now recomputes and redraws twice. Keeping one watcher is enough here.

Also applies to: 83-86

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

In `@apps/frontend/src/components/ScatterPlot.vue` around lines 24 - 26, There are
two identical watchers observing props.items that both call updateData and use {
deep: true, immediate: true }, causing duplicate recomputation; remove the
duplicate watcher (keep only one watch(() => props.items, (newItems) =>
updateData(newItems), { deep: true, immediate: true })) and delete the other
watcher block (the second occurrence around the update/redraw logic) so changes
to props.items trigger a single update via updateData.
apps/frontend/src/composables/useItems.ts (1)

173-179: Use a shared CreateItemPayload type instead of redeclaring it here.

This payload shape is now duplicated across the composable and API layers, and it has already drifted on description support/optionality. Pulling it into one shared type will make the next field change much safer.

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

In `@apps/frontend/src/composables/useItems.ts` around lines 173 - 179, Replace
the inline payload type declared in createItem with the shared CreateItemPayload
type: import the shared type and change the signature from async function
createItem(payload: { ... }) to async function createItem(payload:
CreateItemPayload): Promise<string>; ensure the imported CreateItemPayload's
field nullability/optionality (e.g., description, durationMinutes) is used
rather than the local declaration and update any local usages inside createItem
to match the shared shape.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/frontend/src/api/honoClient.ts`:
- Around line 26-28: The constructor for HonoClient currently assigns
this.baseUrl to baseUrl || import.meta.env.VITE_HONO_BASE_URL and can end up
undefined; change the constructor in the HonoClient class to validate and
normalize the base URL: read baseUrl || import.meta.env.VITE_HONO_BASE_URL into
a local variable, throw a clear Error if it's missing/empty, and normalize it
(e.g., ensure no trailing slash or ensure consistent scheme) before assigning to
this.baseUrl so downstream URL builds (like in request methods) never see
undefined.

In `@apps/frontend/src/components/ScatterPlot.vue`:
- Around line 31-52: updateCanvasSize currently only calls draw() after changing
canvas dimensions so point positions computed in updateData() (which depend on
canvas size) remain stale; modify updateCanvasSize to call updateData() after
resizing (and then draw()) so coordinates are recomputed using the new canvas
dimensions; locate updateCanvasSize, updateData, draw, canvasRef and
containerRef in ScatterPlot.vue and ensure the sequence is resize ->
updateData() -> draw() so mounted renders and later resizes use correct
positions.

In `@apps/frontend/src/composables/useGraph.ts`:
- Around line 37-41: The plotting uses m as a 0–100 percentage but the form
produces 1–10 values; update the mapping inside the graphItems.value assignment
where m is computed (currently const m = item.motivation ??
config.defaultMotivation) to normalize the 1–10 scale to 0–100 before computing
y (e.g., convert motivation * 10 or ((motivation - 1) / 9) * 100 depending on
desired mapping), so y uses a percent-compatible m for correct vertical
positioning.

In `@apps/frontend/src/views/MainDashboard.vue`:
- Around line 153-175: The debug helper functions testCreate and testFetch
(which call createItem, fetchActiveItems and getCurrentToken and log
items.value) are exposed in the production UI; wrap their definitions and any UI
elements that call them in a runtime DEV guard (if (import.meta.env.DEV) { ...
}) or remove them entirely so they are not registered/printed in production
builds; ensure any buttons or bindings for these helpers (also referenced around
the code block that includes the other debug actions) are similarly gated so
they cannot be invoked outside development.
- Around line 223-231: The description input is using the same id/label as the
title, causing the second label to target the title; change the description
input's id from "item-title" to a unique id like "item-description" and update
its corresponding <label for="..."> to match, ensure the v-model
(newItemDescription) remains attached to that input, and consider adding an
appropriate placeholder and autocomplete attribute (e.g., autocomplete="off" or
"description") to aid accessibility and browser autofill.

---

Outside diff comments:
In `@apps/frontend/src/composables/useItems.ts`:
- Around line 181-188: The current catch wraps both createItem and
fetchActiveItems so a refresh failure turns a successful create into an error;
change the flow in useItems.ts so you await itemRepository.createItem(payload)
first, then call fetchActiveItems() inside its own try/catch (do not rethrow on
refresh failure), log or set error.value for the refresh error (e.g., "Failed to
refresh items after create") but always return the created id from createItem;
keep createItem, fetchActiveItems and error.value references to locate the code.

---

Nitpick comments:
In `@apps/frontend/src/components/ScatterPlot.vue`:
- Around line 24-26: There are two identical watchers observing props.items that
both call updateData and use { deep: true, immediate: true }, causing duplicate
recomputation; remove the duplicate watcher (keep only one watch(() =>
props.items, (newItems) => updateData(newItems), { deep: true, immediate: true
})) and delete the other watcher block (the second occurrence around the
update/redraw logic) so changes to props.items trigger a single update via
updateData.

In `@apps/frontend/src/composables/useItems.ts`:
- Around line 173-179: Replace the inline payload type declared in createItem
with the shared CreateItemPayload type: import the shared type and change the
signature from async function createItem(payload: { ... }) to async function
createItem(payload: CreateItemPayload): Promise<string>; ensure the imported
CreateItemPayload's field nullability/optionality (e.g., description,
durationMinutes) is used rather than the local declaration and update any local
usages inside createItem to match the shared shape.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bc2c37ad-b8dd-4a54-ad4b-c46f8e14affa

📥 Commits

Reviewing files that changed from the base of the PR and between 4218be5 and b6d06e0.

📒 Files selected for processing (7)
  • apps/frontend/src/App.vue
  • apps/frontend/src/api/honoClient.ts
  • apps/frontend/src/components/ScatterPlot.vue
  • apps/frontend/src/composables/useGraph.ts
  • apps/frontend/src/composables/useItems.ts
  • apps/frontend/src/types/graph.ts
  • apps/frontend/src/views/MainDashboard.vue
✅ Files skipped from review due to trivial changes (1)
  • apps/frontend/src/App.vue

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@aki91-g aki91-g merged commit b52484a into main Mar 10, 2026
3 checks passed
@aki91-g aki91-g deleted the mvp/issue49 branch March 10, 2026 11:39
@aki91-g aki91-g restored the mvp/issue49 branch March 10, 2026 13:06
This was referenced Mar 10, 2026
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