Files

72 lines
5.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 13 — Frontend (Vue 3 SPA)
Vue 3 + TypeScript + Vite + Pinia + Vue Router + Tailwind, pnpm, in `web/`. Styling authority is [14-design-system.md](14-design-system.md). All API access through one typed client; all live updates through one SSE module.
## Structure
- [ ] `web/src/api/client.ts` — typed fetch wrapper (base `/api/v1`, JSON, error envelope → typed `ApiError`, cookie credentials)
- [ ] `web/src/api/sse.ts` — EventSource wrapper: connect after login, auto-reconnect with backoff, dispatch frames to the `realtime` store, expose `onReconnect` hooks (pages refetch)
- [ ] `web/src/router/index.ts` — routes below; global guard redirects unauthenticated → `/login` (bootstraps via `GET /me`)
- [ ] Layout: `AppShell` (fixed sidebar + navbar + `<router-view>`), auth pages bare
- [ ] Vite dev proxy: `/api`, `/files`, `/webhooks` → Go server port
## Routes & pages
- [ ] `/login` — email/password + OAuth buttons (hidden per config)
- [ ] `/register` — sign-up (notes that first user becomes admin)
- [ ] `/oauth/callback` — post-OAuth landing, bootstraps session, redirects
- [ ] `/`**Dashboard**: favorite + recent projects, "assigned to me" issue list, cross-project activity feed
- [ ] `/inbox` — notification inbox (unread filter, mark read/all)
- [ ] `/search` — full search page (type tabs)
- [ ] `/projects` — project cards (favorites first, status/priority badges, favorite toggle)
- [ ] `/projects/:id`**Project overview**: description (markdown), members, links, attachments, dependencies (both directions), activity feed
- [ ] `/projects/:id/issues`**Issue table**: sortable columns, FilterBar, URL-synced filters/sort, row click → detail
- [ ] `/projects/:id/board`**Kanban**: 7 fixed status columns, drag-and-drop (optimistic), card = `#N`, title, labels, assignee avatar, points badge, blocked indicator, epic color strip
- [ ] `/projects/:id/issues/:num`**Issue detail**: editable title/description, sidebar (status, priority, points, assignee, epic, dates, labels, watchers, watch toggle), sub-issues list (+create), blockers list, attachments, links, activity feed comments with resolve, MarkdownEditor for comments
- [ ] `/projects/:id/epics` — epic list with progress bars (counts + points), status filter
- [ ] `/projects/:id/epics/:epicId` — epic detail: description, status, color, ordered issue list (drag to reorder, attach existing / create new)
- [ ] `/projects/:id/wiki` — page list; `/projects/:id/wiki/:slug` — view; `/projects/:id/wiki/:slug/edit` + `/projects/:id/wiki/new` — edit/create with preview
- [ ] `/projects/:id/settings` — tabs: general (fields, status, git URL, transfer, delete) | members | labels | webhooks (incoming secret, outgoing CRUD + delivery log) | export | danger zone — owner-gated tabs hidden for members
- [ ] `/settings` — tabs: profile | security (password) | tokens (PAT create/reveal-once/revoke) | notifications (email_mode)
- [ ] `/admin/users` — admin only: user list, admin toggle, delete
- [ ] 404 page; project-scope 404s render "not found or no access"
## Pinia stores
- [ ] `auth` — me, bootstrap, login/logout, guards
- [ ] `projects` — list + current project (members, labels, dependencies)
- [ ] `issues` — table query state (filters/sort/page, URL-synced), detail cache
- [ ] `board` — per-status ordered lists, optimistic move (rank computed client-side between neighbors, PATCH sent, rollback on error)
- [ ] `epics` — list + detail + ordering
- [ ] `comments` — per-issue comments + resolve state
- [ ] `wiki` — page list + current page
- [ ] `notifications` — unread count, inbox, mark-read
- [ ] `realtime` — SSE connection state; routes `data` frames: if the pointed-at resource is in an active store (current board/table/detail/feed), patch or refetch it; `notification` frames → `notifications` store + toast
- [ ] `search` — palette state, recents (localStorage)
- [ ] `ui` — toasts, modals, sidebar collapse
## Shared components
- [ ] `KanbanBoard` / `KanbanColumn` / `IssueCard` — drag via vuedraggable or a small pointer-events implementation; column headers show count
- [ ] `IssueTable` + `FilterBar` (status/assignee/label/priority/epic pickers + text search) + `SortHeader`
- [ ] `MarkdownEditor` — textarea + write/preview tabs, `@` mention autocomplete (project members), `#` issue autocomplete, paste/drop image → attachment upload
- [ ] `MarkdownView` — markdown-it + DOMPurify, mention chips, `#N` router-links, code highlight
- [ ] `ActivityFeed` — renders audit entries (icon + actor + verb + target + relative time)
- [ ] `NotificationBell` — unread badge, dropdown of latest 10, link to `/inbox`
- [ ] `CommandPalette` — Cmd/Ctrl+K overlay ([10-search.md](10-search.md))
- [ ] Badges/pills: `StatusBadge` (per-status colors), `PriorityBadge`, `PointsBadge`, `LabelPill` (label color), `EpicPill` (epic color)
- [ ] `UserAvatar` (initials fallback) + `AssigneePicker` + `MemberPicker`
- [ ] `EpicProgressBar` (counts + points tooltip)
- [ ] `WatchButton`, `FavoriteStar`
- [ ] `AttachmentUploader` (drag-drop zone) + `AttachmentList` (image preview, download, delete)
- [ ] `DatePicker`, `ConfirmDialog`, `ToastHost`, `EmptyState` (illustrated, per design system)
## Behaviors
- [ ] Optimistic updates for board drags and inline status/assignee edits; rollback + toast on API error
- [ ] URL is the source of truth for table filters/sort (shareable, refresh-safe)
- [ ] SSE reconnect → refetch active page data + unread count ([09-notifications-realtime.md](09-notifications-realtime.md))
- [ ] Keyboard: Cmd/Ctrl+K palette; `c` new issue on board/table pages; Esc closes modals
- [ ] Every list has loading skeletons + designed empty states; destructive actions use `ConfirmDialog`
- [ ] Route titles set per page (`SoloPM — {project} — {page}`)