Initial commit: Leopost Full — merge di Leopost, Post Generator e Autopilot OS
- Backend FastAPI con multi-LLM (Claude/OpenAI/Gemini) - Publishing su Facebook, Instagram, YouTube, TikTok - Calendario editoriale con awareness levels (PAS, AIDA, BAB...) - Design system Editorial Fresh (Fraunces + DM Sans) - Scheduler automatico, gestione commenti AI, affiliate links Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
156
backend/app/models.py
Normal file
156
backend/app/models.py
Normal file
@@ -0,0 +1,156 @@
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, JSON, String, Text
|
||||
|
||||
from .database import Base
|
||||
|
||||
|
||||
# === Phase 1: Core ===
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
username = Column(String(50), unique=True, nullable=False)
|
||||
hashed_password = Column(String(255), nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
|
||||
class Character(Base):
|
||||
__tablename__ = "characters"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String(100), nullable=False)
|
||||
niche = Column(String(200), nullable=False)
|
||||
topics = Column(JSON, default=list)
|
||||
tone = Column(Text)
|
||||
visual_style = Column(JSON, default=dict)
|
||||
social_accounts = Column(JSON, default=dict)
|
||||
affiliate_links = Column(JSON, default=list)
|
||||
avatar_url = Column(String(500))
|
||||
is_active = Column(Boolean, default=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
|
||||
# === Phase 2: Content Generation ===
|
||||
|
||||
class Post(Base):
|
||||
__tablename__ = "posts"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
character_id = Column(Integer, ForeignKey("characters.id"), nullable=False)
|
||||
content_type = Column(String(20), default="text") # text, image, video, carousel
|
||||
text_content = Column(Text)
|
||||
hashtags = Column(JSON, default=list)
|
||||
image_url = Column(String(500))
|
||||
video_url = Column(String(500))
|
||||
media_urls = Column(JSON, default=list)
|
||||
affiliate_links_used = Column(JSON, default=list)
|
||||
llm_provider = Column(String(50))
|
||||
llm_model = Column(String(100))
|
||||
platform_hint = Column(String(20)) # which platform this was generated for
|
||||
status = Column(String(20), default="draft") # draft, approved, scheduled, published, failed
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
|
||||
# === Phase 4: Affiliate Links ===
|
||||
|
||||
class AffiliateLink(Base):
|
||||
__tablename__ = "affiliate_links"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
character_id = Column(Integer, ForeignKey("characters.id"), nullable=True) # null = global
|
||||
network = Column(String(100), nullable=False) # amazon, clickbank, etc.
|
||||
name = Column(String(200), nullable=False)
|
||||
url = Column(String(1000), nullable=False)
|
||||
tag = Column(String(100))
|
||||
topics = Column(JSON, default=list) # relevant topics for auto-insertion
|
||||
is_active = Column(Boolean, default=True)
|
||||
click_count = Column(Integer, default=0)
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
|
||||
# === Phase 5: Scheduling ===
|
||||
|
||||
class EditorialPlan(Base):
|
||||
__tablename__ = "editorial_plans"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
character_id = Column(Integer, ForeignKey("characters.id"), nullable=False)
|
||||
name = Column(String(200), nullable=False)
|
||||
frequency = Column(String(20), default="daily") # daily, twice_daily, weekly, custom
|
||||
posts_per_day = Column(Integer, default=1)
|
||||
platforms = Column(JSON, default=list) # ["facebook", "instagram", "youtube"]
|
||||
content_types = Column(JSON, default=list) # ["text", "image", "video"]
|
||||
posting_times = Column(JSON, default=list) # ["09:00", "18:00"]
|
||||
start_date = Column(DateTime)
|
||||
end_date = Column(DateTime, nullable=True)
|
||||
is_active = Column(Boolean, default=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
|
||||
class ScheduledPost(Base):
|
||||
__tablename__ = "scheduled_posts"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
plan_id = Column(Integer, ForeignKey("editorial_plans.id"), nullable=True)
|
||||
post_id = Column(Integer, ForeignKey("posts.id"), nullable=False)
|
||||
platform = Column(String(20), nullable=False)
|
||||
scheduled_at = Column(DateTime, nullable=False)
|
||||
published_at = Column(DateTime, nullable=True)
|
||||
status = Column(String(20), default="pending") # pending, publishing, published, failed
|
||||
error_message = Column(Text, nullable=True)
|
||||
external_post_id = Column(String(200), nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
|
||||
# === Phase 6-10: Social Accounts ===
|
||||
|
||||
class SocialAccount(Base):
|
||||
__tablename__ = "social_accounts"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
character_id = Column(Integer, ForeignKey("characters.id"), nullable=False)
|
||||
platform = Column(String(20), nullable=False) # facebook, instagram, youtube, tiktok
|
||||
account_name = Column(String(200))
|
||||
account_id = Column(String(200))
|
||||
access_token = Column(Text)
|
||||
refresh_token = Column(Text, nullable=True)
|
||||
token_expires_at = Column(DateTime, nullable=True)
|
||||
page_id = Column(String(200), nullable=True) # Facebook page ID
|
||||
extra_data = Column(JSON, default=dict) # platform-specific data
|
||||
is_active = Column(Boolean, default=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
|
||||
# === Phase 11: Comment Management ===
|
||||
|
||||
class Comment(Base):
|
||||
__tablename__ = "comments"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
scheduled_post_id = Column(Integer, ForeignKey("scheduled_posts.id"), nullable=True)
|
||||
platform = Column(String(20), nullable=False)
|
||||
external_comment_id = Column(String(200))
|
||||
author_name = Column(String(200))
|
||||
author_id = Column(String(200))
|
||||
content = Column(Text)
|
||||
ai_suggested_reply = Column(Text, nullable=True)
|
||||
approved_reply = Column(Text, nullable=True)
|
||||
reply_status = Column(String(20), default="pending") # pending, approved, replied, ignored
|
||||
replied_at = Column(DateTime, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
|
||||
# === System Settings ===
|
||||
|
||||
class SystemSetting(Base):
|
||||
__tablename__ = "system_settings"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
key = Column(String(100), unique=True, nullable=False)
|
||||
value = Column(JSON)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
Reference in New Issue
Block a user