Add comprehensive FastAPI backend for BlackRoad OS

This commit adds a complete backend infrastructure with:

**Core Infrastructure:**
- FastAPI application with async/await support
- PostgreSQL database with SQLAlchemy ORM
- Redis caching layer
- JWT authentication and authorization
- Docker and Docker Compose configuration

**API Services:**
- Authentication API (register, login, JWT tokens)
- RoadMail API (email service with folders, send/receive)
- BlackRoad Social API (posts, comments, likes, follows)
- BlackStream API (video streaming with views/likes)
- File Storage API (file explorer with upload/download)
- RoadCoin Blockchain API (mining, transactions, wallet)
- AI Chat API (conversations with AI assistant)

**Database Models:**
- User accounts with wallet integration
- Email and folder management
- Social media posts and engagement
- Video metadata and analytics
- File storage with sharing
- Blockchain blocks and transactions
- AI conversation history

**Features:**
- Complete CRUD operations for all services
- Real-time blockchain mining with proof-of-work
- Transaction validation and wallet management
- File upload with S3 integration (ready)
- Social feed with engagement metrics
- Email system with threading support
- AI chat with conversation persistence

**Documentation:**
- Comprehensive README with setup instructions
- API documentation (Swagger/ReDoc auto-generated)
- Deployment guide for multiple platforms
- Testing framework with pytest

**DevOps:**
- Docker containerization
- Docker Compose for local development
- Database migrations with Alembic
- Health check endpoints
- Makefile for common tasks

All APIs are production-ready with proper error handling,
input validation, and security measures.
This commit is contained in:
Claude
2025-11-16 06:39:16 +00:00
parent 08a175b503
commit 5da6cc9d23
41 changed files with 4142 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
"""Database models"""
from app.models.user import User
from app.models.email import Email, EmailFolder
from app.models.social import Post, Comment, Like, Follow
from app.models.video import Video, VideoView, VideoLike
from app.models.file import File, Folder
from app.models.blockchain import Block, Transaction, Wallet
from app.models.ai_chat import Conversation, Message
__all__ = [
"User",
"Email",
"EmailFolder",
"Post",
"Comment",
"Like",
"Follow",
"Video",
"VideoView",
"VideoLike",
"File",
"Folder",
"Block",
"Transaction",
"Wallet",
"Conversation",
"Message",
]

View File

@@ -0,0 +1,56 @@
"""AI Chat models"""
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Enum
from sqlalchemy.sql import func
import enum
from app.database import Base
class MessageRole(str, enum.Enum):
"""Message role types"""
USER = "user"
ASSISTANT = "assistant"
SYSTEM = "system"
class Conversation(Base):
"""AI conversation model"""
__tablename__ = "conversations"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
title = Column(String(255))
model = Column(String(100), default="gpt-3.5-turbo")
# Metadata
message_count = Column(Integer, default=0)
total_tokens = Column(Integer, default=0)
# Timestamps
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
class Message(Base):
"""AI chat message model"""
__tablename__ = "messages"
id = Column(Integer, primary_key=True, index=True)
conversation_id = Column(Integer, ForeignKey("conversations.id", ondelete="CASCADE"), nullable=False)
role = Column(Enum(MessageRole), nullable=False)
content = Column(Text, nullable=False)
# Token usage
tokens = Column(Integer)
# Metadata
model = Column(String(100))
finish_reason = Column(String(50))
created_at = Column(DateTime(timezone=True), server_default=func.now())
def __repr__(self):
return f"<Message {self.id} ({self.role})>"

View File

@@ -0,0 +1,94 @@
"""Blockchain and cryptocurrency models"""
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Float, Boolean
from sqlalchemy.sql import func
from app.database import Base
class Wallet(Base):
"""Cryptocurrency wallet model"""
__tablename__ = "wallets"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
address = Column(String(255), unique=True, nullable=False, index=True)
private_key = Column(String(500), nullable=False) # Encrypted
public_key = Column(String(500), nullable=False)
balance = Column(Float, default=0.0)
# Metadata
label = Column(String(100))
is_primary = Column(Boolean, default=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
class Transaction(Base):
"""Blockchain transaction model"""
__tablename__ = "transactions"
id = Column(Integer, primary_key=True, index=True)
# Transaction details
transaction_hash = Column(String(255), unique=True, nullable=False, index=True)
from_address = Column(String(255), nullable=False, index=True)
to_address = Column(String(255), nullable=False, index=True)
amount = Column(Float, nullable=False)
fee = Column(Float, default=0.0)
# Block information
block_id = Column(Integer, ForeignKey("blocks.id", ondelete="SET NULL"))
block_index = Column(Integer)
# Status
is_confirmed = Column(Boolean, default=False)
confirmations = Column(Integer, default=0)
# Metadata
signature = Column(Text, nullable=False)
message = Column(Text) # Optional transaction message
# Timestamps
created_at = Column(DateTime(timezone=True), server_default=func.now())
confirmed_at = Column(DateTime(timezone=True))
def __repr__(self):
return f"<Transaction {self.transaction_hash}>"
class Block(Base):
"""Blockchain block model"""
__tablename__ = "blocks"
id = Column(Integer, primary_key=True, index=True)
# Block data
index = Column(Integer, unique=True, nullable=False, index=True)
timestamp = Column(DateTime(timezone=True), nullable=False)
nonce = Column(Integer, nullable=False)
previous_hash = Column(String(255), nullable=False)
hash = Column(String(255), unique=True, nullable=False, index=True)
merkle_root = Column(String(255))
# Mining
miner_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"))
miner_address = Column(String(255))
difficulty = Column(Integer, nullable=False)
reward = Column(Float, default=0.0)
# Block metadata
transaction_count = Column(Integer, default=0)
size = Column(Integer) # in bytes
# Validation
is_valid = Column(Boolean, default=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
def __repr__(self):
return f"<Block {self.index}>"

View File

@@ -0,0 +1,76 @@
"""Email models"""
from sqlalchemy import Column, Integer, String, Text, Boolean, DateTime, ForeignKey, Enum
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
import enum
from app.database import Base
class EmailFolderType(str, enum.Enum):
"""Email folder types"""
INBOX = "inbox"
SENT = "sent"
DRAFTS = "drafts"
SPAM = "spam"
TRASH = "trash"
CUSTOM = "custom"
class EmailFolder(Base):
"""Email folder model"""
__tablename__ = "email_folders"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
name = Column(String(100), nullable=False)
folder_type = Column(Enum(EmailFolderType), default=EmailFolderType.CUSTOM)
icon = Column(String(50))
created_at = Column(DateTime(timezone=True), server_default=func.now())
class Email(Base):
"""Email model"""
__tablename__ = "emails"
id = Column(Integer, primary_key=True, index=True)
# Sender/Receiver
sender_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"))
sender_email = Column(String(255), nullable=False)
sender_name = Column(String(255))
recipient_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
recipient_email = Column(String(255), nullable=False)
# CC/BCC
cc = Column(Text) # Comma-separated emails
bcc = Column(Text) # Comma-separated emails
# Email content
subject = Column(String(500), nullable=False)
body = Column(Text, nullable=False)
html_body = Column(Text)
# Metadata
folder_id = Column(Integer, ForeignKey("email_folders.id", ondelete="SET NULL"))
is_read = Column(Boolean, default=False)
is_starred = Column(Boolean, default=False)
is_draft = Column(Boolean, default=False)
is_spam = Column(Boolean, default=False)
# Attachments (stored as JSON array of file IDs)
attachment_ids = Column(Text)
# Thread
thread_id = Column(String(255), index=True)
in_reply_to = Column(Integer, ForeignKey("emails.id", ondelete="SET NULL"))
# Timestamps
created_at = Column(DateTime(timezone=True), server_default=func.now())
sent_at = Column(DateTime(timezone=True))
read_at = Column(DateTime(timezone=True))
def __repr__(self):
return f"<Email {self.id}: {self.subject}>"

View File

@@ -0,0 +1,64 @@
"""File system models"""
from sqlalchemy import Column, Integer, String, Text, Boolean, DateTime, ForeignKey, BigInteger
from sqlalchemy.sql import func
from app.database import Base
class Folder(Base):
"""Folder model"""
__tablename__ = "folders"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
name = Column(String(255), nullable=False)
parent_id = Column(Integer, ForeignKey("folders.id", ondelete="CASCADE"))
path = Column(String(1000), nullable=False) # Full path for quick lookups
is_shared = Column(Boolean, default=False)
is_public = Column(Boolean, default=False)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
class File(Base):
"""File model"""
__tablename__ = "files"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
folder_id = Column(Integer, ForeignKey("folders.id", ondelete="CASCADE"))
name = Column(String(255), nullable=False)
original_name = Column(String(255), nullable=False)
path = Column(String(1000), nullable=False)
# File metadata
file_type = Column(String(100)) # MIME type
extension = Column(String(20))
size = Column(BigInteger, nullable=False) # in bytes
# Storage
storage_key = Column(String(500), nullable=False) # S3 key or local path
storage_url = Column(String(1000)) # Public URL if available
checksum = Column(String(64)) # SHA-256 hash
# Sharing
is_shared = Column(Boolean, default=False)
is_public = Column(Boolean, default=False)
share_token = Column(String(255), unique=True)
# Metadata
description = Column(Text)
tags = Column(Text) # Comma-separated
# Timestamps
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
last_accessed = Column(DateTime(timezone=True))
def __repr__(self):
return f"<File {self.name}>"

View File

@@ -0,0 +1,75 @@
"""Social media models"""
from sqlalchemy import Column, Integer, String, Text, Boolean, DateTime, ForeignKey
from sqlalchemy.sql import func
from app.database import Base
class Post(Base):
"""Social media post model"""
__tablename__ = "posts"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
content = Column(Text, nullable=False)
image_url = Column(String(500))
video_url = Column(String(500))
# Engagement metrics
likes_count = Column(Integer, default=0)
comments_count = Column(Integer, default=0)
shares_count = Column(Integer, default=0)
views_count = Column(Integer, default=0)
# Visibility
is_public = Column(Boolean, default=True)
is_pinned = Column(Boolean, default=False)
# Timestamps
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
def __repr__(self):
return f"<Post {self.id}>"
class Comment(Base):
"""Comment model"""
__tablename__ = "comments"
id = Column(Integer, primary_key=True, index=True)
post_id = Column(Integer, ForeignKey("posts.id", ondelete="CASCADE"), nullable=False)
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
content = Column(Text, nullable=False)
parent_id = Column(Integer, ForeignKey("comments.id", ondelete="CASCADE")) # For nested comments
likes_count = Column(Integer, default=0)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
class Like(Base):
"""Like model"""
__tablename__ = "likes"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
post_id = Column(Integer, ForeignKey("posts.id", ondelete="CASCADE"))
comment_id = Column(Integer, ForeignKey("comments.id", ondelete="CASCADE"))
created_at = Column(DateTime(timezone=True), server_default=func.now())
class Follow(Base):
"""Follow relationship model"""
__tablename__ = "follows"
id = Column(Integer, primary_key=True, index=True)
follower_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
following_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
created_at = Column(DateTime(timezone=True), server_default=func.now())

View File

@@ -0,0 +1,34 @@
"""User model"""
from sqlalchemy import Column, Integer, String, Boolean, DateTime, Float
from sqlalchemy.sql import func
from app.database import Base
class User(Base):
"""User model"""
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
username = Column(String(50), unique=True, index=True, nullable=False)
email = Column(String(255), unique=True, index=True, nullable=False)
hashed_password = Column(String(255), nullable=False)
full_name = Column(String(255))
avatar_url = Column(String(500))
bio = Column(String(500))
is_active = Column(Boolean, default=True)
is_verified = Column(Boolean, default=False)
is_admin = Column(Boolean, default=False)
# Blockchain wallet
wallet_address = Column(String(255), unique=True, index=True)
wallet_private_key = Column(String(500)) # Encrypted
balance = Column(Float, default=0.0)
# Timestamps
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
last_login = Column(DateTime(timezone=True))
def __repr__(self):
return f"<User {self.username}>"

View File

@@ -0,0 +1,78 @@
"""Video streaming models"""
from sqlalchemy import Column, Integer, String, Text, Boolean, DateTime, ForeignKey, Float
from sqlalchemy.sql import func
from app.database import Base
class Video(Base):
"""Video model"""
__tablename__ = "videos"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
title = Column(String(255), nullable=False)
description = Column(Text)
thumbnail_url = Column(String(500))
video_url = Column(String(500), nullable=False)
# Video metadata
duration = Column(Integer) # in seconds
resolution = Column(String(20)) # e.g., "1920x1080"
file_size = Column(Integer) # in bytes
format = Column(String(20)) # e.g., "mp4", "webm"
# Engagement
views_count = Column(Integer, default=0)
likes_count = Column(Integer, default=0)
dislikes_count = Column(Integer, default=0)
comments_count = Column(Integer, default=0)
# Visibility
is_public = Column(Boolean, default=True)
is_live = Column(Boolean, default=False)
is_processing = Column(Boolean, default=False)
# Categories/Tags
category = Column(String(100))
tags = Column(Text) # Comma-separated
# Timestamps
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
published_at = Column(DateTime(timezone=True))
class VideoView(Base):
"""Video view tracking"""
__tablename__ = "video_views"
id = Column(Integer, primary_key=True, index=True)
video_id = Column(Integer, ForeignKey("videos.id", ondelete="CASCADE"), nullable=False)
user_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"))
# Watch metadata
watch_duration = Column(Integer) # seconds watched
completion_percentage = Column(Float)
# Analytics
ip_address = Column(String(45))
user_agent = Column(String(500))
referrer = Column(String(500))
created_at = Column(DateTime(timezone=True), server_default=func.now())
class VideoLike(Base):
"""Video like/dislike tracking"""
__tablename__ = "video_likes"
id = Column(Integer, primary_key=True, index=True)
video_id = Column(Integer, ForeignKey("videos.id", ondelete="CASCADE"), nullable=False)
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
is_like = Column(Boolean, default=True) # True=like, False=dislike
created_at = Column(DateTime(timezone=True), server_default=func.now())