feat(cache): add persistent smartdata-backed cache with LocalTsmDb, cache cleaner, and DcRouter integration

This commit is contained in:
2026-02-10 11:22:15 +00:00
parent f3f1f58b67
commit 41fe7a8a47
15 changed files with 282 additions and 39 deletions

View File

@@ -1316,4 +1316,87 @@ The configuration UI has been converted from an editable interface to a read-onl
- Numbers formatted with locale separators
- Byte sizes auto-formatted (B, KB, MB, GB)
- Time values shown with "seconds" suffix
- Nested objects with visual indentation
- Nested objects with visual indentation
## Smartdata Cache System (2026-02-03)
### Overview
DcRouter now uses smartdata + LocalTsmDb for persistent caching. Data is stored at `/etc/dcrouter/tsmdb`.
### Technology Stack
| Layer | Package | Purpose |
|-------|---------|---------|
| ORM | `@push.rocks/smartdata` | Document classes, decorators, queries |
| Database | `@push.rocks/smartmongo` (LocalTsmDb) | Embedded TsmDB via Unix socket |
### TC39 Decorators
The project uses TC39 Stage 3 decorators (not experimental decorators). The tsconfig was updated:
- Removed `experimentalDecorators: true`
- Removed `emitDecoratorMetadata: true`
This is required for smartdata v7+ compatibility.
### Cache Document Classes
Located in `ts/cache/documents/`:
| Class | Purpose | Default TTL |
|-------|---------|-------------|
| `CachedEmail` | Email queue items | 30 days |
| `CachedIPReputation` | IP reputation lookups | 24 hours |
| `CachedBounce` | Bounce records | 30 days |
| `CachedSuppression` | Suppression list | 30 days / permanent |
| `CachedDKIMKey` | DKIM key pairs | 90 days |
### Usage Pattern
```typescript
// Document classes use smartdata decorators
@plugins.smartdata.Collection(() => getDb())
export class CachedEmail extends CachedDocument<CachedEmail> {
@plugins.smartdata.svDb()
public createdAt: Date = new Date();
@plugins.smartdata.svDb()
public expiresAt: Date = new Date(Date.now() + TTL.DAYS_30);
@plugins.smartdata.unI()
@plugins.smartdata.svDb()
public id: string;
// ...
}
// Query examples
const email = await CachedEmail.getInstance({ id: 'abc123' });
const pending = await CachedEmail.getInstances({ status: 'pending' });
await email.save();
await email.delete();
```
### Configuration
```typescript
const dcRouter = new DcRouter({
cacheConfig: {
enabled: true,
storagePath: '/etc/dcrouter/tsmdb',
dbName: 'dcrouter',
cleanupIntervalHours: 1,
ttlConfig: {
emails: 30, // days
ipReputation: 1, // days
bounces: 30, // days
dkimKeys: 90, // days
suppression: 30 // days
}
}
});
```
### Cache Cleaner
- Runs hourly by default (configurable via `cleanupIntervalHours`)
- Finds and deletes documents where `expiresAt < now()`
- Uses smartdata's `getInstances()` + `delete()` pattern
### Key Files
- `ts/cache/classes.cachedb.ts` - CacheDb singleton wrapper
- `ts/cache/classes.cached.document.ts` - Base class with TTL support
- `ts/cache/classes.cache.cleaner.ts` - Periodic cleanup service
- `ts/cache/documents/*.ts` - Document class definitions