Skip to content

[frontend] change task URLs from /tasks/:id to /task/:slug/:number#38

Open
capcom6 wants to merge 1 commit into
masterfrom
frontend/task-slug-url
Open

[frontend] change task URLs from /tasks/:id to /task/:slug/:number#38
capcom6 wants to merge 1 commit into
masterfrom
frontend/task-slug-url

Conversation

@capcom6

@capcom6 capcom6 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor
  • Add backend endpoint GET /api/v1/tasks/by-project/:slug/:number
  • Update frontend routes: /task/:slug/:number and /task/:slug/:number/edit
  • Update all navigation calls to use project_slug + number
  • Replace onMount with for reactive data fetching on param change
  • Fix infinite loop in App.svelte by removing sync call from effect body
  • Use plain variable instead of for assigning mutex
  • Update parseProjectSlugFromPath to recognize new URL pattern
  • Add example request to requests.http

Summary by CodeRabbit

  • New Features
    • Added an authenticated “friendly URL” task lookup by project slug and sequential number (/tasks/{slug}/{number}), including edit support.
    • Introduced a redirect flow to send legacy task links to the canonical /task/{slug}/{number} route.
  • Bug Fixes
    • Updated all task navigation (dashboards, tables, project/task pages) to use /task/{slug}/{number} instead of legacy ID-based paths.
    • Improved task detail/edit pages to reliably load from URL-derived parameters and avoid stale state during navigation.
    • Enhanced recent-project tracking to recognize additional task-related URL/hash patterns.
  • Documentation
    • Added Swagger/OpenAPI docs and request examples for the new slug+number endpoint.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Task retrieval now supports project slug and sequential number identifiers. Frontend routes, navigation, task detail loading, editing, mutations, attachment handling, legacy redirects, and recent-project parsing use the canonical task URL.

Changes

Canonical task route migration

Layer / File(s) Summary
Backend task lookup endpoint
internal/server/tasks/handler.go, internal/server/docs/docs.go, requests.http
Adds an authenticated /tasks/:slug/:number handler, validates inputs, retrieves task details, documents the endpoint, and adds an HTTP request example.
Frontend canonical routes and navigation
frontend/src/App.svelte, frontend/src/lib/api/tasks.ts, frontend/src/lib/components/TaskTable.svelte, frontend/src/lib/pages/dashboard-*.svelte, frontend/src/lib/pages/project-tasks.svelte, frontend/src/lib/pages/task-new.svelte, frontend/src/lib/pages/task-redirect.svelte, frontend/src/lib/stores/recent-projects.svelte.ts
Defines slug-and-number task routes, adds the matching API helper, updates task links and redirects, preserves legacy task URLs through a redirect page, parses new paths for recent-project tracking, and updates task form prop wiring.
Task detail loading and mutations
frontend/src/lib/pages/task-detail.svelte
Loads tasks by slug and number, retains the internal task ID for mutations, updates attachment handling, and routes editing through the canonical URL.
Task edit loading and redirect
frontend/src/lib/pages/task-edit.svelte
Loads task and project data reactively from route parameters, guards against stale results, updates by internal task ID, and redirects using the updated task’s slug and number.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Frontend
  participant TaskAPI
  participant TaskService
  User->>Frontend: Open /task/{slug}/{number}
  Frontend->>TaskAPI: GET /tasks/{slug}/{number}
  TaskAPI->>TaskService: GetByProjectAndNumber(slug, number)
  TaskService-->>TaskAPI: Task details
  TaskAPI-->>Frontend: TaskDetailsResponse
  Frontend-->>User: Render task detail
Loading

Possibly related PRs

Suggested reviewers: dudina-ma

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: migrating task URLs from ID-based routes to slug-and-number routes.
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.

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.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

🤖 Pull request artifacts

Platform File
🐳 Docker GitHub Container Registry
🍎 Darwin arm64 backend_Darwin_arm64.tar.gz
🍎 Darwin x86_64 backend_Darwin_x86_64.tar.gz
🐧 Linux arm64 backend_Linux_arm64.tar.gz
🐧 Linux i386 backend_Linux_i386.tar.gz
🐧 Linux x86_64 backend_Linux_x86_64.tar.gz
🪟 Windows arm64 backend_Windows_arm64.zip
🪟 Windows i386 backend_Windows_i386.zip
🪟 Windows x86_64 backend_Windows_x86_64.zip

@capcom6

capcom6 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@capcom6

capcom6 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your plan includes PR reviews subject to rate limits. More reviews will be available in 35 minutes.

@capcom6

capcom6 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your plan includes PR reviews subject to rate limits. More reviews will be available in 58 minutes.

@capcom6
capcom6 force-pushed the frontend/task-slug-url branch from 38ca146 to 2ce88f3 Compare July 8, 2026 01:36
@capcom6
capcom6 requested a review from dudina-ma July 8, 2026 07:56
@capcom6 capcom6 added the ready PR is ready to merge label Jul 8, 2026
@capcom6
capcom6 force-pushed the frontend/task-slug-url branch from 2ce88f3 to 63d96f4 Compare July 9, 2026 00:59
@github-actions github-actions Bot removed the ready PR is ready to merge label Jul 9, 2026
@capcom6

capcom6 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your plan includes PR reviews subject to rate limits. More reviews will be available in 57 minutes.

@capcom6

capcom6 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@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

🧹 Nitpick comments (1)
frontend/src/lib/pages/task-new.svelte (1)

61-61: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Consider URL-encoding the project slug in the navigate call.

parseProjectSlugFromPath in recent-projects.svelte.ts uses decodeURIComponent on the slug, implying slugs may contain encoded characters. Using encodeURIComponent here ensures round-trip consistency.

♻️ Proposed refactor
-    navigate(`/task/${task.project_slug}/${task.number}`);
+    navigate(`/task/${encodeURIComponent(task.project_slug)}/${task.number}`);
🤖 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 `@frontend/src/lib/pages/task-new.svelte` at line 61, URL-encode the project
slug before constructing the task route in the navigation call. Update the
navigate call in the task creation flow to wrap task.project_slug with
encodeURIComponent, preserving compatibility with parseProjectSlugFromPath’s
decodeURIComponent handling.
🤖 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 `@internal/server/tasks/handler.go`:
- Around line 189-198: Remove the unreachable empty-slug validation from
getByProjectAndNumber, and after parsing the task number, reject values less
than 1 with a fiber.StatusBadRequest error matching the existing invalid-number
handling.

In `@requests.http`:
- Around line 251-255: Update the “Get task by project slug and number” example
request to use the registered two-segment route `/tasks/{slug}/{number}`; remove
the extra `by-project` segment so it targets `/tasks/my-new-project/1`,
consistent with the handler route and Swagger documentation.

---

Nitpick comments:
In `@frontend/src/lib/pages/task-new.svelte`:
- Line 61: URL-encode the project slug before constructing the task route in the
navigation call. Update the navigate call in the task creation flow to wrap
task.project_slug with encodeURIComponent, preserving compatibility with
parseProjectSlugFromPath’s decodeURIComponent handling.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 945a3c63-575b-49b1-9518-0a093d605d2f

📥 Commits

Reviewing files that changed from the base of the PR and between 8d80806 and 63d96f4.

📒 Files selected for processing (12)
  • frontend/src/App.svelte
  • frontend/src/lib/api/tasks.ts
  • frontend/src/lib/pages/dashboard-personal.svelte
  • frontend/src/lib/pages/dashboard-tasks.svelte
  • frontend/src/lib/pages/project-tasks.svelte
  • frontend/src/lib/pages/task-detail.svelte
  • frontend/src/lib/pages/task-edit.svelte
  • frontend/src/lib/pages/task-new.svelte
  • frontend/src/lib/stores/recent-projects.svelte.ts
  • internal/server/docs/docs.go
  • internal/server/tasks/handler.go
  • requests.http

Comment thread internal/server/tasks/handler.go
Comment thread requests.http
@coderabbitai coderabbitai Bot added the ready PR is ready to merge label Jul 10, 2026
@capcom6
capcom6 force-pushed the frontend/task-slug-url branch from 3bfe17d to 2bbd06e Compare July 14, 2026 01:21
@github-actions github-actions Bot removed the ready PR is ready to merge label Jul 14, 2026
@capcom6
capcom6 force-pushed the frontend/task-slug-url branch 2 times, most recently from 11d870a to 408e38c Compare July 18, 2026 01:32
@capcom6 capcom6 added the ready PR is ready to merge label Jul 18, 2026
- Add backend endpoint GET /api/v1/tasks/by-project/:slug/:number
- Update frontend routes: /task/:slug/:number and /task/:slug/:number/edit
- Update all navigation calls to use project_slug + number
- Replace onMount with  for reactive data fetching on param change
- Fix infinite  loop in App.svelte by removing sync call from effect body
- Use plain variable instead of  for assigning mutex
- Update parseProjectSlugFromPath to recognize new URL pattern
- Add example request to requests.http
@capcom6
capcom6 force-pushed the frontend/task-slug-url branch from 408e38c to f02a191 Compare July 21, 2026 00:04
@github-actions github-actions Bot removed the ready PR is ready to merge label Jul 21, 2026

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

🤖 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 `@frontend/src/lib/pages/task-redirect.svelte`:
- Around line 9-23: Update the $effect in task-redirect.svelte to track whether
the effect has been invalidated or the component unmounted, and return a cleanup
function that marks it inactive. Guard both the getTask(id) success handler
before calling navigate and the error handler before assigning error, so stale
requests cannot redirect or update state.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 50939855-7111-44fc-84dd-55a5fcb21f02

📥 Commits

Reviewing files that changed from the base of the PR and between 3bfe17d and f02a191.

📒 Files selected for processing (14)
  • frontend/src/App.svelte
  • frontend/src/lib/api/tasks.ts
  • frontend/src/lib/components/TaskTable.svelte
  • frontend/src/lib/pages/dashboard-personal.svelte
  • frontend/src/lib/pages/dashboard-tasks.svelte
  • frontend/src/lib/pages/project-tasks.svelte
  • frontend/src/lib/pages/task-detail.svelte
  • frontend/src/lib/pages/task-edit.svelte
  • frontend/src/lib/pages/task-new.svelte
  • frontend/src/lib/pages/task-redirect.svelte
  • frontend/src/lib/stores/recent-projects.svelte.ts
  • internal/server/docs/docs.go
  • internal/server/tasks/handler.go
  • requests.http
🚧 Files skipped from review as they are similar to previous changes (11)
  • frontend/src/lib/pages/project-tasks.svelte
  • requests.http
  • frontend/src/lib/pages/task-new.svelte
  • frontend/src/lib/pages/dashboard-tasks.svelte
  • frontend/src/lib/pages/dashboard-personal.svelte
  • frontend/src/lib/pages/task-edit.svelte
  • frontend/src/App.svelte
  • internal/server/tasks/handler.go
  • frontend/src/lib/stores/recent-projects.svelte.ts
  • internal/server/docs/docs.go
  • frontend/src/lib/pages/task-detail.svelte

Comment on lines +9 to +23
$effect(() => {
const id = Number(params.id);
if (!id) {
error = "Invalid task ID";
return;
}

getTask(id)
.then((task) => {
navigate(`/task/${task.project_slug}/${task.number}`);
})
.catch((e: any) => {
error = e.message || "Failed to load task";
});
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Prevent race conditions and state updates after unmount.

Since $effect tracks dependencies and re-runs when params.id changes, an older network request might resolve after a newer one, causing a redirection to the wrong task. Furthermore, if the component unmounts before the request completes, navigate will still be invoked and could interrupt the user's manual navigation.

Add a cleanup function to ignore the promise result if the effect is invalidated or unmounted.

🛡️ Proposed fix to add an effect cleanup flag
   $effect(() => {
+    let cancelled = false;
     const id = Number(params.id);
     if (!id) {
       error = "Invalid task ID";
       return;
     }
 
     getTask(id)
       .then((task) => {
-        navigate(`/task/${task.project_slug}/${task.number}`);
+        if (!cancelled) {
+          navigate(`/task/${task.project_slug}/${task.number}`);
+        }
       })
       .catch((e: any) => {
-        error = e.message || "Failed to load task";
+        if (!cancelled) {
+          error = e.message || "Failed to load task";
+        }
       });
+
+    return () => {
+      cancelled = true;
+    };
   });
📝 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
$effect(() => {
const id = Number(params.id);
if (!id) {
error = "Invalid task ID";
return;
}
getTask(id)
.then((task) => {
navigate(`/task/${task.project_slug}/${task.number}`);
})
.catch((e: any) => {
error = e.message || "Failed to load task";
});
});
$effect(() => {
let cancelled = false;
const id = Number(params.id);
if (!id) {
error = "Invalid task ID";
return;
}
getTask(id)
.then((task) => {
if (!cancelled) {
navigate(`/task/${task.project_slug}/${task.number}`);
}
})
.catch((e: any) => {
if (!cancelled) {
error = e.message || "Failed to load task";
}
});
return () => {
cancelled = true;
};
});
🤖 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 `@frontend/src/lib/pages/task-redirect.svelte` around lines 9 - 23, Update the
$effect in task-redirect.svelte to track whether the effect has been invalidated
or the component unmounted, and return a cleanup function that marks it
inactive. Guard both the getTask(id) success handler before calling navigate and
the error handler before assigning error, so stale requests cannot redirect or
update state.

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