Inventory Health & Deprecation Tracking
Two new admin dashboard tabs โ Inventory and Deprecation โ provide operational visibility into product stock health and API lifecycle management.
NOTE
Both panels are lazy-loaded and only accessible to users with the PLATFORM_ADMIN role. See Custom RBAC for permission details.
Architecture Overview
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Admin Dashboard (/admin) โ
โ โโโโโโโโโโโ โโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโ โ
โ โOverview โ โUsers โ โAnalytics โ โPayments โ More โพ โ
โ โโโโโโโโโโโ โโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโ โ โโ
โ โโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโ โโโโดโโโโ โ
โ โInventory โ โDeprecation โ โTrash โ โ
โ โ Panel โ โ Tracker โ โHist. โ โ
โ โโโโโโฌโโโโโโ โโโโโโโโโฌโโโโโโโโโ โTemp. โ โ
โ โ โ โSearchโ โ
โ โผ โผ โโโโโโโโ โ
โ GET_ADMIN_PRODUCTS GET /admin/deprecated-fields โ
โ (GraphQL) (REST) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Inventory Health Panel
Data Source
The Inventory panel consumes the existing GET_ADMIN_PRODUCTS GraphQL query, which returns product data including totalInventory and the associated Malet handle. All stock analysis is performed client-side โ no additional backend APIs are required.
Store: `inventoryStore.svelte.ts`
Pure functions exported for testing and reuse:
// Core analysis
getStockStatus(totalInventory: number, threshold: number): StockStatus
enrichWithStockInfo(products: AdminProduct[], threshold: number): ProductStockInfo[]
computeLowStockProducts(products: AdminProduct[], threshold: number): ProductStockInfo[]
computeOutOfStockProducts(products: AdminProduct[]): ProductStockInfo[]
computeHealthSummary(products: AdminProduct[], threshold: number): InventoryHealthSummary
// Configuration
validateThreshold(value: number): { valid: boolean; error?: string }
loadThreshold(): number // from localStorage
saveThreshold(value: number) // to localStorage
Types
type StockStatus = 'ok' | 'low' | 'out';
interface ProductStockInfo {
id: string;
name: string;
totalInventory: number;
trackInventory: boolean;
status: StockStatus;
delta: number; // threshold - inventory (negative = above)
maletHandle?: string;
}
interface InventoryHealthSummary {
total: number; // all products
tracked: number; // products with inventory tracking
ok: number;
low: number;
out: number;
}
Threshold Configuration
| Property | Value |
|---|---|
| Default | 10 units |
| Range | 1 โ 100 |
| Validation | Zod z.number().int().min(1).max(100) |
| Persistence | localStorage key: ngwenya_low_stock_threshold |
IMPORTANT
The threshold is a client-side setting, not stored on the backend. A future enhancement could add a lowStockThreshold field to the Product entity for per-product or per-Malet configuration.
Component: `InventoryPanel.svelte`
Props:
{ products: AdminProduct[] } // passed from admin +page.svelte
Sections:
- Health Summary Cards โ clickable filters (All / OK / Low / Out)
- Stock Table โ product name, Malet handle, inventory count, threshold delta, status badge
- Config Sidebar โ threshold slider + number input, summary stats
Deprecation Tracking Panel
Data Source
Unlike other admin panels that use GraphQL, the Deprecation Tracker consumes the gateway's REST API directly:
| Endpoint | Method | Description |
|---|---|---|
/admin/deprecated-fields |
GET |
Returns the full usage report |
/admin/deprecated-fields/reset |
POST |
Resets all in-memory counters |
These endpoints are served by the DeprecationController in the gateway's DeprecationModule, backed by the FieldUsageService which uses the FieldUsagePlugin (Apollo Server plugin) to intercept and record deprecated field access during GraphQL resolution.
WARNING
Usage counters are in-memory and reset on gateway restart. They are not persisted to a database. This is intentional for simplicity โ a Redis-backed persistence layer can be added if needed.
Store: `deprecationStore.svelte.ts`
// API
fetchDeprecationReport(): Promise<DeprecationReport>
resetDeprecationCounters(): Promise<{ message: string }>
// Pure functions
sortByUsageCount(records: FieldUsageRecord[]): FieldUsageRecord[]
sortByLastSeen(records: FieldUsageRecord[]): FieldUsageRecord[]
groupByType(records: FieldUsageRecord[]): Record<string, FieldUsageRecord[]>
computeSummary(report: DeprecationReport): SummaryStats
formatFieldPath(record: FieldUsageRecord): string // "Type.field"
formatTimestamp(dateStr: string | null): string
Types
interface FieldUsageRecord {
typeName: string;
fieldName: string;
deprecationReason: string;
usageCount: number;
firstSeenAt: string | null;
lastSeenAt: string | null;
}
interface DeprecationReport {
fields: FieldUsageRecord[];
totalTracked: number;
totalUsage: number;
}
Component: `DeprecationTracker.svelte`
Sections:
- Summary Bar โ total tracked fields, total usage count, most-used field
- Sort Toggle โ switch between "By Usage" and "By Recent"
- Fields Table โ
Type.fieldpath, deprecation reason, usage count (color-coded: red > 100, amber > 10), timestamps - Reset Counters โ button with confirmation dialog
Admin Dashboard Navigation
With 10 total tabs, the admin dashboard uses a primary + overflow pattern:
| Primary Tabs (always visible) | More โพ Dropdown |
|---|---|
| Overview, Users, Analytics, Payments, Inventory | Trash, Edit History, Templates, Search Config, Deprecation |
When a "More" tab is active, the dropdown button shows the active tab's label and highlights with the accent color.
Testing
| Test File | Tests | Coverage |
|---|---|---|
tests/inventoryStore.test.ts |
21 | Stock status, enrichment, filtering, summary, threshold validation, constants |
tests/deprecationStore.test.ts |
11 | Sorting, grouping, summary computation, formatting |
Run:
npx vitest run tests/inventoryStore.test.ts tests/deprecationStore.test.ts
Related
- Admin Analytics Dashboards โ Revenue, Blog, and User analytics panels in the same admin dashboard
- Search Configuration โ Per-vertical synonym management admin tab
- Payments History โ Paginated Murchase table admin tab
- Custom RBAC โ
PLATFORM_ADMINrole and permission definitions - Edit History Audit Trail โ Field-level diff viewer for Products and Services