Detail page now has a "Copy URL" button that copies the image's direct file URL to the clipboard. A toast service (BehaviorSubject-backed, auto-dismissing after 3s) confirms success or failure. ToastComponent is registered at the app root and available to all future features. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3.6 KiB
Implementation Plan: Copy URL & Toast Notifications
Branch: 016-copy-url-toast | Date: 2026-05-09 | Spec: spec.md
Input: Feature specification from specs/016-copy-url-toast/spec.md
Summary
Add a "Copy URL" button to the image detail page that copies the image's direct file URL to the clipboard, with a reusable toast notification service wired to confirm success or failure. All changes are UI-only; no API changes are required.
Technical Context
Language/Version: TypeScript (strict mode), Angular latest stable
Primary Dependencies: Angular (@angular/core, @angular/common), RxJS (BehaviorSubject), browser Clipboard API (navigator.clipboard.writeText)
Storage: N/A
Testing: Karma/Jasmine (ng test)
Target Platform: Browser (modern; Clipboard API requires HTTPS — already in place)
Project Type: Angular standalone SPA
Performance Goals: Copy action completes in < 100ms perceived latency; toast appears within 300ms of action
Constraints: TypeScript strict mode, ChangeDetectionStrategy.OnPush on all components, no new npm dependencies
Scale/Scope: Two new files (service + component), two modified files (detail + app component)
Constitution Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
| Principle | Status | Notes |
|---|---|---|
| §2.1 Strict separation of concerns | ✓ PASS | Pure UI change; no API knowledge in UI beyond what's already in ImageRecord.file_url |
| §2.6 No speculative abstraction | ✓ PASS | Toast service is justified: used immediately by this feature and explicitly planned for reuse (upload confirmation, delete confirmation, filter feedback). Two concrete use cases exist. |
| §5.1 Tests alongside implementation | ✓ PASS | Tests required for ToastService and the copy button on DetailComponent |
| §5.2 Test pyramid | ✓ PASS | Unit tests only (no API/DB involved); Karma/Jasmine |
| §6 Tech stack | ✓ PASS | Angular, TypeScript strict — no new dependencies |
| §7.3 Linting | ✓ PASS | ng lint must pass before task is done |
| §8 Scope boundaries | ✓ PASS | No multi-user, no embeds, no public sharing infrastructure — just a clipboard copy |
Post-design re-check: No violations. Feature is entirely additive.
Project Structure
Documentation (this feature)
specs/016-copy-url-toast/
├── plan.md ← this file
├── research.md ← Phase 0 output
├── quickstart.md ← Phase 1 output
├── contracts/
│ └── toast-service.md ← Phase 1 output
└── tasks.md ← /speckit-tasks output
Source Code
ui/src/app/
├── app.component.ts ← modified: add <app-toast> to template
├── services/
│ └── toast.service.ts ← new: singleton toast service
├── toast/
│ └── toast.component.ts ← new: toast display component
└── detail/
└── detail.component.ts ← modified: add Copy URL button + inject ToastService
ui/src/app/services/
toast.service.spec.ts ← new: unit tests for ToastService
ui/src/app/toast/
toast.component.spec.ts ← new: unit tests for ToastComponent
ui/src/app/detail/
detail.component.spec.ts ← modified: tests for copy button behaviour
Structure Decision: Single-project Angular SPA. Toast service lives in services/ alongside ImageService and TagService. Toast component gets its own toast/ directory following the existing component-per-directory convention.