iOS v1 prerequisites: Idempotency-Key + ASCII QR pairing #8
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
posta/server!8
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "ios-v1-prereqs"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Two server-side changes the iOS v1 client depends on, both small and self-contained (per
TODO.md).Idempotency-KeyonPOST /api/v1/messages. Migration v4 addsidempotency_keys (token_id, idempotency_key, row_id, payload_hash, created_at). A newLookupOrEnqueueIdempotentdoes lookup-or-insert atomically in one tx, returns the row's current state on replay, and returnsErrIdempotencyMismatch(→ 409) when the payload diverges from the stored hash. Records older than 24h are swept opportunistically on each call. The handler reads the optionalIdempotency-Keyheader; on replay it reuses the response shape but skips theoutbound-stateSSE publish so subscribers don't see the same row twice.posta-server token create. After the plaintext token, the CLI prints aposta+v1://<host>#token=<token>URI and a UTF-8 block QR encoding the same URI. Host comes from the per-identity manifest entry viadaemon.IdentityHost.--no-qrsuppresses both for scripted use.CLIENT_API.mdupdated for both — new Idempotency section underPOST /messages, and the Pairing section reflects the new CLI output.Test plan
go vet ./...cleango test ./...cleanLookupOrEnqueueIdempotent: replay returns same row + current state; mismatched payload →ErrIdempotencyMismatch; same key from a different token produces an independent row; records older thanIdempotencyTTLare swept on next callsendMessageoverhttptest: same key + same body → identical 202 twice with exactly one SSE publish; same key + different body → 409idempotency-mismatch; same key + different bearer → independent rowsrenderQR: dimensions and quiet zone are right; every module's dark/light agrees withrsc.io/qrbit-for-bit🤖 Generated with Claude Code