Файли
rilaxik 6245213110
ci / test (push) Successful in 34s
pre mvp (#1)
Reviewed-on: #1
Co-authored-by: Danya H <[email protected]>
2026-11-08 18:55:18 +00:00

5.1 KiB

Architecture

Context

Telegram user
     |
     | updates, long polling
     v
+-------------+        +------------------+
|  bot process| <----> |  Telegram Bot API|
+------+------+        +------------------+
       |
       | GORM
       v
+-------------+
|  PostgreSQL |
+-------------+

One bot process. Telegram is an untrusted input source and an output channel, never a store. PostgreSQL is the only stateful dependency.

Packages

cmd/bot/               composition root: config, wiring, run loop, shutdown
internal/config/       environment parsing and validation
internal/domain/       entities, enums, invariants, domain errors
internal/service/      use cases: users, lists, items, access, sessions
internal/repository/   GORM repository implementations
internal/database/     connection setup, pool tuning, migrations
internal/telegram/      telego routes, feature handlers, keyboards, rendering
internal/events/       publisher interface and no-op implementation
docs/                  architecture, infrastructure, plan, notes
Package Responsibility
cmd/bot Reads config, constructs concrete types, injects them, starts polling, handles SIGTERM.
config Loads env and .env, validates required values, fails fast.
domain Entities and rules: list ownership, item status, urgency, reservation. No I/O.
service Use cases and authorization. Owns transactions. Declares repository interfaces.
repository GORM models and queries. Implements service interfaces.
database Opens the pool, sets limits, exposes migration entry point.
telegram Routes and middleware; feature subpackages own commands, callbacks, and views.
events Publisher seam for future notifications and activity feeds.

Telegram layout

telegram/
  bot.go, routes.go, middleware.go   lifecycle, routing, identity, bot-access gate, ordering
  shared/                            sender, reply keyboard, callback codec, user context, pending text router
  menu/                              /start, /help, /cancel
  access/                            owner /allow and /kick commands
  list/                              list index, create, rename, delete
  item/                              list menu, paginated item list, item screens, prompts
  share/                             owner share management, pending shares

Features register their own telegohandler routes. All callback data is built and validated in shared; feature packages only wrap the typed builders. Free-text prompts are dispatched through shared.PendingRouter, so the root text handler does not grow with each feature. The item package owns the list detail screen because it renders item rows and pagination; the list package delegates to it after create and rename. The share package owns share management; the item list menu links to it for owners.

The root middleware gate checks bot access before any feature runs. The owner comes from BOT_OWNER_ID; everyone else must have a row in bot_access. Usernames are only stored on access grants so pending grants can be resolved, and are refreshed when the user contacts the bot.

Layering

cmd/bot
   |
telegram
   |
service
   |
domain

Rules:

  • domain imports only the standard library.
  • service imports domain and declares the repository interfaces it needs.
  • repository imports domain and GORM, and implements those interfaces.
  • telegram imports service and domain. It never imports repository.
  • cmd/bot is the only place that knows concrete implementations.
  • Dependencies point inward. Nothing calls from service back into telegram.

This is manual dependency injection. Constructors return concrete types; interfaces are declared at the consumer. A DI library is unnecessary at this size.

Domain summary

  • bot_access: grants bot access by numeric Telegram ID, or by username until the matching user contacts the bot.
  • users: one row per allowed Telegram user, keyed by telegram_id.
  • lists: owned by exactly one user.
  • list_shares: grants a user reader or editor access to a list.
  • items: belong to a list, have status (open/done), urgency (low/normal/high), and at most one reserver.
  • pending_shares: shares granted by username before that user contacts the bot.

Bot access is checked once per update before a user row is ensured. The owner is always allowed. After the user row is ensured, pending shares that match the user's Telegram ID or username are activated. One Authorize(ctx, userID, listID, action) call remains the source of truth for list access. Revoking bot access also removes the user's shares; owned lists are never touched.

Schema, access matrix, callback format, and use-case details live in docs/temp-notes.md.