reph

Templates · Engineering

Technical spec template

Implementation-level spec: overview, goals, approach, milestones

Start with this template →Sign in

Opens on reph with the template ready to start. No account needed; sign in to keep your document.

Use it when

The design is agreed and an engineer needs an implementation plan reviewers can check: modules touched, data flow, milestones and tests

Who it's for

EngineerTech lead

Part of a kit

Engineering rituals, step 4 of 7. Propose, decide, build and review: RFC, design doc, ADR, spec, PR description and review checklist.

Filled example

The template filled in for a made-up company, so you can see what good looks like.

Idempotent payment capture

Author: Tomas Berg · Date: 2026-09-08

Overview

Halden Labs' billing service sometimes charges a customer twice when a client retries a capture request after a network timeout. This spec adds idempotency keys to POST /v2/captures so a retried request returns the original result instead of creating a second charge.

Goals

  • A retried capture with the same Idempotency-Key never creates a second charge.
  • Duplicate captures drop from about 40 a month to zero within one release.
  • p95 latency of the capture endpoint rises by no more than 10 ms.

Non-goals

  • Idempotency for refunds and payouts (follow-up spec).
  • Changing the payment processor integration.

Approach

Store each key with a request hash and the response in a new idempotency_keys table, written in the same transaction as the capture. A unique constraint on the key makes concurrent retries safe without a distributed lock.

Detailed design

New middleware idempotency.ts in billing/http reads the header, hashes the body, and either replays a stored response or reserves the key. CaptureService.capture() takes the reservation and stores the response before commit. Keys expire after 24 hours via the existing cleanup job.

Mermaid diagram (drawn as a picture in reph)
sequenceDiagram
    participant C as Checkout client
    participant A as Billing API
    participant S as CaptureService
    participant D as Postgres
    C->>A: POST /v2/captures (Idempotency-Key)
    A->>D: Insert key as reserved
    alt key already completed
        D-->>A: Stored response
        A-->>C: 200 replayed
    else new key
        A->>S: capture()
        S->>D: Insert charge and response in one transaction
        S-->>A: Charge
        A-->>C: 201 Created
    end

A key reused with a different body returns 422 idempotency_mismatch. A key still reserved by an in-flight request returns 409 so the client retries later.

Sequencing

  1. Migration for idempotency_keys (no reads yet).
  2. Middleware behind flag capture_idempotency, off.
  3. Checkout clients start sending the header.
  4. Flag on at 10%, then 100%.

Milestones

Milestone Owner Date
Migration and middleware merged Tomas Berg 2026-09-19
Clients send the header Hana Ito 2026-09-26
Flag at 100% Tomas Berg 2026-10-03

Testing strategy

Unit tests cover replay, mismatch and in-flight cases. An integration test fires 20 concurrent identical captures and asserts exactly one charge. It does not prove behavior under a Postgres failover; that is covered by the staging chaos run.

Risks

Risk Likelihood Impact Mitigation
Table growth slows inserts Low Medium 24 hour expiry, index on created_at
Old clients send no key High Low Behavior unchanged without a key

Open questions

Review

Reviewer Role Status
Grace Okafor Billing tech lead Approved
Hana Ito Checkout engineer Approved with comments

Review by: 2026-09-12

Decision Date Decided by Notes
Approved, keys scoped per merchant 2026-09-11 Grace Okafor Hana to confirm client retry backoff

The template

Show the blank template

Technical spec

Author: [your name] · Date: [date]

Overview

What is being built, in a paragraph someone outside the team could follow.

Goals

Outcomes this spec commits to delivering, stated so they can be checked once it ships.

Non-goals

  • Explicitly out of scope for this spec

Approach

The chosen implementation approach and why, one level above code.

Detailed design

Enough detail that another engineer could pick this up and implement it: modules touched, new types/interfaces, data flow, edge cases.

The main request path, end to end. Replace the participants with your real components; delete the diagram if the change has no interesting interaction.

Mermaid diagram (drawn as a picture in reph)
sequenceDiagram
    participant C as Client
    participant A as API
    participant S as Service
    participant D as Database
    C->>A: Request
    A->>S: Validate and call
    S->>D: Read or write
    D-->>S: Result
    S-->>A: Response
    A-->>C: 200 OK

Sequencing

What must land before what, and why (feature flags, backfills, dependent services).

Milestones

Milestone Owner Date

Testing strategy

Unit, integration, e2e coverage; what a passing test suite proves and what it doesn't.

Risks

Risk Likelihood Impact Mitigation

Open questions

Review

Who must approve before implementation starts, and by when.

Reviewer Role Status
Pending
Pending

Review by: [date]

Decision Date Decided by Notes

Questions

How is this different from a design doc?
A design doc decides what and why; a spec says how, at the level of modules, interfaces and sequencing
How detailed should it be?
Enough that another engineer could implement it without asking you
Who signs off?
The reviewers in the Review section, usually the tech lead plus one engineer from each team whose code changes

Fill it with your agent

Connect Claude to reph over MCP, then paste this. The draft arrives as suggestions you accept or reject section by section. How to connect Claude.

Find my reph doc "Technical spec" with search_docs, then read it with read_doc. Draft overview, detailed design, sequence diagram and milestones from the approved design doc or RFC, the relevant source files and the ticket list I paste. Name real modules and interfaces. File it with suggest_edit, one replace_section op per section (heading line kept) so each can be accepted alone. Ask each open question (anything inferred rather than read, guessed milestone dates) with add_comment quoting that section's heading line, then call request_review with a one-line summary.

Related templates

Start with this template →Sign in