# Research: Copy URL & Toast Notifications

## Decision 1: Toast Service Architecture

**Decision**: `BehaviorSubject<Toast | null>` singleton service, one active toast at a time — new toasts replace the current one.

**Rationale**: The simplest approach that satisfies FR-007 (reusable from anywhere) and FR-008 (multiple toasts don't overlap illegibly). A queue adds complexity with no meaningful UX benefit for this app's usage pattern (copy URL, upload confirm, etc. — actions that don't overlap in practice). Replacing the current toast on rapid successive calls is acceptable and visually cleaner than a stack. The `BehaviorSubject` integrates naturally with Angular's `async` pipe and OnPush change detection.

**Alternatives considered**:
- `Subject` (not `BehaviorSubject`): Late subscribers miss toasts that already fired. Rejected — component may subscribe after service emits if change detection is deferred.
- Toast queue (array): Adds observable complexity and UI layout decisions. Rejected — over-engineered for this use case.
- Angular CDK Overlay: Official but heavy. Pulls in CDK dependency for a feature that needs ~30 lines of code. Rejected per §2.6 (no speculative abstraction) and §6 (no new dependencies).

---

## Decision 2: Clipboard API Usage

**Decision**: `navigator.clipboard.writeText(url)` — no polyfill, no fallback to `document.execCommand`.

**Rationale**: `execCommand('copy')` is deprecated and removed in some browsers. The Clipboard API is supported in all modern browsers (Chrome 66+, Firefox 63+, Safari 13.1+). The app already requires HTTPS in production (Let's Encrypt via cert-manager), which satisfies the Clipboard API's secure context requirement. On failure (permission denied, API unavailable), catch the rejected Promise and show an error toast.

**Alternatives considered**:
- `execCommand('copy')` fallback: Deprecated, inconsistent, adds code complexity. The failure path (error toast) covers the rare unavailability case more cleanly.

---

## Decision 3: What URL to Copy

**Decision**: Copy `image.file_url` as-is (the direct image file URL).

**Rationale**: `file_url` is the CDN URL in production (e.g. `https://cdn.reactbin.juggalol.com/…`) — already absolute. In development it is relative (`/api/v1/images/{id}/file`); for dev use, prepend `window.location.origin`. The direct file URL is the right thing to share for a reaction image library: it embeds inline when pasted into Discord/Slack without requiring a click-through.

**Alternatives considered**:
- Detail page URL (`/images/{id}`): The user can already copy this from the browser address bar. The file URL is the value-add.
- Always prepend `window.location.origin`: Works for both environments, adds a guard. Included as a defensive measure for the dev case.

---

## Decision 4: Toast Positioning

**Decision**: Fixed position, bottom-center of the viewport.

**Rationale**: Bottom-center is less intrusive than top-right for a brief confirmation toast. It doesn't overlap the image or the copy button. `pointer-events: none` ensures it never blocks interaction.

**Alternatives considered**:
- Top-right: Common convention (Material, Bootstrap) but overlaps the header/nav area in this layout.
- Top-center: Similar issue.

---

## Decision 5: OnPush compatibility

**Decision**: `ToastComponent` uses `ChangeDetectionStrategy.OnPush` with the `async` pipe consuming `toastService.current$`. Angular's `async` pipe calls `markForCheck()` automatically when the observable emits, making it fully compatible with OnPush.

**Rationale**: Consistent with all other components in the project. No manual `markForCheck()` calls needed in `ToastComponent`.
