Files
bambuddy/PLAN.md
T

187 lines
6.1 KiB
Markdown

# Notifications Feature Implementation Plan
## Overview
Add push notifications for print events (start, complete, fail) with support for multiple notification providers.
## Supported Providers (Initial Release)
1. **CallMeBot/WhatsApp** - Free, uses HTTP API with phone number + API key
2. **ntfy** - Self-hosted or ntfy.sh, simple HTTP POST
3. **Pushover** - Commercial ($5 one-time), HTTP API with user key + app token
4. **Telegram** - Free bot API, requires bot token + chat ID
5. **Email (SMTP)** - Universal fallback
## Database Design
### New Table: `notification_providers`
```sql
CREATE TABLE notification_providers (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL, -- User-defined name ("My WhatsApp")
provider_type TEXT NOT NULL, -- "callmebot", "ntfy", "pushover", "telegram", "email"
enabled BOOLEAN DEFAULT true,
-- Provider-specific config (JSON or individual fields)
config TEXT NOT NULL, -- JSON: {"phone": "+1234", "apikey": "xxx"}
-- Event triggers (which events send notifications)
on_print_start BOOLEAN DEFAULT false,
on_print_complete BOOLEAN DEFAULT true,
on_print_failed BOOLEAN DEFAULT true,
-- Optional: Link to specific printer (NULL = all printers)
printer_id INTEGER REFERENCES printers(id) ON DELETE SET NULL,
-- Timestamps
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
```
### Config JSON Structure by Provider
```python
# CallMeBot/WhatsApp
{"phone": "+1234567890", "apikey": "123456"}
# ntfy
{"server": "https://ntfy.sh", "topic": "my-printer", "auth_token": "optional"}
# Pushover
{"user_key": "xxx", "app_token": "yyy", "priority": 0}
# Telegram
{"bot_token": "123:ABC", "chat_id": "12345678"}
# Email (SMTP)
{"smtp_server": "smtp.gmail.com", "smtp_port": 587, "username": "x", "password": "y", "from_email": "x@gmail.com", "to_email": "dest@example.com"}
```
## Backend Implementation
### 1. Model: `backend/app/models/notification.py`
- SQLAlchemy model for `notification_providers` table
- Relationship to Printer (optional, nullable)
### 2. Schema: `backend/app/schemas/notification.py`
- `NotificationProviderBase` - Common fields
- `NotificationProviderCreate` - For creating new providers
- `NotificationProviderUpdate` - For partial updates
- `NotificationProviderResponse` - API response with id/timestamps
- `NotificationTestRequest` - For testing notifications
### 3. Service: `backend/app/services/notification_service.py`
Core notification dispatcher with provider implementations:
```python
class NotificationService:
async def send_notification(self, provider: NotificationProvider, event: str, data: dict) -> bool
async def on_print_start(self, printer_id: int, data: dict, db: AsyncSession)
async def on_print_complete(self, printer_id: int, status: str, data: dict, db: AsyncSession)
# Provider-specific methods
async def _send_callmebot(self, config: dict, message: str) -> bool
async def _send_ntfy(self, config: dict, title: str, message: str) -> bool
async def _send_pushover(self, config: dict, title: str, message: str) -> bool
async def _send_telegram(self, config: dict, message: str) -> bool
async def _send_email(self, config: dict, subject: str, body: str) -> bool
```
### 4. Routes: `backend/app/api/routes/notifications.py`
```
GET /notifications/ - List all providers
POST /notifications/ - Create provider
GET /notifications/{id} - Get provider details
PATCH /notifications/{id} - Update provider
DELETE /notifications/{id} - Delete provider
POST /notifications/{id}/test - Send test notification
POST /notifications/test-config - Test config before saving
```
### 5. Integration in `main.py`
Add calls to notification service in existing event handlers:
- `on_print_start()` - After smart_plug_manager call (line ~244)
- `on_print_complete()` - After archive update (line ~580)
## Frontend Implementation
### 1. API Client: `frontend/src/api/client.ts`
Add types and API methods for notification providers.
### 2. Components
- `NotificationProviderCard.tsx` - Display single provider with enable/disable toggle
- `AddNotificationModal.tsx` - Modal for adding/editing providers with provider-specific forms
### 3. Settings Page Integration
Add "Notifications" section in SettingsPage.tsx (similar to Smart Plugs section):
- List of configured providers
- Add button
- Per-provider enable/disable
- Test button
- Event toggles (start/complete/failed)
## Message Templates
### Print Started
```
🖨️ Print Started
{printer_name}: {filename}
Estimated time: {est_time}
```
### Print Completed
```
✅ Print Completed
{printer_name}: {filename}
Time: {actual_time}
Filament: {filament_used}g
```
### Print Failed
```
❌ Print Failed
{printer_name}: {filename}
Status: {failure_reason}
Progress: {progress}%
```
## Implementation Order
### Phase 1: Backend Core
1. Create notification model with migrations
2. Create notification schema
3. Create notification service with all 5 providers
4. Create notification routes (CRUD + test)
5. Register routes in main.py
6. Integrate into print event handlers
### Phase 2: Frontend
7. Add API types and methods
8. Create NotificationProviderCard component
9. Create AddNotificationModal component
10. Add Notifications section to SettingsPage
### Phase 3: Testing & Polish
11. Test each provider
12. Add error handling and logging
13. Handle network failures gracefully (don't block print events)
## Technical Notes
### Async HTTP Requests
Use `httpx` (already available) for async HTTP calls to notification APIs.
### Error Handling
- Notifications should NEVER block print events
- Log failures but continue processing
- Store last_error and last_success timestamps for UI feedback
### Security
- Store credentials in database (SQLite file already contains access codes)
- Consider encryption for sensitive fields in future
### Rate Limiting
- Debounce rapid events (don't spam on quick start/stop cycles)
- Consider per-provider rate limits
## Questions for User
None - proceeding with the 5 providers as discussed.