aee0f09db8
- Datafabrik: Dockerfile fix, agentorkestrering fungerar - Vision: Identify-modell, FAISS, OCR alla testade - API: Alla 7 integrationstester passerade - Upplösare: Entitetsupplösning verifierad
405 lines
15 KiB
Python
405 lines
15 KiB
Python
"""
|
|
Landvex Admin Backend - Unified Models
|
|
Includes: Content, quiXzoom, Economy, HR, Aid Intelligence
|
|
"""
|
|
from sqlalchemy import Column, Integer, String, Float, DateTime, Boolean, Text, JSON, ForeignKey, Enum, Numeric
|
|
from sqlalchemy.ext.declarative import declarative_base
|
|
from sqlalchemy.orm import relationship
|
|
from datetime import datetime
|
|
import enum
|
|
|
|
Base = declarative_base()
|
|
|
|
# ─── USER & AUTH ──────────────────────────────────────────────────────────────
|
|
|
|
class UserRole(str, enum.Enum):
|
|
SUPER_ADMIN = "super_admin"
|
|
ADMIN = "admin"
|
|
MANAGER = "manager"
|
|
EDITOR = "editor"
|
|
VIEWER = "viewer"
|
|
ANALYST = "analyst"
|
|
QUIXZOOM_MANAGER = "quixzoom_manager"
|
|
ECONOMY_MANAGER = "economy_manager"
|
|
HR_MANAGER = "hr_manager"
|
|
AID_MANAGER = "aid_manager"
|
|
|
|
class UserStatus(str, enum.Enum):
|
|
ACTIVE = "active"
|
|
INACTIVE = "inactive"
|
|
SUSPENDED = "suspended"
|
|
|
|
class TenantType(str, enum.Enum):
|
|
ENTERPRISE = "enterprise"
|
|
SMALL_BUSINESS = "small_business"
|
|
INDIVIDUAL = "individual"
|
|
MUNICIPALITY = "municipality"
|
|
GOVERNMENT = "government"
|
|
NGO = "ngo"
|
|
|
|
class TenantStatus(str, enum.Enum):
|
|
ACTIVE = "active"
|
|
INACTIVE = "inactive"
|
|
SUSPENDED = "suspended"
|
|
PENDING = "pending"
|
|
|
|
class Tenant(Base):
|
|
__tablename__ = "tenants"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
tenant_id = Column(String(50), unique=True, nullable=False)
|
|
name = Column(String(255), nullable=False)
|
|
tenant_type = Column(Enum(TenantType), default=TenantType.ENTERPRISE)
|
|
status = Column(Enum(TenantStatus), default=TenantStatus.ACTIVE)
|
|
settings = Column(JSON)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
class Invitation(Base):
|
|
__tablename__ = "invitations"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
invitation_id = Column(String(50), unique=True, nullable=False)
|
|
email = Column(String(255), nullable=False)
|
|
role = Column(Enum(UserRole), default=UserRole.VIEWER)
|
|
tenant_id = Column(Integer, ForeignKey("tenants.id"))
|
|
invited_by = Column(Integer, ForeignKey("users.id"))
|
|
status = Column(String(50), default="pending") # pending, accepted, expired
|
|
expires_at = Column(DateTime)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
class AuditAction(str, enum.Enum):
|
|
CREATE = "create"
|
|
UPDATE = "update"
|
|
DELETE = "delete"
|
|
LOGIN = "login"
|
|
LOGOUT = "logout"
|
|
INVITE = "invite"
|
|
ACCEPT = "accept"
|
|
|
|
class AuditLog(Base):
|
|
__tablename__ = "audit_logs"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
action = Column(Enum(AuditAction), nullable=False)
|
|
entity_type = Column(String(100)) # user, tenant, invitation, etc.
|
|
entity_id = Column(String(100))
|
|
user_id = Column(Integer, ForeignKey("users.id"))
|
|
tenant_id = Column(Integer, ForeignKey("tenants.id"))
|
|
details = Column(JSON)
|
|
ip_address = Column(String(50))
|
|
user_agent = Column(String(500))
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
class User(Base):
|
|
__tablename__ = "users"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
email = Column(String(255), unique=True, index=True, nullable=False)
|
|
hashed_password = Column(String(255), nullable=False)
|
|
full_name = Column(String(255))
|
|
role = Column(Enum(UserRole), default=UserRole.VIEWER)
|
|
tenant_id = Column(Integer, ForeignKey("tenants.id"))
|
|
status = Column(Enum(UserStatus), default=UserStatus.ACTIVE)
|
|
is_active = Column(Boolean, default=True)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
last_login = Column(DateTime)
|
|
|
|
# ─── CONTENT MODULE ───────────────────────────────────────────────────────────
|
|
|
|
class ArticleStatus(str, enum.Enum):
|
|
DRAFT = "draft"
|
|
REVIEW = "review"
|
|
PUBLISHED = "published"
|
|
ARCHIVED = "archived"
|
|
|
|
class Article(Base):
|
|
__tablename__ = "articles"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
title = Column(String(500), nullable=False)
|
|
slug = Column(String(500), unique=True, index=True, nullable=False)
|
|
content = Column(Text)
|
|
excerpt = Column(String(1000))
|
|
author_id = Column(Integer, ForeignKey("users.id"))
|
|
status = Column(Enum(ArticleStatus), default=ArticleStatus.DRAFT)
|
|
seo_title = Column(String(70))
|
|
seo_description = Column(String(160))
|
|
keywords = Column(JSON)
|
|
published_at = Column(DateTime)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
author = relationship("User")
|
|
|
|
class SEOMetadata(Base):
|
|
__tablename__ = "seo_metadata"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
page_path = Column(String(500), unique=True, nullable=False)
|
|
title = Column(String(70))
|
|
description = Column(String(160))
|
|
canonical_url = Column(String(500))
|
|
og_image = Column(String(500))
|
|
schema_markup = Column(JSON)
|
|
last_audit = Column(DateTime)
|
|
audit_score = Column(Integer)
|
|
|
|
# ─── QUIXZOOM MODULE ──────────────────────────────────────────────────────────
|
|
|
|
class MissionStatus(str, enum.Enum):
|
|
DRAFT = "draft"
|
|
PENDING = "pending"
|
|
ACTIVE = "active"
|
|
PAUSED = "paused"
|
|
COMPLETED = "completed"
|
|
CANCELLED = "cancelled"
|
|
|
|
class Mission(Base):
|
|
__tablename__ = "missions"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
mission_id = Column(String(50), unique=True, nullable=False)
|
|
title = Column(String(500), nullable=False)
|
|
description = Column(Text)
|
|
city = Column(String(255))
|
|
country = Column(String(255))
|
|
location = Column(JSON)
|
|
reward_amount = Column(Numeric(10, 2))
|
|
reward_currency = Column(String(3), default="SEK")
|
|
status = Column(Enum(MissionStatus), default=MissionStatus.DRAFT)
|
|
requirements = Column(JSON)
|
|
start_date = Column(DateTime)
|
|
end_date = Column(DateTime)
|
|
max_submissions = Column(Integer)
|
|
created_by = Column(Integer, ForeignKey("users.id"))
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
class Contributor(Base):
|
|
__tablename__ = "contributors"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
contributor_id = Column(String(50), unique=True, nullable=False)
|
|
email = Column(String(255), unique=True)
|
|
full_name = Column(String(255))
|
|
phone = Column(String(50))
|
|
country = Column(String(255))
|
|
city = Column(String(255))
|
|
reputation_score = Column(Integer, default=0)
|
|
total_earnings = Column(Numeric(10, 2), default=0)
|
|
total_submissions = Column(Integer, default=0)
|
|
verified = Column(Boolean, default=False)
|
|
status = Column(String(50), default="active")
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
class Submission(Base):
|
|
__tablename__ = "submissions"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
submission_id = Column(String(50), unique=True, nullable=False)
|
|
mission_id = Column(Integer, ForeignKey("missions.id"))
|
|
contributor_id = Column(Integer, ForeignKey("contributors.id"))
|
|
status = Column(String(50), default="pending")
|
|
media_urls = Column(JSON)
|
|
location = Column(JSON)
|
|
ai_score = Column(Float)
|
|
reviewer_notes = Column(Text)
|
|
submitted_at = Column(DateTime, default=datetime.utcnow)
|
|
reviewed_at = Column(DateTime)
|
|
reviewed_by = Column(Integer, ForeignKey("users.id"))
|
|
|
|
# ─── ECONOMY MODULE ───────────────────────────────────────────────────────────
|
|
|
|
class AccountType(str, enum.Enum):
|
|
ASSET = "asset"
|
|
LIABILITY = "liability"
|
|
EQUITY = "equity"
|
|
REVENUE = "revenue"
|
|
EXPENSE = "expense"
|
|
|
|
class Account(Base):
|
|
__tablename__ = "accounts"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
account_number = Column(String(20), unique=True, nullable=False)
|
|
name = Column(String(255), nullable=False)
|
|
account_type = Column(Enum(AccountType), nullable=False)
|
|
parent_id = Column(Integer, ForeignKey("accounts.id"))
|
|
balance = Column(Numeric(12, 2), default=0)
|
|
currency = Column(String(3), default="SEK")
|
|
description = Column(Text)
|
|
is_active = Column(Boolean, default=True)
|
|
|
|
parent = relationship("Account", remote_side=[id])
|
|
|
|
class Transaction(Base):
|
|
__tablename__ = "transactions"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
transaction_id = Column(String(50), unique=True, nullable=False)
|
|
date = Column(DateTime, nullable=False)
|
|
description = Column(Text)
|
|
reference = Column(String(255))
|
|
amount = Column(Numeric(12, 2), nullable=False)
|
|
debit_account_id = Column(Integer, ForeignKey("accounts.id"))
|
|
credit_account_id = Column(Integer, ForeignKey("accounts.id"))
|
|
status = Column(String(50), default="posted")
|
|
created_by = Column(Integer, ForeignKey("users.id"))
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
class BankAccount(Base):
|
|
__tablename__ = "bank_accounts"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
bank_name = Column(String(255), nullable=False)
|
|
account_name = Column(String(255))
|
|
account_number = Column(String(100))
|
|
iban = Column(String(100))
|
|
bic = Column(String(20))
|
|
currency = Column(String(3), default="SEK")
|
|
current_balance = Column(Numeric(12, 2), default=0)
|
|
account_type = Column(String(50))
|
|
is_active = Column(Boolean, default=True)
|
|
|
|
# ─── HR MODULE ────────────────────────────────────────────────────────────────
|
|
|
|
class EmployeeStatus(str, enum.Enum):
|
|
ACTIVE = "active"
|
|
ON_LEAVE = "on_leave"
|
|
TERMINATED = "terminated"
|
|
CONTRACT = "contract"
|
|
|
|
class Employee(Base):
|
|
__tablename__ = "employees"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
employee_id = Column(String(50), unique=True, nullable=False)
|
|
first_name = Column(String(255), nullable=False)
|
|
last_name = Column(String(255), nullable=False)
|
|
email = Column(String(255), unique=True)
|
|
phone = Column(String(50))
|
|
department = Column(String(255))
|
|
position = Column(String(255))
|
|
start_date = Column(DateTime)
|
|
end_date = Column(DateTime)
|
|
salary = Column(Numeric(10, 2))
|
|
salary_currency = Column(String(3), default="SEK")
|
|
status = Column(Enum(EmployeeStatus), default=EmployeeStatus.ACTIVE)
|
|
manager_id = Column(Integer, ForeignKey("employees.id"))
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
class Contractor(Base):
|
|
__tablename__ = "contractors"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
contractor_id = Column(String(50), unique=True, nullable=False)
|
|
company_name = Column(String(255))
|
|
contact_name = Column(String(255))
|
|
email = Column(String(255))
|
|
phone = Column(String(50))
|
|
services = Column(JSON)
|
|
hourly_rate = Column(Numeric(10, 2))
|
|
currency = Column(String(3), default="SEK")
|
|
contract_start = Column(DateTime)
|
|
contract_end = Column(DateTime)
|
|
status = Column(String(50), default="active")
|
|
|
|
# ─── AID INTELLIGENCE MODULE ─────────────────────────────────────────────────
|
|
|
|
class AidProjectType(str, enum.Enum):
|
|
SCHOOL = "school"
|
|
HOSPITAL = "hospital"
|
|
ROAD = "road"
|
|
BRIDGE = "bridge"
|
|
WATER = "water"
|
|
POWER = "power"
|
|
AGRICULTURE = "agriculture"
|
|
RENEWABLE = "renewable"
|
|
HOUSING = "housing"
|
|
SANITATION = "sanitation"
|
|
DIGITAL = "digital"
|
|
ENVIRONMENTAL = "environmental"
|
|
EMERGENCY = "emergency"
|
|
FOOD = "food"
|
|
EDUCATION = "education"
|
|
HEALTHCARE = "healthcare"
|
|
MICROFINANCE = "microfinance"
|
|
WOMEN_EMPOWERMENT = "women_empowerment"
|
|
YOUTH_EMPLOYMENT = "youth_employment"
|
|
|
|
class AidProjectStatus(str, enum.Enum):
|
|
PLANNED = "planned"
|
|
ACTIVE = "active"
|
|
COMPLETED = "completed"
|
|
DELAYED = "delayed"
|
|
ABANDONED = "abandoned"
|
|
UNDER_MAINTENANCE = "under_maintenance"
|
|
|
|
class AidProject(Base):
|
|
__tablename__ = "aid_projects"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
project_id = Column(String(50), unique=True, nullable=False)
|
|
name = Column(String(500), nullable=False)
|
|
description = Column(Text)
|
|
country = Column(String(255), nullable=False)
|
|
region = Column(String(255))
|
|
district = Column(String(255))
|
|
project_type = Column(Enum(AidProjectType), nullable=False)
|
|
status = Column(Enum(AidProjectStatus), default=AidProjectStatus.PLANNED)
|
|
funding_agency = Column(String(255))
|
|
implementing_partner = Column(String(255))
|
|
budget_usd = Column(Numeric(12, 2))
|
|
start_date = Column(DateTime)
|
|
expected_completion = Column(DateTime)
|
|
actual_completion = Column(DateTime)
|
|
location = Column(JSON)
|
|
aii_score = Column(Integer)
|
|
confidence = Column(Integer)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
class AidObservation(Base):
|
|
__tablename__ = "aid_observations"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
observation_id = Column(String(50), unique=True, nullable=False)
|
|
project_id = Column(Integer, ForeignKey("aid_projects.id"))
|
|
observation_type = Column(String(50), nullable=False)
|
|
date = Column(DateTime, nullable=False)
|
|
contributor_id = Column(String(100))
|
|
location = Column(JSON)
|
|
media_urls = Column(JSON)
|
|
ai_analysis = Column(JSON)
|
|
confidence = Column(Integer)
|
|
verified = Column(Boolean, default=False)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
class AidAlert(Base):
|
|
__tablename__ = "aid_alerts"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
alert_id = Column(String(50), unique=True, nullable=False)
|
|
severity = Column(String(20), nullable=False)
|
|
alert_type = Column(String(100), nullable=False)
|
|
project_id = Column(Integer, ForeignKey("aid_projects.id"))
|
|
description = Column(Text)
|
|
detected_at = Column(DateTime, default=datetime.utcnow)
|
|
confidence = Column(Integer)
|
|
status = Column(String(50), default="open")
|
|
resolved_at = Column(DateTime)
|
|
resolved_by = Column(Integer, ForeignKey("users.id"))
|
|
|
|
# ─── SYSTEM HEALTH ────────────────────────────────────────────────────────────
|
|
|
|
class ServiceHealth(Base):
|
|
__tablename__ = "service_health"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
service_name = Column(String(255), nullable=False)
|
|
service_url = Column(String(500))
|
|
status = Column(String(50), default="unknown")
|
|
last_check = Column(DateTime, default=datetime.utcnow)
|
|
response_time_ms = Column(Integer)
|
|
error_rate = Column(Float)
|
|
uptime_percentage = Column(Float)
|