WeatherGuard: The Telegram Weather Bot That Only Talks to People You Approve
A NestJS and React monorepo that turns weather data into a gated alert system, using Clerk, Telegram deep links, cron scheduling, and a strict user state machine.
- WeatherGuard treats alerts as an access-control problem, not a forecasting problem.
- A Clerk session becomes a Telegram identity through deep linking, so the system never asks users to paste a code by hand.
- Approval, chat binding, and notification toggles are separate gates, which makes the delivery path safer and easier to reason about.
- The repo is a prototype, but its scheduler, guards, and fallback logic already resemble a small notification infrastructure.
Most weather tools answer a simple question: what is the forecast? WeatherGuard asks a stricter one: who is allowed to hear it? That shift changes everything. The app becomes a permissioned delivery system, with weather data as the payload and Telegram as the channel.
The real product is control, not forecasts
That matters for any group that needs private alerts: a team watching travel conditions, a club coordinating event weather, or a small organization that does not want to broadcast updates in public. WeatherGuard sits in the narrow space between a weather feed and a private message channel. It is a notification layer with a gate, not a generic dashboard.
The codebase reflects that idea. The repository is split into an /api service built with NestJS and an /admin app built with React and Vite. The split is practical, but the more interesting part is that the backend owns the rules of delivery while the frontend mainly handles identity, approval, and connection.
A three-step identity bridge from web app to Telegram chat
The user state machine keeps notifications separate from approval
The user model is more disciplined than a typical bot project needs to be. Users move through PENDING, APPROVED, or REJECTED, but approval is not the same as delivery. The schema also tracks telegramChatId and notificationsEnabled, which lets the system remember that a user is allowed in while still letting them opt out of alerts.
| State | Can receive alerts? | Why it matters |
|---|---|---|
| Pending | No | The user exists, but a moderator has not granted access. |
| Approved with notifications on | Yes | This is the only path that reaches the scheduler. |
| Approved with notifications off | No | The user stays approved, but delivery stops without revoking access. |
| Rejected | No | The system keeps the relationship closed. |
That separation is subtle, and it is the kind of detail that makes a prototype feel like a product instead of a demo. It prevents approval from being overloaded with preference, and it prevents preference from being overloaded with trust.
The scheduler is the heartbeat
The delivery engine runs on a minute-by-minute cron job. Each tick fetches weather, loads the approved recipient set, and filters again before anything is sent. In other words, the system does not trust a single database flag. It checks the whole chain every time.
@Cron('*/1 * * * *')
async handleWeatherUpdates() {
const weather = await this.weatherService.getCurrentWeather();
const users = await this.usersService.getApprovedUsers();
const recipients = users.filter(user =>
user.status === UserStatus.APPROVED &&
user.telegramChatId &&
user.notificationsEnabled
);
for (const user of recipients) {
await this.telegramService.sendWeatherUpdate(user.telegramChatId, weather);
}
}
That tiny filter is the whole product in miniature. It says the system cares about three things before it sends a message: the person is approved, the Telegram binding exists, and alerts are enabled. Everything else is noise.
Why the system is harder to break than it looks
The repo layers its defenses. ClerkAuthGuard verifies browser identity. AdminGuard limits sensitive actions like approvals. The backend also uses role checks, fallback weather data, and retry logic for Telegram delivery. None of those pieces is magical on its own, but together they reduce the chance that a bad state turns into a bad send.
| Layer | What it protects | What it prevents |
|---|---|---|
| Clerk auth | Browser access | Unauthenticated admin actions |
| Admin guard | Moderation endpoints | Non-admins approving users |
| State machine | Recipient eligibility | Sending to unreviewed users |
| Notification toggle | User preference | Spamming someone who opted out |
| Retry logic | Telegram delivery | Transient network failures |
The fallback weather path is worth noting too. If the external API fails or the key is missing, the service keeps the system alive with substitute data instead of collapsing the scheduler. That is a pragmatic choice. It keeps the alerting pipeline operational even when the weather source is not.
What WeatherGuard is really competing with
WeatherGuard is not competing with a full weather platform. It is competing with the awkward glue people usually build around notifications. That includes smart home automations, one-off API wrappers, and no-code tools that can send a weather-triggered message but do not really understand access control.
| Option | Best for | Access control | Self-hosted | Shape of the product |
|---|---|---|---|---|
| WeatherGuard | Private weather alerts | Built in | Yes | Permissioned delivery system |
| Home Assistant weather automations | Broad home automation | Indirect | Yes | General automation platform |
| wttr.in | Quick weather lookup | None | Yes | Weather data surface |
| Zapier or IFTTT | Simple no-code triggers | Limited | No | Hosted automation glue |
That comparison makes the niche clear. WeatherGuard is narrow on purpose. It is built for a case where the right answer is not "send an alert" but "send it only to the people who were explicitly admitted."
The trade-off: elegant pattern, early-stage product
The repo looks disciplined, but the public surface is still thin. There is no broad ecosystem, no visible author footprint to anchor a larger narrative, and no evidence that this is meant to be a finished consumer product. That is not a flaw. It is a signal that the interesting part here is the architecture, not the market.
Seen that way, WeatherGuard is a strong prototype. It shows how to bind web identity to a chat channel, how to separate approval from delivery, and how to build a notification path that fails closed instead of open. That is a useful pattern even if you never care about weather.