Skip to content

ADR-003: Mailing Address Schema Design

Status

Accepted

Context

The identity service integrates with twoCircles as the identity provider, which stores address data in a generic line-based format:

  • line1: Street name
  • line2: House number
  • line3: Addition (e.g. "A")

We needed to decide how to model the mailing address in our GraphQL schema, specifically whether to mirror twoCircles' generic line format or use semantically named fields.

Option A: Generic line fields (Stripe/Shopify pattern)

graphql
input MailingAddressInput {
	line1: String
	line2: String
	line3: String
	city: String
	postalCode: String
	countryCode: CountryCode
}

Maps 1:1 to twoCircles. Used by Stripe and other large public APIs as the lowest common denominator for international addresses.

Option B: Structured fields

graphql
input MailingAddressInput {
	street: String
	houseNumber: String
	houseNumberSuffix: String
	city: String
	postalCode: String
	countryCode: CountryCode
}

Semantically named fields that map to twoCircles' format in the identity service mapper layer.

Decision

We adopt structured fields (Option B).

Rationale

1. Private API with a single controlled consumer

The generic line format is the right default for public APIs with unknown consumers (e.g. Stripe). Our GraphQL API is private with a single consumer: the React Native app. Optimizing for that consumer's developer experience is the correct trade-off.

2. No parsing required in React Native

With structured fields, each field maps directly to a form input. With generic line fields, the app would need to know that line1=street, line2=houseNumber, line3=houseNumberSuffix to render meaningful form inputs — moving the twoCircles coupling into the client.

3. Coupling is isolated to the mapper

The twoCircles-specific mapping (street → line1, houseNumber → line2, houseNumberSuffix → line3) lives exclusively in the identity service's mapper. If twoCircles changes their format, only the mapper needs to change — not the schema or the app.

4. houseNumberSuffix over addition

The field is named houseNumberSuffix rather than addition (a direct translation of the Dutch "toevoeging") because it is self-documenting in English and makes clear it is a suffix to the house number, consistent with the NEN 5825 Dutch addressing standard.

Consequences

Positive

  • Clear form mapping: React Native renders fields without any decoding logic
  • Single source of truth: twoCircles coupling is isolated to the identity service mapper
  • Readable schema: Field names are self-documenting for any consumer

Negative

  • Dutch-centric structure: houseNumber and houseNumberSuffix are concepts that don't exist in all address systems (e.g. US, UK)

Risks

  • International addresses: If we ever need to support non-Dutch address formats, the structured fields may not map cleanly. Mitigation: All address fields are optional, so street can serve as a free-text catch-all for countries that don't use a separate house number. If a more complex international format is required, a separate InternationalMailingAddressInput type can be introduced without breaking existing logic or clients.