Add CarPass gamification scoring foundation
This commit is contained in:
94
app/models/gamification.py
Normal file
94
app/models/gamification.py
Normal file
@@ -0,0 +1,94 @@
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
|
||||
from sqlalchemy import (
|
||||
JSON,
|
||||
Boolean,
|
||||
DateTime,
|
||||
ForeignKey,
|
||||
Integer,
|
||||
Numeric,
|
||||
String,
|
||||
UniqueConstraint,
|
||||
func,
|
||||
)
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class Achievement(Base):
|
||||
__tablename__ = "achievements"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
code: Mapped[str] = mapped_column(String(80), unique=True, index=True)
|
||||
scope: Mapped[str] = mapped_column(String(24), default="user", server_default="user", index=True)
|
||||
title: Mapped[str] = mapped_column(String(120))
|
||||
description: Mapped[str] = mapped_column(String(260))
|
||||
icon: Mapped[str | None] = mapped_column(String(40))
|
||||
category: Mapped[str | None] = mapped_column(String(40), index=True)
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True, server_default="true", index=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
|
||||
class UserAchievement(Base):
|
||||
__tablename__ = "user_achievements"
|
||||
__table_args__ = (
|
||||
UniqueConstraint(
|
||||
"user_id",
|
||||
"achievement_id",
|
||||
"vehicle_id",
|
||||
"service_center_id",
|
||||
name="uq_user_achievement_scope",
|
||||
),
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
achievement_id: Mapped[int] = mapped_column(ForeignKey("achievements.id", ondelete="CASCADE"), index=True)
|
||||
vehicle_id: Mapped[int | None] = mapped_column(ForeignKey("cars.id", ondelete="CASCADE"), index=True)
|
||||
service_center_id: Mapped[int | None] = mapped_column(ForeignKey("service_centers.id", ondelete="CASCADE"), index=True)
|
||||
unlocked_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True)
|
||||
metadata_json: Mapped[dict | None] = mapped_column(JSON)
|
||||
|
||||
|
||||
class VehicleScore(Base):
|
||||
__tablename__ = "vehicle_scores"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
vehicle_id: Mapped[int] = mapped_column(ForeignKey("cars.id", ondelete="CASCADE"), unique=True, index=True)
|
||||
completeness_score: Mapped[int] = mapped_column(Integer, default=0, server_default="0")
|
||||
verified_history_score: Mapped[int] = mapped_column(Integer, default=0, server_default="0")
|
||||
maintenance_health_score: Mapped[int] = mapped_column(Integer, default=100, server_default="100")
|
||||
maintenance_status: Mapped[str] = mapped_column(String(24), default="unknown", server_default="unknown", index=True)
|
||||
profile_quality: Mapped[str] = mapped_column(String(40), default="basic", server_default="basic", index=True)
|
||||
verified_history_status: Mapped[str] = mapped_column(String(40), default="self_reported", server_default="self_reported", index=True)
|
||||
missing_items: Mapped[list | None] = mapped_column(JSON)
|
||||
computed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
|
||||
class ServiceCenterScore(Base):
|
||||
__tablename__ = "service_center_scores"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
service_center_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("service_centers.id", ondelete="CASCADE"), unique=True, index=True
|
||||
)
|
||||
trust_score: Mapped[int] = mapped_column(Integer, default=0, server_default="0")
|
||||
trust_level: Mapped[str] = mapped_column(String(40), default="new_service", server_default="new_service", index=True)
|
||||
confirmed_visits_count: Mapped[int] = mapped_column(Integer, default=0, server_default="0")
|
||||
confirmation_rate: Mapped[Decimal] = mapped_column(Numeric(5, 2), default=0, server_default="0")
|
||||
dispute_rate: Mapped[Decimal] = mapped_column(Numeric(5, 2), default=0, server_default="0")
|
||||
computed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
|
||||
class EngagementEvent(Base):
|
||||
__tablename__ = "engagement_events"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), index=True)
|
||||
vehicle_id: Mapped[int | None] = mapped_column(ForeignKey("cars.id", ondelete="CASCADE"), index=True)
|
||||
service_center_id: Mapped[int | None] = mapped_column(ForeignKey("service_centers.id", ondelete="CASCADE"), index=True)
|
||||
event_type: Mapped[str] = mapped_column(String(80), index=True)
|
||||
metadata_json: Mapped[dict | None] = mapped_column(JSON)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True)
|
||||
Reference in New Issue
Block a user