# FAVO Reward Lifecycle V1

## Scope

This release adds explicit reward lifecycle support:

- ONE_TIME
- REPEATABLE
- SPEND_POINTS entitlement interpretation

The database change adds `reward_unlocks.cycle_number`.

Existing unlock records are preserved as cycle 1.

The existing Reward Redemption V1 token flow remains compatible because redemption still targets `reward_unlock_id`.

## Configuration

Program `rules_json` controls the lifecycle.

### ONE_TIME

```json
{"points":100,"reward_mode":"ONE_TIME"}
```

A customer can have one unlock for that reward.

### REPEATABLE

```json
{"points":100,"reward_mode":"REPEATABLE","cycle":100}
```

With 330 points, eligible cycles are 1, 2 and 3.

The system does not deduct points. The unlocks are entitlements.

### SPEND_POINTS

```json
{"points_cost":100,"reward_mode":"SPEND_POINTS"}
```

This mode identifies a points-cost reward. The current V1 UnlockService creates the entitlement but does not mutate the loyalty ledger. Point deduction must happen atomically at redemption when this mode is enabled for a real production program.

## Important

Do not manually delete reward unlock rows to reset a cycle. They are historical entitlement records.

Do not alter `loyalty_transactions` to simulate reward redemption. That ledger remains the source of truth for loyalty balance.

## Deployment

The deployment script only installs code and migration files. It does not execute SQL.

See the command sequence supplied with this package.

## Migration registration

FAVO currently uses `schema_migrations(id, migration, applied_at)`.

After successful SQL execution, register:

```sql
INSERT INTO schema_migrations (migration, applied_at)
VALUES ('009_reward_lifecycle.sql', NOW());
```

Only register it after the migration succeeds.
