docs: add per-module READMEs with architecture and DB schemas

Each module now has a README.md documenting commands, architecture,
and database schema (KV keys, JSON structure, field descriptions).
Trading README enhanced with full schemas for user portfolio and
price cache objects.
This commit is contained in:
2026-04-14 15:53:37 +07:00
parent d7988e38e6
commit c8ce28a15b
5 changed files with 147 additions and 5 deletions

View File

@@ -0,0 +1,20 @@
# Loldle Module
League of Legends guessing game — currently a stub proving the plugin system.
## Commands
| Command | Visibility | Description |
|---------|-----------|-------------|
| `/loldle` | public | Start a loldle game (stub) |
| `/lstats` | protected | Show loldle stats (stub) |
| `/ggwp` | private | Easter egg — "gg well played" |
## Architecture
- All commands return stub responses. Real game logic is not yet implemented.
- No `init()` hook — this module does not use KV storage yet.
## Database
**No KV usage currently.** When game logic is implemented, it will use KV namespace prefix `loldle:`.

View File

@@ -0,0 +1,35 @@
# Misc Module
Health check and DB demonstration. Exercises all three visibility levels.
## Commands
| Command | Visibility | Description |
|---------|-----------|-------------|
| `/ping` | public | Health check — replies "pong" and records timestamp |
| `/mstats` | protected | Shows last `/ping` timestamp |
| `/fortytwo` | private | Easter egg — replies "The answer." |
## Architecture
- `/ping` writes a timestamp to KV on every call (best-effort — KV failure doesn't block the reply).
- `/mstats` reads the last ping timestamp and formats it as ISO string.
- `/fortytwo` is a hidden command demonstrating private visibility.
## Database
KV namespace prefix: `misc:`
| Key | Type | Description | Example |
|-----|------|-------------|---------|
| `last_ping` | JSON | Timestamp of the most recent `/ping` call | `{ "at": 1713100000000 }` |
### Schema: `last_ping`
```json
{
"at": 1713100000000
}
```
- `at` — Unix epoch milliseconds (`Date.now()`)

View File

@@ -28,16 +28,48 @@ Paper-trading system where each Telegram user manages a virtual portfolio.
Currencies: VND, USD.
## Data Model
## Database
Per-user portfolio stored as a single KV object at key `user:<telegramId>`:
KV namespace prefix: `trading:`
```js
{ currency: { VND, USD }, stock: {}, crypto: {}, others: {}, totalvnd: 0 }
| Key | Type | Description |
|-----|------|-------------|
| `user:<telegramId>` | JSON | Per-user portfolio (balances + holdings) |
| `prices:latest` | JSON | Cached merged prices from all APIs |
### Schema: `user:<telegramId>`
```json
{
"currency": { "VND": 5000000, "USD": 100 },
"stock": { "TCB": 10, "FPT": 5 },
"crypto": { "BTC": 0.005, "ETH": 1.2 },
"others": { "GOLD": 0.1 },
"totalvnd": 10000000
}
```
- `totalvnd` tracks cumulative VND value of all top-ups (cost basis for P&L)
- `currency` — fiat balances (VND, USD)
- `stock` / `crypto` / `others` — asset quantities keyed by symbol
- `totalvnd` — cumulative VND value of all top-ups (cost basis for P&L)
- VND is the sole settlement currency — buy/sell deducts/adds VND
- Empty categories are `{}`, not absent — migration-safe loading fills missing keys
### Schema: `prices:latest`
```json
{
"ts": 1713100000000,
"crypto": { "BTC": 1500000000, "ETH": 50000000, "SOL": 3000000 },
"stock": { "TCB": 25000, "VPB": 18000, "FPT": 120000, "VNM": 70000, "HPG": 28000 },
"forex": { "USD": 25400 },
"others": { "GOLD": 72000000 }
}
```
- `ts` — Unix epoch milliseconds of last fetch
- All prices in VND per unit
- Cache TTL: 60 seconds (stale fallback up to 5 minutes)
## Price Sources

View File

@@ -0,0 +1,20 @@
# Util Module
Core bot utilities — informational commands that read framework metadata.
## Commands
| Command | Visibility | Description |
|---------|-----------|-------------|
| `/info` | public | Echoes chat id, thread id, sender id (debug helper) |
| `/help` | public | Renders all public + protected commands grouped by module |
## Architecture
- `/help` is a pure renderer over `getCurrentRegistry()` — it reads the registry's command maps and formats them as Telegram HTML. Modules with zero visible commands are omitted. Private commands are always excluded.
- `/info` reads grammY context fields (`ctx.chat.id`, `ctx.message.message_thread_id`, `ctx.from.id`). No external state.
- HTML injection is prevented via `escapeHtml()` on all user-influenced strings.
## Database
**No KV usage.** This module has no `init()` hook and does not store any data.

View File

@@ -0,0 +1,35 @@
# Wordle Module
Word guessing game — currently a stub proving the plugin system.
## Commands
| Command | Visibility | Description |
|---------|-----------|-------------|
| `/wordle` | public | Start a wordle game (stub) |
| `/wstats` | protected | Show wordle stats |
| `/konami` | private | Easter egg — "secret wordle mode" |
## Architecture
- All commands return stub responses. Real game logic is not yet implemented.
- `/wstats` reads a `stats` key from KV (returns 0 games played when empty).
- Module captures `db` in closure via `init()` for future game state persistence.
## Database
KV namespace prefix: `wordle:`
| Key | Type | Description | Example |
|-----|------|-------------|---------|
| `stats` | JSON | Aggregate game statistics (planned) | `{ "gamesPlayed": 0 }` |
### Schema: `stats` (planned)
```json
{
"gamesPlayed": 0
}
```
No data is currently written — the module only reads this key defensively.