Initial commit: AutonetSellCar platform with deployment system

- Frontend: Next.js 14 with TypeScript
- Backend: FastAPI with SQLAlchemy
- Agent: Carmodoo sync agent
- Deployment: Docker Compose based staging/production setup
- Scripts: Automated deployment with rollback support

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
AutonetSellCar Deploy
2025-12-30 13:24:39 +09:00
commit 1f0dcb1ddb
224 changed files with 55119 additions and 0 deletions

View File

@@ -0,0 +1,111 @@
"""
Visitor tracking models for analytics
"""
from sqlalchemy import Column, Integer, String, DateTime, Text, Index
from sqlalchemy.sql import func
from ..database import Base
class VisitorLog(Base):
"""
Raw visitor log - tracks every page visit
IP addresses are hashed for privacy
"""
__tablename__ = "visitor_logs"
id = Column(Integer, primary_key=True, index=True)
# Visitor identification (hashed for privacy)
visitor_hash = Column(String(64), nullable=False, index=True) # SHA256 hash of IP + User-Agent
ip_hash = Column(String(64), nullable=False) # SHA256 hash of IP only
# Session tracking
session_id = Column(String(64), nullable=True, index=True) # Cookie-based session ID
user_id = Column(Integer, nullable=True, index=True) # If logged in
# Page information
page_path = Column(String(500), nullable=False, index=True)
page_title = Column(String(200), nullable=True)
referrer = Column(String(1000), nullable=True)
referrer_domain = Column(String(200), nullable=True, index=True)
# Device information
device_type = Column(String(20), nullable=True, index=True) # mobile, desktop, tablet
browser = Column(String(50), nullable=True, index=True)
browser_version = Column(String(20), nullable=True)
os = Column(String(50), nullable=True)
os_version = Column(String(20), nullable=True)
# Geographic information (from IP geolocation)
country = Column(String(50), nullable=True, index=True)
country_code = Column(String(5), nullable=True)
city = Column(String(100), nullable=True)
region = Column(String(100), nullable=True)
# UTM parameters
utm_source = Column(String(100), nullable=True)
utm_medium = Column(String(100), nullable=True)
utm_campaign = Column(String(100), nullable=True)
# Timestamp
visited_at = Column(DateTime(timezone=True), server_default=func.now(), index=True)
class VisitorDailyStats(Base):
"""
Aggregated daily statistics for faster queries
Pre-computed by a scheduled task
"""
__tablename__ = "visitor_daily_stats"
id = Column(Integer, primary_key=True, index=True)
stat_date = Column(String(10), nullable=False, unique=True, index=True) # YYYY-MM-DD
# Visitor counts
total_visits = Column(Integer, default=0)
unique_visitors = Column(Integer, default=0)
# Device breakdown (JSON string)
device_breakdown = Column(Text) # {"mobile": 100, "desktop": 200, "tablet": 20}
# Browser breakdown (JSON string)
browser_breakdown = Column(Text) # {"Chrome": 150, "Safari": 100, ...}
# Country breakdown (JSON string)
country_breakdown = Column(Text) # {"MN": 200, "RU": 50, "KR": 30}
# Top pages (JSON string)
top_pages = Column(Text) # [{"path": "/", "views": 500}, ...]
# Top referrers (JSON string)
top_referrers = Column(Text) # [{"domain": "google.com", "visits": 100}, ...]
# Timestamps
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
class VisitorSession(Base):
"""
Track visitor sessions for better analytics
"""
__tablename__ = "visitor_sessions"
id = Column(Integer, primary_key=True, index=True)
session_id = Column(String(64), unique=True, nullable=False, index=True)
visitor_hash = Column(String(64), nullable=False, index=True)
user_id = Column(Integer, nullable=True)
# Session info
first_page = Column(String(500))
last_page = Column(String(500))
page_count = Column(Integer, default=1)
# Device/geo info (copied from first visit)
device_type = Column(String(20))
browser = Column(String(50))
country = Column(String(50))
# Timestamps
started_at = Column(DateTime(timezone=True), server_default=func.now(), index=True)
last_activity_at = Column(DateTime(timezone=True), server_default=func.now())