Files
AutonetSellCar/backend/app/models/visitor.py
AutonetSellCar Deploy b8f0ae4d28 feat: Add real-time visitor map with IP geolocation
- Add latitude/longitude columns to visitor_logs model
- Update visitor_service to fetch and store coordinates from ip-api.com
- Add /admin/map-data API endpoint for map visualization
- Create VisitorMap component using Leaflet/OpenStreetMap
- Integrate map into visitor-stats admin page
- 30-second auto-refresh with animation for new visitors
- Color-coded markers (red: active, blue: recent)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 18:31:22 +09:00

114 lines
4.0 KiB
Python

"""
Visitor tracking models for analytics
"""
from sqlalchemy import Column, Integer, String, DateTime, Text, Index, Float
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)
latitude = Column(Float, nullable=True)
longitude = Column(Float, 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())