docs: define opaque payer token handling

This commit is contained in:
2026-08-20 13:22:11 +03:30
parent 2753162a75
commit 6e0cc0b3fd
3 changed files with 32 additions and 3 deletions

View File

@@ -11,6 +11,7 @@ For every Go-related task, always invoke and follow the `golang-how-to` skill, t
- The backend is the authority for authentication, authorization, tenant isolation, metric definitions, and data provenance. - The backend is the authority for authentication, authorization, tenant isolation, metric definitions, and data provenance.
- Every merchant-scoped query derives merchant identity from the authenticated server-side session; never trust a client-supplied merchant identifier as authorization. - Every merchant-scoped query derives merchant identity from the authenticated server-side session; never trust a client-supplied merchant identifier as authorization.
- Cross-merchant results are minimum-cohort, anonymized aggregates only. - Cross-merchant results are minimum-cohort, anonymized aggregates only.
- Treat `payer_card_key` as an opaque, merchant-scoped source token with unverified upstream semantics. Retain it unchanged only for internal deterministic analytics; never expose it through merchant APIs, logs, exports, or AI inputs, and never describe it as a card number or verified person identifier.
- Use integer minor currency units or an explicitly documented fixed-precision representation; never floating point for money. - Use integer minor currency units or an explicitly documented fixed-precision representation; never floating point for money.
- Interpret timezone-naive challenge timestamps as `Asia/Tehran`, preserve their source provenance, and normalize canonical database/API timestamps to UTC `timestamptz`/ISO 8601. Any change to this assumption requires a new import version and ADR. - Interpret timezone-naive challenge timestamps as `Asia/Tehran`, preserve their source provenance, and normalize canonical database/API timestamps to UTC `timestamptz`/ISO 8601. Any change to this assumption requires a new import version and ADR.
- Raw imports are immutable inputs; corrections are new import versions, not silent mutation. - Raw imports are immutable inputs; corrections are new import versions, not silent mutation.

View File

@@ -154,8 +154,9 @@ Resolved: use Ent for application persistence/modeling and pgx/PostgreSQL `COPY`
Resolved: interpret timezone-naive source timestamps as `Asia/Tehran`, normalize canonical timestamps to UTC, expose ISO-8601 timestamps through APIs, and retain the immutable source/import provenance needed to reproduce the conversion. See ADR 0004. Resolved: interpret timezone-naive source timestamps as `Asia/Tehran`, normalize canonical timestamps to UTC, expose ISO-8601 timestamps through APIs, and retain the immutable source/import provenance needed to reproduce the conversion. See ADR 0004.
Resolved: retain `payer_card_key` unchanged as a restricted, merchant-scoped opaque source token for internal repeat-payer analytics. Do not HMAC it, expose it, log it, export it, or send it to AI providers. Its upstream semantics remain unverified. See ADR 0005.
Remaining approval gates: Remaining approval gates:
1. Whether `payer_card_key` must be retained, irreversibly transformed, or omitted after derived analytics. 1. Minimum cohort size and suppression policy for peer benchmarks.
2. Minimum cohort size and suppression policy for peer benchmarks. 2. Physical partitioning/materialization strategy, which must follow measured query needs rather than the logical ERD alone.
3. Physical partitioning/materialization strategy, which must follow measured query needs rather than the logical ERD alone.

View File

@@ -0,0 +1,27 @@
# ADR 0005: Retain the opaque payer token without additional pseudonymization
- Status: Accepted
- Date: 2026-08-20
## Context
The dataset does not document the semantics or generation method of `payer_card_key`. Profiling found 1,034,368 populated rows and 402,173 distinct values. Values are opaque alphanumeric tokens 6–11 characters long. They repeat within a merchant, enabling repeat-payer analysis, but no observed token appears under multiple merchants. Approximately 53% of rows are missing the value.
Applying HMAC would preserve equality while adding secret storage, rotation, and re-import operations. Because the supplied value is already opaque and empirically merchant-scoped, that extra transformation provides limited benefit for this dataset and does not make the identifier anonymous.
## Decision
Retain the supplied `payer_card_key` unchanged as a nullable, restricted internal analytical field. Treat it only as an opaque merchant-scoped token with unverified upstream semantics.
Every lookup, grouping, or uniqueness calculation involving the token must include the merchant boundary. The token must never be returned by merchant-facing APIs, written to logs or traces, included in exports, rendered in the frontend, or sent to AvalAI/another third party. It must not be described as a card number, account number, or verified unique person.
Metrics derived from it must disclose source coverage and use language such as “شناسه پرداخت‌کننده در داده‌های موجود,” not claims about verified customers. A production source contract or evidence of reversibility/cross-merchant linkability triggers a new security review and ADR.
## Consequences
- Repeat-token frequency, retry, success, and approximate returning-payer analyses remain possible.
- No new pseudonymization secret or rotation workflow is required for the hackathon dataset.
- Database access remains more privileged than dashboard/API access because the token is still linkable behavioral data.
- Missing coverage prevents treating distinct-token counts as complete payer counts.
- Tests must verify tenant scoping and assert that DTOs, logs, exports, and AI payloads cannot contain the field.