ali-ahnaf / ali-ahnaf/pocket_pixel

Introduce NanoDI dependency injection container in the API workspace

未關閉
#274 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視
backend up for grabs
主要語言
TypeScript
星號
14
分支
91
PR 合併指標
30 天內沒有已合併 PR

描述

### 📌 Context / background

Right now the API in `packages/api` wires its dependencies by hand. Every service and repository is created once with `new` and exported as a shared singleton from two files:

- `packages/api/src/services/index.ts` — ~18 `new SomeService()` lines
- `packages/api/src/repositories/index.ts` — ~11 `new SomeRepository()` lines

Each service then pulls its dependencies through constructor parameters that **default to those singletons**, e.g. in `packages/api/src/services/transactions.service.ts`:

```ts
constructor(
private readonly transactions: TransactionsRepository = transactionsRepository,
private readonly vaults = vaultsRepository,
) {}
```

This works, but wiring order is manual and fragile: a new dependency means editing the index file, and the default-parameter pattern couples every service file to the singleton graph. [NanoDI](https://github.com/andersnm/nanodi) is a tiny, decorator-free DI container for TypeScript/Node that can register these classes and resolve the graph for us — a natural fit for the existing `route → service → repository → entity` layering described in `CLAUDE.md`.

> 🧩 **Dependency injection (DI)** = instead of a class building its own dependencies, a central "container" creates them and hands them in. Makes wiring explicit and swapping in test mocks trivial.

### 🎯 Problem / goal

Replace the manual singleton wiring with a NanoDI container so that:

- Services and repositories are **registered once** with the container.
- Consumers (routes, scheduler, tests) resolve instances from the container instead of importing hand-built singletons.
- Unit tests can register mock repositories without relying on default constructor parameters.

### 🛠️ Suggested approach

Start small — do **not** convert every service in one PR. Pick 1–2 services (e.g. `TransactionsService` + `TransactionsRepository`) as a pilot, prove the pattern, then follow up.

1. **Add the dependency** to the API workspace: `npm install nanodi -w packages/api`. Confirm it ships types and works with this repo's CommonJS/ts-node setup.
2. **Create a container module**, e.g. `packages/api/src/container.ts`, that registers repositories and services with NanoDI. Look at how `packages/api/src/services/index.ts` and `packages/api/src/repositories/index.ts` build the graph today and reproduce it as container registrations.
3. **Resolve from the container** at the composition root. Check where the current singletons are imported (routes under `packages/api/src/routes`, the scheduler in `packages/api/src/scheduler/recurring-scheduler.ts`, and `packages/api/src/index.ts`) and switch the pilot service's consumers to resolve it from the container.
4. **Keep the constructor-injection shape.** NanoDI should supply the dependencies the constructor currently defaults to; the default-parameter fallbacks can stay for now so existing tests keep passing during migration.
5. **Update the pilot service's unit test** (`packages/api/src/tests`) to register mocks via the container instead of passing them positionally.
6. **Document the pattern** — add a short note to `CLAUDE.md` under the "API request flow" section describing how to register a new service/repository with the container, so the next contributor follows the DI path, not the old singleton path.

⚠️ Follow the repo rule: no `try/catch` in routes, no business logic moved into wiring, and run `npm run test:api` after the change.

### ✅ Acceptance criteria

- [ ] `nanodi` added as a dependency of `packages/api`.
- [ ] A container module registers the pilot service(s) and their repositories.
- [ ] The pilot service is resolved from the container at its consumers (route/scheduler), not from the hand-built singleton.
- [ ] The pilot service's unit test uses the container to inject mocks and still passes.
- [ ] `npm run test:api` is green.
- [ ] `CLAUDE.md` documents how to register a new service/repository with NanoDI.
- [ ] PR describes what changed and notes this is a pilot, with follow-up issues for migrating the remaining services.

貢獻指南

這個儲存庫沒有索引到貢獻指南

研究方向

Start by reading packages/api/src/services/index.ts, packages/api/src/repositories/index.ts, and transactions.service.ts to understand the current singleton graph. Then inspect route consumers, packages/api/src/scheduler/recurring-scheduler.ts, packages/api/src/index.ts, the pilot unit test under packages/api/src/tests, and the API request flow in CLAUDE.md. Done means the pilot resolves through a container, tests inject mocks through it, npm run test:api passes, and the pattern is documented.

由索引模型根據 Issue 內容生成。

評估

技術堆疊
nodejs, typescript
領域
api, backend, developer-experience, testing
Issue 類型
功能
難度
4/5
預估耗時
3-5 天
活躍度
冷清
描述清晰度
描述清楚
新手友好度
52/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。