# pllist Access-based Telegram bot for creating and managing lists of planned purchases. A user owns lists. A list contains items. Items can be added, marked done, and reserved by the person responsible for buying them. Items carry an urgency level. An owner can share a list with other users as a reader or an editor. Bot access itself is allowlisted: the owner runs `/allow` and `/kick`. The codebase stays small but extensible. - Architecture: `docs/architecture.md` - Infrastructure: `docs/infra.md` - MVP plan: `docs/roadmap-mvp.md` - Other notes: `docs/temp-*.md` ## Stack - Go 1.27 - `github.com/mymmrac/telego` for the Telegram Bot API, long polling - GORM with PostgreSQL - `github.com/joho/godotenv` for local environment loading - Docker Compose for local development - Gitea for version control and CI, Dokploy for deployment ## Commands ```sh cp .env.example .env # fill values make build # build bin/bot make run # run bin/bot go test ./... # unit tests go vet ./... # static checks gofmt -l . # formatting check ``` ## Engineering rules 1. Use constructor injection. Build concrete types in `cmd/bot/main.go` and pass dependencies down. No package-level globals and no `init()` side effects. 2. Define small interfaces where they are consumed, not next to the implementation. 3. Keep business rules in `internal/domain` and `internal/service`. Handlers parse input and render output only. 4. Route every list operation through one authorization function. Do not reimplement access checks in handlers or repositories. 5. Implement item changes as domain methods (`Reserve`, `Release`, `Complete`, `Reopen`, `SetUrgency`). Do not assign state fields from handlers. 6. Apply DRY to behavior: one callback-data codec, one keyboard builder per view, one error-to-message mapper. 7. Use sentinel domain errors (`ErrNotFound`, `ErrForbidden`, `ErrConflict`, `ErrInvalidInput`) and map them in the Telegram layer. Never leak database errors to users. 8. Revalidate authorization on every callback. Callback data is untrusted and limited to 64 bytes. 9. Reserve items with a conditional database update, not read-then-write. 10. Emit future side effects through `events.Publisher`. Services never call Telegram directly. 11. Keep Telegram types out of `domain` and `service`. 12. Test every access-matrix row and every item transition. 13. Never commit secrets. `.env` is ignored; keep `.env.example` current. 14. Update the docs when a design decision changes.