Commit Graph
137 Commits
Author SHA1 Message Date
tiennm99 2090bfc911 refactor(storage): store mongo value as JSON string, not BinData
Persist the KV value field as a BSON string so it is directly readable in
the Atlas/Compass UI, matching DynamoDB's String storage. Reads still accept
BSON binary as a backward-compat fallback. Non-UTF-8 callers must encode
upstream, same constraint as DynamoDB; all current callers write JSON.
2026-06-28 10:50:41 +07:00
tiennm99 24a51f1e86 docs(plan): update self-host phases with completion status and implementation details
Mark phases 1–5 (MongoDB, cron, polling, migration, decommission) as completed.
Update phase files with finalized implementation notes and test coverage summaries.
2026-06-28 09:58:41 +07:00
tiennm99 15343f6fa7 docs(selfhost): add Coolify deploy + AWS decommission guides; retire AWS docs
Add comprehensive Coolify deployment guide with MongoDB Atlas + networking setup.
Add AWS decommission runbook for safe teardown. Update AWS guides to note
deprecation. Update main README with self-hosted quickstart and architecture overview.
2026-06-28 09:58:37 +07:00
tiennm99 b0b4b4b4c0 feat(selfhost): containerize for Coolify + decommission AWS deploy
Add multi-stage Dockerfile, docker-compose.yml for local dev, .env.example template,
and Makefile helpers. Disable GitHub Actions AWS deploy workflow. Supports Coolify
container orchestration for self-hosted deployments.
2026-06-28 09:58:32 +07:00
tiennm99 3f4802b24c feat(migrate): add DynamoDB-to-MongoDB data migrator
Add standalone migrator tool with scan-and-transform logic for moving persisted
state from DynamoDB to MongoDB. Includes tests and README with usage instructions.
2026-06-28 09:58:28 +07:00
tiennm99 5f8819ae46 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 884957cce4 feat(server): wire MongoDB + cron + polling; rename owner/admin envs
Wire MongoDB client and cron scheduler into server initialization. Rename
TELEGRAM_OWNER to TELEGRAM_ADMIN_ID and SLACK_OWNER to SLACK_ADMIN_ID
for clarity. Enable long-polling as default with cron scheduler for self-hosted.
2026-06-28 09:58:20 +07:00
tiennm99 213b2651be feat(telegram): switch to long polling, remove webhook path
Replace webhook-based updates with long-polling GetUpdates loop. Eliminates
external HTTP endpoint requirement and simplifies self-hosted deployments.
Removes webhook.go and associated webhook routing from server.
2026-06-28 09:58:16 +07:00
tiennm99 f66dd61a8b feat(cron): add in-process cron scheduler
Add robfig/cron-based task scheduler with per-UTC-date idempotency guard. Enables
scheduled jobs (e.g., daily price checks) without external scheduler dependency.
Module interface updated to support cron registration.
2026-06-28 09:58:12 +07:00
tiennm99 a4c6d2f95c feat(storage): add MongoDB KVProvider backend
Add MongoDB-backed storage provider with connection pooling, key-value operations
(get, set, delete), and comprehensive test coverage. Integrates mongo-driver
dependency for self-hosted deployments.
2026-06-28 09:58:07 +07:00
tiennm99 b2417be7c3 docs(selfhost): long polling, minimal env surface, AWS decommission scope
- Telegram transport: long polling only (delete webhook code path)
- Mongo auto-selected from MONGO_URL; in-process cron always-on
  (drop KV_PROVIDER, CRON_MODE, PORT from required env)
- Drop stock/coin/gold API URL overrides (use coded providers);
  remove stock income-events feature + FireAnt token
- Gold VNAppMob key auto-fetched/cached in DB (no env)
- Rename OWNER_ID, ADMIN_IDS; add Phase 5 AWS full decommission
- Final env: TELEGRAM_BOT_TOKEN, MONGO_URL, MONGO_DATABASE, MODULES,
  OWNER_ID, ADMIN_IDS (+ optional GEMINI_API_KEY)
- Red-team (15 findings) + validation (5 sessions) logged
2026-06-27 21:35:12 +07:00
tiennm99 c673cd5278 docs(selfhost): plan Coolify + MongoDB Atlas self-host with AWS decommission
Add 5-phase plan to self-host on Coolify (docker-compose) with a MongoDB
Atlas backend, an in-process cron scheduler, DynamoDB->Atlas migration,
and full AWS teardown. Red-teamed and validated; decommission scope
verified against live AWS/Cloudflare accounts. Include free-tier audit
and S3-elimination research reports. Ignore wrangler local cache.
2026-06-27 20:46:43 +07:00
tiennm99 c1530af018 refactor(stock): drop symbol cache 2026-06-25 17:30:57 +07:00
tiennm99 475d149545 docs(stock): add price provider research 2026-06-25 17:17:08 +07:00
tiennm99 350f1efee1 fix(stock): drop yahoo price fallback 2026-06-25 17:16:54 +07:00
tiennm99 35372d25d7 fix(stock): expose ssi quote response errors 2026-06-25 16:12:12 +07:00
tiennm99 5e8f457995 docs(stock): record ssi provider research 2026-06-25 15:52:43 +07:00
tiennm99 e15f6ae1f1 fix(stock): use ssi price provider 2026-06-25 15:51:33 +07:00
tiennm99 d02a110d8e 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 97f376025d 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 0c649e3963 docs(plan): add coin sell message plan 2026-06-20 09:52:35 +07:00
tiennm99 68cc1486ea fix(coin): improve sell insufficient message 2026-06-20 09:52:23 +07:00
tiennm99 919fa74665 fix(coin): sell command accepts USD amount with dust and zero-price guards
- Change /coin_sell semantics from quantity to USD amount

- Add price-validity and dust-quantity guards to buy/sell

- Improve usage text and error messages

- Add tests for invalid amount, dust, zero price, and insufficient holdings
2026-06-16 17:27:39 +07:00
tiennm99 9eef87ad52 fix(coin): use Binance public market-data endpoint data-api.binance.vision 2026-06-15 14:09:11 +07:00
tiennm99 af993d640d docs(plans): add VNAppMob key parsing bug-fix plan 2026-06-15 12:20:44 +07:00
tiennm99 67387ff350 fix(gold): parse VNAppMob JWT object wrapper 2026-06-15 12:20:40 +07:00
tiennm99 c889d77472 fix(gold): use GET for VNAppMob key refresh endpoint
VNAppMob /api/request_api_key returns 405 for POST and accepts GET.
2026-06-15 11:17:50 +07:00
tiennm99 abde3a1c87 feat(gold): remove XAU/USD fallback and use VNAppMob SJC only 2026-06-15 11:04:06 +07:00
tiennm99 ae2b97ed26 chore(plans): add VNAppMob integration plan and completion report 2026-06-15 10:49:19 +07:00
tiennm99 57356ac312 docs(gold): document VNAppMob SJC pricing and env vars 2026-06-15 10:49:19 +07:00
tiennm99 b37a8dcd6f feat(gold): integrate VNAppMob SJC gold price with auto-refresh API key 2026-06-15 10:49:19 +07:00
tiennm99 2dc78733a1 chore: remove one-time stock-key migration tool
Migration complete and verified in production; the trading->stock
DynamoDB partition copy is no longer needed and the old trading rows
have been deleted.
2026-06-12 15:46:03 +07:00
tiennm99 5f0f6f3fcd fix(migrate): check fmt.Fprintf return to satisfy errcheck lint 2026-06-12 15:12:07 +07:00
tiennm99 e6ad2891dd 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
tiennm99 8b4690df6a fix(deploy): include coin module in ModulesCSV overrides
coin was registered in the catalog and template default but absent from
the ModulesCSV override in both deploy.yml and samconfig.toml, so the
deployed Lambda never loaded it and all coin_* commands went unregistered.

Add a registration checklist to docs/deploy-aws.md to prevent recurrence.
2026-06-12 11:22:16 +07:00
tiennm99 73be8415e7 fix(coin): accept symbol-first trades 2026-06-12 11:07:27 +07:00
tiennm99 31f6bc0a32 feat(coin): register telegram commands 2026-06-12 10:53:19 +07:00
tiennm99 3cb176d5b2 feat(coin): add crypto paper trading 2026-06-12 10:47:02 +07:00
tiennm99 89ea8f428d feat(gold): add gold commands to Telegram menu 2026-06-11 22:28:24 +07:00
tiennm99 2be3303563 fix(deploy): include gold module in CI ModulesCSV override
CI's --parameter-overrides replaces samconfig.toml values, so every
push reverted the stack to the pre-gold module list.
2026-06-11 22:21:19 +07:00
tiennm99 1293377584 feat(gold): add multi-provider gold price fallback chain
Replace goldprice.org (403s datacenter IPs) with a provider chain:
gold-api.com -> Swissquote public quotes -> NBP daily fixing (PLN/gram
converted via the shared FX table). Per-provider failures are logged;
a full-chain outage surfaces as a retryable error instead of the
silent no-price reply.
2026-06-11 22:11:30 +07:00
tiennm99 e099e8a766 fix(deploy): enable gold module in ModulesCSV 2026-06-11 21:57:05 +07:00
tiennm99 1c74cfc9c6 fix(gold): drop redundant embedded selectors in portfolio tests 2026-06-11 21:49:03 +07:00
tiennm99 3cad105a81 fix(storage): report missing CAS support as unsupported instead of conflict
- prefix.go: return errors.ErrUnsupported when inner store lacks CompareAndSwap, enabling fail-fast instead of infinite retries
- Adds comprehensive CAS semantics test coverage for all KV backends:
  * memory_kv_test.go: new tests for basic operations and CAS failures
  * prefix_test.go: tests for wrapped CAS errors and unsupported operations
  * dynamodb_kv_test.go, firestore_kv_test.go: CAS failure scenarios
- portfolio_test.go: test retry exhaustion, business-error short-circuit, concurrent updates, and fail-fast on unsupported CAS
2026-06-11 21:40:16 +07:00
tiennm99 0a795b1436 feat(gold): add compare-and-swap portfolio updates with multi-backend support
Implement atomic UpdatePortfolio with retry pattern for concurrent-safe updates.
Add CAS support to DynamoDB, Firestore, Memory, and prefix stores.
2026-06-11 21:12:58 +07:00
tiennm99 a826525145 feat(gold): add /gold_price command showing spot price in USD and VND
Read-only price lookup. Displays XAU USD/oz, USD/VND rate, and VND/luong.
No arguments, no portfolio mutation, no keylock needed.
2026-06-11 18:13:39 +07:00
tiennm99 2304657cb6 feat(gold): add gold paper trading module
Opt-in module for gold paper trading with VND currency.
Commands: /gold_topup, /gold_buy, /gold_sell, /gold_stats.
Pricing: spot XAU USD converted to VND per luong via GoldPrice.org + ExchangeRate-API.
Features: FX caching, dust normalization (1e-9), HTTPS-only URL validation,
per-user key locking, namespace isolation from trading module.
2026-06-11 17:13:02 +07:00
tiennm99 7c74917d80 fix: simplify trade income event fetcher 2026-06-05 14:26:57 +07:00
tiennm99 340172206a feat: add trade income events check 2026-06-05 14:21:38 +07:00
tiennm99 8b6f8b9ce7 feat: register trade income commands 2026-06-05 13:58:22 +07:00