
## Overview

Applications can define **opt-ins** (consent items) that users can **accept** or **decline**.

- **Required opt-ins**: must be accepted to register / continue using the app.
- **Optional opt-ins**: can be accepted or declined. Users can revisit and change their decision later.

Opt-ins are configured on the **Application** and support i18n via `title` and `description` objects.

## Data model

Each opt-in has:

- `id`: string identifier (stable)
- `title`: i18n object (e.g. `{ en: "...", de: "..." }`)
- `description`: i18n object
- `required`: boolean
- `active`: boolean (inactive opt-ins are hidden)

User state is tracked with:

- `optInDecisions[]`: all opt-in decisions, each with `{ optInId, status: "accepted" | "declined", decidedAt }`

## Enforcement

### Registration

During registration, the UI shows the active opt-ins and blocks submission until all **required** opt-ins are accepted. The server validates required acceptance as well.

### Catch-up redirect

If a user is signed in and a **new required** opt-in is added later, the user is redirected to `/opt-ins` until they accept it.

## Optional opt-ins reminder

When there are **new / undecided active optional opt-ins**, the app shows a small reminder banner **once per session** (sessionStorage) to invite the user to review them.

- **Review** navigates to `/opt-ins`.
- **Dismiss** hides the banner for the current session.

## User-facing page

Users can always visit `/opt-ins` to review all active opt-ins and see their current status and decision dates.
