The deploy workflow no longer relies on a missing AWS_ACCOUNT_ID secret,
preventing invalid assume-role ARNs and matching the repo's documented AWS setup.
Rename:
- Go module github.com/tiennm99/miti99bot-go → github.com/tiennm99/miti99bot
- CloudFormation stack miti99bot-aws-port → miti99bot
- Drop "port", "Cloud Run", "GCP", "cutover", "Phase NN" framing from
active code and docs — project reads as canonical AWS-Lambda from now on.
AWS deploy guide + flow fix:
- New docs/deploy-aws-free-tier-guide.md — Ubuntu 24.04 ARM64 onboarding
with project-local venv (pip awscli + sam-cli), SSM secrets via read -s,
idempotent OIDC provider + role creation, $1 budget alarm.
- Drop sam build from the pipeline — provided.al2023 + makefile builder
expects a Makefile in CodeUri (build/lambda/, the output dir), so the
step always fails. sam deploy --template-file template.yaml now reads
the raw template and zips build/lambda/ directly.
- Rollback section rewritten — use continue-update-rollback /
cancel-update-stack / git-SHA redeploy. Drop the broken
--use-previous-template recipe.
- DynamoDB free-tier row corrected (on-demand is 2.5M read / 1M write
request units, not 25 RCU/WCU).
Updated:
- README.md fully rewritten (drops port/legacy framing, lists modules,
points new users at the free-tier guide).
- aws/README.md retitled "AWS account setup", phase numbers stripped.
- Makefile / .github/workflows/deploy.yml — sam deploy flow.
- samconfig.toml — stack_name = "miti99bot".
- Go comments — Cloud Run → Lambda, Cloud Scheduler → EventBridge
Scheduler, Cloud Logging → CloudWatch Logs.
- Struct field GCPProject → FirestoreProject (env GOOGLE_CLOUD_PROJECT
unchanged).
Plus advisory reports under plans/reports/ from the code-reviewer +
researcher passes that informed the fixes.
Verified: go vet ./..., go build ./..., go test ./... all green.
- golangci-lint-action@v6 doesn't support golangci-lint v2.x; v7 does.
This was the only thing breaking CI; subsequent steps were skipped.
- Firestore emulator step removed for now — storage_test.go skips when
FIRESTORE_EMULATOR_HOST is unset, and the gcloud emulator install
adds 30-60s of CI time for tests not yet on the merge-gating path.
Re-add when storage-layer changes need emulator coverage.
Phase 6 of the 2026-05-09 review remediation plan. Bundle of small
hygiene fixes — none individually urgent but better folded together
than scattered across follow-ups.
- .golangci.yml: enable errcheck/govet/gosec/staticcheck/unused/
ineffassign/gocyclo/misspell/revive. Tuned to the codebase style
(no universal exported-doc requirement, gocyclo cap at 20 to
accommodate handler dispatch). 0 issues across the tree.
- ci.yml: add golangci-lint job + govulncheck (informational).
- Defensive guards:
- registry.go: Module.Name mismatch now errors at Build instead of
silently overwriting (TestBuild_RejectsFactoryNameMismatch).
- cmd/server/main.go: PORT env validated numerically + 0..65535.
- firestore_provider.go: For() re-validates module name; invalid
names return an invalidStore whose every op errors with
ErrInvalidModuleName.
- Dead code removal:
- wordle: gameTTLSeconds const + pickDaily/hashDJB2/todayUTC
helpers + their tests deleted (pickDaily was unused;
daily.go renamed pick_random.go).
- Dependency: golang.org/x/net v0.52.0 -> v0.54.0 (resolves
GO-2026-4918 HTTP/2 infinite-loop CVE).
- Deferred from the original phase plan: Docker digest pinning
(Dependabot handles), per-handler file splits (largest file 279 LOC;
splits would churn for marginal gain).
go test -race -count=1 ./... clean (15 packages); golangci-lint run
clean (0 issues).
Phase 5 of the 2026-05-09 review remediation plan. Closes the
handler-layer test gap (5 modules at 0% coverage in the audit) and
ends the storage-package's CI t.Skip on Firestore emulator tests.
- internal/testutil: Update fixture builders (NewPrivateMessage,
NewGroupMessage, NewSupergroupMessage, NewChannelMessage) plus a
RecordingBot that wraps the real go-telegram/bot.Bot with an
httptest server. The bot library hits the test server instead of
Telegram; multipart form fields are captured per call. Tests assert
on Sent() / LastSent() / AssertSentText().
- Handler tests added: misc (4), util (7), wordle (10), loldle (9),
loldleemoji (8). Cover happy paths, error paths, auth gates,
group-vs-private subject keying, KV side effects.
- Coverage 44.7% -> 69.8% (verified via -coverprofile). All packages
now report coverage in CI output.
- CI: ci.yml installs cloud-firestore-emulator beta component and
starts it on localhost:8090 before go test. Sets
FIRESTORE_EMULATOR_HOST + GOOGLE_CLOUD_PROJECT env so the storage
package's emulator-gated tests execute instead of skipping.
go test -race -count=1 ./... clean across all 15 packages locally.
Implements Phases 02 (partial) and 03 of the go-port-cloud-run plan.
Introduces module framework with per-module KV prefix isolation,
health check endpoint, request timeout protection, and comprehensive
test coverage. Cloud Run deployment deferred to Phase 01.
Security hardening: constant-time secret comparison, cron auth bridge,
and secrets stripped from dependency environment exports. Includes
Dockerfile, GitHub CI workflow (vet + race + build), and integration
tests for module lifecycle.
KV payload cleanup:
- drop lastResultAt from stats (never read)
- drop solved/giveup flags from game state (round is immediately
replaced after finish, making the flags transient noise)
- skip redundant saveGame on winning/giveup/out-of-guesses paths;
startFreshGame overwrites anyway
Code cleanup:
- delete daily.js + daily.test.js (pickDaily/todayUtc were speculative
"future use" — only pickRandom was wired in, inlined into handlers)
- drop the dead switch default in compare.js
- trim file preambles across the module
Docs: rewrite README around current behavior with loldle.net as the
sole data source; update scraper header to match the raw schema.
Node 24 + wrangler 4.x both accept `import ... with { type: "json" }`,
so the generated champions-data.js wrapper is no longer needed.
Drop scripts/build-loldle-data.js and the build:loldle-data npm script.
Scraper writes champions.json only.
loldle.net's JS bundle ships the complete set of classic-mode axes in
plaintext, so ddragon merging is no longer needed. Scraper now produces
the final schema directly.
Schema changes: drop title, skinCount, image, and genre (ddragon-only).
Replace genre (class tags like Fighter/Mage) with species (Human/Darkin/
Vastayan) — the axis loldle.net actually uses. Promote region to a
multi-value field so multi-region champions compare correctly.
Handlers no longer show "Name — Title" on win/giveup.
Adds loldle module with classic-mode champion guessing. Ports comparison
logic from tiennm99/loldle (lib/classic-mode.js) and bundles champion
data from tiennm99/loldle-data. Adds GH Actions workflow that re-syncs
champions.json on cross-repo dispatch from loldle-data.
- Three public commands: /loldle, /loldle_giveup, /loldle_stats
- Per-user daily state + streak stats in KV (3-day TTL on games)
- champions-data.js wrapper sidesteps Node 24 / esbuild disagreement on
JSON import attributes; generator script + npm run build:loldle-data
- register script now tolerates missing .env.deploy (env-file-if-exists)
so Workers Builds can inject env vars directly
- fix(scripts): escape stray */ in migrate.js docstring that broke node
- 16 new unit tests (compare, daily, lookup); dispatcher test updated
for the new command set