Parent PRD
#1
What to build
Wire the admin dashboard and client tracking page to the GitHub sync backend (shipped in #8). Adds the UI layer for repo selection, pushing tasks as GitHub issues, displaying issue links, and reflecting issue status on the client tracking page.
Repo picker (admin): In the admin project view, when a project is in review or active status, show a dropdown of available GitHub repos (fetched via GET /github/repos). Selecting a repo calls PUT /projects/:slug/github-repo and persists. The current selection is shown when the project already has githubRepo set.
Push to GitHub (admin): A single "Push to GitHub" button triggers POST /github/projects/:slug/push. Disabled when no repo selected, no tasks exist, or all tasks already have GitHub issues. While pushing: button shows progress state; on success: refresh task list. Errors surface as inline alert.
GitHub issue links (admin): For each task with a githubIssueNumber, render an external link icon next to the task title that opens githubIssueUrl in a new tab.
Client polling (public): On the client tracking page (/p/:slug), when the project has active or complete status and at least one task has a githubIssueNumber, call POST /github/projects/:slug/sync once on mount. The mutation result refreshes the cached client-view so task statuses (done/pending) reflect the latest GitHub state.
Acceptance criteria
Blocked by
None — backend (#8) shipped in commit cfc6f49.
User stories addressed
- User story 13
- User story 14
- User story 15
TDD slice plan (suggested)
- API client functions (
lib/github-api-client.ts): listAvailableRepos, setProjectGithubRepo, pushTasksToGithub, syncGithubIssueStatus — mock fetch only at boundary.
- Repo picker component (admin): dropdown bound to query + mutation; tests mock the API client functions.
- Push button + state: tests cover disabled states, loading state, success cache invalidation, error alert.
- Issue link rendering (task list): test that link only appears when
githubIssueNumber !== null and href equals githubIssueUrl.
- Client polling: test that sync mutation fires once on mount only when conditions met, and updates cached
client-view on success.
Backend endpoints (already shipped — issue #8)
| Method |
Path |
Auth |
Purpose |
| GET |
/github/repos |
admin |
List available repos for dropdown |
| PUT |
/projects/:slug/github-repo |
admin |
Persist selected repo |
| POST |
/github/projects/:slug/push |
admin |
Create issues for unsynced tasks |
| POST |
/github/projects/:slug/sync |
public |
Refresh task statuses from GitHub |
Notes
GITHUB_TOKEN must be set as a Cloudflare Worker secret on staging/production before this UI can work end-to-end (delegate to DevOps).
- Polling is one-shot on mount, not interval-based — interval/cron polling is a follow-up consideration.
- Existing admin project view:
apps/user-application/src/routes/_auth/app/projects/$slug.tsx
- Existing client view:
apps/user-application/src/routes/p/$slug.tsx and components/spec/spec-tracking-view.tsx
Parent PRD
#1
What to build
Wire the admin dashboard and client tracking page to the GitHub sync backend (shipped in #8). Adds the UI layer for repo selection, pushing tasks as GitHub issues, displaying issue links, and reflecting issue status on the client tracking page.
Repo picker (admin): In the admin project view, when a project is in
revieworactivestatus, show a dropdown of available GitHub repos (fetched viaGET /github/repos). Selecting a repo callsPUT /projects/:slug/github-repoand persists. The current selection is shown when the project already hasgithubReposet.Push to GitHub (admin): A single "Push to GitHub" button triggers
POST /github/projects/:slug/push. Disabled when no repo selected, no tasks exist, or all tasks already have GitHub issues. While pushing: button shows progress state; on success: refresh task list. Errors surface as inline alert.GitHub issue links (admin): For each task with a
githubIssueNumber, render an external link icon next to the task title that opensgithubIssueUrlin a new tab.Client polling (public): On the client tracking page (
/p/:slug), when the project hasactiveorcompletestatus and at least one task has agithubIssueNumber, callPOST /github/projects/:slug/synconce on mount. The mutation result refreshes the cachedclient-viewso task statuses (done/pending) reflect the latest GitHub state.Acceptance criteria
GET /github/reposPUT /projects/:slug/github-repoand shows the saved value on reloadgithubIssueUrl, opens in new tab)/p/:slug) calls sync API once on mount when project isactive/completewith linked issuesi18n/messages/{en,pl}.jsontext-white,bg-gray-*, etc.)Blocked by
None — backend (#8) shipped in commit
cfc6f49.User stories addressed
TDD slice plan (suggested)
lib/github-api-client.ts):listAvailableRepos,setProjectGithubRepo,pushTasksToGithub,syncGithubIssueStatus— mock fetch only at boundary.githubIssueNumber !== nulland href equalsgithubIssueUrl.client-viewon success.Backend endpoints (already shipped — issue #8)
/github/repos/projects/:slug/github-repo/github/projects/:slug/push/github/projects/:slug/syncNotes
GITHUB_TOKENmust be set as a Cloudflare Worker secret on staging/production before this UI can work end-to-end (delegate to DevOps).apps/user-application/src/routes/_auth/app/projects/$slug.tsxapps/user-application/src/routes/p/$slug.tsxandcomponents/spec/spec-tracking-view.tsx