# DeleteNotificationSubscription

## Permission Scope

subscriptionSelf

## Overview

deleteNotificationSubscription is the idempotent self-service `unsubscribe` counterpart to `createNotificationSubscription`. It hard-deletes the NotificationSubscription row identified by `(userId, sourceType, sourceId)`. When no row exists, the command returns success without modifying state — repeat clicks, retries, or unsubscribe from a never-subscribed source are no-ops. The caller must be the target user. There is no soft-delete: a subsequent re-subscribe creates a new row with a fresh `subscribedAt` timestamp.

## Business Rules

- `userId`, `sourceType`, `sourceId` are required
- The caller must be the target user (`ctx.actorId == userId`)
- Tenant isolation is enforced by the platform's company-scoped data access, not an explicit module check: the `NotificationSubscription` row carries no `companyId` and `User` lives in another module, so a cross-tenant subscription is simply not visible to the company-scoped query and resolves as the idempotent no-op below
- Idempotent: returns success when no matching row exists, with zero rows deleted
- Hard delete; no soft-delete or tombstone

## Process Flow

```mermaid
flowchart TD
    A[Receive unsubscribe request] --> B{Caller is target user?}
    B -->|No| C[Return FORBIDDEN]
    B -->|Yes| E{Existing NotificationSubscription for userId, sourceType, sourceId?}
    E -->|No| F[Return success, idempotent no-op]
    E -->|Yes| G[Hard-delete the row]
    G --> H[Return success]
```

## External Dependencies

- None - authorization is resolved from the caller context alone

## Error Scenarios

- **FORBIDDEN**: Caller is not authorized to perform this operation in the target scope

## Test Cases

- deletes the NotificationSubscription row when one exists for the supplied triple
- returns success without deleting anything when no matching row exists (idempotent)
- returns FORBIDDEN when the caller is not the target user
- a subsequent re-subscribe after delete creates a new row with a fresh subscribedAt timestamp
- deleting one user's subscription does not affect another user's subscription on the same source
