32 Commits
Author SHA1 Message Date
tiennm99 5e96490254 refactor: remove completed one-time startup migrations
Production data is migrated and every marker is recorded in the system
collection, so the stock dividend-history, sticker legacy-pack and stats
stock_dividend migrations no longer do anything. Stats keeps its startup
index creation and still hides retired stock_dividend rows.
2026-10-08 10:35:21 +07:00
tiennm99 7008a57cf5 refactor!: rebrand miti99bot to tiennm99bot
BREAKING CHANGE: the Go module path is now github.com/tiennm99/tiennm99bot,
the default sticker pack is stickers_by_<bot username>, and the health body,
deploy DM, User-Agents and image names say tiennm99bot.
2026-10-07 15:14:02 +07:00
tiennm99 cf620a257e docs: fix stale code comments and add missing package docs
Correct comments that described the retired webhook transport, a removed
/cron route, the old KV store and wrapper types, and behaviour that has since
changed; drop plan and review labels; reword two startup log lines that
overstated or misnamed what they report.
2026-09-30 14:19:01 +07:00
tiennm99 bd0ad6b817 fix(stock): key pending dividends by user and event to stop duplicate buttons
Repeated /stock_portfolio calls stacked a random-token pending key per
call, and applying the dividend cleaned up only the pressed one — the
rest kept live buttons until the TTL sweep. Keys are now deterministic
(pending-dividend:<userID>:<eventID>) so re-suggesting overwrites the
previous action, retires the old message's button, and applying leaves
exactly one key to delete. Callback data carries <userID>:<eventID>
instead of a token; presses are still validated against the stored
owner, chat, and message binding.
2026-08-05 13:59:48 +07:00
tiennm99 59534a9c4b feat(stock): reduce cost basis when applying cash dividends
Cash dividends are a return of capital: the payout still credits the
VND balance, and now also lowers the position's remaining cost basis
(floored at zero) so the ticker's unrealized P&L reflects dividends
already received. Zero basis is now a valid open-position state;
negative basis remains invalid. Share dividends are unchanged.
2026-08-05 11:43:21 +07:00
tiennm99 52a8b928f0 feat(stock): add detailed stock info command 2026-07-23 12:27:12 +07:00
tiennm99 803df7ce99 feat(stock): add stock events lookup 2026-07-23 10:03:41 +07:00
tiennm99 f9d1e52f6d fix(stock): retire dividend command and migrate stats 2026-07-22 18:55:57 +07:00
tiennm99 7009d5f7b2 fix(portfolio): tighten mobile column formatting 2026-07-22 17:36:29 +07:00
tiennm99 df240a5db0 feat(stock): persist per-user dividend history 2026-07-22 16:17:29 +07:00
tiennm99 7a0163ec01 feat: format compact portfolio numbers 2026-07-22 12:27:52 +07:00
tiennm99 7487d21499 fix(stock): note currency in portfolio title 2026-07-22 10:59:40 +07:00
tiennm99 ec06095ee7 chore(stock): log dividend event checks 2026-07-21 18:50:48 +07:00
tiennm99 d0098dafdd feat(stock): add dividend event buttons 2026-07-21 18:19:50 +07:00
tiennm99 96ba34384a refactor(portfolio): retire completed migrations 2026-07-21 17:13:19 +07:00
tiennm99 7083079b39 feat(portfolio): nest asset positions 2026-07-21 16:42:33 +07:00
tiennm99 0dd93e3bf9 feat(portfolio): track stock and coin cost basis 2026-07-21 15:52:05 +07:00
tiennm99 a211b7f8b7 fix(commands): remove examples from command discovery 2026-07-21 13:52:53 +07:00
tiennm99 b5c7427520 fix(commands): render examples conditionally with inline help code 2026-07-21 13:21:01 +07:00
tiennm99 f5ba9d4032 feat(commands): improve discovery and normalize parameters 2026-07-21 11:45:20 +07:00
tiennm99 8b2ac571d9 feat(stock): add ratio dividend commands 2026-07-20 17:32:37 +07:00
tiennm99 e6d5bc3cc9 feat: refine command names and behavior 2026-07-01 13:19:42 +07:00
tiennm99 788f1015b5 feat(commands): simplify portfolio command names 2026-07-01 10:53:52 +07:00
tiennm99 15a3239ab1 refactor(storage): replace KVStore with generic typed DocStore[T]
Delete the byte-oriented KVStore/VersionedStore abstraction and the
DynamoDB/memory KV backends. Add a generic typed store (DocStore[T] with
Provider/Collection/Typed) persisting each value as a flattened native
Mongo document (storedDoc[T] via bson inline) — no value envelope.

- MongoDB is the only runtime backend; memory kept for tests/local.
- All modules + deploynotify use typed stores; persisted structs carry
  bson tags == json names (incl. nested lolschedule/wordle types).
- lolschedule wraps its array/scalar values in named structs.
- migrate-dynamo-to-mongo writes the flattened shape via Typed[bson.M]
  with wrap rules; Scan/--dry-run/--verify retained.

Verified: go vet/build clean; full go test green hermetically and
in-container vs real Mongo 7 + DynamoDB Local (storage integration +
migrator e2e).
2026-06-28 18:02:11 +07:00
tiennm99 f399717613 refactor(stock): remove FireAnt income-events command
Drop FireAnt-based /income command per AWS decommission plan. Simplifies
stock module and reduces third-party dependencies. Updates telegram-commands.json.
2026-06-28 09:58:25 +07:00
tiennm99 c107489f89 refactor(stock): drop symbol cache 2026-06-25 17:30:57 +07:00
tiennm99 412d25b19e fix(stock): drop yahoo price fallback 2026-06-25 17:16:54 +07:00
tiennm99 006ad2b676 fix(stock): expose ssi quote response errors 2026-06-25 16:12:12 +07:00
tiennm99 78e51157d7 fix(stock): use ssi price provider 2026-06-25 15:51:33 +07:00
tiennm99 c0cfcfb8d5 fix(modules): fetch stats prices sequentially to reuse pooled connections
Parallelizing the per-symbol fetches opened N simultaneous TLS handshakes into
an empty connection pool. On the memory-constrained Lambda (256MB ~0.15 vCPU)
those CPU-bound handshakes thrashed and each exceeded the per-fetch timeout, so
every ticker rendered "(no price)". Sequential fetches reuse the price client's
keep-alive connection (one handshake), which is why the code was sequential by
design.

- revert stock and coin stats loops to sequential (keep the reply-budget
  sub-context and 3s per-fetch timeout)
- log per-symbol fetch failures instead of silently swallowing them
2026-06-25 14:28:25 +07:00
tiennm99 958da76d33 fix(modules): reserve reply budget and cap price-fetch timeouts in stats handlers
Stats handlers reused the single bounded update context for both upstream
price fetches and the final Telegram reply, while per-upstream HTTP timeouts
equalled the whole-handler budget. One slow upstream drained the deadline and
the reply failed with "context deadline exceeded" (observed on /stock_stats).

- add chathelper.FetchContext: fetches run under a child context that reserves
  a tail of the deadline for the reply, which is sent on the original context
- cap kbs/coin/gold/vnappmob HTTP timeouts at 3s so one hung upstream cannot
  consume the reply budget
- fetch held stock/coin prices concurrently (bounded) so total latency tracks
  the slowest single fetch instead of their sum; per-symbol failures degrade to
  a "no price" line and the summary still sends
2026-06-25 14:07:59 +07:00
tiennm99 32417e4196 refactor(stock): rename trading module to stock
Rename the `trading` module to `stock` across code, config, and docs for
naming consistency with the sibling coin/gold modules.

- Module: internal/modules/trading -> internal/modules/stock (package,
  factory, registry key in cmd/server)
- Commands: trade_* -> stock_* (telegram-commands.json)
- Env/SAM params: TRADING_INCOME_EVENTS_* -> STOCK_INCOME_EVENTS_*
- ModulesCSV updated in template.yaml, samconfig.toml, deploy.yml
- Add cmd/migrate-stock-key: idempotent, non-destructive DynamoDB
  partition copy (pk=trading -> pk=stock) with dry-run default

Production DynamoDB data already migrated (8 keys: 2 portfolios + 6
symbol-cache rows); old trading partition retained as rollback snapshot.
2026-06-12 14:52:12 +07:00