Add additional lint rules
This commit is contained in:
parent
02d782c3da
commit
420b18eb78
67 changed files with 3686 additions and 1415 deletions
54
docs/lint_resolution_plan.md
Normal file
54
docs/lint_resolution_plan.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# MeshiTrack ESLint Remediation & Clean-up Plan
|
||||
|
||||
This document establishes a highly structured, quantitative, and actionable plan to resolve the remaining **ESLint violations** across the MeshiTrack monorepo. Following the auto-formatting runs (which successfully wiped out all 279 Prettier warnings), we have mapped out all remaining violations into distinct, manageable categories.
|
||||
|
||||
---
|
||||
|
||||
## 📊 1. Quantitative Breakdown of Remaining Violations
|
||||
|
||||
| Rule ID | API Package Violations | Web Package Violations | Total Violations | Critical Remediation Category |
|
||||
| :--- | :---: | :---: | :---: | :--- |
|
||||
| **`@typescript-eslint/explicit-function-return-type`** | 165 | 50 | **215** | Stage 2: Return Boundary Annotations |
|
||||
| **`@typescript-eslint/no-unsafe-member-access`** | 63 | 117 | **180** | Stage 3: Unsafe-`any` Remediation & Unknown Parsing |
|
||||
| **`@typescript-eslint/naming-convention`** | 76 | 43 | **119** | Stage 1: Fine-tuning Rule Rules |
|
||||
| **`@typescript-eslint/no-unsafe-assignment`** | 43 | 33 | **76** | Stage 3: Unsafe-`any` Remediation & Unknown Parsing |
|
||||
| **`@typescript-eslint/no-explicit-any`** | 15 | 38 | **53** | Stage 3: Type-safe Mocking & unknown Shift |
|
||||
| **`@typescript-eslint/no-unsafe-return`** / **`no-unsafe-call`** | 43 | 25 | **68** | Stage 3: Unsafe-`any` Remediation & Unknown Parsing |
|
||||
| **`@typescript-eslint/no-floating-promises`** / **`no-misused-promises`** | 4 | 26 | **30** | Stage 4: Safe Asynchronous Execution |
|
||||
| **`@typescript-eslint/member-ordering`** | 15 | 4 | **19** | Stage 5: Structural Class Ordering |
|
||||
| **Others** (e.g. `unused-vars`, `prefer-const`) | 5 | 5 | **10** | Stage 6: Minor Cleanups |
|
||||
| **Total Structural Errors** | **428** | **341** | **769** | |
|
||||
|
||||
---
|
||||
|
||||
## 📅 2. Stage-by-Stage Remediation Strategy
|
||||
|
||||
### 🛠️ Stage 1: Rule Refinement (Remediation: ~120 Errors Resolved)
|
||||
Before refactoring active files, we fine-tune our rules to represent real-world Javascript/TypeScript practices:
|
||||
1. **Allow `PascalCase` on variables**: We have already enabled `PascalCase` for variables in both packages, allowing React component functions (e.g. `const TopBar = ...`) and database model objects (e.g. `const UserModel = ...`) to parse correctly.
|
||||
2. **Exclude dynamic API/Database keys**: We will configure `@typescript-eslint/naming-convention` to ignore property names containing leading/trailing underscores (like `_id` and `__v`) or specific HTTP headers in controllers.
|
||||
|
||||
---
|
||||
|
||||
### 📝 Stage 2: Explicit Boundary Return Types (Remediation: 215 Errors Resolved)
|
||||
To prevent type-drift, we will add explicit return signatures to the codebase:
|
||||
1. **Service and Repository Boundaries**: Add explicit return types to all public methods in all services (e.g., `Promise<ShoppingListDocument[]>`, `Promise<void>`).
|
||||
2. **Fastify Route Handlers**: Specify return types or configure ESLint to allow implicit handler return values since Fastify structures routing objects automatically.
|
||||
|
||||
---
|
||||
|
||||
### 🛡️ Stage 3: Unsafe-`any` Eradication (Remediation: 377 Errors Resolved)
|
||||
The largest source of logic leaks resides in un-typed values and `as any` casting:
|
||||
1. **Shift to `unknown` for Boundary Payloads**: For Fastify dynamic requests (`request.body`, `request.params`) and Next.js dynamic states, specify types as `unknown` and parse them safely via **Zod schemas**.
|
||||
2. **Standardize Test Suite Mocks**: Replace `as any` mock variables in unit tests with type-safe mock generators or `Partial<T>` objects (e.g. using `vi.mocked()` correctly).
|
||||
|
||||
---
|
||||
|
||||
### ⚡ Stage 4: Floating Promises & misuses (Remediation: 30 Errors Resolved)
|
||||
1. **Await floating promises**: Add correct `await` statements to database connections and route registrations.
|
||||
2. **Explicit Background Tasks**: Mark intentional background hooks (like event logs) with `void` (e.g. `void this.logEvent(...)`) to document intention.
|
||||
|
||||
---
|
||||
|
||||
### 🧱 Stage 5: Structural Class Member Ordering (Remediation: 19 Errors Resolved)
|
||||
1. Organize the 19 classes failing the ordering rule to place fields at the top, followed by constructors, followed by public methods, followed by private methods.
|
||||
166
docs/modules_cleanup_blueprint.md
Normal file
166
docs/modules_cleanup_blueprint.md
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
# MeshiTrack Monorepo Clean-up Blueprint
|
||||
|
||||
This playbook maps out the precise, incremental, batch-by-batch process to refactor all remaining active modules in both `@meshitrack/api` and `@meshitrack/web` to achieve complete ESLint compliance under our strict new guidelines, while keeping our **100.00% test coverage** pristine.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 The Core Refactoring Strategy
|
||||
|
||||
For every class/module we clean up, we follow the established **Shopping Lists Reference Standard**:
|
||||
1. **Repositories**:
|
||||
* Add explicit type parameter annotations for return values (e.g. `: Promise<Document | null>`).
|
||||
* Put private helper methods at the very bottom (under public methods) to satisfy `@typescript-eslint/member-ordering`.
|
||||
* Type query filters explicitly rather than using `any`.
|
||||
2. **Services**:
|
||||
* Keep class properties explicit and `readonly` (e.g. `private readonly repository: Repository`).
|
||||
* Add explicit return signatures (e.g. `: Promise<ShoppingListDocument>`).
|
||||
* Avoid `any` completely; use precise casts (e.g. `as ServingUnit`) or type guards.
|
||||
3. **Routes**:
|
||||
* Cast Fastify inputs explicitly (`request.params as { ... }` and `request.body as ...`).
|
||||
* Annotate serialization return contracts explicitly (e.g. `serializeList(doc: Document): SerializedContract`).
|
||||
* Wrap WebSocket handshakes or un-typed third party plugins in local ESLint overrides.
|
||||
|
||||
---
|
||||
|
||||
## 📅 The Batch Playbook
|
||||
|
||||
### 🧱 Batch 1: Core Identity & Household Foundation
|
||||
Enforces structural types on our identity schemas, auth profiles, and tenant containers.
|
||||
|
||||
* **Target Backend Files**:
|
||||
* `packages/api/src/modules/users/users.repository.ts`
|
||||
* `packages/api/src/modules/users/users.service.ts`
|
||||
* `packages/api/src/modules/users/users.routes.ts`
|
||||
* `packages/api/src/modules/households/households.repository.ts`
|
||||
* `packages/api/src/modules/households/households.service.ts`
|
||||
* `packages/api/src/modules/households/households.routes.ts`
|
||||
* **Key Focus**:
|
||||
* Ensure user keycloak sync mapping has explicit return contracts.
|
||||
* Cast tenant properties safely across fastify injection boundaries.
|
||||
* **Verification Runner**:
|
||||
```bash
|
||||
cd packages/api
|
||||
npx eslint src/modules/users src/modules/households --fix
|
||||
npx vitest run tests/modules/users tests/modules/households
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 💊 Batch 2: Medicine Cabinet & Consumption Logs
|
||||
Refactors the active cabinet inventory, item counts, and historical events tracking.
|
||||
|
||||
* **Target Backend Files**:
|
||||
* `packages/api/src/modules/medicines/medicines.repository.ts`
|
||||
* `packages/api/src/modules/medicines/medicines.service.ts`
|
||||
* `packages/api/src/modules/medicines/medicines.routes.ts`
|
||||
* `packages/api/src/modules/cabinet/cabinet.repository.ts`
|
||||
* `packages/api/src/modules/cabinet/cabinet.service.ts`
|
||||
* `packages/api/src/modules/cabinet/cabinet.routes.ts`
|
||||
* `packages/api/src/modules/cabinet-events/cabinet-events.repository.ts`
|
||||
* `packages/api/src/modules/cabinet-events/cabinet-events.service.ts`
|
||||
* `packages/api/src/modules/cabinet-events/cabinet-events.routes.ts`
|
||||
* **Key Focus**:
|
||||
* Clean up dosage calculations in the service layer, replacing implicit float types.
|
||||
* Ensure strict sorting sequence in historical event queries.
|
||||
* **Verification Runner**:
|
||||
```bash
|
||||
cd packages/api
|
||||
npx eslint src/modules/medicines src/modules/cabinet src/modules/cabinet-events --fix
|
||||
npx vitest run tests/modules/medicines tests/modules/cabinet tests/modules/cabinet-events
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🏪 Batch 3: Store Catalog & Price Registry
|
||||
Enforces type safety on retail outlets, product mappings, and historical pricing logs.
|
||||
|
||||
* **Target Backend Files**:
|
||||
* `packages/api/src/modules/stores/stores.repository.ts`
|
||||
* `packages/api/src/modules/stores/stores.service.ts`
|
||||
* `packages/api/src/modules/stores/stores.routes.ts`
|
||||
* `packages/api/src/modules/medicine-products/medicine-products.repository.ts`
|
||||
* `packages/api/src/modules/medicine-products/medicine-products.service.ts`
|
||||
* `packages/api/src/modules/medicine-products/medicine-products.routes.ts`
|
||||
* `packages/api/src/modules/medicine-prices/medicine-prices.repository.ts`
|
||||
* `packages/api/src/modules/medicine-prices/medicine-prices.service.ts`
|
||||
* `packages/api/src/modules/medicine-prices/medicine-prices.routes.ts`
|
||||
* **Key Focus**:
|
||||
* Eradicate `any` structures used in price conversions and store tags.
|
||||
* **Verification Runner**:
|
||||
```bash
|
||||
cd packages/api
|
||||
npx eslint src/modules/stores src/modules/medicine-products src/modules/medicine-prices --fix
|
||||
npx vitest run tests/modules/stores tests/modules/medicine-products tests/modules/medicine-prices
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### ⏰ Batch 4: Regimens, Refills & Alert Scheduler
|
||||
Tracks routines, alert thresholds, and automated refilling triggers.
|
||||
|
||||
* **Target Backend Files**:
|
||||
* `packages/api/src/modules/regimens/regimens.repository.ts`
|
||||
* `packages/api/src/modules/regimens/regimens.service.ts`
|
||||
* `packages/api/src/modules/regimens/regimens.routes.ts`
|
||||
* `packages/api/src/modules/refills/refills.repository.ts`
|
||||
* `packages/api/src/modules/refills/refills.service.ts`
|
||||
* `packages/api/src/modules/refills/refills.routes.ts`
|
||||
* `packages/api/src/modules/organizer/organizer.repository.ts`
|
||||
* `packages/api/src/modules/organizer/organizer.service.ts`
|
||||
* `packages/api/src/modules/organizer/organizer.routes.ts`
|
||||
* **Key Focus**:
|
||||
* Explicitly handle routine status triggers and scheduling date windows.
|
||||
* **Verification Runner**:
|
||||
```bash
|
||||
cd packages/api
|
||||
npx eslint src/modules/regimens src/modules/refills src/modules/organizer --fix
|
||||
npx vitest run tests/modules/regimens tests/modules/refills tests/modules/organizer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🧠 Batch 5: Nutrition, LLM Providers & Health
|
||||
Enforces guidelines on target metrics, no-op mock LLM interfaces, and health endpoints.
|
||||
|
||||
* **Target Backend Files**:
|
||||
* `packages/api/src/modules/nutrition-targets/nutrition-target.repository.ts`
|
||||
* `packages/api/src/modules/nutrition-targets/nutrition-target.service.ts`
|
||||
* `packages/api/src/modules/nutrition-targets/nutrition-target.routes.ts`
|
||||
* `packages/api/src/modules/llm/no-op-llm.provider.ts`
|
||||
* `packages/api/src/modules/health/health.routes.ts`
|
||||
* **Key Focus**:
|
||||
* Annotate mock responses in the LLM provider class explicitly.
|
||||
* **Verification Runner**:
|
||||
```bash
|
||||
cd packages/api
|
||||
npx eslint src/modules/nutrition-targets src/modules/llm src/modules/health --fix
|
||||
npx vitest run tests/modules/nutrition-targets tests/modules/llm tests/modules/health
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 💻 Batch 6: Frontend API Client Services
|
||||
Brings complete TypeScript strictness to our web fetch and Axios mock endpoints.
|
||||
|
||||
* **Target Frontend Files**:
|
||||
* `packages/web/src/services/api-client.ts`
|
||||
* `packages/web/src/services/cabinet.ts`
|
||||
* `packages/web/src/services/cabinet-events.ts`
|
||||
* `packages/web/src/services/households.ts`
|
||||
* `packages/web/src/services/medicines.ts`
|
||||
* `packages/web/src/services/medicine-prices.ts`
|
||||
* `packages/web/src/services/nutrition-targets.ts`
|
||||
* `packages/web/src/services/organizer.ts`
|
||||
* `packages/web/src/services/refills.ts`
|
||||
* `packages/web/src/services/regimens.ts`
|
||||
* `packages/web/src/services/shopping-lists.ts`
|
||||
* `packages/web/src/services/stores.ts`
|
||||
* **Key Focus**:
|
||||
* Annotate Axios return response structures explicitly as `Promise<AxiosResponse<T>>` or type mappers.
|
||||
* Eliminate implicit parameters.
|
||||
* **Verification Runner**:
|
||||
```bash
|
||||
cd packages/web
|
||||
npx eslint src/services --fix
|
||||
npx vitest run tests/services
|
||||
```
|
||||
122
docs/style-guidelines.md
Normal file
122
docs/style-guidelines.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
# MeshiTrack Coding Style & Engineering Guidelines
|
||||
|
||||
This document establishes the official coding standards, architectural paradigms, and TypeScript guidelines for the MeshiTrack monorepo. These guidelines are designed to enforce clean, testable, object-oriented codebases with pristine type-safety under strict quality gates.
|
||||
|
||||
---
|
||||
|
||||
## 🏛️ 1. Encapsulation & Class Member Accessibility
|
||||
|
||||
To ensure clear visibility boundaries, clean interfaces, and easy maintainability:
|
||||
|
||||
1. **Mandatory Accessibility Modifiers**: Every field, constructor, and method in a class must explicitly declare its accessibility modifier (`public`, `protected`, or `private`).
|
||||
2. **Mandate Explicit Fields**: Classes that participate in dependency injection (e.g. Services, Repositories, Providers) must explicitly declare their properties at the class level rather than relying on TypeScript constructor parameter properties.
|
||||
3. **Class Member Ordering**: Group class members in a predictable sequence:
|
||||
* Static Fields (Public -> Protected -> Private)
|
||||
* Instance Fields (Public -> Protected -> Private)
|
||||
* Constructor
|
||||
* Public Methods
|
||||
* Protected Methods
|
||||
* Private Methods
|
||||
|
||||
### Example:
|
||||
```typescript
|
||||
export class ShoppingListsService {
|
||||
// 1. Explicit, readonly instance properties
|
||||
private readonly shoppingListsRepository: ShoppingListsRepository;
|
||||
|
||||
// 2. Explicit constructor receiving DI payload
|
||||
public constructor({ shoppingListsRepository }: Deps) {
|
||||
this.shoppingListsRepository = shoppingListsRepository;
|
||||
}
|
||||
|
||||
// 3. Public class methods
|
||||
public async list(householdId: string): Promise<ShoppingListDocument[]> {
|
||||
return this.shoppingListsRepository.list(householdId);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ 2. Boundary Types & Return Types
|
||||
|
||||
To prevent type-drift across software boundaries:
|
||||
|
||||
1. **Explicit Return Types on Boundary Functions**: All public methods of class instances (Services, Repositories, Providers) and all exported module functions must explicitly declare their return types.
|
||||
2. **Relegate Inference to Callbacks**: Local, inline variables and anonymous arrow callbacks (e.g. within array map/filter functions) may utilize automatic type inference for conciseness.
|
||||
|
||||
### Example:
|
||||
```typescript
|
||||
// 🟢 Good: Explicitly defined return type on the boundary method
|
||||
public async list(householdId: string): Promise<ShoppingList[]> {
|
||||
const lists = await this.shoppingListsRepository.list(householdId);
|
||||
return lists.filter(item => item.status === 'active'); // Inline inference is okay
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚫 3. Eradicating `any` & Enforcing Type-Safety
|
||||
|
||||
TypeScript's `any` type compromises the integrity of our codebase and makes refactoring fragile.
|
||||
|
||||
1. **No Explicit `any`**: The use of explicit `any` is strictly prohibited throughout the codebase, including in test files.
|
||||
2. **Restrict Unsafe Operations**: We enforce strict type-checked rules to prevent the propagation of `any`:
|
||||
* Assigning an `any` to a variable/property is blocked (`@typescript-eslint/no-unsafe-assignment`).
|
||||
* Reading a property off of an `any` is blocked (`@typescript-eslint/no-unsafe-member-access`).
|
||||
* Invoking functions typed as `any` is blocked (`@typescript-eslint/no-unsafe-call`).
|
||||
* Returning an `any` from a function is blocked (`@typescript-eslint/no-unsafe-return`).
|
||||
3. **Prefer `unknown` for Dynamic Inputs**: Any unchecked external input (e.g., API payloads, database responses, dynamic JSON files) must be typed as `unknown` and validated at the boundary using **Zod schemas** or type guards.
|
||||
4. **Type-Safe Mocking**: Instead of casting mocks with `as any`, use highly targeted partial types or precise mocks.
|
||||
|
||||
---
|
||||
|
||||
## 🏷️ 4. Naming Conventions & File Structures
|
||||
|
||||
Uniform naming conventions prevent conflicts and reduce cognitive load:
|
||||
|
||||
1. **Directories**: Lowercase `kebab-case` (e.g., `shopping-lists/`).
|
||||
2. **Files**: `PascalCase` matching the primary class or component exported in the file (e.g., `ShoppingListsService.ts`), ensuring class name and file name are aligned.
|
||||
3. **Identifiers**:
|
||||
* **PascalCase**: Classes, Interfaces, Type Aliases, Enums.
|
||||
* **camelCase**: Properties, Methods, Variables, Parameters, Functions.
|
||||
* **UPPER_CASE**: Top-level static read-only constants.
|
||||
4. **Prohibit Hungarian Notation**: Do not prefix interfaces with `I` (e.g. write `ShoppingListsRepository`, NOT `IShoppingListsRepository`).
|
||||
|
||||
---
|
||||
|
||||
## 🛑 5. Structured Domain Exceptions
|
||||
|
||||
Exception mapping must be uniform, semantic, and highly testable:
|
||||
|
||||
1. **Prohibit Generic `Error` Throwing**: The service and business layers must never throw generic `new Error('message')` for operational domain failures.
|
||||
2. **Domain-Specific Exceptions**: Throw subclasses of `AppError` (e.g. `NotFoundError`, `ConflictError`, `BadRequestError`) containing semantic properties like status codes and optional structured sub-details.
|
||||
3. **Prevent Stack Leakage**: Our custom exceptions map directly to HTTP responses in central middleware, ensuring internal database schemas or runtime details are never leaked to external clients.
|
||||
|
||||
### Example:
|
||||
```typescript
|
||||
// 🟢 Good: Highly testable, structured domain-level exception
|
||||
if (!updated) {
|
||||
throw new NotFoundError('Shopping list not found');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧱 6. OOP vs. Functional Boundaries
|
||||
|
||||
We keep class-based OOP strictly segregated from pure stateless helpers:
|
||||
|
||||
1. **Stateful Layers -> Classes**: Services, Repositories, and Providers must be class-based to properly encapsulate state, DI, and persistence hooks.
|
||||
2. **Stateless Operations -> Standalone Pure Functions**: Math utilities, date/string formatters, and mapping helpers must be written as standalone, exported functions in pure modules.
|
||||
3. **No Utility Classes**: Do not write static utility classes (classes composed solely of static helper methods). Use direct ES module exports.
|
||||
|
||||
---
|
||||
|
||||
## ⚡ 7. Asynchronous Programming Integrity
|
||||
|
||||
To prevent background crashes, memory leaks, and silent failures:
|
||||
|
||||
1. **Mandate `async/await`**: Use `async/await` exclusively instead of Promise chains (`.then()`, `.catch()`).
|
||||
2. **Block Floating Promises**: Every Promise must be `await`ed or returned.
|
||||
3. **Explicit Voiding for Intentional Background Tasks**: If a task must run in the background (fire-and-forget), it must be explicitly voided (e.g. `void this.trackEvent()`) and handle its exceptions internally to prevent uncaught runtime rejections.
|
||||
Loading…
Add table
Add a link
Reference in a new issue