0001-use-generic-inmemory-adapter

ADR 0001: Use a generic in-memory adapter with a Refresh mapping function

Date: 2025-09-08 Status: accepted

Context

We need a read-only adapter service that presents normalized project/customer/person data to a frontend. Multiple upstream systems (GitLab, Gitea, Redmine) will be supported. Implementing full filtering and sorting logic separately for each upstream client would be duplicative and error-prone.

Decision

Introduce a single generic in-memory adapter component which:

  • Accepts a small RefreshFunc(ctx) implemented by each upstream adapter. The RefreshFunc fetches upstream DTOs and maps them into the normalized model.Project, model.Customer and model.Person types.
  • Stores the normalized data in-memory and implements List*/Get* with centralized filtering, full-text search and sorting logic.
  • Exposes Refresh(ctx) error so the service (or tests) can trigger a reload of upstream data on demand.

Consequences

Positive:

  • Upstream adapters are tiny: they only have to implement fetching + mapping.
  • Centralized, consistent filtering/sorting semantics across all adapters.

Negative / trade-offs:

  • The in-memory cache means large upstream data sets may consume memory; adapters should consider limiting what they return or support streaming/partial fetch approaches when necessary.

Operational notes:

  • Provide an admin endpoint or startup hook to trigger Refresh.

Next steps

  • Implement generic adapter (done).
  • Refactor existing in-memory sample adapter to use the generic adapter (done).
  • Add optional admin endpoint to trigger Refresh (future).

Author: Jone Marius Vignes Approver: Jone Marius Vignes

Alternatives considered

  • Per-adapter filtering: implement filtering and sorting inside each upstream adapter. This keeps the generic adapter simpler but duplicates logic and risks inconsistent behavior across adapters.
  • Persistent normalized store: map upstream data into a durable database and run queries there. This supports large datasets but adds operational complexity and negates the “adapter-only” lightweight goal.
  • Streaming/partial fetch: keep only a window of upstream items in memory and fetch more on demand. This reduces memory usage but complicates filtering and consistency.