Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
Priorität 1 (Kritisch): - Pricing Page: Stripe Checkout-Button mit API-Anbindung - TLD Price Alert API + Frontend-Integration mit Toggle - Blog Newsletter-Formular mit API-Anbindung Priorität 2 (Wichtig): - Favicon + Manifest.json für PWA-Support - Dashboard: Stripe Billing Portal Link für zahlende Kunden - Upgrade-Button für Scout-User Priorität 3 (CI/CD): - GitHub Actions CI Pipeline (lint, build, docker, security) - GitHub Actions Deploy Pipeline (automated SSH deployment) Neue Backend-Features: - Price Alert Model + API (/api/v1/price-alerts) - Toggle, Status-Check, CRUD-Operationen Updates: - README.md mit vollständiger API-Dokumentation - Layout mit korrektem Manifest-Pfad
57 lines
2.1 KiB
Python
57 lines
2.1 KiB
Python
"""Price Alert model for TLD price notifications."""
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
from sqlalchemy import String, Float, Boolean, DateTime, Integer, ForeignKey, UniqueConstraint
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.database import Base
|
|
|
|
|
|
class PriceAlert(Base):
|
|
"""
|
|
Price Alert model for tracking user's TLD price subscriptions.
|
|
|
|
Users can subscribe to price alerts for specific TLDs and get notified
|
|
when prices change by a certain threshold.
|
|
"""
|
|
|
|
__tablename__ = "price_alerts"
|
|
__table_args__ = (
|
|
UniqueConstraint('user_id', 'tld', name='unique_user_tld_alert'),
|
|
)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True, index=True)
|
|
|
|
# User who created the alert
|
|
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), nullable=False)
|
|
|
|
# TLD to monitor (without dot, e.g., "com", "io")
|
|
tld: Mapped[str] = mapped_column(String(50), index=True, nullable=False)
|
|
|
|
# Alert settings
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
|
|
# Optional: only alert if price drops below this threshold
|
|
target_price: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
|
|
|
|
# Optional: only alert if price changes by this percentage
|
|
threshold_percent: Mapped[float] = mapped_column(Float, default=5.0) # 5% default
|
|
|
|
# Track last notification to avoid spam
|
|
last_notified_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
|
|
last_notified_price: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
|
|
|
|
# Timestamps
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
|
|
)
|
|
|
|
# Relationship to user
|
|
user: Mapped["User"] = relationship("User", backref="price_alerts")
|
|
|
|
def __repr__(self) -> str:
|
|
status = "active" if self.is_active else "paused"
|
|
return f"<PriceAlert user={self.user_id} tld=.{self.tld} ({status})>"
|
|
|