- FastAPI backend mit Domain-Check, TLD-Pricing, User-Management - Next.js frontend mit modernem UI - Sortierbare TLD-Tabelle mit Mini-Charts - Domain availability monitoring - Subscription tiers (Starter, Professional, Enterprise) - Authentication & Authorization - Scheduler für automatische Domain-Checks
140 lines
4.3 KiB
Python
140 lines
4.3 KiB
Python
"""Subscription model."""
|
|
from datetime import datetime
|
|
from enum import Enum
|
|
from sqlalchemy import String, DateTime, ForeignKey, Integer, Boolean, Enum as SQLEnum
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.database import Base
|
|
|
|
|
|
class SubscriptionTier(str, Enum):
|
|
"""Subscription tiers matching frontend pricing."""
|
|
STARTER = "starter" # Free
|
|
PROFESSIONAL = "professional" # $4.99/mo
|
|
ENTERPRISE = "enterprise" # $9.99/mo
|
|
|
|
|
|
class SubscriptionStatus(str, Enum):
|
|
"""Subscription status."""
|
|
ACTIVE = "active"
|
|
CANCELLED = "cancelled"
|
|
EXPIRED = "expired"
|
|
PENDING = "pending"
|
|
|
|
|
|
# Plan configuration
|
|
TIER_CONFIG = {
|
|
SubscriptionTier.STARTER: {
|
|
"name": "Starter",
|
|
"price": 0,
|
|
"domain_limit": 3,
|
|
"check_frequency": "daily", # daily, hourly
|
|
"history_days": 0, # No history
|
|
"features": {
|
|
"email_alerts": True,
|
|
"priority_alerts": False,
|
|
"full_whois": False,
|
|
"expiration_tracking": False,
|
|
"api_access": False,
|
|
"webhooks": False,
|
|
}
|
|
},
|
|
SubscriptionTier.PROFESSIONAL: {
|
|
"name": "Professional",
|
|
"price": 4.99,
|
|
"domain_limit": 25,
|
|
"check_frequency": "daily",
|
|
"history_days": 30,
|
|
"features": {
|
|
"email_alerts": True,
|
|
"priority_alerts": True,
|
|
"full_whois": True,
|
|
"expiration_tracking": True,
|
|
"api_access": False,
|
|
"webhooks": False,
|
|
}
|
|
},
|
|
SubscriptionTier.ENTERPRISE: {
|
|
"name": "Enterprise",
|
|
"price": 9.99,
|
|
"domain_limit": 100,
|
|
"check_frequency": "hourly",
|
|
"history_days": -1, # Unlimited
|
|
"features": {
|
|
"email_alerts": True,
|
|
"priority_alerts": True,
|
|
"full_whois": True,
|
|
"expiration_tracking": True,
|
|
"api_access": True,
|
|
"webhooks": True,
|
|
}
|
|
},
|
|
}
|
|
|
|
|
|
class Subscription(Base):
|
|
"""Subscription model for tracking user plans."""
|
|
|
|
__tablename__ = "subscriptions"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True, index=True)
|
|
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), unique=True, nullable=False)
|
|
|
|
# Plan details
|
|
tier: Mapped[SubscriptionTier] = mapped_column(
|
|
SQLEnum(SubscriptionTier), default=SubscriptionTier.STARTER
|
|
)
|
|
status: Mapped[SubscriptionStatus] = mapped_column(
|
|
SQLEnum(SubscriptionStatus), default=SubscriptionStatus.ACTIVE
|
|
)
|
|
|
|
# Limits
|
|
domain_limit: Mapped[int] = mapped_column(Integer, default=3)
|
|
|
|
# Payment info (for future integration)
|
|
payment_reference: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
|
|
# Dates
|
|
started_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
expires_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
cancelled_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
|
|
# Relationship
|
|
user: Mapped["User"] = relationship("User", back_populates="subscription")
|
|
|
|
@property
|
|
def is_active(self) -> bool:
|
|
"""Check if subscription is currently active."""
|
|
if self.status != SubscriptionStatus.ACTIVE:
|
|
return False
|
|
if self.expires_at and self.expires_at < datetime.utcnow():
|
|
return False
|
|
return True
|
|
|
|
@property
|
|
def config(self) -> dict:
|
|
"""Get configuration for this subscription tier."""
|
|
return TIER_CONFIG.get(self.tier, TIER_CONFIG[SubscriptionTier.STARTER])
|
|
|
|
@property
|
|
def max_domains(self) -> int:
|
|
"""Get maximum allowed domains for this subscription."""
|
|
return self.config["domain_limit"]
|
|
|
|
@property
|
|
def check_frequency(self) -> str:
|
|
"""Get check frequency for this subscription."""
|
|
return self.config["check_frequency"]
|
|
|
|
@property
|
|
def history_days(self) -> int:
|
|
"""Get history retention days. -1 = unlimited."""
|
|
return self.config["history_days"]
|
|
|
|
def has_feature(self, feature: str) -> bool:
|
|
"""Check if subscription has a specific feature."""
|
|
return self.config.get("features", {}).get(feature, False)
|
|
|
|
def __repr__(self) -> str:
|
|
return f"<Subscription {self.tier.value} for user {self.user_id}>"
|