Implement a persistence adapter so usage, services, and API keys survive process restarts
Description
Every data store in src/index.ts is an in-memory Map/Set (usageStore, servicesStore, servicesMetadata, servicesDisabled, apiKeyStore, webhookStore, eventLog) and the comments openly state that "a process restart resets the counters." For a metering and billing backend this is a correctness hazard: a restart silently drops unsettled usage that real money is owed against. This issue introduces a storage abstraction with a pluggable backend so durability becomes possible without rewriting every handler.
Requirements and context
- Repository scope:
Agentpay-Org/Agentpay-backend only.
- Define a
Store interface (get/set/delete/entries/scan-by-prefix) in a new src/store/index.ts that the existing handlers consume instead of touching Map directly.
- Ship an
InMemoryStore implementation (preserving current behaviour) and a file-backed or SQLite-backed implementation selected via an env var (e.g. STORAGE_DRIVER=memory|sqlite).
- Migrate
usageStore, servicesStore, servicesDisabled, servicesMetadata, and apiKeyStore to the new interface without changing any HTTP response shape.
- Keep the composite key convention
${agent}::${serviceId} (usageKey in src/index.ts) intact so existing exports and rollups still work.
- Add graceful-shutdown flush so the
SIGTERM/SIGINT handler persists state before exit.
Suggested execution
- Fork the repo and create a branch
git checkout -b feature/db-01-persistence-adapter
- Implement changes
- Write code in: new
src/store/index.ts and refactor the store accesses in src/index.ts.
- Write comprehensive tests in: new
src/store/store.test.ts — round-trip persistence, restart simulation, prefix scans.
- Add documentation: update
README.md with a "Persistence" section documenting STORAGE_DRIVER and the on-disk format.
- Add TSDoc comments on every method of the
Store interface.
- Validate security assumptions: no path traversal on the file path, safe serialization, no secret keys written in plaintext logs.
- Test and commit
Test and commit
- Run
npm run build, npm test, and npm run lint.
- Cover edge cases: empty store, restart with existing data, concurrent writes, corrupt/missing data file.
- Include the full
npm test output and a short note on the durability guarantees in the PR description.
Example commit message
feat: add pluggable persistence adapter with in-memory and sqlite drivers
Guidelines
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
Community & contribution rewards
- 💬 Join the AgentPay community on Discord for questions, reviews, and faster merges: https://discord.gg/eXvRKkgcv
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward.
Implement a persistence adapter so usage, services, and API keys survive process restarts
Description
Every data store in
src/index.tsis an in-memoryMap/Set(usageStore,servicesStore,servicesMetadata,servicesDisabled,apiKeyStore,webhookStore,eventLog) and the comments openly state that "a process restart resets the counters." For a metering and billing backend this is a correctness hazard: a restart silently drops unsettled usage that real money is owed against. This issue introduces a storage abstraction with a pluggable backend so durability becomes possible without rewriting every handler.Requirements and context
Agentpay-Org/Agentpay-backendonly.Storeinterface (get/set/delete/entries/scan-by-prefix) in a newsrc/store/index.tsthat the existing handlers consume instead of touchingMapdirectly.InMemoryStoreimplementation (preserving current behaviour) and a file-backed or SQLite-backed implementation selected via an env var (e.g.STORAGE_DRIVER=memory|sqlite).usageStore,servicesStore,servicesDisabled,servicesMetadata, andapiKeyStoreto the new interface without changing any HTTP response shape.${agent}::${serviceId}(usageKeyinsrc/index.ts) intact so existing exports and rollups still work.SIGTERM/SIGINThandler persists state before exit.Suggested execution
git checkout -b feature/db-01-persistence-adaptersrc/store/index.tsand refactor the store accesses insrc/index.ts.src/store/store.test.ts— round-trip persistence, restart simulation, prefix scans.README.mdwith a "Persistence" section documentingSTORAGE_DRIVERand the on-disk format.Storeinterface.Test and commit
npm run build,npm test, andnpm run lint.npm testoutput and a short note on the durability guarantees in the PR description.Example commit message
feat: add pluggable persistence adapter with in-memory and sqlite driversGuidelines
Community & contribution rewards