> ## Documentation Index
> Fetch the complete documentation index at: https://woku.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Quarantines

> Anti-duplicate rules that limit how many times a respondent can submit the same form within a time window

<Info>
  **Available on the Corporate plan.** This functionality is part of woku's enterprise capabilities. [Talk to our sales team](https://woku.app/pricing).
</Info>

A **quarantine** is a per-company rule that limits how many
responses the same respondent (identified by email or phone) can
submit within a sliding time window. When the limit is
exceeded, the API responds with `429` and the form's public screen
shows a specific message, without revealing the rule.

Typical uses:

* Anti-spam: block the same email trying to leave several reviews
  in a row to inflate a rating.
* Light anti-fraud: limit 1 response per employee per month per
  program.
* Data quality: prevent the same customer from submitting the same
  form twice by mistake.

## Model

Each quarantine belongs to a company and defines:

| Field                       | Type                                            | Description                                                                                   |
| --------------------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `name`                      | string                                          | Name shown in the panel.                                                                      |
| `description`               | optional string                                 | What the rule is for.                                                                         |
| `respondentIdentifier`      | `'email' \| 'phone'`                            | Which submission field identifies the respondent.                                             |
| `windowDurationMin`         | number                                          | Window in minutes within which previous submissions are counted.                              |
| `maxResponsesPerRespondent` | number                                          | Number allowed before blocking.                                                               |
| `enabled`                   | boolean                                         | Whether it is active.                                                                         |
| `priority`                  | number                                          | Evaluation order. A lower value evaluates first; the first rule that blocks stops evaluation. |
| `metrics`                   | `{ totalBlocked, totalAllowed, lastBlockedAt }` | Live counters, with no extra aggregations.                                                    |

Email identification is done against the **SHA-256 hash** of the
email, never against the plaintext email: the evaluator does not
decrypt data on the critical path.

## Enable a quarantine

1. Go to **Quarantines** in the side menu.
2. Click **New quarantine**.
3. Fill in the name, identifier, window in minutes and limit.
4. Save.

> The backend requires a name, an identifier, a window ≥ 1 and a limit ≥ 1.

## How it is evaluated

For each incoming form submission:

1. The evaluator loads the company's active quarantines,
   ordered by `priority` ASC.

2. For each rule, it computes the respondent value (normalized and
   hashed email, or phone as-is), counts previous submissions
   with the same identifier within the window, and
   compares against `maxResponsesPerRespondent`.

3. If a rule blocks, evaluation stops and the backend throws
   `HTTP 429` with the following body:

   ```json theme={null}
   {
     "code": "QUARANTINE_BLOCKED",
     "quarantineId": "65f...",
     "remainingMinutes": 45
   }
   ```

4. If no rule blocks, the `totalAllowed` counters are
   incremented and the submission continues its normal flow.

The `remainingMinutes` field indicates the window duration, not the
exact time until the next response is accepted (it is a sliding
window).

## Simulator

The builder includes a **Simulator** panel that runs the real logic
against a test email or phone, but with `dryRun: true`,
**it does not increment the counters or persist anything**. Useful for validating
a newly created rule before exposing it to real traffic.

## What the respondent sees

On `review.woku.app` (and in any SDK that consumes the API), a
`429 QUARANTINE_BLOCKED` translates into a generic screen:

> You already sent us this response recently. Try again in
> approximately N minutes.

We intentionally **do not reveal the rule name or the
identifier** that triggered it, so as not to give clues to an attacker
who intends to enumerate the active rules.

## Guarantees

* **Privacy**: the evaluator works with the search hash of the
  email, never with the plaintext email.
* **Atomic**: the `totalBlocked` and `totalAllowed` counters are
  updated with MongoDB's `$inc`; concurrent submissions cannot
  lose updates.
* **No impact if there are no rules**: the initial query is backed
  by the `{ companyId, enabled, priority }` index and returns empty
  in microseconds when there are no active quarantines for the company.
* **Auditable**: each block is recorded in the [audit
  log](/docs/en/seguridad/audit-log) as `quarantine.create`,
  `quarantine.update`, etc. Individual blocks are not
  recorded as separate entries to avoid flooding the log; the live
  counters are the source.

## Known limitations (V1)

* `respondentIdentifier` only supports `email` or `phone`. Custom
  identifiers (a `customFields` field) and `deviceId` are left for V2.
* Quarantine by `wokuId`/`formId` is not applied yet: the rule
  is global to the company. Once the submission starts carrying `formId`,
  the per-form filter activates without any data migration.
* The phone identifier compares the value as it arrives
  (without E.164 normalization). We recommend that the customer normalize
  before sending.

## Loss of access

If all members of the company are blocked by mistake
(for example a rule with `maxResponsesPerRespondent: 0`), an
admin can disable the quarantine from the panel, and new submissions
pass immediately. Previous metrics are preserved.
