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 normalizedmodel.Project,model.Customerandmodel.Persontypes. - Stores the normalized data in-memory and implements
List*/Get*with centralized filtering, full-text search and sorting logic. - Exposes
Refresh(ctx) errorso 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.