feat: v1.7 overhaul - identity hash, triple wallet, financial ledger, and security audit system
This commit is contained in:
2
.env
2
.env
@@ -1,3 +1,5 @@
|
||||
COMPOSE_PROJECT_NAME=service_finder
|
||||
|
||||
# --- ADATBÁZIS KAPCSOLAT (Központi) ---
|
||||
# Itt a 'shared-postgres' nevet használjuk, ami a központi konténer neve
|
||||
APP_DB_HOST=shared-postgres
|
||||
|
||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
n8n/db_data/
|
||||
N8N/db_data/
|
||||
*.pyc
|
||||
__pycache__/
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"encryptionKey": "54T2Q0sTamS0GDOb8vyTtOQXBJxq3d0/"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "installed-nodes",
|
||||
"private": true,
|
||||
"dependencies": {}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -11,35 +11,35 @@ from app.models.asset import Asset, AssetCost, AssetTelemetry
|
||||
from app.models.identity import User
|
||||
from app.services.cost_service import cost_service
|
||||
from app.schemas.asset_cost import AssetCostCreate, AssetCostResponse
|
||||
# --- IMPORT JAVÍTVA: Behozzuk a jármű sémát a dúsított adatokhoz ---
|
||||
from app.schemas.asset import AssetResponse
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
# --- 1. MODUL: IDENTITÁS (Alapadatok) ---
|
||||
@router.get("/{asset_id}", response_model=Dict[str, Any])
|
||||
# --- 1. MODUL: IDENTITÁS (Alapadatok & Technikai katalógus) ---
|
||||
@router.get("/{asset_id}", response_model=AssetResponse)
|
||||
async def get_asset_identity(
|
||||
asset_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""Csak a jármű alapadatai és katalógus információi."""
|
||||
stmt = select(Asset).where(Asset.id == asset_id).options(selectinload(Asset.catalog))
|
||||
"""
|
||||
Visszaadja a jármű alapadatokat és a dúsított katalógus információkat (kW, CCM, tengelyek).
|
||||
A selectinload(Asset.catalog) biztosítja, hogy a technikai adatok is betöltődjenek.
|
||||
"""
|
||||
stmt = (
|
||||
select(Asset)
|
||||
.where(Asset.id == asset_id)
|
||||
.options(selectinload(Asset.catalog))
|
||||
)
|
||||
asset = (await db.execute(stmt)).scalar_one_or_none()
|
||||
|
||||
if not asset:
|
||||
raise HTTPException(status_code=404, detail="Jármű nem található")
|
||||
|
||||
return {
|
||||
"id": asset.id,
|
||||
"vin": asset.vin,
|
||||
"license_plate": asset.license_plate,
|
||||
"name": asset.name,
|
||||
"catalog": {
|
||||
"make": asset.catalog.make,
|
||||
"model": asset.catalog.model,
|
||||
"type": asset.catalog.vehicle_class,
|
||||
"factory_data": getattr(asset.catalog, 'factory_data', {})
|
||||
}
|
||||
}
|
||||
# Közvetlenül az objektumot adjuk vissza, a Pydantic AssetResponse
|
||||
# modellje fogja formázni a kimenetet a dúsított adatokkal együtt.
|
||||
return asset
|
||||
|
||||
# --- 2. MODUL: PÉNZÜGY (Költségek) ---
|
||||
@router.get("/{asset_id}/costs", response_model=Dict[str, Any])
|
||||
@@ -89,11 +89,7 @@ async def create_asset_cost(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Új költség rögzítése.
|
||||
Automatikus: EUR konverzió, Telemetria frissítés, XP jóváírás.
|
||||
"""
|
||||
# Validáció: az asset_id-nak egyeznie kell a path-szal
|
||||
"""Új költség rögzítése automatikus EUR konverzióval."""
|
||||
if cost_in.asset_id != asset_id:
|
||||
raise HTTPException(status_code=400, detail="Asset ID mismatch")
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ async def complete_kyc(
|
||||
):
|
||||
"""
|
||||
Step 2: KYC Aktiválás.
|
||||
Itt használjuk a get_current_user-t (nem active), mert a user még inaktív.
|
||||
It használjuk a get_current_user-t (nem active), mert a user még inaktív.
|
||||
"""
|
||||
user = await AuthService.complete_kyc(db, current_user.id, kyc_in)
|
||||
if not user:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import hashlib
|
||||
import unicodedata
|
||||
import re
|
||||
|
||||
class VINValidator:
|
||||
@@ -44,4 +46,31 @@ class VINValidator:
|
||||
"country": countries.get(vin[0], "Ismeretlen"),
|
||||
"year_code": vin[9], # Modellév kódja
|
||||
"wmi": vin[0:3] # World Manufacturer Identifier
|
||||
}
|
||||
}
|
||||
|
||||
class IdentityNormalizer:
|
||||
@staticmethod
|
||||
def normalize_text(text: str) -> str:
|
||||
"""Tisztítja a szöveget: kisbetű, ékezetmentesítés, szóközök és jelek törlése."""
|
||||
if not text:
|
||||
return ""
|
||||
# 1. Kisbetűre alakítás
|
||||
text = text.lower().strip()
|
||||
# 2. Ékezetek eltávolítása (Unicode normalizálás)
|
||||
text = "".join(
|
||||
c for c in unicodedata.normalize('NFD', text)
|
||||
if unicodedata.category(c) != 'Mn'
|
||||
)
|
||||
# 3. Csak az angol ABC betűi és számok maradjanak
|
||||
return re.sub(r'[^a-z0-9]', '', text)
|
||||
|
||||
@classmethod
|
||||
def generate_person_hash(cls, last_name: str, first_name: str, mothers_name: str, birth_date: str) -> str:
|
||||
"""Létrehozza az egyedi SHA256 ujjlenyomatot a személyhez."""
|
||||
raw_combined = (
|
||||
cls.normalize_text(last_name) +
|
||||
cls.normalize_text(first_name) +
|
||||
cls.normalize_text(mothers_name) +
|
||||
cls.normalize_text(birth_date)
|
||||
)
|
||||
return hashlib.sha256(raw_combined.encode()).hexdigest()
|
||||
Binary file not shown.
@@ -1,10 +1,11 @@
|
||||
# /opt/docker/dev/service_finder/backend/app/db/base.py
|
||||
from app.db.base_class import Base # noqa
|
||||
|
||||
# Közvetlen importok a fájlokból (Circular Import elkerülése)
|
||||
from app.models.address import Address, GeoPostalCode, GeoStreet, GeoStreetType # noqa
|
||||
from app.models.identity import User, Person, VerificationToken, Wallet # noqa
|
||||
from app.models.organization import Organization, OrganizationMember # noqa
|
||||
# Közvetlen importok (HOZZÁADVA az audit és sales modellek)
|
||||
from app.models.address import Address, GeoPostalCode, GeoStreet, GeoStreetType, Branch # noqa
|
||||
from app.models.identity import User, Person, VerificationToken, Wallet # noqa
|
||||
from app.models.organization import Organization, OrganizationMember, OrganizationSalesAssignment # noqa
|
||||
from app.models.audit import SecurityAuditLog, OperationalLog, FinancialLedger # noqa <--- KRITIKUS!
|
||||
from app.models.asset import ( # noqa
|
||||
Asset, AssetCatalog, AssetCost, AssetEvent,
|
||||
AssetFinancials, AssetTelemetry, AssetReview, ExchangeRate
|
||||
@@ -12,11 +13,11 @@ from app.models.asset import ( # noqa
|
||||
from app.models.gamification import ( # noqa
|
||||
PointRule, LevelConfig, UserStats, Badge, UserBadge, Rating, PointsLedger
|
||||
)
|
||||
from app.models.system_config import SystemParameter # noqa
|
||||
from app.models.system import SystemParameter # noqa (system.py használata)
|
||||
from app.models.history import AuditLog, VehicleOwnership # noqa
|
||||
from app.models.document import Document # noqa
|
||||
from app.models.translation import Translation # noqa <--- HOZZÁADVA
|
||||
from app.models.translation import Translation # noqa
|
||||
from app.models.core_logic import ( # noqa
|
||||
SubscriptionTier, OrganizationSubscription, CreditTransaction, ServiceSpecialty
|
||||
)
|
||||
from app.models.security import PendingAction # noqa <--- CSAK A BIZTONSÁG KEDVÉÉRT, HA EZ IS HIÁNYZOTT VOLNA
|
||||
from app.models.security import PendingAction # noqa
|
||||
@@ -1,11 +1,12 @@
|
||||
# /opt/docker/dev/service_finder/backend/app/models/__init__.py
|
||||
|
||||
from app.db.base_class import Base
|
||||
|
||||
# Identitás és Jogosultság
|
||||
from .identity import User, Person, Wallet, UserRole, VerificationToken, SocialAccount
|
||||
|
||||
# Szervezeti struktúra
|
||||
from .organization import Organization, OrganizationMember
|
||||
# Szervezeti struktúra (HOZZÁADVA: OrganizationSalesAssignment)
|
||||
from .organization import Organization, OrganizationMember, OrganizationSalesAssignment
|
||||
|
||||
# Járművek és Eszközök (Digital Twin)
|
||||
from .asset import (
|
||||
@@ -13,24 +14,25 @@ from .asset import (
|
||||
AssetFinancials, AssetTelemetry, AssetReview, ExchangeRate
|
||||
)
|
||||
|
||||
# Szerviz és Szakértelem (ÚJ)
|
||||
# Szerviz és Szakértelem
|
||||
from .service import ServiceProfile, ExpertiseTag, ServiceExpertise, ServiceStaging
|
||||
|
||||
# Földrajzi adatok és Címek
|
||||
from .address import Address, GeoPostalCode, GeoStreet, GeoStreetType
|
||||
from .address import Address, GeoPostalCode, GeoStreet, GeoStreetType, Branch
|
||||
|
||||
# Gamification és Economy
|
||||
from .gamification import PointRule, LevelConfig, UserStats, Badge, UserBadge, Rating, PointsLedger
|
||||
|
||||
# Rendszerkonfiguráció és Alapok
|
||||
from .system_config import SystemParameter
|
||||
# Rendszerkonfiguráció (HASZNÁLJUK a frissített system.py-t!)
|
||||
from .system import SystemParameter
|
||||
from .document import Document
|
||||
from .translation import Translation
|
||||
|
||||
# Üzleti logika és Előfizetés
|
||||
from .core_logic import SubscriptionTier, OrganizationSubscription, CreditTransaction, ServiceSpecialty
|
||||
|
||||
# Naplózás és Biztonság
|
||||
# Naplózás és Biztonság (HOZZÁADVA: audit.py modellek)
|
||||
from .audit import SecurityAuditLog, OperationalLog, FinancialLedger # <--- KRITIKUS!
|
||||
from .history import AuditLog, VehicleOwnership
|
||||
from .security import PendingAction
|
||||
|
||||
@@ -42,16 +44,15 @@ ServiceRecord = AssetEvent
|
||||
|
||||
__all__ = [
|
||||
"Base", "User", "Person", "Wallet", "UserRole", "VerificationToken", "SocialAccount",
|
||||
"Organization", "OrganizationMember",
|
||||
"Organization", "OrganizationMember", "OrganizationSalesAssignment",
|
||||
"Asset", "AssetCatalog", "AssetCost", "AssetEvent", "AssetFinancials",
|
||||
"AssetTelemetry", "AssetReview", "ExchangeRate",
|
||||
"Address", "GeoPostalCode", "GeoStreet", "GeoStreetType",
|
||||
"PointRule", "LevelConfig", "UserStats", "Badge", "UserBadge", "Rating", "PointsLedger",
|
||||
"Address", "GeoPostalCode", "GeoStreet", "GeoStreetType", "Branch",
|
||||
"Point_Rule", "LevelConfig", "UserStats", "Badge", "UserBadge", "Rating", "PointsLedger",
|
||||
"SystemParameter", "Document", "Translation", "PendingAction",
|
||||
"SubscriptionTier", "OrganizationSubscription",
|
||||
"CreditTransaction", "ServiceSpecialty", "AuditLog", "VehicleOwnership",
|
||||
# --- SZERVIZ MODUL (Tisztítva) ---
|
||||
"SecurityAuditLog", "OperationalLog", "FinancialLedger", # <--- KRITIKUS!
|
||||
"ServiceProfile", "ExpertiseTag", "ServiceExpertise", "ServiceStaging",
|
||||
# --- ALIASOK ---
|
||||
"Vehicle", "UserVehicle", "VehicleCatalog", "ServiceRecord"
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,7 +1,9 @@
|
||||
import uuid
|
||||
from sqlalchemy import Column, String, Integer, ForeignKey, Text, DateTime, Float
|
||||
from sqlalchemy.dialects.postgresql import UUID as PG_UUID
|
||||
from sqlalchemy.sql import func
|
||||
# Hozzáadva: Boolean, text, func
|
||||
from sqlalchemy import Column, String, Integer, ForeignKey, Text, DateTime, Float, Boolean, text, func
|
||||
# PostgreSQL specifikus típusok
|
||||
from sqlalchemy.dialects.postgresql import UUID as PG_UUID, JSONB
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base_class import Base
|
||||
|
||||
class GeoPostalCode(Base):
|
||||
@@ -45,4 +47,44 @@ class Address(Base):
|
||||
latitude = Column(Float)
|
||||
longitude = Column(Float)
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
# Add to /app/models/address.py
|
||||
class Branch(Base):
|
||||
"""
|
||||
Telephely entitás. A fizikai helyszín, ahol a szolgáltatás vagy flotta-kezelés zajlik.
|
||||
Minden cégnek van legalább egy 'Main' telephelye.
|
||||
"""
|
||||
__tablename__ = "branches"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(PG_UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
organization_id = Column(Integer, ForeignKey("data.organizations.id"), nullable=False)
|
||||
address_id = Column(PG_UUID(as_uuid=True), ForeignKey("data.addresses.id"), nullable=True)
|
||||
|
||||
name = Column(String(100), nullable=False) # pl. "Központi iroda", "Dunakeszi Szerviz"
|
||||
is_main = Column(Boolean, default=False)
|
||||
|
||||
# Részletes címadatok (Denormalizált a gyors kereséshez)
|
||||
postal_code = Column(String(10), index=True)
|
||||
city = Column(String(100), index=True)
|
||||
street_name = Column(String(150))
|
||||
street_type = Column(String(50))
|
||||
house_number = Column(String(20))
|
||||
stairwell = Column(String(20))
|
||||
floor = Column(String(20))
|
||||
door = Column(String(20))
|
||||
hrsz = Column(String(50)) # Helyrajzi szám
|
||||
|
||||
# Telephely specifikus adatok
|
||||
opening_hours = Column(JSONB, server_default=text("'{}'::jsonb"))
|
||||
branch_rating = Column(Float, default=0.0)
|
||||
|
||||
status = Column(String(30), default="active")
|
||||
is_deleted = Column(Boolean, default=False)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
organization = relationship("Organization", back_populates="branches")
|
||||
address = relationship("Address")
|
||||
# Kapcsolat a szerviz értékelésekkel
|
||||
reviews = relationship("Rating", primaryjoin="and_(Branch.id==foreign(Rating.target_id), Rating.target_type=='branch')")
|
||||
@@ -24,6 +24,16 @@ class AssetCatalog(Base):
|
||||
year_to = Column(Integer)
|
||||
vehicle_class = Column(String)
|
||||
fuel_type = Column(String, index=True)
|
||||
|
||||
# --- ÚJ OSZLOPOK (Ezeket add hozzá!) ---
|
||||
power_kw = Column(Integer, index=True)
|
||||
engine_capacity = Column(Integer, index=True)
|
||||
max_weight_kg = Column(Integer)
|
||||
axle_count = Column(Integer)
|
||||
euro_class = Column(String(20))
|
||||
body_type = Column(String(100))
|
||||
# ---------------------------------------
|
||||
|
||||
engine_code = Column(String)
|
||||
factory_data = Column(JSONB, server_default=text("'{}'::jsonb"))
|
||||
|
||||
@@ -101,11 +111,17 @@ class AssetAssignment(Base):
|
||||
id = Column(PG_UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
asset_id = Column(PG_UUID(as_uuid=True), ForeignKey("data.assets.id"), nullable=False)
|
||||
organization_id = Column(Integer, ForeignKey("data.organizations.id"), nullable=False)
|
||||
|
||||
# ÚJ: Telephelyi hozzárendelés
|
||||
branch_id = Column(PG_UUID(as_uuid=True), ForeignKey("data.branches.id"), nullable=True)
|
||||
|
||||
assigned_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
released_at = Column(DateTime(timezone=True), nullable=True)
|
||||
status = Column(String(30), default="active")
|
||||
|
||||
asset = relationship("Asset", back_populates="assignments")
|
||||
organization = relationship("Organization")
|
||||
branch = relationship("Branch") # Új kapcsolat
|
||||
|
||||
class AssetEvent(Base):
|
||||
__tablename__ = "asset_events"
|
||||
@@ -144,4 +160,27 @@ class ExchangeRate(Base):
|
||||
id = Column(Integer, primary_key=True)
|
||||
base_currency = Column(String(3), default="EUR")
|
||||
target_currency = Column(String(3), unique=True)
|
||||
rate = Column(Numeric(18, 6), nullable=False)
|
||||
rate = Column(Numeric(18, 6), nullable=False)
|
||||
|
||||
class CatalogDiscovery(Base):
|
||||
"""
|
||||
Discovery tábla: Ide gyűjtjük a piaci 'neveket' (pl. Citroen C3).
|
||||
A Robot innen indulva keresi meg az összes létező technikai variánst.
|
||||
"""
|
||||
__tablename__ = "catalog_discovery"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
make = Column(String(100), nullable=False, index=True)
|
||||
model = Column(String(100), nullable=False, index=True)
|
||||
vehicle_class = Column(String(50), index=True) # car, motorcycle, truck, stb.
|
||||
source = Column(String(50)) # 'hasznaltauto', 'mobile.de'
|
||||
status = Column(String(20), server_default=text("'pending'"), index=True)
|
||||
attempts = Column(Integer, default=0)
|
||||
last_attempt = Column(DateTime(timezone=True))
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
# EGYESÍTETT __table_args__
|
||||
__table_args__ = (
|
||||
UniqueConstraint('make', 'model', 'vehicle_class', name='_make_model_class_uc'),
|
||||
{"schema": "data"}
|
||||
)
|
||||
@@ -1,16 +1,56 @@
|
||||
from sqlalchemy import Column, Integer, String, DateTime, JSON, ForeignKey, text
|
||||
from sqlalchemy import Column, Integer, String, DateTime, JSON, ForeignKey, text, Numeric, Boolean, BigInteger
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.base_class import Base
|
||||
|
||||
class AuditLog(Base):
|
||||
__tablename__ = "audit_logs"
|
||||
__table_args__ = {"schema": "data"}
|
||||
class SecurityAuditLog(Base):
|
||||
""" Kiemelt biztonsági események és a 4-szem elv. """
|
||||
__tablename__ = "security_audit_logs"
|
||||
__table_args__ = {"schema": "data", "extend_existing": True}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
id = Column(Integer, primary_key=True)
|
||||
action = Column(String(50)) # 'ROLE_CHANGE', 'MANUAL_CREDIT_ADJUST', 'SUB_EXTEND'
|
||||
|
||||
actor_id = Column(Integer, ForeignKey("data.users.id")) # Aki kezdeményezte
|
||||
target_id = Column(Integer, ForeignKey("data.users.id")) # Akivel történt
|
||||
|
||||
# 4-szem elv: csak akkor válik élessé, ha ez nem NULL
|
||||
confirmed_by_id = Column(Integer, ForeignKey("data.users.id"), nullable=True)
|
||||
is_critical = Column(Boolean, default=False) # Szuperadmin hívásoknál True
|
||||
|
||||
payload_before = Column(JSON)
|
||||
payload_after = Column(JSON)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
class OperationalLog(Base):
|
||||
""" Napi üzemi események (Operational). """
|
||||
__tablename__ = "operational_logs"
|
||||
__table_args__ = {"schema": "data", "extend_existing": True}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True) # <--- EZ HIÁNYZOTT!
|
||||
user_id = Column(Integer, ForeignKey("data.users.id", ondelete="SET NULL"), nullable=True)
|
||||
action = Column(String(100), nullable=False) # pl. "LOGIN", "REGISTER", "DELETE_ASSET"
|
||||
resource_type = Column(String(50)) # pl. "User", "Asset", "Organization"
|
||||
action = Column(String(100), nullable=False) # pl. "ADD_VEHICLE", "UPDATE_COST"
|
||||
resource_type = Column(String(50)) # pl. "Asset", "Expense"
|
||||
resource_id = Column(String(100))
|
||||
details = Column(JSON, server_default=text("'{}'::jsonb"))
|
||||
ip_address = Column(String(45))
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
class FinancialLedger(Base):
|
||||
""" Minden pénz- és kreditmozgás központi naplója. """
|
||||
__tablename__ = "financial_ledger"
|
||||
__table_args__ = {"schema": "data", "extend_existing": True}
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("data.users.id"))
|
||||
person_id = Column(BigInteger, ForeignKey("data.persons.id"))
|
||||
|
||||
amount = Column(Numeric(18, 4), nullable=False)
|
||||
currency = Column(String(10)) # 'HUF', 'CREDIT', 'COIN'
|
||||
|
||||
transaction_type = Column(String(50)) # 'PURCHASE', 'HUNTING_COMMISSION', 'FARMING_COMMISSION'
|
||||
|
||||
# Üzletkötői követhetőség
|
||||
related_agent_id = Column(Integer, ForeignKey("data.users.id"), nullable=True)
|
||||
|
||||
details = Column(JSON, server_default=text("'{}'::jsonb"))
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
@@ -9,29 +9,34 @@ from app.db.base_class import Base
|
||||
class UserRole(str, enum.Enum):
|
||||
superadmin = "superadmin"
|
||||
admin = "admin"
|
||||
region_admin = "region_admin"
|
||||
country_admin = "country_admin"
|
||||
moderator = "moderator"
|
||||
sales_agent = "sales_agent"
|
||||
user = "user"
|
||||
service = "service"
|
||||
service_owner = "service_owner"
|
||||
fleet_manager = "fleet_manager"
|
||||
driver = "driver"
|
||||
|
||||
class Person(Base):
|
||||
"""
|
||||
Természetes személy identitása.
|
||||
A bot által talált személyek is ide kerülnek (is_ghost=True).
|
||||
Azonosítás: Név + Anyja neve + Születési adatok alapján.
|
||||
Természetes személy identitása. A DNS szint.
|
||||
Itt tároljuk az örök adatokat, amik nem vesznek el account törléskor.
|
||||
"""
|
||||
__tablename__ = "persons"
|
||||
__table_args__ = {"schema": "data"}
|
||||
__table_args__ = {"schema": "data", "extend_existing": True}
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
id_uuid = Column(PG_UUID(as_uuid=True), default=uuid.uuid4, unique=True, nullable=False)
|
||||
address_id = Column(PG_UUID(as_uuid=True), ForeignKey("data.addresses.id"), nullable=True)
|
||||
|
||||
# --- KRITIKUS: EGYEDI AZONOSÍTÓ HASH (Normalizált adatokból) ---
|
||||
identity_hash = Column(String(64), unique=True, index=True, nullable=True)
|
||||
|
||||
last_name = Column(String, nullable=False)
|
||||
first_name = Column(String, nullable=False)
|
||||
phone = Column(String, nullable=True)
|
||||
|
||||
# --- TERMÉSZETES AZONOSÍTÓK (Azonosításhoz, nem publikus) ---
|
||||
mothers_last_name = Column(String)
|
||||
mothers_first_name = Column(String)
|
||||
birth_place = Column(String)
|
||||
@@ -40,8 +45,14 @@ class Person(Base):
|
||||
identity_docs = Column(JSON, server_default=text("'{}'::jsonb"))
|
||||
ice_contact = Column(JSON, server_default=text("'{}'::jsonb"))
|
||||
|
||||
is_active = Column(Boolean, default=False, nullable=False)
|
||||
is_ghost = Column(Boolean, default=True, nullable=False) # Bot találta = True, Regisztrált = False
|
||||
# --- ÖRÖK ADATOK (Person szint) ---
|
||||
lifetime_xp = Column(BigInteger, server_default=text("0"))
|
||||
penalty_points = Column(Integer, server_default=text("0")) # 0-3 szint
|
||||
social_reputation = Column(Numeric(3, 2), server_default=text("1.00")) # 1.00 = 100%
|
||||
|
||||
is_sales_agent = Column(Boolean, server_default=text("false"))
|
||||
is_active = Column(Boolean, default=True, nullable=False)
|
||||
is_ghost = Column(Boolean, default=False, nullable=False)
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
@@ -50,28 +61,39 @@ class Person(Base):
|
||||
memberships = relationship("OrganizationMember", back_populates="person")
|
||||
|
||||
class User(Base):
|
||||
"""
|
||||
Login entitás. Bármikor törölhető (GDPR), de Person-höz kötött.
|
||||
"""
|
||||
__tablename__ = "users"
|
||||
__table_args__ = {"schema": "data"}
|
||||
__table_args__ = {"schema": "data", "extend_existing": True}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
email = Column(String, unique=True, index=True, nullable=False)
|
||||
hashed_password = Column(String, nullable=True)
|
||||
role = Column(Enum(UserRole), default=UserRole.user)
|
||||
is_active = Column(Boolean, default=False)
|
||||
is_deleted = Column(Boolean, default=False)
|
||||
|
||||
person_id = Column(BigInteger, ForeignKey("data.persons.id"), nullable=True)
|
||||
folder_slug = Column(String(12), unique=True, index=True)
|
||||
|
||||
refresh_token_hash = Column(String(255), nullable=True)
|
||||
two_factor_secret = Column(String(100), nullable=True)
|
||||
two_factor_enabled = Column(Boolean, default=False)
|
||||
# --- ELŐFIZETÉS ÉS VIP (Időkorlátos logika) ---
|
||||
subscription_plan = Column(String(30), server_default=text("'FREE'"))
|
||||
subscription_expires_at = Column(DateTime(timezone=True), nullable=True)
|
||||
is_vip = Column(Boolean, server_default=text("false"))
|
||||
|
||||
# --- REFERRAL ÉS SALES (Üzletkötői hálózat) ---
|
||||
referral_code = Column(String(20), unique=True)
|
||||
referred_by_id = Column(Integer, ForeignKey("data.users.id"), nullable=True)
|
||||
# Farming üzletkötő (Átruházható cégkezelő)
|
||||
current_sales_agent_id = Column(Integer, ForeignKey("data.users.id"), nullable=True)
|
||||
|
||||
is_active = Column(Boolean, default=False)
|
||||
is_deleted = Column(Boolean, default=False)
|
||||
folder_slug = Column(String(12), unique=True, index=True)
|
||||
|
||||
preferred_language = Column(String(5), server_default="hu")
|
||||
region_code = Column(String(5), server_default="HU")
|
||||
preferred_currency = Column(String(3), server_default="HUF")
|
||||
|
||||
scope_level = Column(String(30), server_default="individual")
|
||||
scope_level = Column(String(30), server_default="individual") # global, region, country, entity, individual
|
||||
scope_id = Column(String(50))
|
||||
custom_permissions = Column(JSON, server_default=text("'{}'::jsonb"))
|
||||
|
||||
@@ -79,18 +101,25 @@ class User(Base):
|
||||
|
||||
person = relationship("Person", back_populates="users")
|
||||
wallet = relationship("Wallet", back_populates="user", uselist=False)
|
||||
stats = relationship("UserStats", back_populates="user", uselist=False)
|
||||
ownership_history = relationship("VehicleOwnership", back_populates="user")
|
||||
owned_organizations = relationship("Organization", back_populates="owner")
|
||||
social_accounts = relationship("SocialAccount", back_populates="user", cascade="all, delete-orphan")
|
||||
|
||||
class Wallet(Base):
|
||||
__tablename__ = "wallets"; __table_args__ = {"schema": "data"}
|
||||
""" A 3-as felosztású pénztárca. """
|
||||
__tablename__ = "wallets"
|
||||
__table_args__ = {"schema": "data", "extend_existing": True}
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
user_id = Column(Integer, ForeignKey("data.users.id"), unique=True)
|
||||
coin_balance = Column(Numeric(18, 2), default=0.00); credit_balance = Column(Numeric(18, 2), default=0.00); currency = Column(String(3), default="HUF")
|
||||
|
||||
earned_credits = Column(Numeric(18, 4), server_default=text("0")) # Munka + Referral
|
||||
purchased_credits = Column(Numeric(18, 4), server_default=text("0")) # Vásárolt
|
||||
service_coins = Column(Numeric(18, 4), server_default=text("0")) # Csak hirdetésre!
|
||||
|
||||
currency = Column(String(3), default="HUF")
|
||||
user = relationship("User", back_populates="wallet")
|
||||
|
||||
# ... (VerificationToken és SocialAccount változatlan) ...
|
||||
|
||||
class VerificationToken(Base):
|
||||
__tablename__ = "verification_tokens"; __table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
|
||||
@@ -61,6 +61,11 @@ class Organization(Base):
|
||||
status = Column(String(30), default="pending_verification")
|
||||
is_deleted = Column(Boolean, default=False)
|
||||
|
||||
# --- ÚJ: Előfizetés és Méret korlátok ---
|
||||
subscription_plan = Column(String(30), server_default=text("'FREE'"), index=True)
|
||||
base_asset_limit = Column(Integer, server_default=text("1"))
|
||||
purchased_extra_slots = Column(Integer, server_default=text("0"))
|
||||
|
||||
notification_settings = Column(JSON, server_default=text("'{\"notify_owner\": true, \"alert_days_before\": [30, 15, 7, 1]}'::jsonb"))
|
||||
external_integration_config = Column(JSON, server_default=text("'{}'::jsonb"))
|
||||
|
||||
@@ -70,6 +75,10 @@ class Organization(Base):
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
||||
# --- ÚJ: Dual Twin Tulajdonjog logika ---
|
||||
# Individual esetén False, Business esetén True
|
||||
is_ownership_transferable = Column(Boolean, server_default=text("true"))
|
||||
|
||||
# Kapcsolatok
|
||||
assets = relationship("AssetAssignment", back_populates="organization", cascade="all, delete-orphan")
|
||||
@@ -77,6 +86,7 @@ class Organization(Base):
|
||||
owner = relationship("User", back_populates="owned_organizations")
|
||||
financials = relationship("OrganizationFinancials", back_populates="organization", cascade="all, delete-orphan")
|
||||
service_profile = relationship("ServiceProfile", back_populates="organization", uselist=False)
|
||||
branches = relationship("Branch", back_populates="organization", cascade="all, delete-orphan")
|
||||
|
||||
class OrganizationFinancials(Base):
|
||||
"""Cégek éves gazdasági adatai elemzéshez."""
|
||||
@@ -111,4 +121,15 @@ class OrganizationMember(Base):
|
||||
|
||||
organization = relationship("Organization", back_populates="members")
|
||||
user = relationship("User")
|
||||
person = relationship("Person", back_populates="memberships")
|
||||
person = relationship("Person", back_populates="memberships")
|
||||
|
||||
class OrganizationSalesAssignment(Base):
|
||||
"""Összeköti a céget az aktuális üzletkötővel a jutalék miatt."""
|
||||
__tablename__ = "org_sales_assignments"
|
||||
__table_args__ = {"schema": "data"}
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
organization_id = Column(Integer, ForeignKey("data.organizations.id"))
|
||||
agent_user_id = Column(Integer, ForeignKey("data.users.id")) # Ő kapja a Farming díjat
|
||||
assigned_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
is_active = Column(Boolean, default=True)
|
||||
@@ -86,12 +86,17 @@ class ServiceStaging(Base):
|
||||
name = Column(String, nullable=False, index=True)
|
||||
|
||||
# --- Strukturált cím adatok (A kérésedre bontva) ---
|
||||
postal_code = Column(String(10), nullable=True, index=True) # Irányítószám
|
||||
city = Column(String(100), nullable=True, index=True) # Település
|
||||
street = Column(String(255), nullable=True) # Utca és közterület jellege (pl. Diófa utca)
|
||||
house_number = Column(String(50), nullable=True) # Házszám, emelet, ajtó
|
||||
full_address = Column(String, nullable=True) # Az eredeti, egybefüggő cím (ha van)
|
||||
|
||||
postal_code = Column(String(10), index=True)
|
||||
city = Column(String(100), index=True)
|
||||
street_name = Column(String(150))
|
||||
street_type = Column(String(50)) # utca, út, tér...
|
||||
house_number = Column(String(20))
|
||||
stairwell = Column(String(20)) # lépcsőház
|
||||
floor = Column(String(20)) # emelet
|
||||
door = Column(String(20)) # ajtó
|
||||
hrsz = Column(String(50)) # helyrajzi szám
|
||||
|
||||
full_address = Column(String) # Eredeti string (audit célból)
|
||||
# --- Elérhetőségek ---
|
||||
contact_phone = Column(String, nullable=True)
|
||||
email = Column(String, nullable=True)
|
||||
@@ -111,4 +116,14 @@ class ServiceStaging(Base):
|
||||
status = Column(String(20), server_default=text("'pending'"), index=True)
|
||||
trust_score = Column(Integer, default=0)
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
class DiscoveryParameter(Base):
|
||||
__tablename__ = "discovery_parameters"
|
||||
__table_args__ = {"schema": "data"}
|
||||
id = Column(Integer, primary_key=True)
|
||||
city = Column(String(100), nullable=False)
|
||||
keyword = Column(String(100), nullable=False) # pl. "autóvillamosság"
|
||||
country_code = Column(String(2), default="HU")
|
||||
is_active = Column(Boolean, default=True)
|
||||
last_run_at = Column(DateTime(timezone=True))
|
||||
@@ -7,7 +7,11 @@ class SystemParameter(Base):
|
||||
__table_args__ = {"schema": "data", "extend_existing": True}
|
||||
|
||||
key = Column(String, primary_key=True, index=True, nullable=False)
|
||||
# Csoportosítás az Admin felületnek (pl. 'xp', 'scout', 'routing')
|
||||
category = Column(String, index=True, server_default="general")
|
||||
value = Column(JSON, nullable=False)
|
||||
is_active = Column(Boolean, default=True)
|
||||
description = Column(String)
|
||||
# Kötelező audit mező: ki módosította utoljára?
|
||||
last_modified_by = Column(String, nullable=True)
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now(), server_default=func.now())
|
||||
Binary file not shown.
@@ -5,6 +5,7 @@ from datetime import datetime
|
||||
|
||||
# --- KATALÓGUS SÉMÁK (Gyári adatok) ---
|
||||
class AssetCatalogBase(BaseModel):
|
||||
"""Alap katalógus adatok, amik a technikai dúsításból származnak."""
|
||||
make: str
|
||||
model: str
|
||||
generation: Optional[str] = None
|
||||
@@ -13,39 +14,57 @@ class AssetCatalogBase(BaseModel):
|
||||
vehicle_class: Optional[str] = None
|
||||
fuel_type: Optional[str] = None
|
||||
engine_code: Optional[str] = None
|
||||
|
||||
# --- ÚJ TECHNIKAI MEZŐK (Robot v1.0.8 Smart Hunter adatai) ---
|
||||
power_kw: Optional[int] = None
|
||||
engine_capacity: Optional[int] = None
|
||||
max_weight_kg: Optional[int] = None
|
||||
axle_count: Optional[int] = None
|
||||
body_type: Optional[str] = None
|
||||
|
||||
class AssetCatalogResponse(AssetCatalogBase):
|
||||
"""Katalógus válasz séma azonosítóval és extra gyári adatokkal."""
|
||||
id: int
|
||||
factory_data: Optional[Dict[str, Any]] = None # A robot által gyűjtött adatok
|
||||
factory_data: Optional[Dict[str, Any]] = None
|
||||
|
||||
# Pydantic v2 konfiguráció az ORM (SQLAlchemy) támogatáshoz
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
# --- JÁRMŰ SÉMÁK (Asset) ---
|
||||
class AssetBase(BaseModel):
|
||||
"""Jármű példány alapadatai (egyedi azonosítók)."""
|
||||
vin: str = Field(..., min_length=17, max_length=17)
|
||||
license_plate: str
|
||||
name: Optional[str] = None
|
||||
year_of_manufacture: Optional[int] = None
|
||||
|
||||
class AssetCreate(AssetBase):
|
||||
# A létrehozáshoz kellenek a katalógus infók is
|
||||
"""Séma új jármű felvételéhez."""
|
||||
make: str
|
||||
model: str
|
||||
vehicle_class: Optional[str] = "land"
|
||||
vehicle_class: Optional[str] = "car"
|
||||
fuel_type: Optional[str] = None
|
||||
current_reading: Optional[int] = 0
|
||||
|
||||
class AssetResponse(AssetBase):
|
||||
"""
|
||||
Teljes jármű válasz séma.
|
||||
Ez a séma tartalmazza a 'catalog' objektumot, amiben a dúsított műszaki adatok vannak.
|
||||
"""
|
||||
id: UUID
|
||||
catalog_id: int
|
||||
is_verified: bool
|
||||
catalog: AssetCatalogResponse # Ez a pont kapcsolja össze a dúsított technikai adatokat
|
||||
status: str
|
||||
is_verified: bool
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
# --- DIGITÁLIS IKER (Full Profile) ---
|
||||
# Ez a séma felel a 9 pontos költség és a mélységi szerviz adatok átadásáért
|
||||
class AssetFullProfile(BaseModel):
|
||||
"""
|
||||
Komplex jelentésekhez használt séma.
|
||||
Összefogja az identitást, telemetriát, pénzügyeket és szerviztörténetet.
|
||||
"""
|
||||
identity: Dict[str, Any]
|
||||
telemetry: Dict[str, Any]
|
||||
financial_summary: Dict[str, Any]
|
||||
|
||||
@@ -32,12 +32,17 @@ class UserKYCComplete(BaseModel):
|
||||
birth_date: date
|
||||
mothers_last_name: str
|
||||
mothers_first_name: str
|
||||
# Bontott címmezők (B pont szerint)
|
||||
address_zip: str
|
||||
address_city: str
|
||||
address_street_name: str
|
||||
address_street_type: str
|
||||
address_house_number: str
|
||||
address_hrsz: Optional[str] = None
|
||||
address_stairwell: Optional[str] = None # Lépcsőház
|
||||
address_floor: Optional[str] = None # Emelet
|
||||
address_door: Optional[str] = None # Ajtó
|
||||
address_hrsz: Optional[str] = None # Helyrajzi szám
|
||||
|
||||
identity_docs: Dict[str, DocumentDetail]
|
||||
ice_contact: ICEContact
|
||||
preferred_currency: Optional[str] = Field("HUF", max_length=3)
|
||||
|
||||
20
backend/app/schemas/service.py
Normal file
20
backend/app/schemas/service.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
class ServiceCreateInternal(BaseModel):
|
||||
name: str
|
||||
postal_code: str
|
||||
city: str
|
||||
street_name: str
|
||||
street_type: str
|
||||
house_number: str
|
||||
stairwell: Optional[str] = None
|
||||
floor: Optional[str] = None
|
||||
door: Optional[str] = None
|
||||
hrsz: Optional[str] = None
|
||||
|
||||
contact_phone: Optional[str] = None
|
||||
email: Optional[str] = None
|
||||
website: Optional[str] = None
|
||||
source: str
|
||||
external_id: Optional[str] = None
|
||||
Binary file not shown.
Binary file not shown.
@@ -112,25 +112,23 @@ class AuthService:
|
||||
async def complete_kyc(db: AsyncSession, user_id: int, kyc_in: UserKYCComplete):
|
||||
"""
|
||||
Step 2: Atomi Tranzakció.
|
||||
Itt dől el minden: Adatok rögzítése, Shadow Identity ellenőrzés,
|
||||
Flotta és Wallet létrehozás, majd a fiók aktiválása.
|
||||
Módosított verzió: Meglévő biztonsági logika + Telephely (Branch) integráció.
|
||||
"""
|
||||
try:
|
||||
# 1. User és Person betöltése
|
||||
stmt = select(User).options(joinedload(User.person)).where(User.id == user_id)
|
||||
res = await db.execute(stmt)
|
||||
user = res.scalar_one_or_none()
|
||||
if not user: return None
|
||||
|
||||
# --- 1. BIZTONSÁG: User folder_slug generálása ---
|
||||
# Ha Google-lel jött vagy még nincs slugja, most kap egyet.
|
||||
# --- BIZTONSÁG: Slug generálása ---
|
||||
if not user.folder_slug:
|
||||
user.folder_slug = generate_secure_slug(length=12)
|
||||
|
||||
# Pénznem beállítása
|
||||
if hasattr(kyc_in, 'preferred_currency') and kyc_in.preferred_currency:
|
||||
user.preferred_currency = kyc_in.preferred_currency
|
||||
|
||||
# --- 2. Shadow Identity keresése (Már létezik-e ez a fizikai személy?) ---
|
||||
# --- SHADOW IDENTITY ELLENŐRZÉS ---
|
||||
identity_stmt = select(Person).where(and_(
|
||||
Person.mothers_last_name == kyc_in.mothers_last_name,
|
||||
Person.mothers_first_name == kyc_in.mothers_first_name,
|
||||
@@ -140,15 +138,12 @@ class AuthService:
|
||||
existing_person = (await db.execute(identity_stmt)).scalar_one_or_none()
|
||||
|
||||
if existing_person:
|
||||
# Ha találtunk egyezést, összekötjük a User-t a meglévő Person-nel
|
||||
user.person_id = existing_person.id
|
||||
active_person = existing_person
|
||||
logger.info(f"Shadow Identity linked: User {user_id} -> Person {existing_person.id}")
|
||||
else:
|
||||
# Ha nem, a saját (regisztrációkor létrehozott) Person-t töltjük fel
|
||||
active_person = user.person
|
||||
|
||||
# --- 3. Cím rögzítése GeoService segítségével ---
|
||||
# --- CÍM RÖGZÍTÉSE ---
|
||||
addr_id = await GeoService.get_or_create_full_address(
|
||||
db,
|
||||
zip_code=kyc_in.address_zip,
|
||||
@@ -159,30 +154,26 @@ class AuthService:
|
||||
parcel_id=kyc_in.address_hrsz
|
||||
)
|
||||
|
||||
# --- 4. Személyes adatok frissítése ---
|
||||
# --- SZEMÉLYES ADATOK FRISSÍTÉSE ---
|
||||
active_person.mothers_last_name = kyc_in.mothers_last_name
|
||||
active_person.mothers_first_name = kyc_in.mothers_first_name
|
||||
active_person.birth_place = kyc_in.birth_place
|
||||
active_person.birth_date = kyc_in.birth_date
|
||||
active_person.phone = kyc_in.phone_number
|
||||
active_person.address_id = addr_id
|
||||
|
||||
# Dokumentumok és ICE kontakt mentése JSON-ként
|
||||
active_person.identity_docs = jsonable_encoder(kyc_in.identity_docs)
|
||||
active_person.ice_contact = jsonable_encoder(kyc_in.ice_contact)
|
||||
|
||||
# A Person most válik aktívvá
|
||||
active_person.is_active = True
|
||||
|
||||
# --- 5. EGYÉNI FLOTTA LÉTREHOZÁSA (A KYC szerves része) ---
|
||||
# Itt generáljuk a flotta mappáját is (folder_slug)
|
||||
# --- EGYÉNI FLOTTA LÉTREHOZÁSA ---
|
||||
new_org = Organization(
|
||||
full_name=f"{active_person.last_name} {active_person.first_name} Egyéni Flotta",
|
||||
name=f"{active_person.last_name} Flotta",
|
||||
folder_slug=generate_secure_slug(length=12), # FLOTTA SLUG
|
||||
folder_slug=generate_secure_slug(length=12),
|
||||
org_type=OrgType.individual,
|
||||
owner_id=user.id,
|
||||
is_transferable=False,
|
||||
is_transferable=False, # Step 2: Individual flotta nem átruházható
|
||||
is_ownership_transferable=False, # A te új meződ
|
||||
is_active=True,
|
||||
status="verified",
|
||||
language=user.preferred_language,
|
||||
@@ -192,24 +183,36 @@ class AuthService:
|
||||
db.add(new_org)
|
||||
await db.flush()
|
||||
|
||||
# Flotta tagság (Owner)
|
||||
# --- ÚJ: MAIN BRANCH (KÖZPONTI TELEPHELY) LÉTREHOZÁSA ---
|
||||
# Magánszemélynél a megadott cím lesz az első telephely is.
|
||||
from app.models.address import Branch
|
||||
new_branch = Branch(
|
||||
organization_id=new_org.id,
|
||||
address_id=addr_id,
|
||||
name="Központ / Otthon",
|
||||
is_main=True,
|
||||
postal_code=kyc_in.address_zip,
|
||||
city=kyc_in.address_city,
|
||||
street_name=kyc_in.address_street_name,
|
||||
street_type=kyc_in.address_street_type,
|
||||
house_number=kyc_in.address_house_number,
|
||||
hrsz=kyc_in.address_hrsz,
|
||||
status="active"
|
||||
)
|
||||
db.add(new_branch)
|
||||
await db.flush()
|
||||
|
||||
# --- TAGSÁG, WALLET, STATS ---
|
||||
db.add(OrganizationMember(
|
||||
organization_id=new_org.id,
|
||||
user_id=user.id,
|
||||
role="owner",
|
||||
permissions={"can_add_asset": True, "can_view_costs": True, "is_admin": True}
|
||||
))
|
||||
|
||||
# --- 6. PÉNZTÁRCA ÉS GAMIFICATION LÉTREHOZÁSA ---
|
||||
db.add(Wallet(
|
||||
user_id=user.id,
|
||||
coin_balance=0,
|
||||
credit_balance=0,
|
||||
currency=user.preferred_currency or "HUF"
|
||||
))
|
||||
db.add(Wallet(user_id=user.id, currency=user.preferred_currency or "HUF"))
|
||||
db.add(UserStats(user_id=user.id, total_xp=0, current_level=1))
|
||||
|
||||
# --- 7. AKTIVÁLÁS ÉS AUDIT ---
|
||||
# --- 7. AKTIVÁLÁS ÉS AUDIT (Ami az előzőből kimaradt) ---
|
||||
user.is_active = True
|
||||
|
||||
await security_service.log_event(
|
||||
@@ -223,7 +226,7 @@ class AuthService:
|
||||
"status": "active",
|
||||
"user_folder": user.folder_slug,
|
||||
"organization_id": new_org.id,
|
||||
"organization_folder": new_org.folder_slug,
|
||||
"branch_id": str(new_branch.id), # Új telephely az auditban
|
||||
"wallet_created": True
|
||||
}
|
||||
)
|
||||
@@ -231,6 +234,7 @@ class AuthService:
|
||||
await db.commit()
|
||||
await db.refresh(user)
|
||||
return user
|
||||
|
||||
except Exception as e:
|
||||
await db.rollback()
|
||||
logger.error(f"KYC Atomi Tranzakció Hiba: {str(e)}")
|
||||
|
||||
@@ -45,22 +45,42 @@ class GeoService:
|
||||
"""), {"n": street_type.lower()})
|
||||
|
||||
# 4. Központi Address rekord rögzítése
|
||||
full_text = f"{zip_code} {city}, {street_name} {street_type} {house_number}"
|
||||
addr_res = await db.execute(text("""
|
||||
INSERT INTO data.addresses (postal_code_id, street_name, street_type, house_number, parcel_id, full_address_text)
|
||||
VALUES (:zid, :sn, :st, :hn, :pid, :txt)
|
||||
full_text = f"{zip_code} {city}, {street_name} {street_type} {house_number}."
|
||||
if stairwell: full_text += f" {stairwell}. lph,"
|
||||
if floor: full_text += f" {floor}. em,"
|
||||
if door: full_text += f" {door}. ajtó"
|
||||
|
||||
query = text("""
|
||||
INSERT INTO data.addresses (
|
||||
postal_code_id, street_name, street_type, house_number,
|
||||
stairwell, floor, door, parcel_id, full_address_text
|
||||
)
|
||||
VALUES (
|
||||
(SELECT id FROM data.geo_postal_codes WHERE zip_code = :z AND city = :c LIMIT 1),
|
||||
:sn, :st, :hn, :sw, :fl, :dr, :pid, :txt
|
||||
)
|
||||
ON CONFLICT DO NOTHING
|
||||
RETURNING id
|
||||
"""), {
|
||||
"zid": zip_id, "sn": street_name, "st": street_type, "hn": house_number, "pid": parcel_id, "txt": full_text
|
||||
})
|
||||
addr_id = addr_res.scalar()
|
||||
""")
|
||||
|
||||
params = {
|
||||
"z": zip_code, "c": city, "sn": street_name, "st": street_type,
|
||||
"hn": house_number, "sw": stairwell, "fl": floor, "dr": door,
|
||||
"pid": parcel_id, "txt": full_text
|
||||
}
|
||||
|
||||
res = await db.execute(query, params)
|
||||
addr_id = res.scalar()
|
||||
|
||||
if not addr_id:
|
||||
# Ha már létezett, lekérjük az azonosítót
|
||||
# Ha már létezett ilyen részletes cím, lekérjük
|
||||
addr_id = (await db.execute(text("""
|
||||
SELECT id FROM data.addresses
|
||||
WHERE postal_code_id = :zid AND street_name = :sn AND street_type = :st AND house_number = :hn
|
||||
"""), {"zid": zip_id, "sn": street_name, "st": street_type, "hn": house_number})).scalar()
|
||||
WHERE street_name = :sn AND house_number = :hn
|
||||
AND (stairwell IS NOT DISTINCT FROM :sw)
|
||||
AND (floor IS NOT DISTINCT FROM :fl)
|
||||
AND (door IS NOT DISTINCT FROM :dr)
|
||||
LIMIT 1
|
||||
"""), params)).scalar()
|
||||
|
||||
return addr_id
|
||||
Binary file not shown.
Binary file not shown.
61
backend/app/workers/brand_seeder.py
Normal file
61
backend/app/workers/brand_seeder.py
Normal file
@@ -0,0 +1,61 @@
|
||||
import asyncio
|
||||
import httpx
|
||||
import logging
|
||||
from sqlalchemy import text
|
||||
from app.db.session import SessionLocal
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger("Smart-Seeder-v1.0.2")
|
||||
|
||||
async def seed_with_priority():
|
||||
# RDW lekérdezés: Márka, Fő kategória és darabszám
|
||||
# Olyan márkákat keresünk, amikből legalább 10 db van
|
||||
URL = "https://opendata.rdw.nl/resource/m9d7-ebf2.json?$select=merk,voertuigsoort,count(*)%20as%20total&$group=merk,voertuigsoort&$having=total%20>=%2010"
|
||||
|
||||
logger.info("📥 Adatok lekérése az RDW-től prioritásos besoroláshoz...")
|
||||
|
||||
async with httpx.AsyncClient(timeout=120) as client:
|
||||
try:
|
||||
resp = await client.get(URL)
|
||||
if resp.status_code != 200:
|
||||
logger.error(f"❌ API hiba: {resp.status_code}")
|
||||
return
|
||||
|
||||
raw_data = resp.json()
|
||||
async with SessionLocal() as db:
|
||||
for entry in raw_data:
|
||||
make = entry.get("merk", "").upper()
|
||||
v_kind = entry.get("voertuigsoort", "")
|
||||
|
||||
# --- PRIORITÁS LOGIKA ---
|
||||
# 1. Személyautó (Personenauto) -> 'pending' (Azonnali feldolgozás)
|
||||
# 2. Motor (Motorfiets) -> 'queued_motor'
|
||||
# 3. Minden más -> 'queued_heavy'
|
||||
|
||||
status = 'queued_heavy'
|
||||
if "Personenauto" in v_kind:
|
||||
status = 'pending'
|
||||
elif "Motorfiets" in v_kind:
|
||||
status = 'queued_motor'
|
||||
|
||||
query = text("""
|
||||
INSERT INTO data.catalog_discovery (make, model, vehicle_class, source, status)
|
||||
VALUES (:make, 'ALL_VARIANTS', :v_class, 'smart_seeder_v2_1', :status)
|
||||
ON CONFLICT (make, model, vehicle_class) DO UPDATE
|
||||
SET status = EXCLUDED.status WHERE data.catalog_discovery.status = 'pending';
|
||||
""")
|
||||
|
||||
await db.execute(query, {
|
||||
"make": make,
|
||||
"v_class": v_kind,
|
||||
"status": status
|
||||
})
|
||||
|
||||
await db.commit()
|
||||
logger.info("✅ A Discovery lista feltöltve és prioritizálva (Autók az élen)!")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Hiba: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(seed_with_priority())
|
||||
@@ -2,178 +2,207 @@ import asyncio
|
||||
import httpx
|
||||
import logging
|
||||
import json
|
||||
import re
|
||||
import os
|
||||
import datetime
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, func, or_, text
|
||||
from sqlalchemy import text
|
||||
from app.db.session import SessionLocal
|
||||
from app.models.asset import AssetCatalog
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger("Robot1-Ghost-Commander-v1.1.9")
|
||||
logger = logging.getLogger("Robot-v1.0.13-Global-Hunter")
|
||||
|
||||
class CatalogScout:
|
||||
class CatalogMaster:
|
||||
"""
|
||||
Robot 1.1.9: Environment Master.
|
||||
- .env alapú hitelesítés (RDW App Token)
|
||||
- Prioritás: RDW (EU) -> NHTSA (US) -> CarQuery (Ban-figyeléssel)
|
||||
- 2.5s lekérési frissítés a biztonságért
|
||||
Master Hunter Robot v1.0.13 - Global Hunter Edition
|
||||
- Holland (RDW), Brit (DVLA) és Amerikai (NHTSA) adatbázis integráció.
|
||||
- Ratio-Filter: Kiszűri a 0.19-es kW/kg arányszámokat.
|
||||
- Multi-field Power Discovery: Minden lehetséges mezőből kinyeri a kW-ot.
|
||||
- Dinamikus évjárat kezelés a duplikációk ellen.
|
||||
"""
|
||||
|
||||
CQ_URL = "https://www.carqueryapi.com/api/0.3/"
|
||||
NHTSA_BASE = "https://vpic.nhtsa.dot.gov/api/vehicles/GetModelsForMakeYear/make/"
|
||||
RDW_URL = "https://opendata.rdw.nl/resource/ed7h-m8uz.json"
|
||||
# API Végpontok
|
||||
RDW_MAIN = "https://opendata.rdw.nl/resource/m9d7-ebf2.json"
|
||||
RDW_FUEL = "https://opendata.rdw.nl/resource/8ys7-d773.json"
|
||||
RDW_AXLE = "https://opendata.rdw.nl/resource/3huj-srit.json"
|
||||
RDW_BODY = "https://opendata.rdw.nl/resource/vezc-m2t6.json"
|
||||
|
||||
# Adatok beolvasása környezeti változókból
|
||||
UK_DVLA = "https://driver-vehicle-licensing.api.gov.uk/vehicle-enquiry/v1/vehicles"
|
||||
US_NHTSA = "https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVinValuesBatch/"
|
||||
|
||||
RDW_TOKEN = os.getenv("RDW_APP_TOKEN")
|
||||
UK_API_KEY = os.getenv("UK_DVLA_API_KEY")
|
||||
|
||||
HEADERS = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
|
||||
"Accept": "application/json",
|
||||
"X-App-Token": RDW_TOKEN
|
||||
HEADERS_RDW = {"X-App-Token": RDW_TOKEN} if RDW_TOKEN else {}
|
||||
HEADERS_UK = {"x-api-key": UK_API_KEY, "Content-Type": "application/json"} if UK_API_KEY else {}
|
||||
|
||||
CATEGORY_MAP = {
|
||||
"Personenauto": "car",
|
||||
"Motorfiets": "motorcycle",
|
||||
"Bedrijfsauto": "truck",
|
||||
"Vrachtwagen": "truck",
|
||||
"Opleggertrekker": "truck",
|
||||
"Bus": "bus",
|
||||
"Aanhangwagen": "trailer",
|
||||
"Oplegger": "trailer",
|
||||
"Landbouw- of bosbouwtrekker": "agricultural",
|
||||
"camper": "camper"
|
||||
}
|
||||
|
||||
# BAN FIGYELŐ ÁLLAPOT
|
||||
cq_banned_until = None
|
||||
|
||||
# --- KATEGÓRIA DEFINÍCIÓK (Szigorúan az eredeti lista szerint) ---
|
||||
MOTO_MAKES = ['ducati', 'ktm', 'triumph', 'aprilia', 'benelli', 'vespa', 'simson', 'mz', 'etz', 'jawa', 'husqvarna', 'gasgas', 'sherco']
|
||||
MARINE_IDS = ['DF', 'DT', 'OUTBOARD', 'MARINE', 'JET SKI', 'SEA-DOO', 'WAVERUNNER', 'YACHT', 'BOAT']
|
||||
AERIAL_IDS = ['CESSNA', 'PIPER', 'AIRBUS', 'BOEING', 'HELICOPTER', 'AIRCRAFT', 'BEECHCRAFT', 'EMBRAER', 'DRONE']
|
||||
ATV_IDS = ['LT-', 'LTZ', 'LTR', 'KINGQUAD', 'QUAD', 'POLARIS', 'CAN-AM', 'MULE', 'RZR', 'ARCTIC CAT', 'UTV', 'SIDE-BY-SIDE']
|
||||
RACING_IDS = ['RM-Z', 'KX', 'CRF', 'YZ', 'SX-F', 'XC-W', 'RM125', 'RM250', 'CR125', 'CR250', 'MC450']
|
||||
MOTO_KEYWORDS = ['CBR', 'GSX', 'YZF', 'NINJA', 'Z1000', 'DR-Z', 'MT-0', 'V-STROM', 'ADVENTURE', 'SCRAMBLER', 'CBF', 'VFR', 'HAYABUSA']
|
||||
BUS_KEYWORDS = ['BUS', 'COACH', 'INTERCITY', 'SHUTTLE', 'TRANSIT']
|
||||
TRUCK_KEYWORDS = ['TRUCK', 'SEMI', 'TRACTOR', 'HAULER', 'ACTROS', 'MAN', 'SCANIA', 'IVECO', 'VOLVO FH', 'DAF', 'TGX', 'RENAULT T']
|
||||
TRAILER_KEYWORDS = ['TRAILER', 'SEMITRAILER', 'PÓTKOCSI', 'UTÁNFUTÓ', 'SCHMITZ', 'KRONE', 'KÖGEL']
|
||||
|
||||
FALLBACK_BRANDS = ['Audi', 'BMW', 'Mercedes-Benz', 'Volkswagen', 'Toyota', 'Ford', 'Honda', 'Hyundai', 'Kia', 'Mazda', 'Nissan', 'Volvo', 'Skoda', 'Opel', 'Tesla', 'Lexus', 'Porsche', 'Dacia', 'Suzuki']
|
||||
|
||||
@classmethod
|
||||
def identify_class(cls, make: str, model: str) -> str:
|
||||
m_full = f"{str(make)} {str(model)}".upper()
|
||||
if any(x in m_full for x in cls.AERIAL_IDS): return "aerial"
|
||||
if any(x in m_full for x in cls.MARINE_IDS): return "marine"
|
||||
if any(x in m_full for x in cls.ATV_IDS): return "atv"
|
||||
if any(x in m_full or str(make).lower() in cls.MOTO_MAKES for x in (cls.RACING_IDS + cls.MOTO_KEYWORDS)):
|
||||
return "motorcycle"
|
||||
if any(x in m_full for x in cls.BUS_KEYWORDS): return "bus"
|
||||
if any(x in m_full for x in cls.TRUCK_KEYWORDS): return "truck"
|
||||
if any(x in m_full for x in cls.TRAILER_KEYWORDS): return "trailer"
|
||||
return "car"
|
||||
def clean_kw(cls, val):
|
||||
"""Speciális kW tisztító: ignorálja az 1.0 alatti arányszámokat."""
|
||||
try:
|
||||
if val is None: return None
|
||||
f_val = float(str(val).replace(',', '.'))
|
||||
if 0 < f_val < 1.0: return None # Ez csak arányszám (kW/kg)
|
||||
v = int(f_val)
|
||||
return v if v > 0 else None
|
||||
except (ValueError, TypeError):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
async def fetch_api(cls, url, params=None, is_cq=False):
|
||||
if is_cq and cls.cq_banned_until and datetime.datetime.now() < cls.cq_banned_until:
|
||||
return "SILENT_SKIP"
|
||||
def clean_int(cls, val):
|
||||
"""Általános egész szám tisztító."""
|
||||
try:
|
||||
if val is None: return None
|
||||
return int(float(str(val).replace(',', '.')))
|
||||
except (ValueError, TypeError):
|
||||
return None
|
||||
|
||||
async with httpx.AsyncClient(headers=cls.HEADERS, follow_redirects=True) as client:
|
||||
@classmethod
|
||||
async def fetch_api(cls, url, params=None, headers=None, method="GET", json_data=None):
|
||||
"""Univerzális API hívó sebességkorlátozással."""
|
||||
async with httpx.AsyncClient(headers=headers, follow_redirects=True) as client:
|
||||
try:
|
||||
# CarQuery: 5.0mp szünet (Hard Ban ellen), többi: 2.5mp (User kérése szerint)
|
||||
await asyncio.sleep(5.0 if is_cq else 2.5)
|
||||
resp = await client.get(url, params=params, timeout=35)
|
||||
|
||||
if resp.status_code == 403 or "denied" in resp.text.lower():
|
||||
logger.error("🚫 CarQuery BAN! 2 óra kényszerpihenő aktiválva.")
|
||||
cls.cq_banned_until = datetime.datetime.now() + datetime.timedelta(hours=2)
|
||||
return "DENIED"
|
||||
|
||||
if resp.status_code != 200: return None
|
||||
content = resp.text.strip()
|
||||
if is_cq:
|
||||
match = re.search(r'(\{.*\}|\[.*\])', content, re.DOTALL)
|
||||
if match: content = match.group(0)
|
||||
return json.loads(content)
|
||||
await asyncio.sleep(1.2) # Biztonsági késleltetés
|
||||
if method == "POST":
|
||||
resp = await client.post(url, json=json_data, timeout=30)
|
||||
else:
|
||||
resp = await client.get(url, params=params, timeout=30)
|
||||
return resp.json() if resp.status_code in [200, 201] else []
|
||||
except Exception as e:
|
||||
logger.error(f"❌ API hiba: {e}")
|
||||
return None
|
||||
logger.error(f"❌ API Hiba ({url}): {e}")
|
||||
return []
|
||||
|
||||
@classmethod
|
||||
async def is_model_processed(cls, db: AsyncSession, make: str, model: str, year: int):
|
||||
stmt = select(AssetCatalog.id).where(AssetCatalog.make == make, AssetCatalog.model == model, AssetCatalog.year_from == year).limit(1)
|
||||
result = await db.execute(stmt)
|
||||
return result.scalars().first() is not None
|
||||
async def get_deep_tech(cls, plate, main_kw=None, vin=None):
|
||||
"""Nemzetközi dúsítás: Holland -> Brit -> Amerikai sorrendben."""
|
||||
res = {"kw": cls.clean_kw(main_kw), "fuel": "Unknown", "axles": None, "body": "Standard", "euro": None}
|
||||
|
||||
# 1. HOLLAND (RDW) DÚSÍTÁS
|
||||
fuel_data = await cls.fetch_api(cls.RDW_FUEL, {"kenteken": plate}, headers=cls.HEADERS_RDW)
|
||||
if fuel_data:
|
||||
f0 = fuel_data[0]
|
||||
if not res["kw"]:
|
||||
res["kw"] = cls.clean_kw(f0.get("nettomaximumvermogen") or f0.get("netto_maximum_vermogen"))
|
||||
res["fuel"] = f0.get("brandstof_omschrijving", "Unknown")
|
||||
res["euro"] = f0.get("uitlaatemissieniveau")
|
||||
|
||||
# 2. BRIT (DVLA) ELLENŐRZÉS (Ha van UK kulcs és még hiányzik adat)
|
||||
if cls.UK_API_KEY and (not res["kw"] or not res["euro"]):
|
||||
uk_data = await cls.fetch_api(cls.UK_DVLA, method="POST", json_data={"registrationNumber": plate}, headers=cls.HEADERS_UK)
|
||||
if uk_data:
|
||||
res["kw"] = res["kw"] or cls.clean_kw(uk_data.get("engineCapacity")) # Brit adatok finomítása
|
||||
res["euro"] = res["euro"] or uk_data.get("euroStatus")
|
||||
|
||||
# 3. AMERIKAI (NHTSA) KUTATÁS (Ha van alvázszám)
|
||||
if vin and len(vin) == 17:
|
||||
us_data = await cls.fetch_api(cls.US_NHTSA, params={"format": "json", "data": vin})
|
||||
if us_data and "Results" in us_data:
|
||||
# Az amerikai adatbázisból kinyerjük a lóerőt (HP), ha a kW még mindig nincs meg
|
||||
hp = us_data["Results"][0].get("EngineHP")
|
||||
if hp and not res["kw"]:
|
||||
res["kw"] = int(float(hp) * 0.7457) # HP -> kW konverzió
|
||||
|
||||
# RDW Extra adatok (Tengely, Karosszéria)
|
||||
axle = await cls.fetch_api(cls.RDW_AXLE, {"kenteken": plate}, headers=cls.HEADERS_RDW)
|
||||
if axle: res["axles"] = cls.clean_int(axle[0].get("aantal_assen"))
|
||||
|
||||
body = await cls.fetch_api(cls.RDW_BODY, {"kenteken": plate}, headers=cls.HEADERS_RDW)
|
||||
if body: res["body"] = body[0].get("carrosserie_omschrijving", "Standard")
|
||||
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
async def auto_heal(cls, db: AsyncSession, cq_active: bool):
|
||||
logger.info("🛠️ Auto-Heal: Hiányos rekordok dúsítása...")
|
||||
stmt = select(AssetCatalog).where(AssetCatalog.engine_variant == 'Standard', AssetCatalog.fuel_type == 'Unknown').limit(20)
|
||||
results = await db.execute(stmt)
|
||||
for r in results.scalars().all():
|
||||
# 1. RDW javítás (Holland Open Data + Token)
|
||||
rdw = await cls.fetch_api(cls.RDW_URL, {"merk": r.make.upper(), "handelsbenaming": r.model.upper(), "$limit": 1})
|
||||
if rdw and isinstance(rdw, list) and len(rdw) > 0:
|
||||
item = rdw[0]
|
||||
r.fuel_type = item.get("brandstof_omschrijving", "Unknown")
|
||||
r.factory_data.update({"hp": item.get("netto_maximum_vermogen"), "cc": item.get("cilinderinhoud"), "source": "heal_v1.9_rdw"})
|
||||
async def process_make(cls, db, task_id, make_name):
|
||||
logger.info(f"🚀 >>> {make_name} GlobalHunter v1.0.13 INDUL...")
|
||||
offset, limit, total_saved = 0, 1000, 0
|
||||
unique_variants = {}
|
||||
|
||||
while True:
|
||||
params = {"merk": make_name.upper(), "$limit": limit, "$offset": offset}
|
||||
main_data = await cls.fetch_api(cls.RDW_MAIN, params, headers=cls.HEADERS_RDW)
|
||||
if not main_data: break
|
||||
|
||||
for item in main_data:
|
||||
plate = item.get("kenteken")
|
||||
if not plate: continue
|
||||
|
||||
model = str(item.get("handelsbenaming", "Unknown")).upper()
|
||||
ccm = cls.clean_int(item.get("cilinderinhoud"))
|
||||
weight = cls.clean_int(item.get("massa_ledig_voertuig") or item.get("massa_rijklaar"))
|
||||
kw_candidate = item.get("netto_maximum_vermogen") or item.get("vermogen_massarijklaar")
|
||||
|
||||
raw_date = item.get("datum_eerste_toelating")
|
||||
prod_year = int(str(raw_date)[:4]) if raw_date else 2024
|
||||
|
||||
v_class = cls.CATEGORY_MAP.get(item.get("voertuigsoort"), "other")
|
||||
if "kampeerwagen" in str(item.get("inrichting", "")).lower(): v_class = "camper"
|
||||
|
||||
# Variáns kulcs: Modell + CCM + Súly + kW + Év = Egyedi technikai ujjlenyomat
|
||||
variant_key = f"{model}-{ccm}-{weight}-{v_class}-{kw_candidate}-{prod_year}"
|
||||
|
||||
if variant_key not in unique_variants:
|
||||
unique_variants[variant_key] = {
|
||||
"model": model, "ccm": ccm, "weight": weight, "v_class": v_class,
|
||||
"plate": plate, "main_kw": kw_candidate, "prod_year": prod_year,
|
||||
"vin": item.get("vin") # Ha az RDW-ben benne van a VIN
|
||||
}
|
||||
|
||||
if len(main_data) < limit or offset > 90000: break
|
||||
offset += limit
|
||||
|
||||
logger.info(f"📊 {len(unique_variants)} egyedi variáns kutatása indul...")
|
||||
|
||||
for key, v in unique_variants.items():
|
||||
deep = await cls.get_deep_tech(v["plate"], main_kw=v["main_kw"], vin=v["vin"])
|
||||
try:
|
||||
db_item = AssetCatalog(
|
||||
make=make_name.upper(), model=v["model"], vehicle_class=v["v_class"],
|
||||
fuel_type=deep["fuel"], power_kw=deep["kw"], engine_capacity=v["ccm"],
|
||||
max_weight_kg=v["weight"], axle_count=deep["axles"], body_type=deep["body"],
|
||||
year_from=v["prod_year"], euro_class=deep["euro"],
|
||||
factory_data={
|
||||
"source": "GlobalHunter-v1.0.13",
|
||||
"sample_plate": v["plate"],
|
||||
"enriched_at": str(datetime.datetime.now())
|
||||
}
|
||||
)
|
||||
db.add(db_item)
|
||||
await db.commit()
|
||||
total_saved += 1
|
||||
if total_saved % 50 == 0: logger.info(f"✅ {total_saved} variáns elmentve.")
|
||||
except Exception:
|
||||
await db.rollback()
|
||||
continue
|
||||
|
||||
# 2. CQ javítás (Ha nem vagyunk kitiltva)
|
||||
if cq_active:
|
||||
t_data = await cls.fetch_api(cls.CQ_URL, {"cmd": "getTrims", "make": r.make.lower(), "model": r.model, "year": r.year_from}, is_cq=True)
|
||||
if t_data and t_data not in ["DENIED", "SILENT_SKIP"] and "Trims" in t_data:
|
||||
t = t_data["Trims"][0]
|
||||
r.engine_variant = t.get("model_trim") or "Standard"
|
||||
r.factory_data.update({"hp": t.get("model_engine_power_ps"), "cc": t.get("model_engine_cc"), "source": "heal_v1.9_cq"})
|
||||
|
||||
await db.execute(text("UPDATE data.catalog_discovery SET status = 'processed' WHERE id = :id"), {"id": task_id})
|
||||
await db.commit()
|
||||
logger.info(f"🏁 {make_name} KÉSZ. {total_saved} rekord rögzítve.")
|
||||
|
||||
@classmethod
|
||||
async def run(cls):
|
||||
logger.info(f"🤖 Robot 1.9.2 indítása (RDW Token: {'Aktív' if cls.RDW_TOKEN else 'HIÁNYZIK!'})")
|
||||
|
||||
for year in range(2026, 1989, -1):
|
||||
logger.info(f"📅 --- CIKLUS: {year} ---")
|
||||
|
||||
cq_now_active = not (cls.cq_banned_until and datetime.datetime.now() < cls.cq_banned_until)
|
||||
|
||||
logger.info("🤖 Robot 1.0.13 (Global Hunter) ONLINE")
|
||||
while True:
|
||||
async with SessionLocal() as db:
|
||||
await cls.auto_heal(db, cq_now_active)
|
||||
|
||||
# 1. MÁRKALISTA (NHTSA + Fallback)
|
||||
makes_to_process = []
|
||||
for b in cls.FALLBACK_BRANDS:
|
||||
makes_to_process.append({"id": b.lower(), "display": b})
|
||||
|
||||
for make in makes_to_process:
|
||||
models_to_fetch = set()
|
||||
|
||||
# A: NHTSA (US)
|
||||
n_data = await cls.fetch_api(f"{cls.NHTSA_BASE}{make['display']}/modelyear/{year}?format=json")
|
||||
if n_data and n_data.get("Results"):
|
||||
for r in n_data["Results"]: models_to_fetch.add(r["Model_Name"])
|
||||
|
||||
# B: RDW (Holland) - Tokennel védve
|
||||
rdw_m = await cls.fetch_api(cls.RDW_URL, {"merk": make['display'].upper(), "$limit": 30})
|
||||
if rdw_m and isinstance(rdw_m, list):
|
||||
for r in rdw_m: models_to_fetch.add(r.get("handelsbenaming"))
|
||||
|
||||
async with SessionLocal() as db:
|
||||
for model_name in models_to_fetch:
|
||||
if not model_name or await cls.is_model_processed(db, make["display"], model_name, year):
|
||||
continue
|
||||
|
||||
# C: CarQuery (Csak ha nincs ban)
|
||||
found_trims = []
|
||||
t_data = await cls.fetch_api(cls.CQ_URL, {"cmd": "getTrims", "make": make["id"], "model": model_name, "year": year}, is_cq=True)
|
||||
if t_data and t_data not in ["DENIED", "SILENT_SKIP"] and "Trims" in t_data:
|
||||
found_trims = t_data["Trims"]
|
||||
|
||||
if not found_trims:
|
||||
found_trims = [{"model_trim": "Standard", "model_engine_fuel": "Unknown"}]
|
||||
|
||||
for t in found_trims:
|
||||
db.add(AssetCatalog(
|
||||
make=make["display"], model=model_name, year_from=year,
|
||||
engine_variant=t.get("model_trim") or "Standard",
|
||||
fuel_type=t.get("model_engine_fuel") or "Unknown",
|
||||
vehicle_class=cls.identify_class(make["display"], model_name),
|
||||
factory_data={
|
||||
"hp": t.get("model_engine_power_ps"), "cc": t.get("model_engine_cc"),
|
||||
"source": "ghost_v1.9.2", "sync_date": str(datetime.datetime.now())
|
||||
}
|
||||
))
|
||||
await db.commit()
|
||||
res = await db.execute(text("SELECT id, make FROM data.catalog_discovery WHERE status = 'pending' LIMIT 1"))
|
||||
task = res.fetchone()
|
||||
if task:
|
||||
await cls.process_make(db, task[0], task[1])
|
||||
else:
|
||||
logger.info("😴 Várólista üres. Alvás 60 mp...")
|
||||
await asyncio.sleep(60)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(CatalogScout.run())
|
||||
asyncio.run(CatalogMaster.run())
|
||||
@@ -1,282 +1,161 @@
|
||||
import asyncio
|
||||
import httpx
|
||||
import logging
|
||||
import uuid
|
||||
import os
|
||||
import sys
|
||||
import csv
|
||||
from datetime import datetime, timezone
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, text
|
||||
from sqlalchemy.orm import selectinload
|
||||
from app.db.session import SessionLocal
|
||||
|
||||
# Modellek importálása
|
||||
from app.models.service import ServiceProfile, ExpertiseTag
|
||||
from app.models.organization import Organization, OrganizationFinancials, OrgType, OrgUserRole, OrganizationMember
|
||||
from app.models.identity import Person
|
||||
from app.models.address import Address, GeoPostalCode
|
||||
from geoalchemy2.elements import WKTElement
|
||||
from datetime import datetime, timezone
|
||||
# Modellek - Az új v1.3 struktúra
|
||||
from app.models.service import ServiceStaging, DiscoveryParameter
|
||||
|
||||
# Naplózás beállítása
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger("Robot2-Dunakeszi-Detective")
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
logger = logging.getLogger("Robot-v1.3-ContinentalScout")
|
||||
|
||||
class ServiceHunter:
|
||||
"""
|
||||
Robot 2.7.2: Dunakeszi Detective - Deep Model Integration.
|
||||
Logika:
|
||||
1. Helyi CSV (Saját beküldés - Cím alapú Geocoding-al - 50 pont Trust)
|
||||
2. OSM (Közösségi adat - 10 pont Trust)
|
||||
3. Google (Adatpótlás/Fallback - 30 pont Trust)
|
||||
Robot v1.3.0: Continental Scout.
|
||||
EU-szintű felderítő motor, Discovery tábla alapú vezérléssel.
|
||||
"""
|
||||
OVERPASS_URL = "http://overpass-api.de/api/interpreter"
|
||||
PLACES_NEW_URL = "https://places.googleapis.com/v1/places:searchNearby"
|
||||
GEOCODE_URL = "https://maps.googleapis.com/maps/api/geocode/json"
|
||||
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
|
||||
LOCAL_CSV_PATH = "/app/app/workers/local_services.csv"
|
||||
|
||||
@classmethod
|
||||
async def geocode_address(cls, address_text):
|
||||
"""Cím szövegből GPS koordinátát és címkomponenseket csinál."""
|
||||
if not cls.GOOGLE_API_KEY:
|
||||
logger.warning("⚠️ Google API kulcs hiányzik!")
|
||||
return None
|
||||
|
||||
params = {"address": address_text, "key": cls.GOOGLE_API_KEY}
|
||||
try:
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(cls.GEOCODE_URL, params=params, timeout=10)
|
||||
if resp.status_code == 200:
|
||||
data = resp.json()
|
||||
if data.get("results"):
|
||||
result = data["results"][0]
|
||||
loc = result["geometry"]["location"]
|
||||
|
||||
# Címkomponensek kinyerése a kötelező mezőkhöz
|
||||
components = result.get("address_components", [])
|
||||
parsed = {"lat": loc["lat"], "lng": loc["lng"], "zip": "", "city": "", "street": "Ismeretlen", "type": "utca", "number": "1"}
|
||||
|
||||
for c in components:
|
||||
types = c.get("types", [])
|
||||
if "postal_code" in types: parsed["zip"] = c["long_name"]
|
||||
if "locality" in types: parsed["city"] = c["long_name"]
|
||||
if "route" in types: parsed["street"] = c["long_name"]
|
||||
if "street_number" in types: parsed["number"] = c["long_name"]
|
||||
|
||||
logger.info(f"📍 Geocoding sikeres: {address_text}")
|
||||
return parsed
|
||||
else:
|
||||
logger.error(f"❌ Geocoding hiba: {resp.status_code}")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Geocoding hiba: {e}")
|
||||
return None
|
||||
async def get_coordinates(cls, city, country_code):
|
||||
"""Város központjának lekérése a keresés indításához."""
|
||||
params = {"address": f"{city}, {country_code}", "key": cls.GOOGLE_API_KEY}
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(cls.GEOCODE_URL, params=params)
|
||||
if resp.status_code == 200:
|
||||
results = resp.json().get("results")
|
||||
if results:
|
||||
loc = results[0]["geometry"]["location"]
|
||||
return loc["lat"], loc["lng"]
|
||||
return None, None
|
||||
|
||||
@classmethod
|
||||
async def get_google_place_details_new(cls, lat, lon):
|
||||
"""Google Places API (New) - Adatpótlás FieldMask használatával."""
|
||||
if not cls.GOOGLE_API_KEY:
|
||||
return None
|
||||
async def get_google_places(cls, lat, lon, keyword):
|
||||
"""Google Places New API - Javított, 400-as hiba elleni védelemmel."""
|
||||
if not cls.GOOGLE_API_KEY: return []
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Goog-Api-Key": cls.GOOGLE_API_KEY,
|
||||
"X-Goog-FieldMask": "places.displayName,places.id,places.types,places.internationalPhoneNumber,places.websiteUri"
|
||||
"X-Goog-FieldMask": "places.displayName,places.id,places.types,places.internationalPhoneNumber,places.websiteUri,places.formattedAddress"
|
||||
}
|
||||
|
||||
# A 'keyword' a TextQuery-hez kellene, a SearchNearby-nél típusokat (includedTypes) használunk.
|
||||
# EU szintű trükk: Ha nincs pontos típus, a 'car_repair' az alapértelmezett.
|
||||
payload = {
|
||||
"includedTypes": ["car_repair", "gas_station", "ev_charging_station", "car_wash", "motorcycle_repair"],
|
||||
"maxResultCount": 1,
|
||||
"includedTypes": ["car_repair", "gas_station", "car_wash", "motorcycle_repair"],
|
||||
"maxResultCount": 20,
|
||||
"locationRestriction": {
|
||||
"circle": {
|
||||
"center": {"latitude": lat, "longitude": lon},
|
||||
"radius": 40.0
|
||||
"radius": 5000.0 # 5km körzet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.post(cls.PLACES_NEW_URL, json=payload, headers=headers, timeout=10)
|
||||
if resp.status_code == 200:
|
||||
places = resp.json().get("places", [])
|
||||
if places:
|
||||
p = places[0]
|
||||
return {
|
||||
"name": p.get("displayName", {}).get("text"),
|
||||
"google_id": p.get("id"),
|
||||
"types": p.get("types", []),
|
||||
"phone": p.get("internationalPhoneNumber"),
|
||||
"website": p.get("websiteUri")
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Google kiegészítő hívás hiba: {e}")
|
||||
return None
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.post(cls.PLACES_NEW_URL, json=payload, headers=headers)
|
||||
if resp.status_code == 200:
|
||||
return resp.json().get("places", [])
|
||||
else:
|
||||
logger.error(f"❌ Google API hiba ({resp.status_code}): {resp.text}")
|
||||
return []
|
||||
|
||||
@classmethod
|
||||
async def import_local_csv(cls, db: AsyncSession):
|
||||
"""Manuális adatok betöltése CSV-ből."""
|
||||
if not os.path.exists(cls.LOCAL_CSV_PATH):
|
||||
return
|
||||
async def save_to_staging(cls, db: AsyncSession, data: dict):
|
||||
"""Mentés a Staging táblába 9-mezős bontással."""
|
||||
stmt = select(ServiceStaging).where(ServiceStaging.external_id == str(data['external_id']))
|
||||
if (await db.execute(stmt)).scalar_one_or_none(): return
|
||||
|
||||
try:
|
||||
with open(cls.LOCAL_CSV_PATH, mode='r', encoding='utf-8') as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
geo_data = None
|
||||
if row.get('cim'):
|
||||
geo_data = await cls.geocode_address(row['cim'])
|
||||
|
||||
if geo_data:
|
||||
element = {
|
||||
"tags": {
|
||||
"name": row['nev'], "phone": row.get('telefon'),
|
||||
"website": row.get('web'), "amenity": row.get('tipus', 'car_repair'),
|
||||
"addr:full": row.get('cim'),
|
||||
"addr:city": geo_data["city"], "addr:zip": geo_data["zip"],
|
||||
"addr:street": geo_data["street"], "addr:type": geo_data["type"],
|
||||
"addr:number": geo_data["number"]
|
||||
},
|
||||
"lat": geo_data["lat"], "lon": geo_data["lng"]
|
||||
}
|
||||
await cls.save_service_deep(db, element, source="local_manual")
|
||||
logger.info("✅ Helyi CSV adatok feldolgozva.")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ CSV feldolgozási hiba: {e}")
|
||||
|
||||
@classmethod
|
||||
async def get_or_create_person(cls, db: AsyncSession, name: str) -> Person:
|
||||
"""Ghost Person kezelése."""
|
||||
names = name.split(' ', 1)
|
||||
last_name = names[0]
|
||||
first_name = names[1] if len(names) > 1 else "Ismeretlen"
|
||||
stmt = select(Person).where(Person.last_name == last_name, Person.first_name == first_name)
|
||||
result = await db.execute(stmt); person = result.scalar_one_or_none()
|
||||
if not person:
|
||||
person = Person(last_name=last_name, first_name=first_name, is_ghost=True, is_active=False)
|
||||
db.add(person); await db.flush()
|
||||
return person
|
||||
|
||||
@classmethod
|
||||
async def enrich_financials(cls, db: AsyncSession, org_id: int):
|
||||
"""Pénzügyi rekord inicializálása."""
|
||||
financial = OrganizationFinancials(
|
||||
organization_id=org_id, year=datetime.now(timezone.utc).year - 1, source="bot_discovery"
|
||||
new_entry = ServiceStaging(
|
||||
name=data['name'],
|
||||
source=data['source'],
|
||||
external_id=str(data['external_id']),
|
||||
# Itt történik a 9-mezős bontás (ha érkezik adat)
|
||||
postal_code=data.get('zip'),
|
||||
city=data.get('city'),
|
||||
street_name=data.get('street'),
|
||||
street_type=data.get('street_type', 'utca'),
|
||||
house_number=data.get('number'),
|
||||
full_address=data.get('full_address'),
|
||||
contact_phone=data.get('phone'),
|
||||
website=data.get('website'),
|
||||
raw_data=data.get('raw', {}),
|
||||
status="pending",
|
||||
trust_score=data.get('trust', 10)
|
||||
)
|
||||
db.add(financial)
|
||||
|
||||
@classmethod
|
||||
async def save_service_deep(cls, db: AsyncSession, element: dict, source="osm"):
|
||||
"""Mély mentés a modelled specifikus mezőneveivel és kötelező értékeivel."""
|
||||
tags = element.get("tags", {})
|
||||
lat, lon = element.get("lat"), element.get("lon")
|
||||
if not lat or not lon: return
|
||||
|
||||
osm_name = tags.get("name") or tags.get("brand") or tags.get("operator")
|
||||
google_data = None
|
||||
if not osm_name or osm_name.lower() in ['aprilia', 'bosch', 'shell', 'mol', 'omv', 'ismeretlen']:
|
||||
google_data = await cls.get_google_place_details_new(lat, lon)
|
||||
|
||||
final_name = (google_data["name"] if google_data else osm_name) or "Ismeretlen Szolgáltató"
|
||||
|
||||
stmt = select(Organization).where(Organization.full_name == final_name)
|
||||
result = await db.execute(stmt); org = result.scalar_one_or_none()
|
||||
|
||||
if not org:
|
||||
# 1. Address létrehozása (a kötelező mezőket kitöltjük az átadott tags-ből vagy alapértékkel)
|
||||
new_addr = Address(
|
||||
latitude=lat,
|
||||
longitude=lon,
|
||||
full_address_text=tags.get("addr:full") or f"2120 Dunakeszi, {tags.get('addr:street', 'Ismeretlen')} {tags.get('addr:housenumber', '1')}",
|
||||
street_name=tags.get("addr:street") or "Ismeretlen",
|
||||
street_type=tags.get("addr:type") or "utca",
|
||||
house_number=tags.get("addr:number") or tags.get("addr:housenumber") or "1"
|
||||
)
|
||||
db.add(new_addr); await db.flush()
|
||||
|
||||
# 2. Organization létrehozása (a modelled alapján ezek a mezők itt vannak)
|
||||
org = Organization(
|
||||
full_name=final_name,
|
||||
name=final_name[:50],
|
||||
org_type=OrgType.service,
|
||||
address_id=new_addr.id,
|
||||
address_city=tags.get("addr:city") or "Dunakeszi",
|
||||
address_zip=tags.get("addr:zip") or "2120",
|
||||
address_street_name=new_addr.street_name,
|
||||
address_street_type=new_addr.street_type,
|
||||
address_house_number=new_addr.house_number
|
||||
)
|
||||
db.add(org); await db.flush()
|
||||
|
||||
# 3. Service Profile
|
||||
trust = 50 if source == "local_manual" else (30 if google_data else 10)
|
||||
spec = {"brands": [], "types": google_data["types"] if google_data else [], "osm_tags": tags}
|
||||
if tags.get("brand"): spec["brands"].append(tags.get("brand"))
|
||||
|
||||
profile = ServiceProfile(
|
||||
organization_id=org.id,
|
||||
location=WKTElement(f'POINT({lon} {lat})', srid=4326),
|
||||
status="ghost",
|
||||
trust_score=trust,
|
||||
google_place_id=google_data["google_id"] if google_data else None,
|
||||
specialization_tags=spec,
|
||||
website=google_data["website"] if google_data else tags.get("website"),
|
||||
contact_phone=google_data["phone"] if google_data else tags.get("phone")
|
||||
)
|
||||
db.add(profile)
|
||||
|
||||
# 4. Tulajdonos rögzítése
|
||||
owner_name = tags.get("operator") or tags.get("contact:person")
|
||||
if owner_name and len(owner_name) > 3:
|
||||
person = await cls.get_or_create_person(db, owner_name)
|
||||
db.add(OrganizationMember(
|
||||
organization_id=org.id,
|
||||
person_id=person.id,
|
||||
role=OrgUserRole.OWNER,
|
||||
is_verified=False
|
||||
))
|
||||
|
||||
await cls.enrich_financials(db, org.id)
|
||||
await db.flush()
|
||||
logger.info(f"✨ [{source.upper()}] Mentve: {final_name} (Bizalom: {trust})")
|
||||
db.add(new_entry)
|
||||
|
||||
@classmethod
|
||||
async def run(cls):
|
||||
logger.info("🤖 Robot 2.7.2: Dunakeszi Detective indítása...")
|
||||
logger.info("🤖 Robot v1.3.0: Continental Scout elindult...")
|
||||
|
||||
# Kapcsolódási védelem
|
||||
connected = False
|
||||
while not connected:
|
||||
try:
|
||||
async with SessionLocal() as db:
|
||||
await db.execute(text("SELECT 1"))
|
||||
connected = True
|
||||
except Exception as e:
|
||||
logger.warning(f"⏳ Várakozás a hálózatra (shared-postgres host?): {e}")
|
||||
await asyncio.sleep(5)
|
||||
|
||||
while True:
|
||||
async with SessionLocal() as db:
|
||||
try:
|
||||
await db.execute(text("SET search_path TO data, public"))
|
||||
# 1. Beküldött CSV feldolgozása (Geocoding-al)
|
||||
await cls.import_local_csv(db)
|
||||
await db.commit()
|
||||
|
||||
# 2. OSM Szkennelés
|
||||
query = """[out:json][timeout:120];area["name"="Dunakeszi"]->.city;(nwr["shop"~"car_repair|motorcycle_repair|tyres|car_parts|motorcycle"](area.city);nwr["amenity"~"car_repair|vehicle_inspection|motorcycle_repair|fuel|charging_station|car_wash"](area.city);nwr["amenity"~"car_repair|fuel|charging_station"](around:5000, 47.63, 19.13););out center;"""
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.post(cls.OVERPASS_URL, data={"data": query}, timeout=120)
|
||||
if resp.status_code == 200:
|
||||
elements = resp.json().get("elements", [])
|
||||
for el in elements:
|
||||
await cls.save_service_deep(db, el, source="osm")
|
||||
await db.commit()
|
||||
# 1. Paraméterek lekérése a táblából
|
||||
stmt = select(DiscoveryParameter).where(DiscoveryParameter.is_active == True)
|
||||
tasks = (await db.execute(stmt)).scalars().all()
|
||||
|
||||
for task in tasks:
|
||||
logger.info(f"🔎 Felderítés: {task.city} ({task.country_code}) -> {task.keyword}")
|
||||
|
||||
# Koordináták beszerzése a kereséshez
|
||||
lat, lon = await cls.get_coordinates(task.city, task.country_code)
|
||||
if not lat: continue
|
||||
|
||||
# --- GOOGLE FÁZIS ---
|
||||
google_places = await cls.get_google_places(lat, lon, task.keyword)
|
||||
for p in google_places:
|
||||
await cls.save_to_staging(db, {
|
||||
"external_id": p.get('id'),
|
||||
"name": p.get('displayName', {}).get('text'),
|
||||
"full_address": p.get('formattedAddress'),
|
||||
"phone": p.get('internationalPhoneNumber'),
|
||||
"website": p.get('websiteUri'),
|
||||
"source": "google",
|
||||
"raw": p,
|
||||
"trust": 30
|
||||
})
|
||||
|
||||
# --- OSM FÁZIS (EU kompatibilis lekérdezés) ---
|
||||
osm_query = f"""[out:json][timeout:60];
|
||||
(nwr["amenity"~"car_repair|fuel"](around:5000, {lat}, {lon}););
|
||||
out center;"""
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.post(cls.OVERPASS_URL, data={"data": osm_query})
|
||||
if resp.status_code == 200:
|
||||
for el in resp.json().get("elements", []):
|
||||
t = el.get("tags", {})
|
||||
await cls.save_to_staging(db, {
|
||||
"external_id": f"osm_{el['id']}",
|
||||
"name": t.get('name', 'Ismeretlen szerviz'),
|
||||
"city": t.get('addr:city', task.city),
|
||||
"zip": t.get('addr:postcode'),
|
||||
"street": t.get('addr:street'),
|
||||
"number": t.get('addr:housenumber'),
|
||||
"source": "osm",
|
||||
"raw": el,
|
||||
"trust": 15
|
||||
})
|
||||
|
||||
task.last_run_at = datetime.now(timezone.utc)
|
||||
await db.commit()
|
||||
logger.info(f"✅ {task.city} felderítve.")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Futáshiba: {e}")
|
||||
logger.error(f"💥 Kritikus hiba a ciklusban: {e}")
|
||||
|
||||
logger.info("😴 Scan kész, 24 óra pihenő...")
|
||||
await asyncio.sleep(86400)
|
||||
logger.info("😴 Minden aktív feladat kész. Alvás 1 órán át...")
|
||||
await asyncio.sleep(3600)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(ServiceHunter.run())
|
||||
282
backend/app/workers/service_hunter_old.py
Normal file
282
backend/app/workers/service_hunter_old.py
Normal file
@@ -0,0 +1,282 @@
|
||||
import asyncio
|
||||
import httpx
|
||||
import logging
|
||||
import uuid
|
||||
import os
|
||||
import sys
|
||||
import csv
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, text
|
||||
from sqlalchemy.orm import selectinload
|
||||
from app.db.session import SessionLocal
|
||||
|
||||
# Modellek importálása
|
||||
from app.models.service import ServiceProfile, ExpertiseTag
|
||||
from app.models.organization import Organization, OrganizationFinancials, OrgType, OrgUserRole, OrganizationMember
|
||||
from app.models.identity import Person
|
||||
from app.models.address import Address, GeoPostalCode
|
||||
from geoalchemy2.elements import WKTElement
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Naplózás beállítása
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger("Robot2-Dunakeszi-Detective")
|
||||
|
||||
class ServiceHunter:
|
||||
"""
|
||||
Robot 2.7.2: Dunakeszi Detective - Deep Model Integration.
|
||||
Logika:
|
||||
1. Helyi CSV (Saját beküldés - Cím alapú Geocoding-al - 50 pont Trust)
|
||||
2. OSM (Közösségi adat - 10 pont Trust)
|
||||
3. Google (Adatpótlás/Fallback - 30 pont Trust)
|
||||
"""
|
||||
OVERPASS_URL = "http://overpass-api.de/api/interpreter"
|
||||
PLACES_NEW_URL = "https://places.googleapis.com/v1/places:searchNearby"
|
||||
GEOCODE_URL = "https://maps.googleapis.com/maps/api/geocode/json"
|
||||
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
|
||||
LOCAL_CSV_PATH = "/app/app/workers/local_services.csv"
|
||||
|
||||
@classmethod
|
||||
async def geocode_address(cls, address_text):
|
||||
"""Cím szövegből GPS koordinátát és címkomponenseket csinál."""
|
||||
if not cls.GOOGLE_API_KEY:
|
||||
logger.warning("⚠️ Google API kulcs hiányzik!")
|
||||
return None
|
||||
|
||||
params = {"address": address_text, "key": cls.GOOGLE_API_KEY}
|
||||
try:
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(cls.GEOCODE_URL, params=params, timeout=10)
|
||||
if resp.status_code == 200:
|
||||
data = resp.json()
|
||||
if data.get("results"):
|
||||
result = data["results"][0]
|
||||
loc = result["geometry"]["location"]
|
||||
|
||||
# Címkomponensek kinyerése a kötelező mezőkhöz
|
||||
components = result.get("address_components", [])
|
||||
parsed = {"lat": loc["lat"], "lng": loc["lng"], "zip": "", "city": "", "street": "Ismeretlen", "type": "utca", "number": "1"}
|
||||
|
||||
for c in components:
|
||||
types = c.get("types", [])
|
||||
if "postal_code" in types: parsed["zip"] = c["long_name"]
|
||||
if "locality" in types: parsed["city"] = c["long_name"]
|
||||
if "route" in types: parsed["street"] = c["long_name"]
|
||||
if "street_number" in types: parsed["number"] = c["long_name"]
|
||||
|
||||
logger.info(f"📍 Geocoding sikeres: {address_text}")
|
||||
return parsed
|
||||
else:
|
||||
logger.error(f"❌ Geocoding hiba: {resp.status_code}")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Geocoding hiba: {e}")
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
async def get_google_place_details_new(cls, lat, lon):
|
||||
"""Google Places API (New) - Adatpótlás FieldMask használatával."""
|
||||
if not cls.GOOGLE_API_KEY:
|
||||
return None
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Goog-Api-Key": cls.GOOGLE_API_KEY,
|
||||
"X-Goog-FieldMask": "places.displayName,places.id,places.types,places.internationalPhoneNumber,places.websiteUri"
|
||||
}
|
||||
|
||||
payload = {
|
||||
"includedTypes": ["car_repair", "gas_station", "ev_charging_station", "car_wash", "motorcycle_repair"],
|
||||
"maxResultCount": 1,
|
||||
"locationRestriction": {
|
||||
"circle": {
|
||||
"center": {"latitude": lat, "longitude": lon},
|
||||
"radius": 40.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.post(cls.PLACES_NEW_URL, json=payload, headers=headers, timeout=10)
|
||||
if resp.status_code == 200:
|
||||
places = resp.json().get("places", [])
|
||||
if places:
|
||||
p = places[0]
|
||||
return {
|
||||
"name": p.get("displayName", {}).get("text"),
|
||||
"google_id": p.get("id"),
|
||||
"types": p.get("types", []),
|
||||
"phone": p.get("internationalPhoneNumber"),
|
||||
"website": p.get("websiteUri")
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Google kiegészítő hívás hiba: {e}")
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
async def import_local_csv(cls, db: AsyncSession):
|
||||
"""Manuális adatok betöltése CSV-ből."""
|
||||
if not os.path.exists(cls.LOCAL_CSV_PATH):
|
||||
return
|
||||
|
||||
try:
|
||||
with open(cls.LOCAL_CSV_PATH, mode='r', encoding='utf-8') as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
geo_data = None
|
||||
if row.get('cim'):
|
||||
geo_data = await cls.geocode_address(row['cim'])
|
||||
|
||||
if geo_data:
|
||||
element = {
|
||||
"tags": {
|
||||
"name": row['nev'], "phone": row.get('telefon'),
|
||||
"website": row.get('web'), "amenity": row.get('tipus', 'car_repair'),
|
||||
"addr:full": row.get('cim'),
|
||||
"addr:city": geo_data["city"], "addr:zip": geo_data["zip"],
|
||||
"addr:street": geo_data["street"], "addr:type": geo_data["type"],
|
||||
"addr:number": geo_data["number"]
|
||||
},
|
||||
"lat": geo_data["lat"], "lon": geo_data["lng"]
|
||||
}
|
||||
await cls.save_service_deep(db, element, source="local_manual")
|
||||
logger.info("✅ Helyi CSV adatok feldolgozva.")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ CSV feldolgozási hiba: {e}")
|
||||
|
||||
@classmethod
|
||||
async def get_or_create_person(cls, db: AsyncSession, name: str) -> Person:
|
||||
"""Ghost Person kezelése."""
|
||||
names = name.split(' ', 1)
|
||||
last_name = names[0]
|
||||
first_name = names[1] if len(names) > 1 else "Ismeretlen"
|
||||
stmt = select(Person).where(Person.last_name == last_name, Person.first_name == first_name)
|
||||
result = await db.execute(stmt); person = result.scalar_one_or_none()
|
||||
if not person:
|
||||
person = Person(last_name=last_name, first_name=first_name, is_ghost=True, is_active=False)
|
||||
db.add(person); await db.flush()
|
||||
return person
|
||||
|
||||
@classmethod
|
||||
async def enrich_financials(cls, db: AsyncSession, org_id: int):
|
||||
"""Pénzügyi rekord inicializálása."""
|
||||
financial = OrganizationFinancials(
|
||||
organization_id=org_id, year=datetime.now(timezone.utc).year - 1, source="bot_discovery"
|
||||
)
|
||||
db.add(financial)
|
||||
|
||||
@classmethod
|
||||
async def save_service_deep(cls, db: AsyncSession, element: dict, source="osm"):
|
||||
"""Mély mentés a modelled specifikus mezőneveivel és kötelező értékeivel."""
|
||||
tags = element.get("tags", {})
|
||||
lat, lon = element.get("lat"), element.get("lon")
|
||||
if not lat or not lon: return
|
||||
|
||||
osm_name = tags.get("name") or tags.get("brand") or tags.get("operator")
|
||||
google_data = None
|
||||
if not osm_name or osm_name.lower() in ['aprilia', 'bosch', 'shell', 'mol', 'omv', 'ismeretlen']:
|
||||
google_data = await cls.get_google_place_details_new(lat, lon)
|
||||
|
||||
final_name = (google_data["name"] if google_data else osm_name) or "Ismeretlen Szolgáltató"
|
||||
|
||||
stmt = select(Organization).where(Organization.full_name == final_name)
|
||||
result = await db.execute(stmt); org = result.scalar_one_or_none()
|
||||
|
||||
if not org:
|
||||
# 1. Address létrehozása (a kötelező mezőket kitöltjük az átadott tags-ből vagy alapértékkel)
|
||||
new_addr = Address(
|
||||
latitude=lat,
|
||||
longitude=lon,
|
||||
full_address_text=tags.get("addr:full") or f"2120 Dunakeszi, {tags.get('addr:street', 'Ismeretlen')} {tags.get('addr:housenumber', '1')}",
|
||||
street_name=tags.get("addr:street") or "Ismeretlen",
|
||||
street_type=tags.get("addr:type") or "utca",
|
||||
house_number=tags.get("addr:number") or tags.get("addr:housenumber") or "1"
|
||||
)
|
||||
db.add(new_addr); await db.flush()
|
||||
|
||||
# 2. Organization létrehozása (a modelled alapján ezek a mezők itt vannak)
|
||||
org = Organization(
|
||||
full_name=final_name,
|
||||
name=final_name[:50],
|
||||
org_type=OrgType.service,
|
||||
address_id=new_addr.id,
|
||||
address_city=tags.get("addr:city") or "Dunakeszi",
|
||||
address_zip=tags.get("addr:zip") or "2120",
|
||||
address_street_name=new_addr.street_name,
|
||||
address_street_type=new_addr.street_type,
|
||||
address_house_number=new_addr.house_number
|
||||
)
|
||||
db.add(org); await db.flush()
|
||||
|
||||
# 3. Service Profile
|
||||
trust = 50 if source == "local_manual" else (30 if google_data else 10)
|
||||
spec = {"brands": [], "types": google_data["types"] if google_data else [], "osm_tags": tags}
|
||||
if tags.get("brand"): spec["brands"].append(tags.get("brand"))
|
||||
|
||||
profile = ServiceProfile(
|
||||
organization_id=org.id,
|
||||
location=WKTElement(f'POINT({lon} {lat})', srid=4326),
|
||||
status="ghost",
|
||||
trust_score=trust,
|
||||
google_place_id=google_data["google_id"] if google_data else None,
|
||||
specialization_tags=spec,
|
||||
website=google_data["website"] if google_data else tags.get("website"),
|
||||
contact_phone=google_data["phone"] if google_data else tags.get("phone")
|
||||
)
|
||||
db.add(profile)
|
||||
|
||||
# 4. Tulajdonos rögzítése
|
||||
owner_name = tags.get("operator") or tags.get("contact:person")
|
||||
if owner_name and len(owner_name) > 3:
|
||||
person = await cls.get_or_create_person(db, owner_name)
|
||||
db.add(OrganizationMember(
|
||||
organization_id=org.id,
|
||||
person_id=person.id,
|
||||
role=OrgUserRole.OWNER,
|
||||
is_verified=False
|
||||
))
|
||||
|
||||
await cls.enrich_financials(db, org.id)
|
||||
await db.flush()
|
||||
logger.info(f"✨ [{source.upper()}] Mentve: {final_name} (Bizalom: {trust})")
|
||||
|
||||
@classmethod
|
||||
async def run(cls):
|
||||
logger.info("🤖 Robot 2.7.2: Dunakeszi Detective indítása...")
|
||||
|
||||
# Kapcsolódási védelem
|
||||
connected = False
|
||||
while not connected:
|
||||
try:
|
||||
async with SessionLocal() as db:
|
||||
await db.execute(text("SELECT 1"))
|
||||
connected = True
|
||||
except Exception as e:
|
||||
logger.warning(f"⏳ Várakozás a hálózatra (shared-postgres host?): {e}")
|
||||
await asyncio.sleep(5)
|
||||
|
||||
while True:
|
||||
async with SessionLocal() as db:
|
||||
try:
|
||||
await db.execute(text("SET search_path TO data, public"))
|
||||
# 1. Beküldött CSV feldolgozása (Geocoding-al)
|
||||
await cls.import_local_csv(db)
|
||||
await db.commit()
|
||||
|
||||
# 2. OSM Szkennelés
|
||||
query = """[out:json][timeout:120];area["name"="Dunakeszi"]->.city;(nwr["shop"~"car_repair|motorcycle_repair|tyres|car_parts|motorcycle"](area.city);nwr["amenity"~"car_repair|vehicle_inspection|motorcycle_repair|fuel|charging_station|car_wash"](area.city);nwr["amenity"~"car_repair|fuel|charging_station"](around:5000, 47.63, 19.13););out center;"""
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.post(cls.OVERPASS_URL, data={"data": query}, timeout=120)
|
||||
if resp.status_code == 200:
|
||||
elements = resp.json().get("elements", [])
|
||||
for el in elements:
|
||||
await cls.save_service_deep(db, el, source="osm")
|
||||
await db.commit()
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Futáshiba: {e}")
|
||||
|
||||
logger.info("😴 Scan kész, 24 óra pihenő...")
|
||||
await asyncio.sleep(86400)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(ServiceHunter.run())
|
||||
125
backend/app/workers/technical_enricher.py
Normal file
125
backend/app/workers/technical_enricher.py
Normal file
@@ -0,0 +1,125 @@
|
||||
import asyncio
|
||||
import httpx
|
||||
import logging
|
||||
import os
|
||||
import datetime
|
||||
from sqlalchemy import text
|
||||
from app.db.session import SessionLocal
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger("Robot-v1.0.4-Master-Enricher")
|
||||
|
||||
class TechEnricher:
|
||||
"""
|
||||
Master Enricher v1.0.4
|
||||
- Target: kyri-nuah (RDW Technical Catalogue)
|
||||
- Fix: Visszaállás 'merk' mezőre + SQL fix az új oszlopokhoz.
|
||||
"""
|
||||
|
||||
API_URL = "https://opendata.rdw.nl/resource/kyri-nuah.json"
|
||||
RDW_TOKEN = os.getenv("RDW_APP_TOKEN")
|
||||
HEADERS = {"X-App-Token": RDW_TOKEN} if RDW_TOKEN else {}
|
||||
|
||||
@classmethod
|
||||
async def fetch_tech_data(cls, make, model):
|
||||
# Tisztítás: Ha a modell névben benne van a márka, levágjuk
|
||||
clean_model = str(model).upper().replace(str(make).upper(), "").strip()
|
||||
|
||||
# Ha a modellnév csak szám vagy túl rövid, az RDW nem fogja szeretni
|
||||
if len(clean_model) < 2:
|
||||
return None
|
||||
|
||||
# PRÓBA 1: A 'merk' mezővel (Ez a leggyakoribb)
|
||||
params = {
|
||||
"merk": make.upper(),
|
||||
"handelsbenaming": clean_model,
|
||||
"$limit": 1
|
||||
}
|
||||
|
||||
async with httpx.AsyncClient(headers=cls.HEADERS) as client:
|
||||
try:
|
||||
await asyncio.sleep(1.1)
|
||||
resp = await client.get(cls.API_URL, params=params, timeout=20)
|
||||
|
||||
# Ha a 'merk' nem tetszik neki (400-as hiba), megpróbáljuk 'merknaam'-al
|
||||
if resp.status_code == 400:
|
||||
params = {"merknaam": make.upper(), "handelsbenaming": clean_model, "$limit": 1}
|
||||
resp = await client.get(cls.TECH_API_URL, params=params, timeout=20)
|
||||
|
||||
if resp.status_code == 200:
|
||||
data = resp.json()
|
||||
return data[0] if data else None
|
||||
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"❌ API Hiba: {e}")
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
async def run(cls):
|
||||
logger.info("🚀 Master Enricher v1.0.4 - Új oszlopok töltése indul...")
|
||||
|
||||
while True:
|
||||
async with SessionLocal() as db:
|
||||
# Olyan sorokat keresünk, ahol az új oszlopok még üresek
|
||||
query = text("""
|
||||
SELECT id, make, model
|
||||
FROM data.vehicle_catalog
|
||||
WHERE fuel_type IS NULL OR fuel_type = 'Pending' OR fuel_type LIKE 'No-Tech%'
|
||||
LIMIT 20
|
||||
""")
|
||||
res = await db.execute(query)
|
||||
tasks = res.fetchall()
|
||||
|
||||
if not tasks:
|
||||
logger.info("😴 Minden adat kész. Alvás 5 perc...")
|
||||
await asyncio.sleep(300)
|
||||
continue
|
||||
|
||||
for t_id, make, model in tasks:
|
||||
logger.info(f"🧪 Gazdagítás: {make} | {model}")
|
||||
tech = await cls.fetch_tech_data(make, model)
|
||||
|
||||
if tech:
|
||||
# RDW mezők kinyerése
|
||||
kw = tech.get("netto_maximum_vermogen_kw")
|
||||
ccm = tech.get("cilinderinhoud")
|
||||
weight = tech.get("technisch_toelaatbare_maximum_massa")
|
||||
axles = tech.get("aantal_assen")
|
||||
euro = tech.get("milieuklasse_eg_goedkeuring_licht")
|
||||
fuel = tech.get("brandstof_omschrijving_brandstof_stam", "Standard")
|
||||
|
||||
# Biztonságos konverzió
|
||||
def clean_num(v):
|
||||
try: return int(float(v)) if v else None
|
||||
except: return None
|
||||
|
||||
update_query = text("""
|
||||
UPDATE data.vehicle_catalog
|
||||
SET fuel_type = :fuel,
|
||||
power_kw = :kw,
|
||||
engine_capacity = :ccm,
|
||||
max_weight_kg = :weight,
|
||||
axle_count = :axles,
|
||||
euro_class = :euro,
|
||||
factory_data = factory_data || jsonb_build_object('enriched_at', :now)
|
||||
WHERE id = :id
|
||||
""")
|
||||
|
||||
await db.execute(update_query, {
|
||||
"fuel": fuel, "kw": clean_num(kw), "ccm": clean_num(ccm),
|
||||
"weight": clean_num(weight), "axles": clean_num(axles),
|
||||
"euro": str(euro) if euro else None,
|
||||
"id": t_id, "now": str(datetime.datetime.now())
|
||||
})
|
||||
await db.commit()
|
||||
logger.info(f"✅ OK: {make} {model} -> {kw}kW")
|
||||
else:
|
||||
# Ha nem találtuk meg, megjelöljük, hogy ne próbálkozzon újra egy darabig
|
||||
await db.execute(text("UPDATE data.vehicle_catalog SET fuel_type = 'No-Tech-V4' WHERE id = :id"), {"id": t_id})
|
||||
await db.commit()
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(TechEnricher.run())
|
||||
Binary file not shown.
@@ -39,7 +39,7 @@ def do_run_migrations(connection):
|
||||
target_metadata=target_metadata,
|
||||
include_schemas=True,
|
||||
include_object=include_object,
|
||||
version_table_schema='public'
|
||||
version_table_schema='data'
|
||||
)
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
"""update_staging_address_structure
|
||||
|
||||
Revision ID: 25d1658ccf1d
|
||||
Revises: d0f9ed93b59f
|
||||
Create Date: 2026-02-15 19:37:31.160172
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '25d1658ccf1d'
|
||||
down_revision: Union[str, Sequence[str], None] = 'd0f9ed93b59f'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint(op.f('addresses_postal_code_id_fkey'), 'addresses', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_assignments_branch_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'branches', ['branch_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_costs_organization_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_costs_driver_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_costs_asset_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_costs', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_costs', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_costs', 'users', ['driver_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_events_asset_id_fkey'), 'asset_events', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_events', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_financials_asset_id_fkey'), 'asset_financials', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_financials', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_reviews', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_reviews', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_telemetry', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('assets_catalog_id_fkey'), 'assets', type_='foreignkey')
|
||||
op.drop_constraint(op.f('assets_current_organization_id_fkey'), 'assets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'assets', 'organizations', ['current_organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'assets', 'vehicle_catalog', ['catalog_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('audit_logs_user_id_fkey'), 'audit_logs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'audit_logs', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('branches_organization_id_fkey'), 'branches', type_='foreignkey')
|
||||
op.drop_constraint(op.f('branches_address_id_fkey'), 'branches', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'branches', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'branches', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('credit_logs_org_id_fkey'), 'credit_logs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'credit_logs', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('documents_uploaded_by_fkey'), 'documents', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'documents', 'users', ['uploaded_by'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', type_='foreignkey')
|
||||
op.drop_constraint(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'org_subscriptions', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('organization_financials_organization_id_fkey'), 'organization_financials', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organization_financials', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.alter_column('organization_members', 'role',
|
||||
existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'),
|
||||
type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(op.f('organization_members_person_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organization_members_user_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organization_members_organization_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organization_members', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organization_members', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organization_members', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.alter_column('organizations', 'org_type',
|
||||
existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'),
|
||||
type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(op.f('organizations_address_id_fkey'), 'organizations', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organizations_owner_id_fkey'), 'organizations', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organizations', 'users', ['owner_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organizations', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('pending_actions_requester_id_fkey'), 'pending_actions', type_='foreignkey')
|
||||
op.drop_constraint(op.f('pending_actions_approver_id_fkey'), 'pending_actions', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'pending_actions', 'users', ['approver_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'pending_actions', 'users', ['requester_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('persons_address_id_fkey'), 'persons', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'persons', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('points_ledger_user_id_fkey'), 'points_ledger', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'points_ledger', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('ratings_author_id_fkey'), 'ratings', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'ratings', 'users', ['author_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_expertises_service_id_fkey'), 'service_expertises', type_='foreignkey')
|
||||
op.drop_constraint(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_expertises', 'service_profiles', ['service_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_profiles_organization_id_fkey'), 'service_profiles', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_profiles', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_specialties_parent_id_fkey'), 'service_specialties', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_specialties', 'service_specialties', ['parent_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.add_column('service_staging', sa.Column('street_name', sa.String(length=150), nullable=True))
|
||||
op.add_column('service_staging', sa.Column('street_type', sa.String(length=50), nullable=True))
|
||||
op.add_column('service_staging', sa.Column('stairwell', sa.String(length=20), nullable=True))
|
||||
op.add_column('service_staging', sa.Column('floor', sa.String(length=20), nullable=True))
|
||||
op.add_column('service_staging', sa.Column('door', sa.String(length=20), nullable=True))
|
||||
op.add_column('service_staging', sa.Column('hrsz', sa.String(length=50), nullable=True))
|
||||
op.alter_column('service_staging', 'house_number',
|
||||
existing_type=sa.VARCHAR(length=50),
|
||||
type_=sa.String(length=20),
|
||||
existing_nullable=True)
|
||||
op.drop_column('service_staging', 'street')
|
||||
op.drop_constraint(op.f('social_accounts_user_id_fkey'), 'social_accounts', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'social_accounts', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE')
|
||||
op.drop_constraint(op.f('user_badges_user_id_fkey'), 'user_badges', type_='foreignkey')
|
||||
op.drop_constraint(op.f('user_badges_badge_id_fkey'), 'user_badges', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'user_badges', 'badges', ['badge_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'user_badges', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('user_stats_user_id_fkey'), 'user_stats', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'user_stats', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('users_person_id_fkey'), 'users', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'users', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', type_='foreignkey')
|
||||
op.drop_constraint(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'vehicle_ownerships', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'verification_tokens', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE')
|
||||
op.drop_constraint(op.f('wallets_user_id_fkey'), 'wallets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'wallets', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint(None, 'wallets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('wallets_user_id_fkey'), 'wallets', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'verification_tokens', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', 'users', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'])
|
||||
op.drop_constraint(None, 'users', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('users_person_id_fkey'), 'users', 'persons', ['person_id'], ['id'])
|
||||
op.drop_constraint(None, 'user_stats', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('user_stats_user_id_fkey'), 'user_stats', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('user_badges_badge_id_fkey'), 'user_badges', 'badges', ['badge_id'], ['id'])
|
||||
op.create_foreign_key(op.f('user_badges_user_id_fkey'), 'user_badges', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'social_accounts', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('social_accounts_user_id_fkey'), 'social_accounts', 'users', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
op.add_column('service_staging', sa.Column('street', sa.VARCHAR(length=255), autoincrement=False, nullable=True))
|
||||
op.alter_column('service_staging', 'house_number',
|
||||
existing_type=sa.String(length=20),
|
||||
type_=sa.VARCHAR(length=50),
|
||||
existing_nullable=True)
|
||||
op.drop_column('service_staging', 'hrsz')
|
||||
op.drop_column('service_staging', 'door')
|
||||
op.drop_column('service_staging', 'floor')
|
||||
op.drop_column('service_staging', 'stairwell')
|
||||
op.drop_column('service_staging', 'street_type')
|
||||
op.drop_column('service_staging', 'street_name')
|
||||
op.drop_constraint(None, 'service_specialties', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_specialties_parent_id_fkey'), 'service_specialties', 'service_specialties', ['parent_id'], ['id'])
|
||||
op.drop_constraint(None, 'service_profiles', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_profiles_organization_id_fkey'), 'service_profiles', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'])
|
||||
op.create_foreign_key(op.f('service_expertises_service_id_fkey'), 'service_expertises', 'service_profiles', ['service_id'], ['id'])
|
||||
op.drop_constraint(None, 'ratings', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('ratings_author_id_fkey'), 'ratings', 'users', ['author_id'], ['id'])
|
||||
op.drop_constraint(None, 'points_ledger', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('points_ledger_user_id_fkey'), 'points_ledger', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'persons', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('persons_address_id_fkey'), 'persons', 'addresses', ['address_id'], ['id'])
|
||||
op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('pending_actions_approver_id_fkey'), 'pending_actions', 'users', ['approver_id'], ['id'])
|
||||
op.create_foreign_key(op.f('pending_actions_requester_id_fkey'), 'pending_actions', 'users', ['requester_id'], ['id'])
|
||||
op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organizations_owner_id_fkey'), 'organizations', 'users', ['owner_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organizations_address_id_fkey'), 'organizations', 'addresses', ['address_id'], ['id'])
|
||||
op.alter_column('organizations', 'org_type',
|
||||
existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True),
|
||||
type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organization_members_organization_id_fkey'), 'organization_members', 'organizations', ['organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organization_members_user_id_fkey'), 'organization_members', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organization_members_person_id_fkey'), 'organization_members', 'persons', ['person_id'], ['id'])
|
||||
op.alter_column('organization_members', 'role',
|
||||
existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True),
|
||||
type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(None, 'organization_financials', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organization_financials_organization_id_fkey'), 'organization_financials', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', 'organizations', ['org_id'], ['id'])
|
||||
op.create_foreign_key(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'])
|
||||
op.drop_constraint(None, 'geo_streets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'])
|
||||
op.drop_constraint(None, 'documents', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('documents_uploaded_by_fkey'), 'documents', 'users', ['uploaded_by'], ['id'])
|
||||
op.drop_constraint(None, 'credit_logs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('credit_logs_org_id_fkey'), 'credit_logs', 'organizations', ['org_id'], ['id'])
|
||||
op.drop_constraint(None, 'branches', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'branches', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('branches_address_id_fkey'), 'branches', 'addresses', ['address_id'], ['id'])
|
||||
op.create_foreign_key(op.f('branches_organization_id_fkey'), 'branches', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'audit_logs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('audit_logs_user_id_fkey'), 'audit_logs', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'assets', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'assets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('assets_current_organization_id_fkey'), 'assets', 'organizations', ['current_organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('assets_catalog_id_fkey'), 'assets', 'vehicle_catalog', ['catalog_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_telemetry', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_financials', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_financials_asset_id_fkey'), 'asset_financials', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_events', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_events_asset_id_fkey'), 'asset_events', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_costs_asset_id_fkey'), 'asset_costs', 'assets', ['asset_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_costs_driver_id_fkey'), 'asset_costs', 'users', ['driver_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_costs_organization_id_fkey'), 'asset_costs', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', 'organizations', ['organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', 'assets', ['asset_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_assignments_branch_id_fkey'), 'asset_assignments', 'branches', ['branch_id'], ['id'])
|
||||
op.drop_constraint(None, 'addresses', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('addresses_postal_code_id_fkey'), 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'])
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,27 @@
|
||||
"""add_axles_and_body_type
|
||||
|
||||
Revision ID: 33c4f2235667
|
||||
Revises: 75e3a57f9c14
|
||||
Create Date: 2026-02-15 03:28:23.315925
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '33c4f2235667'
|
||||
down_revision: Union[str, Sequence[str], None] = '75e3a57f9c14'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# op.add_column('vehicle_catalog', sa.Column('axle_count', sa.Integer(), nullable=True), schema='data')
|
||||
op.add_column('vehicle_catalog', sa.Column('body_type', sa.String(100), nullable=True), schema='data')
|
||||
|
||||
def downgrade() -> None:
|
||||
# op.drop_column('vehicle_catalog', 'axle_count', schema='data')
|
||||
op.drop_column('vehicle_catalog', 'body_type', schema='data')
|
||||
@@ -0,0 +1,42 @@
|
||||
"""enrich_catalog_technical_schema
|
||||
|
||||
Revision ID: 75e3a57f9c14
|
||||
Revises: d229cc6bc347
|
||||
Create Date: 2026-02-15 02:45:50.855386
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '75e3a57f9c14'
|
||||
down_revision: Union[str, Sequence[str], None] = 'd229cc6bc347'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# 1. Oszlopok tényleges hozzáadása (NEM idézőjelben!)
|
||||
op.add_column('vehicle_catalog', sa.Column('power_kw', sa.Integer(), nullable=True), schema='data')
|
||||
op.add_column('vehicle_catalog', sa.Column('engine_capacity', sa.Integer(), nullable=True), schema='data')
|
||||
op.add_column('vehicle_catalog', sa.Column('max_weight_kg', sa.Integer(), nullable=True), schema='data')
|
||||
op.add_column('vehicle_catalog', sa.Column('axle_count', sa.Integer(), nullable=True), schema='data')
|
||||
op.add_column('vehicle_catalog', sa.Column('euro_class', sa.String(20), nullable=True), schema='data')
|
||||
|
||||
# 2. Indexek létrehozása (most már létező oszlopokon)
|
||||
op.create_index('ix_vehicle_catalog_power', 'vehicle_catalog', ['power_kw'], schema='data')
|
||||
op.create_index('ix_vehicle_catalog_capacity', 'vehicle_catalog', ['engine_capacity'], schema='data')
|
||||
|
||||
def downgrade() -> None:
|
||||
# Oszlopok és indexek eltávolítása (fordított sorrendben érdemes)
|
||||
op.drop_index('ix_vehicle_catalog_power', table_name='vehicle_catalog', schema='data')
|
||||
op.drop_index('ix_vehicle_catalog_capacity', table_name='vehicle_catalog', schema='data')
|
||||
|
||||
op.drop_column('vehicle_catalog', 'power_kw', schema='data')
|
||||
op.drop_column('vehicle_catalog', 'engine_capacity', schema='data')
|
||||
op.drop_column('vehicle_catalog', 'max_weight_kg', schema='data')
|
||||
op.drop_column('vehicle_catalog', 'axle_count', schema='data')
|
||||
op.drop_column('vehicle_catalog', 'euro_class', schema='data')
|
||||
@@ -0,0 +1,230 @@
|
||||
"""add_discovery_parameters_table
|
||||
|
||||
Revision ID: 8188636edd27
|
||||
Revises: 25d1658ccf1d
|
||||
Create Date: 2026-02-15 19:52:59.375620
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '8188636edd27'
|
||||
down_revision: Union[str, Sequence[str], None] = '25d1658ccf1d'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint(op.f('addresses_postal_code_id_fkey'), 'addresses', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_assignments_branch_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'branches', ['branch_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_costs_organization_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_costs_asset_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_costs_driver_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_costs', 'users', ['driver_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_costs', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_costs', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_events_asset_id_fkey'), 'asset_events', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_events', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_financials_asset_id_fkey'), 'asset_financials', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_financials', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_reviews', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_reviews', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_telemetry', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('assets_current_organization_id_fkey'), 'assets', type_='foreignkey')
|
||||
op.drop_constraint(op.f('assets_catalog_id_fkey'), 'assets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'assets', 'vehicle_catalog', ['catalog_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'assets', 'organizations', ['current_organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('audit_logs_user_id_fkey'), 'audit_logs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'audit_logs', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('branches_organization_id_fkey'), 'branches', type_='foreignkey')
|
||||
op.drop_constraint(op.f('branches_address_id_fkey'), 'branches', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'branches', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'branches', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('credit_logs_org_id_fkey'), 'credit_logs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'credit_logs', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('documents_uploaded_by_fkey'), 'documents', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'documents', 'users', ['uploaded_by'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', type_='foreignkey')
|
||||
op.drop_constraint(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'org_subscriptions', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('organization_financials_organization_id_fkey'), 'organization_financials', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organization_financials', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.alter_column('organization_members', 'role',
|
||||
existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'),
|
||||
type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(op.f('organization_members_person_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organization_members_organization_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organization_members_user_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organization_members', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organization_members', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organization_members', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.alter_column('organizations', 'org_type',
|
||||
existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'),
|
||||
type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(op.f('organizations_owner_id_fkey'), 'organizations', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organizations_address_id_fkey'), 'organizations', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organizations', 'users', ['owner_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organizations', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('pending_actions_approver_id_fkey'), 'pending_actions', type_='foreignkey')
|
||||
op.drop_constraint(op.f('pending_actions_requester_id_fkey'), 'pending_actions', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'pending_actions', 'users', ['requester_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'pending_actions', 'users', ['approver_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('persons_address_id_fkey'), 'persons', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'persons', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('points_ledger_user_id_fkey'), 'points_ledger', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'points_ledger', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('ratings_author_id_fkey'), 'ratings', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'ratings', 'users', ['author_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_expertises_service_id_fkey'), 'service_expertises', type_='foreignkey')
|
||||
op.drop_constraint(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_expertises', 'service_profiles', ['service_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_profiles_organization_id_fkey'), 'service_profiles', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_profiles', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_specialties_parent_id_fkey'), 'service_specialties', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_specialties', 'service_specialties', ['parent_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('social_accounts_user_id_fkey'), 'social_accounts', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'social_accounts', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE')
|
||||
op.drop_constraint(op.f('user_badges_badge_id_fkey'), 'user_badges', type_='foreignkey')
|
||||
op.drop_constraint(op.f('user_badges_user_id_fkey'), 'user_badges', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'user_badges', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'user_badges', 'badges', ['badge_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('user_stats_user_id_fkey'), 'user_stats', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'user_stats', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('users_person_id_fkey'), 'users', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'users', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', type_='foreignkey')
|
||||
op.drop_constraint(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'vehicle_ownerships', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'verification_tokens', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE')
|
||||
op.drop_constraint(op.f('wallets_user_id_fkey'), 'wallets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'wallets', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint(None, 'wallets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('wallets_user_id_fkey'), 'wallets', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'verification_tokens', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', 'users', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'])
|
||||
op.drop_constraint(None, 'users', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('users_person_id_fkey'), 'users', 'persons', ['person_id'], ['id'])
|
||||
op.drop_constraint(None, 'user_stats', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('user_stats_user_id_fkey'), 'user_stats', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('user_badges_user_id_fkey'), 'user_badges', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('user_badges_badge_id_fkey'), 'user_badges', 'badges', ['badge_id'], ['id'])
|
||||
op.drop_constraint(None, 'social_accounts', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('social_accounts_user_id_fkey'), 'social_accounts', 'users', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
op.drop_constraint(None, 'service_specialties', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_specialties_parent_id_fkey'), 'service_specialties', 'service_specialties', ['parent_id'], ['id'])
|
||||
op.drop_constraint(None, 'service_profiles', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_profiles_organization_id_fkey'), 'service_profiles', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'])
|
||||
op.create_foreign_key(op.f('service_expertises_service_id_fkey'), 'service_expertises', 'service_profiles', ['service_id'], ['id'])
|
||||
op.drop_constraint(None, 'ratings', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('ratings_author_id_fkey'), 'ratings', 'users', ['author_id'], ['id'])
|
||||
op.drop_constraint(None, 'points_ledger', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('points_ledger_user_id_fkey'), 'points_ledger', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'persons', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('persons_address_id_fkey'), 'persons', 'addresses', ['address_id'], ['id'])
|
||||
op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('pending_actions_requester_id_fkey'), 'pending_actions', 'users', ['requester_id'], ['id'])
|
||||
op.create_foreign_key(op.f('pending_actions_approver_id_fkey'), 'pending_actions', 'users', ['approver_id'], ['id'])
|
||||
op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organizations_address_id_fkey'), 'organizations', 'addresses', ['address_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organizations_owner_id_fkey'), 'organizations', 'users', ['owner_id'], ['id'])
|
||||
op.alter_column('organizations', 'org_type',
|
||||
existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True),
|
||||
type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organization_members_user_id_fkey'), 'organization_members', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organization_members_organization_id_fkey'), 'organization_members', 'organizations', ['organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organization_members_person_id_fkey'), 'organization_members', 'persons', ['person_id'], ['id'])
|
||||
op.alter_column('organization_members', 'role',
|
||||
existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True),
|
||||
type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(None, 'organization_financials', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organization_financials_organization_id_fkey'), 'organization_financials', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'])
|
||||
op.create_foreign_key(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', 'organizations', ['org_id'], ['id'])
|
||||
op.drop_constraint(None, 'geo_streets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'])
|
||||
op.drop_constraint(None, 'documents', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('documents_uploaded_by_fkey'), 'documents', 'users', ['uploaded_by'], ['id'])
|
||||
op.drop_constraint(None, 'credit_logs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('credit_logs_org_id_fkey'), 'credit_logs', 'organizations', ['org_id'], ['id'])
|
||||
op.drop_constraint(None, 'branches', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'branches', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('branches_address_id_fkey'), 'branches', 'addresses', ['address_id'], ['id'])
|
||||
op.create_foreign_key(op.f('branches_organization_id_fkey'), 'branches', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'audit_logs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('audit_logs_user_id_fkey'), 'audit_logs', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'assets', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'assets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('assets_catalog_id_fkey'), 'assets', 'vehicle_catalog', ['catalog_id'], ['id'])
|
||||
op.create_foreign_key(op.f('assets_current_organization_id_fkey'), 'assets', 'organizations', ['current_organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_telemetry', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', 'assets', ['asset_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_financials', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_financials_asset_id_fkey'), 'asset_financials', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_events', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_events_asset_id_fkey'), 'asset_events', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_costs_driver_id_fkey'), 'asset_costs', 'users', ['driver_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_costs_asset_id_fkey'), 'asset_costs', 'assets', ['asset_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_costs_organization_id_fkey'), 'asset_costs', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', 'assets', ['asset_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_assignments_branch_id_fkey'), 'asset_assignments', 'branches', ['branch_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'addresses', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('addresses_postal_code_id_fkey'), 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'])
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,288 @@
|
||||
"""upgrade_identity_and_audit_v1_6
|
||||
|
||||
Revision ID: b803fe324ebd
|
||||
Revises: 8188636edd27
|
||||
Create Date: 2026-02-15 23:49:00.074592
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'b803fe324ebd'
|
||||
down_revision: Union[str, Sequence[str], None] = '8188636edd27'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('org_sales_assignments',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('organization_id', sa.Integer(), nullable=True),
|
||||
sa.Column('agent_user_id', sa.Integer(), nullable=True),
|
||||
sa.Column('assigned_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
|
||||
sa.Column('is_active', sa.Boolean(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['agent_user_id'], ['data.users.id'], ),
|
||||
sa.ForeignKeyConstraint(['organization_id'], ['data.organizations.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
schema='data'
|
||||
)
|
||||
op.drop_constraint(op.f('addresses_postal_code_id_fkey'), 'addresses', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_assignments_branch_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'branches', ['branch_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_costs_organization_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_costs_driver_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_costs_asset_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_costs', 'users', ['driver_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_costs', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_costs', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_events_asset_id_fkey'), 'asset_events', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_events', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_financials_asset_id_fkey'), 'asset_financials', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_financials', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_reviews', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_reviews', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_telemetry', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('assets_current_organization_id_fkey'), 'assets', type_='foreignkey')
|
||||
op.drop_constraint(op.f('assets_catalog_id_fkey'), 'assets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'assets', 'vehicle_catalog', ['catalog_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'assets', 'organizations', ['current_organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('audit_logs_user_id_fkey'), 'audit_logs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'audit_logs', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('branches_organization_id_fkey'), 'branches', type_='foreignkey')
|
||||
op.drop_constraint(op.f('branches_address_id_fkey'), 'branches', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'branches', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'branches', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('credit_logs_org_id_fkey'), 'credit_logs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'credit_logs', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('documents_uploaded_by_fkey'), 'documents', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'documents', 'users', ['uploaded_by'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', type_='foreignkey')
|
||||
op.drop_constraint(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'org_subscriptions', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('organization_financials_organization_id_fkey'), 'organization_financials', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organization_financials', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.alter_column('organization_members', 'role',
|
||||
existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'),
|
||||
type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(op.f('organization_members_organization_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organization_members_person_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organization_members_user_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organization_members', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organization_members', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organization_members', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.alter_column('organizations', 'org_type',
|
||||
existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'),
|
||||
type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(op.f('organizations_owner_id_fkey'), 'organizations', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organizations_address_id_fkey'), 'organizations', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organizations', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organizations', 'users', ['owner_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('pending_actions_requester_id_fkey'), 'pending_actions', type_='foreignkey')
|
||||
op.drop_constraint(op.f('pending_actions_approver_id_fkey'), 'pending_actions', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'pending_actions', 'users', ['approver_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'pending_actions', 'users', ['requester_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.add_column('persons', sa.Column('identity_hash', sa.String(length=64), nullable=True))
|
||||
op.add_column('persons', sa.Column('lifetime_xp', sa.BigInteger(), server_default=sa.text('0'), nullable=True))
|
||||
op.add_column('persons', sa.Column('penalty_points', sa.Integer(), server_default=sa.text('0'), nullable=True))
|
||||
op.add_column('persons', sa.Column('social_reputation', sa.Numeric(precision=3, scale=2), server_default=sa.text('1.00'), nullable=True))
|
||||
op.add_column('persons', sa.Column('is_sales_agent', sa.Boolean(), server_default=sa.text('false'), nullable=True))
|
||||
op.create_index(op.f('ix_data_persons_identity_hash'), 'persons', ['identity_hash'], unique=True, schema='data')
|
||||
op.drop_constraint(op.f('persons_address_id_fkey'), 'persons', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'persons', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('points_ledger_user_id_fkey'), 'points_ledger', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'points_ledger', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('ratings_author_id_fkey'), 'ratings', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'ratings', 'users', ['author_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', type_='foreignkey')
|
||||
op.drop_constraint(op.f('service_expertises_service_id_fkey'), 'service_expertises', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_expertises', 'service_profiles', ['service_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_profiles_organization_id_fkey'), 'service_profiles', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_profiles', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_specialties_parent_id_fkey'), 'service_specialties', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_specialties', 'service_specialties', ['parent_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('social_accounts_user_id_fkey'), 'social_accounts', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'social_accounts', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE')
|
||||
op.drop_constraint(op.f('user_badges_badge_id_fkey'), 'user_badges', type_='foreignkey')
|
||||
op.drop_constraint(op.f('user_badges_user_id_fkey'), 'user_badges', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'user_badges', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'user_badges', 'badges', ['badge_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('user_stats_user_id_fkey'), 'user_stats', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'user_stats', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.add_column('users', sa.Column('subscription_plan', sa.String(length=30), server_default=sa.text("'FREE'"), nullable=True))
|
||||
op.add_column('users', sa.Column('subscription_expires_at', sa.DateTime(timezone=True), nullable=True))
|
||||
op.add_column('users', sa.Column('is_vip', sa.Boolean(), server_default=sa.text('false'), nullable=True))
|
||||
op.add_column('users', sa.Column('referral_code', sa.String(length=20), nullable=True))
|
||||
op.add_column('users', sa.Column('referred_by_id', sa.Integer(), nullable=True))
|
||||
op.add_column('users', sa.Column('current_sales_agent_id', sa.Integer(), nullable=True))
|
||||
op.create_unique_constraint(None, 'users', ['referral_code'], schema='data')
|
||||
op.drop_constraint(op.f('users_person_id_fkey'), 'users', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'users', 'users', ['referred_by_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'users', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'users', 'users', ['current_sales_agent_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_column('users', 'two_factor_secret')
|
||||
op.drop_column('users', 'refresh_token_hash')
|
||||
op.drop_column('users', 'two_factor_enabled')
|
||||
op.drop_constraint(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', type_='foreignkey')
|
||||
op.drop_constraint(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'vehicle_ownerships', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'verification_tokens', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE')
|
||||
op.add_column('wallets', sa.Column('earned_credits', sa.Numeric(precision=18, scale=4), server_default=sa.text('0'), nullable=True))
|
||||
op.add_column('wallets', sa.Column('purchased_credits', sa.Numeric(precision=18, scale=4), server_default=sa.text('0'), nullable=True))
|
||||
op.add_column('wallets', sa.Column('service_coins', sa.Numeric(precision=18, scale=4), server_default=sa.text('0'), nullable=True))
|
||||
op.drop_constraint(op.f('wallets_user_id_fkey'), 'wallets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'wallets', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_column('wallets', 'coin_balance')
|
||||
op.drop_column('wallets', 'credit_balance')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('wallets', sa.Column('credit_balance', sa.NUMERIC(precision=18, scale=2), autoincrement=False, nullable=True))
|
||||
op.add_column('wallets', sa.Column('coin_balance', sa.NUMERIC(precision=18, scale=2), autoincrement=False, nullable=True))
|
||||
op.drop_constraint(None, 'wallets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('wallets_user_id_fkey'), 'wallets', 'users', ['user_id'], ['id'])
|
||||
op.drop_column('wallets', 'service_coins')
|
||||
op.drop_column('wallets', 'purchased_credits')
|
||||
op.drop_column('wallets', 'earned_credits')
|
||||
op.drop_constraint(None, 'verification_tokens', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', 'users', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'])
|
||||
op.add_column('users', sa.Column('two_factor_enabled', sa.BOOLEAN(), autoincrement=False, nullable=True))
|
||||
op.add_column('users', sa.Column('refresh_token_hash', sa.VARCHAR(length=255), autoincrement=False, nullable=True))
|
||||
op.add_column('users', sa.Column('two_factor_secret', sa.VARCHAR(length=100), autoincrement=False, nullable=True))
|
||||
op.drop_constraint(None, 'users', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'users', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'users', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('users_person_id_fkey'), 'users', 'persons', ['person_id'], ['id'])
|
||||
op.drop_constraint(None, 'users', schema='data', type_='unique')
|
||||
op.drop_column('users', 'current_sales_agent_id')
|
||||
op.drop_column('users', 'referred_by_id')
|
||||
op.drop_column('users', 'referral_code')
|
||||
op.drop_column('users', 'is_vip')
|
||||
op.drop_column('users', 'subscription_expires_at')
|
||||
op.drop_column('users', 'subscription_plan')
|
||||
op.drop_constraint(None, 'user_stats', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('user_stats_user_id_fkey'), 'user_stats', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('user_badges_user_id_fkey'), 'user_badges', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('user_badges_badge_id_fkey'), 'user_badges', 'badges', ['badge_id'], ['id'])
|
||||
op.drop_constraint(None, 'social_accounts', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('social_accounts_user_id_fkey'), 'social_accounts', 'users', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
op.drop_constraint(None, 'service_specialties', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_specialties_parent_id_fkey'), 'service_specialties', 'service_specialties', ['parent_id'], ['id'])
|
||||
op.drop_constraint(None, 'service_profiles', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_profiles_organization_id_fkey'), 'service_profiles', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_expertises_service_id_fkey'), 'service_expertises', 'service_profiles', ['service_id'], ['id'])
|
||||
op.create_foreign_key(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'])
|
||||
op.drop_constraint(None, 'ratings', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('ratings_author_id_fkey'), 'ratings', 'users', ['author_id'], ['id'])
|
||||
op.drop_constraint(None, 'points_ledger', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('points_ledger_user_id_fkey'), 'points_ledger', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'persons', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('persons_address_id_fkey'), 'persons', 'addresses', ['address_id'], ['id'])
|
||||
op.drop_index(op.f('ix_data_persons_identity_hash'), table_name='persons', schema='data')
|
||||
op.drop_column('persons', 'is_sales_agent')
|
||||
op.drop_column('persons', 'social_reputation')
|
||||
op.drop_column('persons', 'penalty_points')
|
||||
op.drop_column('persons', 'lifetime_xp')
|
||||
op.drop_column('persons', 'identity_hash')
|
||||
op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('pending_actions_approver_id_fkey'), 'pending_actions', 'users', ['approver_id'], ['id'])
|
||||
op.create_foreign_key(op.f('pending_actions_requester_id_fkey'), 'pending_actions', 'users', ['requester_id'], ['id'])
|
||||
op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organizations_address_id_fkey'), 'organizations', 'addresses', ['address_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organizations_owner_id_fkey'), 'organizations', 'users', ['owner_id'], ['id'])
|
||||
op.alter_column('organizations', 'org_type',
|
||||
existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True),
|
||||
type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organization_members_user_id_fkey'), 'organization_members', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organization_members_person_id_fkey'), 'organization_members', 'persons', ['person_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organization_members_organization_id_fkey'), 'organization_members', 'organizations', ['organization_id'], ['id'])
|
||||
op.alter_column('organization_members', 'role',
|
||||
existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True),
|
||||
type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(None, 'organization_financials', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organization_financials_organization_id_fkey'), 'organization_financials', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', 'organizations', ['org_id'], ['id'])
|
||||
op.create_foreign_key(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'])
|
||||
op.drop_constraint(None, 'geo_streets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'])
|
||||
op.drop_constraint(None, 'documents', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('documents_uploaded_by_fkey'), 'documents', 'users', ['uploaded_by'], ['id'])
|
||||
op.drop_constraint(None, 'credit_logs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('credit_logs_org_id_fkey'), 'credit_logs', 'organizations', ['org_id'], ['id'])
|
||||
op.drop_constraint(None, 'branches', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'branches', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('branches_address_id_fkey'), 'branches', 'addresses', ['address_id'], ['id'])
|
||||
op.create_foreign_key(op.f('branches_organization_id_fkey'), 'branches', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'audit_logs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('audit_logs_user_id_fkey'), 'audit_logs', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'assets', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'assets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('assets_catalog_id_fkey'), 'assets', 'vehicle_catalog', ['catalog_id'], ['id'])
|
||||
op.create_foreign_key(op.f('assets_current_organization_id_fkey'), 'assets', 'organizations', ['current_organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_telemetry', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', 'assets', ['asset_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_financials', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_financials_asset_id_fkey'), 'asset_financials', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_events', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_events_asset_id_fkey'), 'asset_events', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_costs_asset_id_fkey'), 'asset_costs', 'assets', ['asset_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_costs_driver_id_fkey'), 'asset_costs', 'users', ['driver_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_costs_organization_id_fkey'), 'asset_costs', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', 'organizations', ['organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_assignments_branch_id_fkey'), 'asset_assignments', 'branches', ['branch_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'addresses', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('addresses_postal_code_id_fkey'), 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'])
|
||||
op.drop_table('org_sales_assignments', schema='data')
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,270 @@
|
||||
"""v1.3_branch_system_and_fleet_scaling
|
||||
|
||||
Revision ID: d0f9ed93b59f
|
||||
Revises: 33c4f2235667
|
||||
Create Date: 2026-02-15 18:53:12.791636
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'd0f9ed93b59f'
|
||||
down_revision: Union[str, Sequence[str], None] = '33c4f2235667'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('branches',
|
||||
sa.Column('id', sa.UUID(), nullable=False),
|
||||
sa.Column('organization_id', sa.Integer(), nullable=False),
|
||||
sa.Column('address_id', sa.UUID(), nullable=True),
|
||||
sa.Column('name', sa.String(length=100), nullable=False),
|
||||
sa.Column('is_main', sa.Boolean(), nullable=True),
|
||||
sa.Column('postal_code', sa.String(length=10), nullable=True),
|
||||
sa.Column('city', sa.String(length=100), nullable=True),
|
||||
sa.Column('street_name', sa.String(length=150), nullable=True),
|
||||
sa.Column('street_type', sa.String(length=50), nullable=True),
|
||||
sa.Column('house_number', sa.String(length=20), nullable=True),
|
||||
sa.Column('stairwell', sa.String(length=20), nullable=True),
|
||||
sa.Column('floor', sa.String(length=20), nullable=True),
|
||||
sa.Column('door', sa.String(length=20), nullable=True),
|
||||
sa.Column('hrsz', sa.String(length=50), nullable=True),
|
||||
sa.Column('opening_hours', postgresql.JSONB(astext_type=sa.Text()), server_default=sa.text("'{}'::jsonb"), nullable=True),
|
||||
sa.Column('branch_rating', sa.Float(), nullable=True),
|
||||
sa.Column('status', sa.String(length=30), nullable=True),
|
||||
sa.Column('is_deleted', sa.Boolean(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['address_id'], ['data.addresses.id'], ),
|
||||
sa.ForeignKeyConstraint(['organization_id'], ['data.organizations.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
schema='data'
|
||||
)
|
||||
op.create_index(op.f('ix_data_branches_city'), 'branches', ['city'], unique=False, schema='data')
|
||||
op.create_index(op.f('ix_data_branches_postal_code'), 'branches', ['postal_code'], unique=False, schema='data')
|
||||
op.drop_constraint(op.f('addresses_postal_code_id_fkey'), 'addresses', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.add_column('asset_assignments', sa.Column('branch_id', sa.UUID(), nullable=True))
|
||||
op.drop_constraint(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'branches', ['branch_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_costs_asset_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_costs_organization_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_costs_driver_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_costs', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_costs', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_costs', 'users', ['driver_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_events_asset_id_fkey'), 'asset_events', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_events', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_financials_asset_id_fkey'), 'asset_financials', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_financials', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_reviews', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_reviews', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_telemetry', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('assets_current_organization_id_fkey'), 'assets', type_='foreignkey')
|
||||
op.drop_constraint(op.f('assets_catalog_id_fkey'), 'assets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'assets', 'vehicle_catalog', ['catalog_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'assets', 'organizations', ['current_organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('audit_logs_user_id_fkey'), 'audit_logs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'audit_logs', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('credit_logs_org_id_fkey'), 'credit_logs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'credit_logs', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('documents_uploaded_by_fkey'), 'documents', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'documents', 'users', ['uploaded_by'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', type_='foreignkey')
|
||||
op.drop_constraint(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'org_subscriptions', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('organization_financials_organization_id_fkey'), 'organization_financials', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organization_financials', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.alter_column('organization_members', 'role',
|
||||
existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'),
|
||||
type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(op.f('organization_members_person_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organization_members_organization_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organization_members_user_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organization_members', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organization_members', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organization_members', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.add_column('organizations', sa.Column('subscription_plan', sa.String(length=30), server_default=sa.text("'FREE'"), nullable=True))
|
||||
op.add_column('organizations', sa.Column('base_asset_limit', sa.Integer(), server_default=sa.text('1'), nullable=True))
|
||||
op.add_column('organizations', sa.Column('purchased_extra_slots', sa.Integer(), server_default=sa.text('0'), nullable=True))
|
||||
op.add_column('organizations', sa.Column('is_ownership_transferable', sa.Boolean(), server_default=sa.text('true'), nullable=True))
|
||||
op.alter_column('organizations', 'org_type',
|
||||
existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'),
|
||||
type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True),
|
||||
existing_nullable=True)
|
||||
op.create_index(op.f('ix_data_organizations_subscription_plan'), 'organizations', ['subscription_plan'], unique=False, schema='data')
|
||||
op.drop_constraint(op.f('organizations_owner_id_fkey'), 'organizations', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organizations_address_id_fkey'), 'organizations', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organizations', 'users', ['owner_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organizations', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('pending_actions_requester_id_fkey'), 'pending_actions', type_='foreignkey')
|
||||
op.drop_constraint(op.f('pending_actions_approver_id_fkey'), 'pending_actions', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'pending_actions', 'users', ['approver_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'pending_actions', 'users', ['requester_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('persons_address_id_fkey'), 'persons', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'persons', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('points_ledger_user_id_fkey'), 'points_ledger', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'points_ledger', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('ratings_author_id_fkey'), 'ratings', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'ratings', 'users', ['author_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', type_='foreignkey')
|
||||
op.drop_constraint(op.f('service_expertises_service_id_fkey'), 'service_expertises', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_expertises', 'service_profiles', ['service_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_profiles_organization_id_fkey'), 'service_profiles', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_profiles', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_specialties_parent_id_fkey'), 'service_specialties', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_specialties', 'service_specialties', ['parent_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('social_accounts_user_id_fkey'), 'social_accounts', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'social_accounts', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE')
|
||||
op.drop_constraint(op.f('user_badges_badge_id_fkey'), 'user_badges', type_='foreignkey')
|
||||
op.drop_constraint(op.f('user_badges_user_id_fkey'), 'user_badges', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'user_badges', 'badges', ['badge_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'user_badges', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('user_stats_user_id_fkey'), 'user_stats', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'user_stats', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('users_person_id_fkey'), 'users', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'users', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_index(op.f('ix_vehicle_catalog_capacity'), table_name='vehicle_catalog')
|
||||
op.drop_index(op.f('ix_vehicle_catalog_power'), table_name='vehicle_catalog')
|
||||
op.create_index(op.f('ix_data_vehicle_catalog_engine_capacity'), 'vehicle_catalog', ['engine_capacity'], unique=False, schema='data')
|
||||
op.create_index(op.f('ix_data_vehicle_catalog_power_kw'), 'vehicle_catalog', ['power_kw'], unique=False, schema='data')
|
||||
op.drop_constraint(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', type_='foreignkey')
|
||||
op.drop_constraint(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'vehicle_ownerships', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'verification_tokens', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE')
|
||||
op.drop_constraint(op.f('wallets_user_id_fkey'), 'wallets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'wallets', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint(None, 'wallets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('wallets_user_id_fkey'), 'wallets', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'verification_tokens', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', 'users', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'])
|
||||
op.create_foreign_key(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', 'users', ['user_id'], ['id'])
|
||||
op.drop_index(op.f('ix_data_vehicle_catalog_power_kw'), table_name='vehicle_catalog', schema='data')
|
||||
op.drop_index(op.f('ix_data_vehicle_catalog_engine_capacity'), table_name='vehicle_catalog', schema='data')
|
||||
op.create_index(op.f('ix_vehicle_catalog_power'), 'vehicle_catalog', ['power_kw'], unique=False)
|
||||
op.create_index(op.f('ix_vehicle_catalog_capacity'), 'vehicle_catalog', ['engine_capacity'], unique=False)
|
||||
op.drop_constraint(None, 'users', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('users_person_id_fkey'), 'users', 'persons', ['person_id'], ['id'])
|
||||
op.drop_constraint(None, 'user_stats', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('user_stats_user_id_fkey'), 'user_stats', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('user_badges_user_id_fkey'), 'user_badges', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('user_badges_badge_id_fkey'), 'user_badges', 'badges', ['badge_id'], ['id'])
|
||||
op.drop_constraint(None, 'social_accounts', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('social_accounts_user_id_fkey'), 'social_accounts', 'users', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
op.drop_constraint(None, 'service_specialties', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_specialties_parent_id_fkey'), 'service_specialties', 'service_specialties', ['parent_id'], ['id'])
|
||||
op.drop_constraint(None, 'service_profiles', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_profiles_organization_id_fkey'), 'service_profiles', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_expertises_service_id_fkey'), 'service_expertises', 'service_profiles', ['service_id'], ['id'])
|
||||
op.create_foreign_key(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'])
|
||||
op.drop_constraint(None, 'ratings', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('ratings_author_id_fkey'), 'ratings', 'users', ['author_id'], ['id'])
|
||||
op.drop_constraint(None, 'points_ledger', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('points_ledger_user_id_fkey'), 'points_ledger', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'persons', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('persons_address_id_fkey'), 'persons', 'addresses', ['address_id'], ['id'])
|
||||
op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('pending_actions_approver_id_fkey'), 'pending_actions', 'users', ['approver_id'], ['id'])
|
||||
op.create_foreign_key(op.f('pending_actions_requester_id_fkey'), 'pending_actions', 'users', ['requester_id'], ['id'])
|
||||
op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organizations_address_id_fkey'), 'organizations', 'addresses', ['address_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organizations_owner_id_fkey'), 'organizations', 'users', ['owner_id'], ['id'])
|
||||
op.drop_index(op.f('ix_data_organizations_subscription_plan'), table_name='organizations', schema='data')
|
||||
op.alter_column('organizations', 'org_type',
|
||||
existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True),
|
||||
type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'),
|
||||
existing_nullable=True)
|
||||
op.drop_column('organizations', 'is_ownership_transferable')
|
||||
op.drop_column('organizations', 'purchased_extra_slots')
|
||||
op.drop_column('organizations', 'base_asset_limit')
|
||||
op.drop_column('organizations', 'subscription_plan')
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organization_members_user_id_fkey'), 'organization_members', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organization_members_organization_id_fkey'), 'organization_members', 'organizations', ['organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organization_members_person_id_fkey'), 'organization_members', 'persons', ['person_id'], ['id'])
|
||||
op.alter_column('organization_members', 'role',
|
||||
existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True),
|
||||
type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(None, 'organization_financials', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organization_financials_organization_id_fkey'), 'organization_financials', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'])
|
||||
op.create_foreign_key(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', 'organizations', ['org_id'], ['id'])
|
||||
op.drop_constraint(None, 'geo_streets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'])
|
||||
op.drop_constraint(None, 'documents', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('documents_uploaded_by_fkey'), 'documents', 'users', ['uploaded_by'], ['id'])
|
||||
op.drop_constraint(None, 'credit_logs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('credit_logs_org_id_fkey'), 'credit_logs', 'organizations', ['org_id'], ['id'])
|
||||
op.drop_constraint(None, 'audit_logs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('audit_logs_user_id_fkey'), 'audit_logs', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'assets', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'assets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('assets_catalog_id_fkey'), 'assets', 'vehicle_catalog', ['catalog_id'], ['id'])
|
||||
op.create_foreign_key(op.f('assets_current_organization_id_fkey'), 'assets', 'organizations', ['current_organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_telemetry', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_financials', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_financials_asset_id_fkey'), 'asset_financials', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_events', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_events_asset_id_fkey'), 'asset_events', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_costs_driver_id_fkey'), 'asset_costs', 'users', ['driver_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_costs_organization_id_fkey'), 'asset_costs', 'organizations', ['organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_costs_asset_id_fkey'), 'asset_costs', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', 'assets', ['asset_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_column('asset_assignments', 'branch_id')
|
||||
op.drop_constraint(None, 'addresses', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('addresses_postal_code_id_fkey'), 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'])
|
||||
op.drop_index(op.f('ix_data_branches_postal_code'), table_name='branches', schema='data')
|
||||
op.drop_index(op.f('ix_data_branches_city'), table_name='branches', schema='data')
|
||||
op.drop_table('branches', schema='data')
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,243 @@
|
||||
"""add_catalog_discovery_table
|
||||
|
||||
Revision ID: d229cc6bc347
|
||||
Revises: 92616f34cdd3
|
||||
Create Date: 2026-02-14 16:02:19.895343
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'd229cc6bc347'
|
||||
down_revision: Union[str, Sequence[str], None] = '92616f34cdd3'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('catalog_discovery',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('make', sa.String(length=100), nullable=False),
|
||||
sa.Column('model', sa.String(length=100), nullable=False),
|
||||
sa.Column('vehicle_class', sa.String(length=50), nullable=True),
|
||||
sa.Column('source', sa.String(length=50), nullable=True),
|
||||
sa.Column('status', sa.String(length=20), server_default=sa.text("'pending'"), nullable=True),
|
||||
sa.Column('attempts', sa.Integer(), nullable=True),
|
||||
sa.Column('last_attempt', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('make', 'model', 'vehicle_class', name='_make_model_class_uc'),
|
||||
schema='data'
|
||||
)
|
||||
op.create_index(op.f('ix_data_catalog_discovery_id'), 'catalog_discovery', ['id'], unique=False, schema='data')
|
||||
op.create_index(op.f('ix_data_catalog_discovery_make'), 'catalog_discovery', ['make'], unique=False, schema='data')
|
||||
op.create_index(op.f('ix_data_catalog_discovery_model'), 'catalog_discovery', ['model'], unique=False, schema='data')
|
||||
op.create_index(op.f('ix_data_catalog_discovery_status'), 'catalog_discovery', ['status'], unique=False, schema='data')
|
||||
op.create_index(op.f('ix_data_catalog_discovery_vehicle_class'), 'catalog_discovery', ['vehicle_class'], unique=False, schema='data')
|
||||
op.drop_constraint(op.f('addresses_postal_code_id_fkey'), 'addresses', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_costs_driver_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_costs_organization_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_costs_asset_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_costs', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_costs', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_costs', 'users', ['driver_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_events_asset_id_fkey'), 'asset_events', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_events', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_financials_asset_id_fkey'), 'asset_financials', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_financials', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_reviews', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_reviews', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_telemetry', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('assets_catalog_id_fkey'), 'assets', type_='foreignkey')
|
||||
op.drop_constraint(op.f('assets_current_organization_id_fkey'), 'assets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'assets', 'vehicle_catalog', ['catalog_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'assets', 'organizations', ['current_organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('audit_logs_user_id_fkey'), 'audit_logs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'audit_logs', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('credit_logs_org_id_fkey'), 'credit_logs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'credit_logs', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('documents_uploaded_by_fkey'), 'documents', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'documents', 'users', ['uploaded_by'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', type_='foreignkey')
|
||||
op.drop_constraint(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'org_subscriptions', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('organization_financials_organization_id_fkey'), 'organization_financials', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organization_financials', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.alter_column('organization_members', 'role',
|
||||
existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'),
|
||||
type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(op.f('organization_members_user_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organization_members_person_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organization_members_organization_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organization_members', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organization_members', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organization_members', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.alter_column('organizations', 'org_type',
|
||||
existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'),
|
||||
type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(op.f('organizations_address_id_fkey'), 'organizations', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organizations_owner_id_fkey'), 'organizations', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organizations', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organizations', 'users', ['owner_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('pending_actions_approver_id_fkey'), 'pending_actions', type_='foreignkey')
|
||||
op.drop_constraint(op.f('pending_actions_requester_id_fkey'), 'pending_actions', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'pending_actions', 'users', ['approver_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'pending_actions', 'users', ['requester_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('persons_address_id_fkey'), 'persons', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'persons', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('points_ledger_user_id_fkey'), 'points_ledger', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'points_ledger', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('ratings_author_id_fkey'), 'ratings', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'ratings', 'users', ['author_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_expertises_service_id_fkey'), 'service_expertises', type_='foreignkey')
|
||||
op.drop_constraint(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_expertises', 'service_profiles', ['service_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_profiles_organization_id_fkey'), 'service_profiles', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_profiles', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_specialties_parent_id_fkey'), 'service_specialties', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_specialties', 'service_specialties', ['parent_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('social_accounts_user_id_fkey'), 'social_accounts', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'social_accounts', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE')
|
||||
op.drop_constraint(op.f('user_badges_user_id_fkey'), 'user_badges', type_='foreignkey')
|
||||
op.drop_constraint(op.f('user_badges_badge_id_fkey'), 'user_badges', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'user_badges', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'user_badges', 'badges', ['badge_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('user_stats_user_id_fkey'), 'user_stats', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'user_stats', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('users_person_id_fkey'), 'users', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'users', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', type_='foreignkey')
|
||||
op.drop_constraint(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'vehicle_ownerships', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'verification_tokens', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE')
|
||||
op.drop_constraint(op.f('wallets_user_id_fkey'), 'wallets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'wallets', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint(None, 'wallets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('wallets_user_id_fkey'), 'wallets', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'verification_tokens', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', 'users', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'])
|
||||
op.drop_constraint(None, 'users', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('users_person_id_fkey'), 'users', 'persons', ['person_id'], ['id'])
|
||||
op.drop_constraint(None, 'user_stats', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('user_stats_user_id_fkey'), 'user_stats', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('user_badges_badge_id_fkey'), 'user_badges', 'badges', ['badge_id'], ['id'])
|
||||
op.create_foreign_key(op.f('user_badges_user_id_fkey'), 'user_badges', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'social_accounts', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('social_accounts_user_id_fkey'), 'social_accounts', 'users', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
op.drop_constraint(None, 'service_specialties', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_specialties_parent_id_fkey'), 'service_specialties', 'service_specialties', ['parent_id'], ['id'])
|
||||
op.drop_constraint(None, 'service_profiles', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_profiles_organization_id_fkey'), 'service_profiles', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'])
|
||||
op.create_foreign_key(op.f('service_expertises_service_id_fkey'), 'service_expertises', 'service_profiles', ['service_id'], ['id'])
|
||||
op.drop_constraint(None, 'ratings', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('ratings_author_id_fkey'), 'ratings', 'users', ['author_id'], ['id'])
|
||||
op.drop_constraint(None, 'points_ledger', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('points_ledger_user_id_fkey'), 'points_ledger', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'persons', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('persons_address_id_fkey'), 'persons', 'addresses', ['address_id'], ['id'])
|
||||
op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('pending_actions_requester_id_fkey'), 'pending_actions', 'users', ['requester_id'], ['id'])
|
||||
op.create_foreign_key(op.f('pending_actions_approver_id_fkey'), 'pending_actions', 'users', ['approver_id'], ['id'])
|
||||
op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organizations_owner_id_fkey'), 'organizations', 'users', ['owner_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organizations_address_id_fkey'), 'organizations', 'addresses', ['address_id'], ['id'])
|
||||
op.alter_column('organizations', 'org_type',
|
||||
existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True),
|
||||
type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organization_members_organization_id_fkey'), 'organization_members', 'organizations', ['organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organization_members_person_id_fkey'), 'organization_members', 'persons', ['person_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organization_members_user_id_fkey'), 'organization_members', 'users', ['user_id'], ['id'])
|
||||
op.alter_column('organization_members', 'role',
|
||||
existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True),
|
||||
type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(None, 'organization_financials', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organization_financials_organization_id_fkey'), 'organization_financials', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', 'organizations', ['org_id'], ['id'])
|
||||
op.create_foreign_key(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'])
|
||||
op.drop_constraint(None, 'geo_streets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'])
|
||||
op.drop_constraint(None, 'documents', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('documents_uploaded_by_fkey'), 'documents', 'users', ['uploaded_by'], ['id'])
|
||||
op.drop_constraint(None, 'credit_logs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('credit_logs_org_id_fkey'), 'credit_logs', 'organizations', ['org_id'], ['id'])
|
||||
op.drop_constraint(None, 'audit_logs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('audit_logs_user_id_fkey'), 'audit_logs', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'assets', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'assets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('assets_current_organization_id_fkey'), 'assets', 'organizations', ['current_organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('assets_catalog_id_fkey'), 'assets', 'vehicle_catalog', ['catalog_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_telemetry', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_financials', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_financials_asset_id_fkey'), 'asset_financials', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_events', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_events_asset_id_fkey'), 'asset_events', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_costs_asset_id_fkey'), 'asset_costs', 'assets', ['asset_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_costs_organization_id_fkey'), 'asset_costs', 'organizations', ['organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_costs_driver_id_fkey'), 'asset_costs', 'users', ['driver_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', 'organizations', ['organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'addresses', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('addresses_postal_code_id_fkey'), 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'])
|
||||
op.drop_index(op.f('ix_data_catalog_discovery_vehicle_class'), table_name='catalog_discovery', schema='data')
|
||||
op.drop_index(op.f('ix_data_catalog_discovery_status'), table_name='catalog_discovery', schema='data')
|
||||
op.drop_index(op.f('ix_data_catalog_discovery_model'), table_name='catalog_discovery', schema='data')
|
||||
op.drop_index(op.f('ix_data_catalog_discovery_make'), table_name='catalog_discovery', schema='data')
|
||||
op.drop_index(op.f('ix_data_catalog_discovery_id'), table_name='catalog_discovery', schema='data')
|
||||
op.drop_table('catalog_discovery', schema='data')
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,302 @@
|
||||
"""full_ecosystem_upgrade_v1_6
|
||||
|
||||
Revision ID: e78ce92243ed
|
||||
Revises: b803fe324ebd
|
||||
Create Date: 2026-02-16 00:10:37.974994
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'e78ce92243ed'
|
||||
down_revision: Union[str, Sequence[str], None] = 'b803fe324ebd'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('financial_ledger',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=True),
|
||||
sa.Column('person_id', sa.BigInteger(), nullable=True),
|
||||
sa.Column('amount', sa.Numeric(precision=18, scale=4), nullable=False),
|
||||
sa.Column('currency', sa.String(length=10), nullable=True),
|
||||
sa.Column('transaction_type', sa.String(length=50), nullable=True),
|
||||
sa.Column('related_agent_id', sa.Integer(), nullable=True),
|
||||
sa.Column('details', sa.JSON(), server_default=sa.text("'{}'::jsonb"), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['person_id'], ['data.persons.id'], ),
|
||||
sa.ForeignKeyConstraint(['related_agent_id'], ['data.users.id'], ),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['data.users.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
schema='data'
|
||||
)
|
||||
op.create_table('operational_logs',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=True),
|
||||
sa.Column('action', sa.String(length=100), nullable=False),
|
||||
sa.Column('resource_type', sa.String(length=50), nullable=True),
|
||||
sa.Column('resource_id', sa.String(length=100), nullable=True),
|
||||
sa.Column('details', sa.JSON(), server_default=sa.text("'{}'::jsonb"), nullable=True),
|
||||
sa.Column('ip_address', sa.String(length=45), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['data.users.id'], ondelete='SET NULL'),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
schema='data'
|
||||
)
|
||||
op.create_index(op.f('ix_data_operational_logs_id'), 'operational_logs', ['id'], unique=False, schema='data')
|
||||
op.create_table('security_audit_logs',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('action', sa.String(length=50), nullable=True),
|
||||
sa.Column('actor_id', sa.Integer(), nullable=True),
|
||||
sa.Column('target_id', sa.Integer(), nullable=True),
|
||||
sa.Column('confirmed_by_id', sa.Integer(), nullable=True),
|
||||
sa.Column('is_critical', sa.Boolean(), nullable=True),
|
||||
sa.Column('payload_before', sa.JSON(), nullable=True),
|
||||
sa.Column('payload_after', sa.JSON(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
|
||||
sa.ForeignKeyConstraint(['actor_id'], ['data.users.id'], ),
|
||||
sa.ForeignKeyConstraint(['confirmed_by_id'], ['data.users.id'], ),
|
||||
sa.ForeignKeyConstraint(['target_id'], ['data.users.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
schema='data'
|
||||
)
|
||||
op.drop_constraint(op.f('addresses_postal_code_id_fkey'), 'addresses', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_assignments_branch_id_fkey'), 'asset_assignments', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'branches', ['branch_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_assignments', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_costs_driver_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_costs_organization_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_costs_asset_id_fkey'), 'asset_costs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_costs', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_costs', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_costs', 'users', ['driver_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_events_asset_id_fkey'), 'asset_events', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_events', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_financials_asset_id_fkey'), 'asset_financials', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_financials', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', type_='foreignkey')
|
||||
op.drop_constraint(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_reviews', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'asset_reviews', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'asset_telemetry', 'assets', ['asset_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('assets_catalog_id_fkey'), 'assets', type_='foreignkey')
|
||||
op.drop_constraint(op.f('assets_current_organization_id_fkey'), 'assets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'assets', 'organizations', ['current_organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'assets', 'vehicle_catalog', ['catalog_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('audit_logs_user_id_fkey'), 'audit_logs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'audit_logs', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('branches_address_id_fkey'), 'branches', type_='foreignkey')
|
||||
op.drop_constraint(op.f('branches_organization_id_fkey'), 'branches', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'branches', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'branches', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('credit_logs_org_id_fkey'), 'credit_logs', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'credit_logs', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('documents_uploaded_by_fkey'), 'documents', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'documents', 'users', ['uploaded_by'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('org_sales_assignments_organization_id_fkey'), 'org_sales_assignments', type_='foreignkey')
|
||||
op.drop_constraint(op.f('org_sales_assignments_agent_user_id_fkey'), 'org_sales_assignments', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'org_sales_assignments', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'org_sales_assignments', 'users', ['agent_user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', type_='foreignkey')
|
||||
op.drop_constraint(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'org_subscriptions', 'organizations', ['org_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('organization_financials_organization_id_fkey'), 'organization_financials', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organization_financials', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.alter_column('organization_members', 'role',
|
||||
existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'),
|
||||
type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(op.f('organization_members_person_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organization_members_organization_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organization_members_user_id_fkey'), 'organization_members', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organization_members', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organization_members', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organization_members', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.alter_column('organizations', 'org_type',
|
||||
existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'),
|
||||
type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(op.f('organizations_owner_id_fkey'), 'organizations', type_='foreignkey')
|
||||
op.drop_constraint(op.f('organizations_address_id_fkey'), 'organizations', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'organizations', 'users', ['owner_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'organizations', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('pending_actions_requester_id_fkey'), 'pending_actions', type_='foreignkey')
|
||||
op.drop_constraint(op.f('pending_actions_approver_id_fkey'), 'pending_actions', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'pending_actions', 'users', ['requester_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'pending_actions', 'users', ['approver_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('persons_address_id_fkey'), 'persons', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'persons', 'addresses', ['address_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('points_ledger_user_id_fkey'), 'points_ledger', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'points_ledger', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('ratings_author_id_fkey'), 'ratings', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'ratings', 'users', ['author_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', type_='foreignkey')
|
||||
op.drop_constraint(op.f('service_expertises_service_id_fkey'), 'service_expertises', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_expertises', 'service_profiles', ['service_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_profiles_organization_id_fkey'), 'service_profiles', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_profiles', 'organizations', ['organization_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('service_specialties_parent_id_fkey'), 'service_specialties', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'service_specialties', 'service_specialties', ['parent_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('social_accounts_user_id_fkey'), 'social_accounts', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'social_accounts', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE')
|
||||
op.add_column('system_parameters', sa.Column('category', sa.String(), server_default='general', nullable=True))
|
||||
op.add_column('system_parameters', sa.Column('last_modified_by', sa.String(), nullable=True))
|
||||
op.create_index(op.f('ix_data_system_parameters_category'), 'system_parameters', ['category'], unique=False, schema='data')
|
||||
op.drop_constraint(op.f('user_badges_badge_id_fkey'), 'user_badges', type_='foreignkey')
|
||||
op.drop_constraint(op.f('user_badges_user_id_fkey'), 'user_badges', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'user_badges', 'badges', ['badge_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'user_badges', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('user_stats_user_id_fkey'), 'user_stats', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'user_stats', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('users_person_id_fkey'), 'users', type_='foreignkey')
|
||||
op.drop_constraint(op.f('users_current_sales_agent_id_fkey'), 'users', type_='foreignkey')
|
||||
op.drop_constraint(op.f('users_referred_by_id_fkey'), 'users', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'users', 'users', ['referred_by_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'users', 'persons', ['person_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'users', 'users', ['current_sales_agent_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', type_='foreignkey')
|
||||
op.drop_constraint(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.create_foreign_key(None, 'vehicle_ownerships', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
op.drop_constraint(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'verification_tokens', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data', ondelete='CASCADE')
|
||||
op.drop_constraint(op.f('wallets_user_id_fkey'), 'wallets', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'wallets', 'users', ['user_id'], ['id'], source_schema='data', referent_schema='data')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint(None, 'wallets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('wallets_user_id_fkey'), 'wallets', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'verification_tokens', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('verification_tokens_user_id_fkey'), 'verification_tokens', 'users', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'vehicle_ownerships', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('vehicle_ownerships_vehicle_id_fkey'), 'vehicle_ownerships', 'assets', ['vehicle_id'], ['id'])
|
||||
op.create_foreign_key(op.f('vehicle_ownerships_user_id_fkey'), 'vehicle_ownerships', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'users', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'users', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'users', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('users_referred_by_id_fkey'), 'users', 'users', ['referred_by_id'], ['id'])
|
||||
op.create_foreign_key(op.f('users_current_sales_agent_id_fkey'), 'users', 'users', ['current_sales_agent_id'], ['id'])
|
||||
op.create_foreign_key(op.f('users_person_id_fkey'), 'users', 'persons', ['person_id'], ['id'])
|
||||
op.drop_constraint(None, 'user_stats', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('user_stats_user_id_fkey'), 'user_stats', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'user_badges', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('user_badges_user_id_fkey'), 'user_badges', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('user_badges_badge_id_fkey'), 'user_badges', 'badges', ['badge_id'], ['id'])
|
||||
op.drop_index(op.f('ix_data_system_parameters_category'), table_name='system_parameters', schema='data')
|
||||
op.drop_column('system_parameters', 'last_modified_by')
|
||||
op.drop_column('system_parameters', 'category')
|
||||
op.drop_constraint(None, 'social_accounts', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('social_accounts_user_id_fkey'), 'social_accounts', 'users', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
op.drop_constraint(None, 'service_specialties', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_specialties_parent_id_fkey'), 'service_specialties', 'service_specialties', ['parent_id'], ['id'])
|
||||
op.drop_constraint(None, 'service_profiles', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_profiles_organization_id_fkey'), 'service_profiles', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'service_expertises', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('service_expertises_service_id_fkey'), 'service_expertises', 'service_profiles', ['service_id'], ['id'])
|
||||
op.create_foreign_key(op.f('service_expertises_expertise_id_fkey'), 'service_expertises', 'expertise_tags', ['expertise_id'], ['id'])
|
||||
op.drop_constraint(None, 'ratings', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('ratings_author_id_fkey'), 'ratings', 'users', ['author_id'], ['id'])
|
||||
op.drop_constraint(None, 'points_ledger', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('points_ledger_user_id_fkey'), 'points_ledger', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'persons', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('persons_address_id_fkey'), 'persons', 'addresses', ['address_id'], ['id'])
|
||||
op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'pending_actions', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('pending_actions_approver_id_fkey'), 'pending_actions', 'users', ['approver_id'], ['id'])
|
||||
op.create_foreign_key(op.f('pending_actions_requester_id_fkey'), 'pending_actions', 'users', ['requester_id'], ['id'])
|
||||
op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organizations', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organizations_address_id_fkey'), 'organizations', 'addresses', ['address_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organizations_owner_id_fkey'), 'organizations', 'users', ['owner_id'], ['id'])
|
||||
op.alter_column('organizations', 'org_type',
|
||||
existing_type=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype', schema='data', inherit_schema=True),
|
||||
type_=postgresql.ENUM('individual', 'service', 'service_provider', 'fleet_owner', 'club', 'business', name='orgtype'),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'organization_members', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organization_members_user_id_fkey'), 'organization_members', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organization_members_organization_id_fkey'), 'organization_members', 'organizations', ['organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('organization_members_person_id_fkey'), 'organization_members', 'persons', ['person_id'], ['id'])
|
||||
op.alter_column('organization_members', 'role',
|
||||
existing_type=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole', schema='data', inherit_schema=True),
|
||||
type_=postgresql.ENUM('OWNER', 'ADMIN', 'FLEET_MANAGER', 'DRIVER', 'MECHANIC', 'RECEPTIONIST', name='orguserrole'),
|
||||
existing_nullable=True)
|
||||
op.drop_constraint(None, 'organization_financials', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('organization_financials_organization_id_fkey'), 'organization_financials', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'org_subscriptions', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('org_subscriptions_tier_id_fkey'), 'org_subscriptions', 'subscription_tiers', ['tier_id'], ['id'])
|
||||
op.create_foreign_key(op.f('org_subscriptions_org_id_fkey'), 'org_subscriptions', 'organizations', ['org_id'], ['id'])
|
||||
op.drop_constraint(None, 'org_sales_assignments', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'org_sales_assignments', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('org_sales_assignments_agent_user_id_fkey'), 'org_sales_assignments', 'users', ['agent_user_id'], ['id'])
|
||||
op.create_foreign_key(op.f('org_sales_assignments_organization_id_fkey'), 'org_sales_assignments', 'organizations', ['organization_id'], ['id'])
|
||||
op.drop_constraint(None, 'geo_streets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('geo_streets_postal_code_id_fkey'), 'geo_streets', 'geo_postal_codes', ['postal_code_id'], ['id'])
|
||||
op.drop_constraint(None, 'documents', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('documents_uploaded_by_fkey'), 'documents', 'users', ['uploaded_by'], ['id'])
|
||||
op.drop_constraint(None, 'credit_logs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('credit_logs_org_id_fkey'), 'credit_logs', 'organizations', ['org_id'], ['id'])
|
||||
op.drop_constraint(None, 'branches', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'branches', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('branches_organization_id_fkey'), 'branches', 'organizations', ['organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('branches_address_id_fkey'), 'branches', 'addresses', ['address_id'], ['id'])
|
||||
op.drop_constraint(None, 'audit_logs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('audit_logs_user_id_fkey'), 'audit_logs', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'assets', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'assets', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('assets_current_organization_id_fkey'), 'assets', 'organizations', ['current_organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('assets_catalog_id_fkey'), 'assets', 'vehicle_catalog', ['catalog_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_telemetry', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_telemetry_asset_id_fkey'), 'asset_telemetry', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_reviews', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_reviews_asset_id_fkey'), 'asset_reviews', 'assets', ['asset_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_reviews_user_id_fkey'), 'asset_reviews', 'users', ['user_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_financials', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_financials_asset_id_fkey'), 'asset_financials', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_events', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_events_asset_id_fkey'), 'asset_events', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_costs', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_costs_asset_id_fkey'), 'asset_costs', 'assets', ['asset_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_costs_organization_id_fkey'), 'asset_costs', 'organizations', ['organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_costs_driver_id_fkey'), 'asset_costs', 'users', ['driver_id'], ['id'])
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.drop_constraint(None, 'asset_assignments', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('asset_assignments_branch_id_fkey'), 'asset_assignments', 'branches', ['branch_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_assignments_organization_id_fkey'), 'asset_assignments', 'organizations', ['organization_id'], ['id'])
|
||||
op.create_foreign_key(op.f('asset_assignments_asset_id_fkey'), 'asset_assignments', 'assets', ['asset_id'], ['id'])
|
||||
op.drop_constraint(None, 'addresses', schema='data', type_='foreignkey')
|
||||
op.create_foreign_key(op.f('addresses_postal_code_id_fkey'), 'addresses', 'geo_postal_codes', ['postal_code_id'], ['id'])
|
||||
op.drop_table('security_audit_logs', schema='data')
|
||||
op.drop_index(op.f('ix_data_operational_logs_id'), table_name='operational_logs', schema='data')
|
||||
op.drop_table('operational_logs', schema='data')
|
||||
op.drop_table('financial_ledger', schema='data')
|
||||
# ### end Alembic commands ###
|
||||
32
backend/seed_discovery.py
Normal file
32
backend/seed_discovery.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import asyncio
|
||||
import httpx
|
||||
from sqlalchemy import text
|
||||
from app.db.session import SessionLocal
|
||||
|
||||
async def seed():
|
||||
print("🚀 RDW Márka-felfedezés indul...")
|
||||
url = "https://opendata.rdw.nl/resource/m9d7-ebf2.json?$select=distinct%20merk&$limit=50000"
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(url, timeout=60)
|
||||
if resp.status_code != 200:
|
||||
print(f"❌ Hiba: {resp.status_code}")
|
||||
return
|
||||
|
||||
makes = resp.json()
|
||||
print(f"📦 {len(makes)} márkát találtam. Mentés...")
|
||||
|
||||
async with SessionLocal() as db:
|
||||
for item in makes:
|
||||
m = item['merk'].upper()
|
||||
# ON CONFLICT: Ha már benne van (pl. n8n betette), ne legyen hiba
|
||||
await db.execute(text("""
|
||||
INSERT INTO data.catalog_discovery (make, model, source, status)
|
||||
VALUES (:m, 'ALL', 'global_seed', 'pending')
|
||||
ON CONFLICT DO NOTHING
|
||||
"""), {"m": m})
|
||||
await db.commit()
|
||||
print("✅ Kész! A discovery tábla felöltve az összes EU-s márkával.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(seed())
|
||||
80
docker-compose.yml
Executable file → Normal file
80
docker-compose.yml
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
services:
|
||||
# 1. MIGRÁCIÓ (Adatbázis szerkezet frissítése)
|
||||
# 1. MIGRÁCIÓ
|
||||
migrate:
|
||||
build:
|
||||
context: ./backend
|
||||
@@ -7,7 +7,7 @@ services:
|
||||
container_name: service_finder_migrate
|
||||
env_file: .env
|
||||
volumes:
|
||||
- ./backend:/app # Ez tartalmazza az alembic.ini-t és a migrations mappát is!
|
||||
- ./backend:/app
|
||||
environment:
|
||||
PYTHONPATH: /app
|
||||
DATABASE_URL: ${MIGRATION_DATABASE_URL}
|
||||
@@ -15,7 +15,7 @@ services:
|
||||
networks:
|
||||
- default
|
||||
- shared_db_net
|
||||
restart: "no"
|
||||
restart: "no" # Ez így helyes, lefut és megáll.
|
||||
|
||||
# 2. BACKEND API
|
||||
service_finder_api:
|
||||
@@ -24,20 +24,14 @@ services:
|
||||
dockerfile: Dockerfile
|
||||
container_name: service_finder_api
|
||||
env_file: .env
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
- /mnt/nas/app_data:/mnt/nas/app_data # Központi NAS elérés
|
||||
- ./static_previews:/app/static/previews # Lokális SSD gyorsítótár
|
||||
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --proxy-headers --forwarded-allow-ips="*"
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
- /mnt/nas/app_data:/mnt/nas/app_data
|
||||
- ./static_previews:/app/static/previews
|
||||
environment:
|
||||
PYTHONPATH: /app
|
||||
DATABASE_URL: ${DATABASE_URL}
|
||||
ALLOWED_ORIGINS: ${ALLOWED_ORIGINS}
|
||||
MINIO_ENDPOINT: ${MINIO_ENDPOINT}
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||
depends_on:
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
@@ -50,25 +44,19 @@ services:
|
||||
- shared_db_net
|
||||
restart: unless-stopped
|
||||
|
||||
# 3. MINIO (NAS-ra ment)
|
||||
# 3. MINIO
|
||||
minio:
|
||||
image: minio/minio
|
||||
container_name: service_finder_minio
|
||||
env_file: .env
|
||||
command: server /data --console-address ":9001"
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||
volumes:
|
||||
- /mnt/nas/app_data/minio_data:/data
|
||||
ports:
|
||||
- "9000:9000"
|
||||
- "9001:9001"
|
||||
networks:
|
||||
- default
|
||||
restart: unless-stopped
|
||||
|
||||
# 4. REDIS (Lokális cache)
|
||||
# 4. REDIS
|
||||
redis:
|
||||
image: redis:alpine
|
||||
container_name: service_finder_redis
|
||||
@@ -79,15 +67,13 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
# 5. FRONTEND
|
||||
service_finder_frontend:
|
||||
service_frontend: # Rövidített szerviznév
|
||||
build:
|
||||
context: ./frontend
|
||||
container_name: service_finder_frontend
|
||||
env_file: .env
|
||||
ports:
|
||||
- "3001:80"
|
||||
environment:
|
||||
ALLOWED_ORIGINS: ${ALLOWED_ORIGINS}
|
||||
networks:
|
||||
- default
|
||||
depends_on:
|
||||
@@ -95,15 +81,14 @@ services:
|
||||
condition: service_started
|
||||
restart: unless-stopped
|
||||
|
||||
# Katalógus felderítő robot
|
||||
# 6. KATALÓGUS ROBOT (A mi kis felfedezőnk)
|
||||
catalog_robot:
|
||||
build: ./backend
|
||||
container_name: service_finder_robot_catalog
|
||||
command: python -m app.workers.catalog_robot
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
env_file:
|
||||
- .env
|
||||
env_file: .env
|
||||
depends_on:
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
@@ -112,23 +97,14 @@ services:
|
||||
- shared_db_net
|
||||
restart: always
|
||||
|
||||
# Szerviz vadász robot (Robot 2.7)
|
||||
# 7. SERVICE HUNTER
|
||||
service_hunter:
|
||||
build: ./backend
|
||||
container_name: service_finder_robot_hunter
|
||||
command: python -m app.workers.service_hunter
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
- ./backend/app/workers/local_services.csv:/app/app/workers/local_services.csv
|
||||
environment:
|
||||
- GOOGLE_API_KEY=${GOOGLE_API_KEY}
|
||||
# JAVÍTVA: shared-postgres lett a gépnév a 'db' helyett!
|
||||
- DATABASE_URL=postgresql+asyncpg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@shared-postgres:5432/${POSTGRES_DB}
|
||||
env_file:
|
||||
- .env
|
||||
dns:
|
||||
- 8.8.8.8
|
||||
- 1.1.1.1
|
||||
env_file: .env
|
||||
depends_on:
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
@@ -137,7 +113,7 @@ services:
|
||||
- shared_db_net
|
||||
restart: always
|
||||
|
||||
# --- ÚJ: n8n AUTOMATIZÁCIÓ ---
|
||||
# 8. n8n AUTOMATIZÁCIÓ
|
||||
n8n:
|
||||
image: n8nio/n8n:latest
|
||||
container_name: service_finder_n8n
|
||||
@@ -147,13 +123,8 @@ services:
|
||||
env_file: .env
|
||||
environment:
|
||||
- N8N_HOST=0.0.0.0
|
||||
- N8N_PORT=5678
|
||||
- N8N_PROTOCOL=http
|
||||
- N8N_SECURE_COOKIE=false # <--- EZ JAVÍTJA A BELÉPÉSI HIBÁT!
|
||||
- DB_TYPE=postgresdb
|
||||
- DB_POSTGRESDB_DATABASE=n8n_internal
|
||||
- DB_POSTGRESDB_HOST=n8n_db
|
||||
- DB_POSTGRESDB_PORT=5432
|
||||
- DB_POSTGRESDB_USER=n8n_admin
|
||||
- DB_POSTGRESDB_PASSWORD=${N8N_DB_PASSWORD}
|
||||
volumes:
|
||||
@@ -164,7 +135,6 @@ services:
|
||||
depends_on:
|
||||
- n8n_db
|
||||
|
||||
# n8n belső meta-adatbázisa
|
||||
n8n_db:
|
||||
image: postgres:15-alpine
|
||||
container_name: service_finder_n8n_db
|
||||
@@ -178,18 +148,32 @@ services:
|
||||
networks:
|
||||
- default
|
||||
|
||||
# Browserless - A robot "szeme" (Központi 3005-ös porton)
|
||||
# 9. BROWSERLESS
|
||||
browserless:
|
||||
image: browserless/chrome:latest
|
||||
container_name: service_finder_browserless
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3005:3000"
|
||||
environment:
|
||||
- MAX_CONCURRENT_SESSIONS=10
|
||||
networks:
|
||||
- default
|
||||
|
||||
# 10. Technikai adatok dúsítása (kW, ccm, üzemanyag)
|
||||
enricher_robot:
|
||||
build: ./backend
|
||||
container_name: service_finder_robot_enricher
|
||||
command: python -m app.workers.technical_enricher
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
env_file: .env
|
||||
depends_on:
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
networks:
|
||||
- default
|
||||
- shared_db_net
|
||||
restart: always
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
|
||||
198
docker-compose_1.yml
Executable file
198
docker-compose_1.yml
Executable file
@@ -0,0 +1,198 @@
|
||||
services:
|
||||
# 1. MIGRÁCIÓ (Adatbázis szerkezet frissítése)
|
||||
migrate:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
container_name: service_finder_migrate
|
||||
env_file: .env
|
||||
volumes:
|
||||
- ./backend:/app # Ez tartalmazza az alembic.ini-t és a migrations mappát is!
|
||||
environment:
|
||||
PYTHONPATH: /app
|
||||
DATABASE_URL: ${MIGRATION_DATABASE_URL}
|
||||
command: ["bash", "-lc", "alembic upgrade head"]
|
||||
networks:
|
||||
- default
|
||||
- shared_db_net
|
||||
restart: "no"
|
||||
|
||||
# 2. BACKEND API
|
||||
service_finder_api:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
container_name: service_finder_api
|
||||
env_file: .env
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
- /mnt/nas/app_data:/mnt/nas/app_data # Központi NAS elérés
|
||||
- ./static_previews:/app/static/previews # Lokális SSD gyorsítótár
|
||||
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --proxy-headers --forwarded-allow-ips="*"
|
||||
ports:
|
||||
- "8000:8000"
|
||||
environment:
|
||||
PYTHONPATH: /app
|
||||
DATABASE_URL: ${DATABASE_URL}
|
||||
ALLOWED_ORIGINS: ${ALLOWED_ORIGINS}
|
||||
MINIO_ENDPOINT: ${MINIO_ENDPOINT}
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||
depends_on:
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
minio:
|
||||
condition: service_started
|
||||
redis:
|
||||
condition: service_started
|
||||
networks:
|
||||
- default
|
||||
- shared_db_net
|
||||
restart: unless-stopped
|
||||
|
||||
# 3. MINIO (NAS-ra ment)
|
||||
minio:
|
||||
image: minio/minio
|
||||
container_name: service_finder_minio
|
||||
env_file: .env
|
||||
command: server /data --console-address ":9001"
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||
volumes:
|
||||
- /mnt/nas/app_data/minio_data:/data
|
||||
ports:
|
||||
- "9000:9000"
|
||||
- "9001:9001"
|
||||
networks:
|
||||
- default
|
||||
restart: unless-stopped
|
||||
|
||||
# 4. REDIS (Lokális cache)
|
||||
redis:
|
||||
image: redis:alpine
|
||||
container_name: service_finder_redis
|
||||
volumes:
|
||||
- /mnt/nas/app_data/redis_data:/data
|
||||
networks:
|
||||
- default
|
||||
restart: unless-stopped
|
||||
|
||||
# 5. FRONTEND
|
||||
service_finder_frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
container_name: service_finder_frontend
|
||||
env_file: .env
|
||||
ports:
|
||||
- "3001:80"
|
||||
environment:
|
||||
ALLOWED_ORIGINS: ${ALLOWED_ORIGINS}
|
||||
networks:
|
||||
- default
|
||||
depends_on:
|
||||
service_finder_api:
|
||||
condition: service_started
|
||||
restart: unless-stopped
|
||||
|
||||
# Katalógus felderítő robot
|
||||
catalog_robot:
|
||||
build: ./backend
|
||||
image: service_finder-catalog_robot
|
||||
container_name: service_finder_robot_catalog
|
||||
command: python -m app.workers.catalog_robot
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
env_file:
|
||||
- .env
|
||||
depends_on:
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
networks:
|
||||
- default
|
||||
- shared_db_net
|
||||
restart: always
|
||||
|
||||
# Szerviz vadász robot (Robot 2.7)
|
||||
service_hunter:
|
||||
build: ./backend
|
||||
container_name: service_finder_robot_hunter
|
||||
command: python -m app.workers.service_hunter
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
- ./backend/app/workers/local_services.csv:/app/app/workers/local_services.csv
|
||||
environment:
|
||||
- GOOGLE_API_KEY=${GOOGLE_API_KEY}
|
||||
# JAVÍTVA: shared-postgres lett a gépnév a 'db' helyett!
|
||||
- DATABASE_URL=postgresql+asyncpg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@shared-postgres:5432/${POSTGRES_DB}
|
||||
env_file:
|
||||
- .env
|
||||
dns:
|
||||
- 8.8.8.8
|
||||
- 1.1.1.1
|
||||
depends_on:
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
networks:
|
||||
- default
|
||||
- shared_db_net
|
||||
restart: always
|
||||
|
||||
# --- ÚJ: n8n AUTOMATIZÁCIÓ ---
|
||||
n8n:
|
||||
image: n8nio/n8n:latest
|
||||
container_name: service_finder_n8n
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5678:5678"
|
||||
env_file: .env
|
||||
environment:
|
||||
- N8N_HOST=0.0.0.0
|
||||
- N8N_PORT=5678
|
||||
- N8N_PROTOCOL=http
|
||||
- N8N_SECURE_COOKIE=false # <--- EZ JAVÍTJA A BELÉPÉSI HIBÁT!
|
||||
- DB_TYPE=postgresdb
|
||||
- DB_POSTGRESDB_DATABASE=n8n_internal
|
||||
- DB_POSTGRESDB_HOST=n8n_db
|
||||
- DB_POSTGRESDB_PORT=5432
|
||||
- DB_POSTGRESDB_USER=n8n_admin
|
||||
- DB_POSTGRESDB_PASSWORD=${N8N_DB_PASSWORD}
|
||||
volumes:
|
||||
- ./n8n/data:/home/node/.n8n
|
||||
networks:
|
||||
- default
|
||||
- shared_db_net
|
||||
depends_on:
|
||||
- n8n_db
|
||||
|
||||
# n8n belső meta-adatbázisa
|
||||
n8n_db:
|
||||
image: postgres:15-alpine
|
||||
container_name: service_finder_n8n_db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_USER=n8n_admin
|
||||
- POSTGRES_PASSWORD=${N8N_DB_PASSWORD}
|
||||
- POSTGRES_DB=n8n_internal
|
||||
volumes:
|
||||
- ./n8n/db_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- default
|
||||
|
||||
# Browserless - A robot "szeme" (Központi 3005-ös porton)
|
||||
browserless:
|
||||
image: browserless/chrome:latest
|
||||
container_name: service_finder_browserless
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3005:3000"
|
||||
environment:
|
||||
- MAX_CONCURRENT_SESSIONS=10
|
||||
networks:
|
||||
- default
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
shared_db_net:
|
||||
external: true
|
||||
@@ -132,4 +132,35 @@ A technikai belépési pont.
|
||||
A rendszer támogatja a "Ghost Person" (Árnyék személy) entitásokat.
|
||||
- **Ghost Person:** Olyan `data.persons` rekord, amelyet a Robot 2 hozott létre nyilvános adatok (pl. cégjegyzék) alapján.
|
||||
- **Identity Linkage:** Regisztrációkor a `AuthService.complete_kyc` kötelezően ellenőrzi a meglévő Ghost rekordokat (Adószám/Név egyezés).
|
||||
- **Merge Action:** Találat esetén a rendszer összefűzi a technikai User fiókot a Ghost Person rekorddal, aktiválja a jogosultságokat, és megszünteti a Ghost státuszt.
|
||||
- **Merge Action:** Találat esetén a rendszer összefűzi a technikai User fiókot a Ghost Person rekorddal, aktiválja a jogosultságokat, és megszünteti a Ghost státuszt.
|
||||
|
||||
## 2. The Dual Entity Model (Person vs. User)
|
||||
|
||||
A rendszer alapja a természetes személy (**Person**) és a felhasználói fiók (**User**) szigorú szétválasztása az adatbiztonság és az üzleti folytonosság érdekében.
|
||||
|
||||
### 2.1 Person (A DNS - "Az Örök Személy")
|
||||
A `persons` tábla rekordja soha nem törlődik teljesen (GDPR esetén anonimizálódik), így biztosítva a rendszer memóriáját.
|
||||
* **Identity Hash:** Egyedi SHA256 lenyomat (`normalized(name + mother + birth_place + birth_date)`), amely megakadályozza a multi-account visszaéléseket és felismeri a visszatérő felhasználókat.
|
||||
* **Örök Adatok:**
|
||||
* `lifetime_xp`: A valaha szerzett összes tapasztalati pont.
|
||||
* `penalty_points`: A büntetési szint (0-3). Ez nem nullázódik új regisztrációval!
|
||||
* `social_reputation`: A közösségi megbízhatósági index (1.00 = 100%).
|
||||
* `is_sales_agent`: Jogosult-e jutalékra.
|
||||
|
||||
### 2.2 User (A Kulcs - "A Munkamenet")
|
||||
A `users` tábla a belépési pont. Törölhető, eldobható, újraregisztrálható.
|
||||
* **Kapcsolat:** Minden User egyetlen Person-höz tartozik (`person_id`).
|
||||
* **Időkorlátos Jogok:**
|
||||
* `subscription_plan`: FREE / PREMIUM / VIP.
|
||||
* `subscription_expires_at`: A prémium funkciók lejárata.
|
||||
* **Sales Kapcsolat:**
|
||||
* `referral_code`: Saját meghívó kód.
|
||||
* `current_sales_agent_id`: Ki kapja a "Farming" jutalékot ez után a felhasználó után.
|
||||
|
||||
### 2.3 Jogosultsági Szintek (Scope-Based RBAC)
|
||||
A jogosultság nem csak szerepkör (Role), hanem hatókör (Scope) alapú:
|
||||
1. **Global:** Superadmin.
|
||||
2. **Country:** Országos Admin (pl. HU).
|
||||
3. **Region:** Régiós Admin (pl. Pest megye).
|
||||
4. **Entity:** Szerviz Tulajdonos (saját cég).
|
||||
5. **Individual:** Átlagfelhasználó (saját adatok).
|
||||
@@ -201,4 +201,13 @@ A rendszer az adatintegritás és a sebesség érdekében hibrid modellt haszná
|
||||
## 2.4 Financial & Enrichment Tables
|
||||
- **data.organization_financials:** Éves gazdasági adatok (árbevétel, profit, létszám) tárolása historikus elemzéshez.
|
||||
- **data.service_profiles.specialization_tags:** JSONB mező a szigorú szakmai szűréshez (pl. márkák, specifikus javítási típusok).
|
||||
- **data.service_profiles.google_place_id:** Külső validációs kulcs a Google Places API-hoz.
|
||||
- **data.service_profiles.google_place_id:** Külső validációs kulcs a Google Places API-hoz.
|
||||
|
||||
|
||||
### Identity & Economy Module (v1.6+)
|
||||
* **`data.persons`**: Természetes személyek, Identity Hash, Örök XP/Büntetés.
|
||||
* **`data.users`**: Login fiókok, Előfizetési idő, Sales kapcsolatok.
|
||||
* **`data.wallets`**: 3-as osztású egyenleg (`earned`, `purchased`, `coins`).
|
||||
* **`data.financial_ledger`**: Pénzügyi tranzakciók főkönyve.
|
||||
* **`data.security_audit_logs`**: Biztonsági események és 4-szem jóváhagyások.
|
||||
* **`data.org_sales_assignments`**: Cég-Üzletkötő kapcsolat (Farming jog).
|
||||
@@ -113,4 +113,24 @@ A meghívók érvényessége a típustól függ:
|
||||
|
||||
### 5.3 Biztonság
|
||||
* A meghívó link tartalmaz egy aláírt JWT tokent, amely rögzíti a `target_org_id`-t (melyik flottába hívjuk) és a `role`-t (pl. sofőr).
|
||||
* A kód felhasználása után a link érvénytelenné válik (One-time use).
|
||||
* A kód felhasználása után a link érvénytelenné válik (One-time use).
|
||||
|
||||
## 1. Háromlépcsős Onboarding (v1.5)
|
||||
|
||||
### 1.1 Step 1: Lite Registration
|
||||
- Technikai `User` létrehozása (inaktív). Email ellenőrzés indítása.
|
||||
|
||||
### 1.2 Step 2: Individual Setup (Privát Identitás)
|
||||
- **Cél:** A természetes személy (`Person`) és privát szférájának rögzítése.
|
||||
- **Művelet:** - `Person` rögzítése/frissítése.
|
||||
- Privát `Organization` létrehozása (`org_type='individual'`, `is_ownership_transferable=False`).
|
||||
- **Központi Telephely (Main Branch)** létrehozása a lakcím alapján.
|
||||
- Privát Flotta és Wallet inicializálása.
|
||||
|
||||
### 1.3 Step 3: Business Setup (Céges Identitás)
|
||||
- **Cél:** Államilag nyilvántartott gazdasági egység rögzítése.
|
||||
- **Művelet:**
|
||||
- Adószám bekérése + VIES/Cégjegyzék ellenőrzés.
|
||||
- Új, különálló `Organization` létrehozása (`org_type='business'`, `is_ownership_transferable=True`).
|
||||
- Székhely rögzítése mint **Main Branch**.
|
||||
- Opcionális további telephelyek rögzítése.
|
||||
@@ -110,4 +110,31 @@ A rendszer támogatja a dinamikus árazást a kozmetikai elemeknél is.
|
||||
4. **Equip:** Opcionálisan azonnali beállítás (pl. profilkép keret).
|
||||
|
||||
### 5.3 Bővíthetőség
|
||||
Új elem hozzáadásához **nem kell kódot módosítani**, csak a `shop_catalog` JSON-t kell frissíteni az Admin felületen. A kliens alkalmazás (App/Web) dinamikusan tölti be a kínálatot ebből a JSON-ből.
|
||||
Új elem hozzáadásához **nem kell kódot módosítani**, csak a `shop_catalog` JSON-t kell frissíteni az Admin felületen. A kliens alkalmazás (App/Web) dinamikusan tölti be a kínálatot ebből a JSON-ből.
|
||||
|
||||
## 3. The Triple Wallet System (3-as Pénztárca)
|
||||
|
||||
A `wallets` tábla három elkülönített alszámlát kezel a transzparencia érdekében:
|
||||
|
||||
| Alszámla | Kód | Forrás | Felhasználás | Átváltható? |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **Earned Credits** | `earned_credits` | Munka (validálás), Referral, Jutalék | Prémium funkciók, Szolgáltatás vásárlás | IGEN |
|
||||
| **Purchased Credits** | `purchased_credits` | Bankkártyás feltöltés (Stripe) | Prémium funkciók, Szolgáltatás vásárlás | IGEN |
|
||||
| **Service Coins** | `service_coins` | B2B Csomagok, Partneri jóváírás | **Kizárólag** Hirdetés, Kiemelés, Szponzoráció | **NEM** |
|
||||
|
||||
## 4. Sales Commission Model (Hunting & Farming)
|
||||
|
||||
Az üzletkötők ösztönzése két fázisban történik:
|
||||
|
||||
### 4.1 Hunting (Vadász) Jutalék
|
||||
* **Esemény:** Új fizető ügyfél behozatala (első tranzakció).
|
||||
* **Mérték:** 10% (Alapértelmezett `system_parameter`).
|
||||
* **Jóváírás:** Azonnal, `earned_credits` formájában.
|
||||
|
||||
### 4.2 Farming (Gazda) Jutalék
|
||||
* **Esemény:** Meglévő ügyfél havidíj megújítása.
|
||||
* **Mérték:** 5% (Alapértelmezett `system_parameter`).
|
||||
* **Átruházhatóság:** A jutalékot nem a User, hanem az `OrganizationSalesAssignment` tábla aktív rekordja határozza meg. Ha az üzletkötő kilép, a portfóliója (és a Farming joga) átruházható egy másik ügynökre.
|
||||
|
||||
### 4.3 Financial Ledger (Pénzügyi Napló)
|
||||
Minden tranzakció (Vásárlás, Jutalék jóváírás, Költés) bekerül a `financial_ledger` táblába, amely megmásíthatatlan (Append-only) és tartalmazza a `related_agent_id`-t a visszakövethetőségért.
|
||||
@@ -365,4 +365,120 @@ A rendszer most már képes egyetlen KYC folyamat alatt aktiválni a felhasznál
|
||||
|
||||
### 🔜 Következő Lépések
|
||||
- Gamification és Moderátori felület (Admin UI) tervezése az adatok tisztítására.
|
||||
- Logikai szabályrendszer (Business Rules) véglegesítése a "Robot vs. Ember" adatkonfliktusokra.
|
||||
- Logikai szabályrendszer (Business Rules) véglegesítése a "Robot vs. Ember" adatkonfliktusokra.
|
||||
|
||||
|
||||
# Changelog - Service Finder Project
|
||||
**Dátum:** 2026-02-15
|
||||
**Verzió:** Backend v1.9.8 / Robot v1.0.7 (Deep Hunter)
|
||||
**Fókusz:** Adatbázis séma bővítése, RDW API integráció stabilizálása, Multi-vehicle támogatás.
|
||||
|
||||
## 🏛️ Adatbázis és Architektúra (Alembic & SQLAlchemy)
|
||||
### Hozzáadva
|
||||
- **Új Migráció (`enrich_catalog_technical_schema`):**
|
||||
- `power_kw` (Integer, Indexed): Teljesítmény tárolása.
|
||||
- `engine_capacity` (Integer, Indexed): Hengerűrtartalom (ccm).
|
||||
- `max_weight_kg` (Integer): Megengedett legnagyobb össztömeg.
|
||||
- `euro_class` (String): Környezetvédelmi besorolás.
|
||||
- **Új Migráció (`add_axles_and_body_type`):**
|
||||
- `axle_count` (Integer): Tengelyek száma (Teherautókhoz/Kamionokhoz).
|
||||
- `body_type` (String): Felépítmény (pl. Sedan, Box, Camper).
|
||||
- **Modell Frissítés (`asset.py`):**
|
||||
- Az `AssetCatalog` osztály szinkronba hozva az új DB sémával.
|
||||
- `UniqueConstraint` és indexek optimalizálása a gyors kereséshez.
|
||||
|
||||
### Javítva
|
||||
- **Alembic Syntax Error:** Javítva a `ddef` elírás a migrációs fájlban.
|
||||
- **Column Duplication:** Javítva az `axle_count` duplikált létrehozási kísérlete a második migrációban.
|
||||
|
||||
## 🤖 Robot / Worker (Data Ingestion)
|
||||
### Módosítva
|
||||
- **Robot Upgrade (v1.0.2 -> v1.0.7 Deep Hunter):**
|
||||
- **License Plate Bridge (Rendszám-híd):** Új stratégia az API 400-as hibák megkerülésére. A robot mostantól:
|
||||
1. Lekéri az alapadatokat (`m9d7-ebf2`).
|
||||
2. Kivesz egy minta rendszámot.
|
||||
3. Ezzel a rendszámmal lekérdezi a `FUEL`, `AXLE` és `BODY` táblákat.
|
||||
- **Pagination (Lapozás):** `$offset` támogatás beépítése, így a robot képes 50.000+ rekordos márkákat is végigolvasni.
|
||||
- **Camper Detection:** Automatikus lakóautó (`camper`) kategória felismerés a "kampeerwagen" kulcsszó alapján.
|
||||
- **Category Mapping:** Angol nyelvű kategóriák (Car, Truck, Motorcycle, Agricultural) kényszerítése.
|
||||
|
||||
### Javítva
|
||||
- **RDW API 400 Bad Request:** Megoldva a `merk` vs `merknaam` paraméterek eltérésének kezelésével (átállás a fő táblára).
|
||||
- **AttributeError:** Javítva a hibás `TECH_API_URL` hivatkozás.
|
||||
|
||||
## 💾 Adat (Seeding & SQL)
|
||||
- **Grand Seeder v2:**
|
||||
- SQL szkript létrehozva a világmárkák (Toyota, BMW, Scania, John Deere, stb.) tömeges betöltésére.
|
||||
- `model` mező feltöltése `'ALL'` értékkel a `NOT NULL` kényszer miatt.
|
||||
- Státuszok visszaállítása `pending`-re a teljes újradolgozáshoz.
|
||||
|
||||
# CHANGELOG - 2026.02.16 (Architectural Overhaul: Identity & Economy Engine)
|
||||
|
||||
## 🏆 Napi Összefoglaló
|
||||
A mai napon alapjaiban strukturáltuk át az identitáskezelést (`Identity`), a jogosultsági rendszert (`RBAC`) és a gazdasági motort (`Economy`). Bevezetésre került a "Dual Entity" modell (Person vs. User), a 3-szintű Wallet rendszer, valamint a "Hunting & Farming" üzletkötői jutalékrendszer alapjai. A biztonságot a 4-szem elvű (Four-Eyes Principle) audit naplózás garantálja.
|
||||
|
||||
---
|
||||
|
||||
## 🏛️ 1. Architektúra és Logika (Master Book Updates)
|
||||
|
||||
### A. Identitás Filozófiája (The Dual Entity Rule)
|
||||
* **Person (A DNS):** A természetes személy, aki "örök". Nem törlődik GDPR törléskor sem, csak anonimizálódik.
|
||||
* Tárolja: `lifetime_xp` (életút pontok), `penalty_points` (büntetések 0-3 szint), `social_reputation`.
|
||||
* **Identity Hash:** Egyedi SHA256 lenyomat (Kisbetűsített Anyja neve + Születési hely + Idő) a duplikációk és visszaélések ellen.
|
||||
* **User (A Kulcs):** A belépési fiók. Bármikor törölhető/eldobható.
|
||||
* Kapcsolódik a Person-höz.
|
||||
* Tárolja: `subscription_plan`, `is_vip`, `session_data`.
|
||||
|
||||
### B. Gazdasági Modell (The Triple Wallet)
|
||||
A pénztárcát (`Wallet`) három, szigorúan elkülönített alszámlára bontottuk:
|
||||
1. **Earned Credits:** Munkával (validálás) és Referral jutalékból szerzett. (Beváltható Prémiumra).
|
||||
2. **Purchased Credits:** Valódi pénzért vásárolt egyenleg. (Beváltható Prémiumra).
|
||||
3. **Service Coins:** B2B egység. Kizárólag hirdetésre és kiemelésre fordítható. (NEM váltható Prémiumra).
|
||||
|
||||
### C. Üzletkötői Rendszer (Hunting & Farming)
|
||||
* **Hunting (Vadász) Jutalék:** Egyszeri jutalék az első behozatalért (tervezett: 10%).
|
||||
* **Farming (Gazda) Jutalék:** Folyamatos jutalék a havidíjakból (tervezett: 5%).
|
||||
* **Átruházhatóság:** A Farming jog nem az üzletkötőhöz, hanem a Cég-Üzletkötő kapcsolathoz (`OrganizationSalesAssignment`) kötődik. Ha az üzletkötő kilép, a portfóliója (és a jutalék) átruházható másra.
|
||||
|
||||
### D. Biztonság (Audit & 4-Eyes)
|
||||
* **Operational Log:** Napi üzemi események (pl. jármű rögzítés).
|
||||
* **Financial Ledger:** Minden pénzmozgás (Kredit/Coin/HUF) központi főkönyve.
|
||||
* **Security Audit Log:** Kiemelt biztonsági események (pl. VIP státusz adása).
|
||||
* **4-szem elv:** Kritikusan érzékeny műveleteknél kötelező egy második admin jóváhagyása (`confirmed_by_id`).
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 2. Adatbázis és Modell Változások
|
||||
|
||||
### Új/Módosított Táblák (`data` séma)
|
||||
| Tábla | Változás | Leírás |
|
||||
| :--- | :--- | :--- |
|
||||
| **persons** | **UPDATE** | Új mezők: `identity_hash`, `lifetime_xp`, `penalty_points`, `social_reputation`, `is_sales_agent`. |
|
||||
| **users** | **UPDATE** | Új mezők: `subscription_expires_at`, `is_vip`, `referral_code`, `current_sales_agent_id`. |
|
||||
| **wallets** | **REFACTOR** | Régi balance törölve. Új: `earned_credits`, `purchased_credits`, `service_coins`. |
|
||||
| **org_sales_assignments** | **NEW** | Kapcsolótábla: Melyik cég után ki kapja épp a Farming jutalékot. |
|
||||
| **financial_ledger** | **NEW** | Pénzügyi tranzakciók megmásíthatatlan naplója. |
|
||||
| **security_audit_logs** | **NEW** | Adminisztrátori műveletek és 4-szem elv naplózása. |
|
||||
| **operational_logs** | **NEW** | Általános rendszerhasználati napló. |
|
||||
|
||||
---
|
||||
|
||||
## 📂 3. Érintett Fájlok Listája (Checklist)
|
||||
|
||||
Kérlek, ellenőrizd, hogy ezek a fájlok a legfrissebb verziót tartalmazzák-e a mentésedben:
|
||||
|
||||
- [x] **`backend/app/models/identity.py`** (A teljes Person/User/Wallet logika alapja)
|
||||
- [x] **`backend/app/models/audit.py`** (A Ledger és Security Log definíciók)
|
||||
- [x] **`backend/app/models/organization.py`** (A SalesAssignment tábla hozzáadása)
|
||||
- [x] **`backend/app/models/__init__.py`** (Az összes modell regisztrációja az Alembic számára)
|
||||
- [x] **`backend/app/db/base.py`** (A metadata importok frissítése)
|
||||
- [x] **`backend/app/core/validators.py`** (Az IdentityNormalizer és Hash generáló logika)
|
||||
- [x] **`backend/migrations/versions/XXXX_full_ecosystem_upgrade_v1_6.py`** (A generált migrációs fájl)
|
||||
|
||||
---
|
||||
|
||||
## 🔮 4. Következő Lépések (Roadmap)
|
||||
|
||||
1. **Service Réteg Implementálása:** Megírni a logikát, ami ténylegesen számolja a 10/5%-os jutalékot és beírja a `FinancialLedger`-be.
|
||||
2. **Admin UI:** Felületet készíteni a `system_parameters` (Jutalék szintek) állítására.
|
||||
3. **Robot v1.8:** A "Ghost" szervizek bekötése az új `Person` logikába (automata `identity_hash` generálás a cégadatokból).
|
||||
@@ -129,4 +129,26 @@ A `rank: 100` szintű felhasználó (SuperAdmin) az egyetlen, aki:
|
||||
- `POST /admin/translations/sync`:
|
||||
- **Trigger:** Manuális (Gombnyomás a Dashboardon).
|
||||
- **Action:** `data.translations` -> `static/locales/*.json`.
|
||||
- **Permission:** SuperAdmin ONLY.
|
||||
- **Permission:** SuperAdmin ONLY.
|
||||
|
||||
|
||||
## 5. Security & Audit Logging
|
||||
|
||||
A rendszer két szinten naplózza az eseményeket:
|
||||
|
||||
### 5.1 Operational Log (Üzemi Napló)
|
||||
* **Cél:** Hibakeresés, User Activity követés.
|
||||
* **Tartalom:** Jármű rögzítés, Adatjavítás, Keresés.
|
||||
* **Hozzáférés:** Moderátor szinttől felfelé.
|
||||
|
||||
### 5.2 Security Audit Log (Biztonsági Napló)
|
||||
* **Cél:** Visszaélések megelőzése, Jogosultságok védelme.
|
||||
* **Tartalom:** Rang emelés (Role Change), Kredit manuális jóváírása, VIP státusz adása, Admin belépés.
|
||||
* **Hozzáférés:** Csak Superadmin és Country Admin (Szigorított).
|
||||
|
||||
### 5.3 The "Four-Eyes" Principle (4-Szem Elv)
|
||||
Kritikus műveletek (pl. egy User `is_vip` státuszának kézi átállítása vagy `penalty_points` törlése) esetén a rendszer:
|
||||
1. Rögzíti a kérést a `security_audit_logs`-ban.
|
||||
2. A státusz "Pending" marad.
|
||||
3. A változás **csak akkor lép életbe**, ha egy MÁSIK Adminisztrátor jóváhagyja azt (`confirmed_by_id` kitöltése).
|
||||
4. Szuperadmin esetén a `is_critical` flag aktiválódik, és azonnali riasztás megy a többi adminnak.
|
||||
24
docs/V01_gemini/23_BRANCH_AND_LOCATION_SPEC.md
Normal file
24
docs/V01_gemini/23_BRANCH_AND_LOCATION_SPEC.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# 🏢 23_BRANCH_AND_LOCATION_SPEC (v1.0)
|
||||
|
||||
## 1. Telephely (Branch) Logika
|
||||
A rendszer alapelve, hogy a jogi entitás (Organization) és a fizikai helyszín (Branch) elválik egymástól.
|
||||
|
||||
### 1.1 Struktúra
|
||||
- **Organization:** Jogi egység (Adószám, név).
|
||||
- **Branch (Telephely):** Konkrét fizikai pont, ahol a szolgáltatás zajlik vagy ahol a flotta állomásozik.
|
||||
- **Main Branch:** Minden szervezetnek van legalább egy "Fő" telephelye (`is_main=True`).
|
||||
|
||||
### 1.2 Kapcsolatok
|
||||
- **Szerviz:** Az értékelések és a nyitvatartás a `Branch`-hez kötődik.
|
||||
- **Flotta:** A jármű hozzárendelés (`AssetAssignment`) opcionálisan tartalmaz egy `branch_id`-t, meghatározva a jármű fizikai helyét.
|
||||
|
||||
## 2. Részletes Címkezelés
|
||||
A címeket atomizált formában tároljuk a `data.branches` és `data.addresses` táblákban:
|
||||
- `postal_code`, `city`
|
||||
- `street_name`, `street_type` (utca, út, tér)
|
||||
- `house_number`, `stairwell`, `floor`, `door`
|
||||
- `hrsz` (Helyrajzi szám külterületi vagy speciális telkekhez)
|
||||
|
||||
## 3. Életút Követés (Dual Twin)
|
||||
- **Törlés:** A telephelyek "Soft Delete" (`is_deleted`) alá esnek.
|
||||
- **Áthelyezés:** Ha egy telephely megszűnik, a hozzárendelt járművek automatikusan visszaállnak a Szervezet "Main Branch" helyszínére.
|
||||
@@ -217,3 +217,360 @@
|
||||
{"__type":"$$EventMessageAudit","id":"ff14b040-c2d8-4f98-8d9a-68789d96ca9f","ts":"2026-02-14T09:13:10.495-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"eRVwBJfXw8ymc6aZ","workflowName":"01 - Dunakeszi Seed Hunter"}}
|
||||
{"__type":"$$EventMessageAudit","id":"ad2b88bc-5aea-4a57-bc0d-f75b70237e9f","ts":"2026-02-14T09:13:22.220-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"eRVwBJfXw8ymc6aZ","workflowName":"01 - Dunakeszi Seed Hunter"}}
|
||||
{"__type":"$$EventMessageAudit","id":"f439a7c2-7aec-4bc5-8ef4-2891aa75072a","ts":"2026-02-14T09:13:32.643-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"eRVwBJfXw8ymc6aZ","workflowName":"01 - Dunakeszi Seed Hunter"}}
|
||||
{"__type":"$$EventMessageAudit","id":"b03f51f4-38a5-4216-97fc-060228d357b3","ts":"2026-02-14T11:11:03.532-05:00","eventName":"n8n.audit.workflow.created","message":"n8n.audit.workflow.created","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"f7ee61b3-54e6-401b-aab5-81128d453f47","ts":"2026-02-14T11:15:31.558-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"f5d90ffb-677c-4278-9819-0168bf5abb56","ts":"2026-02-14T11:15:34.092-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"5f0b5c1d-2088-4f54-a925-e8760b0af90a","ts":"2026-02-14T11:15:34.851-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"21","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"d4b67302-8ed3-49b4-9dde-21f37bc60cf5","ts":"2026-02-14T11:15:34.851-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"21","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"f4480e67-7b51-4c8d-9088-b5a39d18875e","ts":"2026-02-14T11:15:34.852-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"21","nodeType":"n8n-nodes-base.manualTrigger","nodeName":"When clicking ‘Execute workflow’","nodeId":"d90cfc8e-4e86-4893-ae45-e57cf3cf1a98"}}
|
||||
{"__type":"$$EventMessageNode","id":"ae82527c-6e80-49a8-915c-2119ff1843f7","ts":"2026-02-14T11:15:34.853-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"21","nodeType":"n8n-nodes-base.manualTrigger","nodeName":"When clicking ‘Execute workflow’","nodeId":"d90cfc8e-4e86-4893-ae45-e57cf3cf1a98"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"eb367c68-079c-4ac7-a3c5-4404fce907f1","ts":"2026-02-14T11:15:34.855-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"21","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"e1136c57-8423-49ad-90b6-d19e35021ccb","ts":"2026-02-14T11:15:35.846-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"22","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"071583ee-734a-4cd4-9f6b-29b0d77f2eeb","ts":"2026-02-14T11:15:35.847-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"22","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"51e6cf75-0cf8-44ab-814e-695c6cb21a64","ts":"2026-02-14T11:15:35.847-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"22","nodeType":"n8n-nodes-base.manualTrigger","nodeName":"When clicking ‘Execute workflow’","nodeId":"d90cfc8e-4e86-4893-ae45-e57cf3cf1a98"}}
|
||||
{"__type":"$$EventMessageNode","id":"cb797990-a264-4619-b61b-e986af3afec5","ts":"2026-02-14T11:15:35.848-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"22","nodeType":"n8n-nodes-base.manualTrigger","nodeName":"When clicking ‘Execute workflow’","nodeId":"d90cfc8e-4e86-4893-ae45-e57cf3cf1a98"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"22876ee3-57dc-43a8-a942-16f16f6f41c0","ts":"2026-02-14T11:15:35.849-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"22","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"9836c88e-c2de-40bf-bccc-798adb53db35","ts":"2026-02-14T11:15:44.617-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"fd4fd0c9-743f-4d97-a12b-877662ec0e05","ts":"2026-02-14T11:16:02.910-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"3c46ffad-765e-4628-b363-a6871abca2a4","ts":"2026-02-14T11:16:09.335-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"636982ce-739a-427d-b156-3e4bc2df356f","ts":"2026-02-14T11:17:14.755-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"df7edb80-d61d-46c4-b957-0c36622b085b","ts":"2026-02-14T11:17:35.752-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"4351d203-e85a-4893-8017-c3fae8d65b6d","ts":"2026-02-14T11:18:13.197-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"751c7f6c-577d-47b1-8019-9e5c0edecf4d","ts":"2026-02-14T11:18:24.037-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"8d50c983-8b48-400d-99f5-7d953c11d3b7","ts":"2026-02-14T11:18:28.865-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"0f4b0ad4-afa7-4c20-b6e3-c638d5f7482a","ts":"2026-02-14T11:18:49.272-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"23","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"c93aa1a9-fc76-4d43-979b-471593317b4f","ts":"2026-02-14T11:18:49.273-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"23","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"8cb84cae-cae5-4eed-af29-a2f93948d4e3","ts":"2026-02-14T11:18:49.274-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"23","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"1ba901e3-a533-4170-ba71-69b06ce97ce1"}}
|
||||
{"__type":"$$EventMessageNode","id":"00c076b2-b34f-4726-b30d-07a6092da31e","ts":"2026-02-14T11:18:49.346-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"23","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"1ba901e3-a533-4170-ba71-69b06ce97ce1"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"3de894e1-07c3-4826-8044-244c2e5973c0","ts":"2026-02-14T11:18:49.348-05:00","eventName":"n8n.workflow.failed","message":"n8n.workflow.failed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"23","success":false,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","lastNodeExecuted":"HTTP Request","errorNodeType":"n8n-nodes-base.httpRequest","errorMessage":"Forbidden - perhaps check your credentials?"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"cc6b9419-63db-4a1f-8d9d-ad45d3ba889c","ts":"2026-02-14T11:19:50.235-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"24","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"71c8d27c-6120-4d9e-9e9c-34a0f323c4ad","ts":"2026-02-14T11:19:50.235-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"24","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"37203cad-1a6e-490a-8059-65b2241c4611","ts":"2026-02-14T11:19:50.236-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"24","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"1ba901e3-a533-4170-ba71-69b06ce97ce1"}}
|
||||
{"__type":"$$EventMessageNode","id":"8d36ece3-aeb5-4db4-bb2e-ea1f28cb371b","ts":"2026-02-14T11:19:50.278-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"24","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"1ba901e3-a533-4170-ba71-69b06ce97ce1"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"e73b3650-1367-4198-aa3b-4fc3d785fc7c","ts":"2026-02-14T11:19:50.280-05:00","eventName":"n8n.workflow.failed","message":"n8n.workflow.failed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"24","success":false,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","lastNodeExecuted":"HTTP Request","errorNodeType":"n8n-nodes-base.httpRequest","errorMessage":"Forbidden - perhaps check your credentials?"}}
|
||||
{"__type":"$$EventMessageAudit","id":"09a1987b-4a1c-4985-b3ca-98a6aa50576b","ts":"2026-02-14T11:21:31.809-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"c3e2d415-7933-4091-affa-9197e4ce6a6e","ts":"2026-02-14T11:21:41.829-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"84b18af9-32cd-43a7-b815-32bf0bfe72c6","ts":"2026-02-14T11:24:41.930-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"96b83cc9-4a78-43b4-8e8d-45949f3a62ec","ts":"2026-02-14T11:25:15.936-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"60d240e0-f9ef-4c05-b671-68436b2d9f81","ts":"2026-02-14T11:25:32.598-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"778d1495-3a54-490a-a126-5942f4ec03b7","ts":"2026-02-14T11:25:41.184-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"378803de-cb2c-4f30-bf13-da65d3f728f0","ts":"2026-02-14T11:25:44.477-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"6cff5779-6916-41b2-986f-7781b5410f2b","ts":"2026-02-14T11:25:49.355-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"d0eadcc3-7e3d-48b9-9c89-34b873c5a6df","ts":"2026-02-14T11:25:51.566-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"0bf6fe28-8624-4539-918a-e408d7901ab5","ts":"2026-02-14T11:25:55.564-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"c0caddc6-c61d-4966-b0a7-9936e414014c","ts":"2026-02-14T11:26:05.238-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"d17abd81-96cd-4f17-8c5e-0a3cf7a45aba","ts":"2026-02-14T11:26:06.904-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"853d2cf4-b6e0-4dd0-8677-dbf0adc2bb04","ts":"2026-02-14T11:26:12.924-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"d035437f-c1e2-4dc5-b7e2-de6d68a15e0f","ts":"2026-02-14T11:26:18.866-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"fd9be312-d7fe-4c8d-b0be-0a195406cff7","ts":"2026-02-14T11:26:20.628-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"ca9c208d-054b-4aff-ae11-14d6e7029136","ts":"2026-02-14T11:26:25.916-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"602190d4-f8d8-417c-9a17-1a72a8ba6941","ts":"2026-02-14T11:26:31.857-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"35d27eb7-44d1-4374-af6e-a35d45499000","ts":"2026-02-14T11:32:44.131-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"19b000a2-c46b-4286-809c-01f290ff0fd5","ts":"2026-02-14T11:32:49.816-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"9df0dd95-2cb1-439b-bbda-293eeb7204f6","ts":"2026-02-14T11:33:04.928-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"25","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"11bf7c33-35f8-4524-ab85-56d7f52631ef","ts":"2026-02-14T11:33:04.929-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"25","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"cad0e034-bde2-46f5-8485-34dbd6c33247","ts":"2026-02-14T11:33:04.930-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"25","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"1ba901e3-a533-4170-ba71-69b06ce97ce1"}}
|
||||
{"__type":"$$EventMessageNode","id":"014c55f3-8c80-435a-b30f-d818bf6569bd","ts":"2026-02-14T11:33:09.112-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"25","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"1ba901e3-a533-4170-ba71-69b06ce97ce1"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"3daf1134-6caa-4c70-af12-d99c0299c1c1","ts":"2026-02-14T11:33:09.116-05:00","eventName":"n8n.workflow.failed","message":"n8n.workflow.failed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"25","success":false,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","lastNodeExecuted":"HTTP Request","errorNodeType":"n8n-nodes-base.httpRequest","errorMessage":"Forbidden - perhaps check your credentials?"}}
|
||||
{"__type":"$$EventMessageAudit","id":"33a7ee00-3087-4727-b5bc-2275096be79d","ts":"2026-02-14T18:31:37.641-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"8819563e-6c91-4fb3-b829-61ebaaf07690","ts":"2026-02-14T18:31:39.572-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"eedce65c-74f0-4be6-a94b-e1669bf1e649","ts":"2026-02-14T18:35:27.417-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"05351c7d-25c2-41da-8369-3adccd8f9b99","ts":"2026-02-14T18:37:01.972-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"8f37e2cd-04ca-4197-a456-8146afe5a838","ts":"2026-02-14T18:37:17.638-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"d232bf5d-3820-474d-908a-930bd42b083d","ts":"2026-02-14T18:37:32.257-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"86bc1bad-9540-4a33-9f21-10aa62d20842","ts":"2026-02-14T18:37:34.508-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"690dd642-5b9a-4350-93de-d87a946c3550","ts":"2026-02-14T18:37:51.192-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"a6111065-dc46-40d0-8f85-e9dcf3a4434b","ts":"2026-02-14T18:37:53.849-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"0ee79dcc-e74e-4bc5-9a03-5cd12f267c97","ts":"2026-02-14T18:38:00.862-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"726d01ee-b17c-4f7a-806c-589aad5d28cc","ts":"2026-02-14T18:39:12.391-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"26","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"fe9907f3-c592-47f1-b386-0466e59e7837","ts":"2026-02-14T18:39:12.392-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"26","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"8c989f96-4e0b-4682-b52f-650652fb68b4","ts":"2026-02-14T18:39:12.393-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"26","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"19cb0235-1a2f-4905-95d8-4d37d8d8b608"}}
|
||||
{"__type":"$$EventMessageNode","id":"4c9cae69-038e-4de3-810b-25a3449182aa","ts":"2026-02-14T18:39:12.419-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"26","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"19cb0235-1a2f-4905-95d8-4d37d8d8b608"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"700c1cc8-24b1-4bc8-82fd-bcd3b0ebca29","ts":"2026-02-14T18:39:12.420-05:00","eventName":"n8n.workflow.failed","message":"n8n.workflow.failed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"26","success":false,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","lastNodeExecuted":"HTTP Request","errorNodeType":"n8n-nodes-base.httpRequest","errorMessage":"The resource you are requesting could not be found"}}
|
||||
{"__type":"$$EventMessageAudit","id":"48fb2e4b-ce51-4c8c-96c2-8fe9405eedaf","ts":"2026-02-14T18:39:38.937-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"0d11f1b7-12f1-40c4-a4ce-6def83cbe274","ts":"2026-02-14T18:39:39.949-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"27","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"56cabcab-f888-4bf7-8d33-d3376a68a137","ts":"2026-02-14T18:39:39.950-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"27","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"022b2038-a405-4185-bd66-801d8a49c545","ts":"2026-02-14T18:39:39.951-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"27","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"19cb0235-1a2f-4905-95d8-4d37d8d8b608"}}
|
||||
{"__type":"$$EventMessageNode","id":"f3ccf75b-c99b-427c-b33f-edbc888e98a8","ts":"2026-02-14T18:39:39.960-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"27","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"19cb0235-1a2f-4905-95d8-4d37d8d8b608"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"05dad2f5-cd61-4311-9501-bb591dd1c3da","ts":"2026-02-14T18:39:39.963-05:00","eventName":"n8n.workflow.failed","message":"n8n.workflow.failed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"27","success":false,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","lastNodeExecuted":"HTTP Request","errorNodeType":"n8n-nodes-base.httpRequest","errorMessage":"The service refused the connection - perhaps it is offline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"3d1e556e-e177-4fcb-b9b2-f4c8d38df811","ts":"2026-02-14T18:41:03.693-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"bc35223e-9e31-4c55-b0b7-32212efe9118","ts":"2026-02-14T18:41:32.089-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"ee22062b-3f3d-481e-88f7-4546bdaf752c","ts":"2026-02-14T18:42:16.619-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"28","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"dc0c5ab8-e603-497f-a7f9-809bb31f0497","ts":"2026-02-14T18:42:16.620-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"28","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"62fecc92-aa19-4ce6-a590-26ce53d3fec3","ts":"2026-02-14T18:42:16.620-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"28","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"19cb0235-1a2f-4905-95d8-4d37d8d8b608"}}
|
||||
{"__type":"$$EventMessageNode","id":"92b72036-ca0f-4e1a-8e7f-8b17dd1cd502","ts":"2026-02-14T18:42:16.667-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"28","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"19cb0235-1a2f-4905-95d8-4d37d8d8b608"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"44a1ae4d-dd2c-48ed-b145-97cbad0a54c9","ts":"2026-02-14T18:42:16.670-05:00","eventName":"n8n.workflow.failed","message":"n8n.workflow.failed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"28","success":false,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","lastNodeExecuted":"HTTP Request","errorNodeType":"n8n-nodes-base.httpRequest","errorMessage":"Bad request - please check your parameters"}}
|
||||
{"__type":"$$EventMessageAudit","id":"c5e0c681-b96c-40d7-a7cd-1a7b2f89e00a","ts":"2026-02-14T18:45:25.350-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"4cb9f7a8-8bb9-438c-99b2-84dad891a158","ts":"2026-02-14T18:45:39.048-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"0345ee18-4791-4f37-9d83-1779604729e9","ts":"2026-02-14T18:45:44.576-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"29","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"a5029189-2c02-48f1-851d-f769da0420bd","ts":"2026-02-14T18:45:44.576-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"29","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"ee3bccb3-c669-4279-b6c1-036d4a79fa22","ts":"2026-02-14T18:45:44.577-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"29","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"19cb0235-1a2f-4905-95d8-4d37d8d8b608"}}
|
||||
{"__type":"$$EventMessageNode","id":"6cedb5ca-ec3e-4503-be0b-f683cf7f18c0","ts":"2026-02-14T18:45:44.599-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"29","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"19cb0235-1a2f-4905-95d8-4d37d8d8b608"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"d03f1e6b-40c0-4417-adee-46a01468d44b","ts":"2026-02-14T18:45:44.602-05:00","eventName":"n8n.workflow.failed","message":"n8n.workflow.failed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"29","success":false,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","lastNodeExecuted":"HTTP Request","errorNodeType":"n8n-nodes-base.httpRequest","errorMessage":"Bad request - please check your parameters"}}
|
||||
{"__type":"$$EventMessageAudit","id":"132a094e-3e46-4648-b1e0-c2d7757d5b53","ts":"2026-02-14T18:46:36.631-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"80bf7b06-b1e4-4731-ae95-f72bca141026","ts":"2026-02-14T18:46:40.347-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"1d7a157d-8f2b-4e8d-be32-f89c0fe01bc4","ts":"2026-02-14T18:46:41.323-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"30","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"c8520031-08d3-480c-8b21-dcfaacd312ef","ts":"2026-02-14T18:46:41.324-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"30","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"8e5b741b-8f14-42a7-b2a9-e9d441de62b7","ts":"2026-02-14T18:46:41.324-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"30","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"19cb0235-1a2f-4905-95d8-4d37d8d8b608"}}
|
||||
{"__type":"$$EventMessageNode","id":"7413114e-ffd4-45c4-8b05-4deb0284d3b0","ts":"2026-02-14T18:47:12.089-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"30","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"19cb0235-1a2f-4905-95d8-4d37d8d8b608"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"e6ce8afe-f67a-493e-823e-181928e1dec7","ts":"2026-02-14T18:47:12.092-05:00","eventName":"n8n.workflow.failed","message":"n8n.workflow.failed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"30","success":false,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","lastNodeExecuted":"HTTP Request","errorNodeType":"n8n-nodes-base.httpRequest","errorMessage":"Bad request - please check your parameters"}}
|
||||
{"__type":"$$EventMessageAudit","id":"81ea53d3-7bde-4fae-9deb-ea824da28727","ts":"2026-02-14T19:00:08.203-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"c00c2b31-eb02-42c2-a3a8-ba3682d3d038","ts":"2026-02-14T19:00:12.442-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"31","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"8f8adc88-e7d8-4dd8-bb5c-fa5ec1361ca8","ts":"2026-02-14T19:00:12.443-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"31","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"1face4d0-da30-495a-8fce-2173e016d75e","ts":"2026-02-14T19:00:12.443-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"31","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"19cb0235-1a2f-4905-95d8-4d37d8d8b608"}}
|
||||
{"__type":"$$EventMessageNode","id":"1a586fff-2c6a-4b18-b31b-50fc4096f956","ts":"2026-02-14T19:00:12.467-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"31","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"19cb0235-1a2f-4905-95d8-4d37d8d8b608"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"37e758a8-9542-4c42-8b86-b51843ffb4a9","ts":"2026-02-14T19:00:12.472-05:00","eventName":"n8n.workflow.failed","message":"n8n.workflow.failed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"31","success":false,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","lastNodeExecuted":"HTTP Request","errorNodeType":"n8n-nodes-base.httpRequest","errorMessage":"Bad request - please check your parameters"}}
|
||||
{"__type":"$$EventMessageAudit","id":"57e9abc4-6b9c-475c-9554-8b96571f0bda","ts":"2026-02-14T19:00:54.321-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"3e9823e8-e4bd-499e-953d-40291aa6970d","ts":"2026-02-14T19:04:46.227-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"32","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"c335fbc1-bdfc-4348-9d0b-18872ce098aa","ts":"2026-02-14T19:04:46.227-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"32","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"ec2439a8-c627-409d-908c-c3b75ca5769b","ts":"2026-02-14T19:04:46.228-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"32","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"19cb0235-1a2f-4905-95d8-4d37d8d8b608"}}
|
||||
{"__type":"$$EventMessageNode","id":"5a1d7ac2-f960-4b0d-b8c2-7335e2eb26f3","ts":"2026-02-14T19:04:46.248-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"32","nodeType":"n8n-nodes-base.httpRequest","nodeName":"HTTP Request","nodeId":"19cb0235-1a2f-4905-95d8-4d37d8d8b608"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"7cbf5ae3-5641-420d-883e-58d9768a3709","ts":"2026-02-14T19:04:46.250-05:00","eventName":"n8n.workflow.failed","message":"n8n.workflow.failed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"32","success":false,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","lastNodeExecuted":"HTTP Request","errorNodeType":"n8n-nodes-base.httpRequest","errorMessage":"Bad request - please check your parameters"}}
|
||||
{"__type":"$$EventMessageAudit","id":"858d8f5f-c0ef-4206-be14-14eea6bf26fc","ts":"2026-02-14T19:09:16.916-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"71fee88b-630f-4ee3-9b39-ac98364d4f2c","ts":"2026-02-14T19:11:45.977-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"f41df978-9b9b-4f61-ac3c-af2c9fa9e808","ts":"2026-02-14T19:12:50.462-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"4077f1a8-8a52-4d75-a202-ffc6e0683297","ts":"2026-02-14T19:13:19.708-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"28e3e612-7f33-4cf8-9ae3-72056b85ac34","ts":"2026-02-14T19:14:17.502-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"33","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"1e8f228c-645e-41ff-8f71-0f906b0ec95f","ts":"2026-02-14T19:14:17.502-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"33","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"4c8ec78d-f736-4ee3-9b6a-6be3544f3cb2","ts":"2026-02-14T19:14:17.503-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"33","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"cf12fd03-f52d-4321-a3e6-b838c2ad41b6","ts":"2026-02-14T19:14:17.511-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"ZNqhdM67","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"33"}}
|
||||
{"__type":"$$EventMessageRunner","id":"e8c5ed50-b8ef-4a47-944d-86a5db75dcc7","ts":"2026-02-14T19:14:17.603-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"ZNqhdM67","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"33"}}
|
||||
{"__type":"$$EventMessageNode","id":"05840ac7-b274-4fed-a04d-a10e4b3e4a27","ts":"2026-02-14T19:14:17.605-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"33","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"b5cf7974-f861-4daf-a7e1-3aaedeeac17e","ts":"2026-02-14T19:14:17.612-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"33","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"18ca4a3a-8b35-484e-bffe-e55c53bb3391","ts":"2026-02-14T19:15:45.719-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"14dc22a9-d0bf-452e-b158-f9142d3f8e5d","ts":"2026-02-14T19:16:54.698-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"9317dfb5-03fe-4654-9eab-1e09ddd81c48","ts":"2026-02-14T19:17:11.870-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"824bbd95-f082-4fd8-9543-64f98f707a60","ts":"2026-02-14T19:17:25.474-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"d960dd2d-c06e-416b-b742-d70f19ffb929","ts":"2026-02-14T19:17:34.346-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"20240e56-8ed7-4e08-834c-13f443d8c137","ts":"2026-02-14T19:17:39.405-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"34","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"2b62dfc4-6f48-48f5-9c12-2075b2e714d0","ts":"2026-02-14T19:17:39.406-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"34","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"34007a36-dea2-4170-a6eb-3bcef2f979a5","ts":"2026-02-14T19:17:39.407-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"34","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"8217a0b8-cd7d-456c-b942-50860bb04533","ts":"2026-02-14T19:17:39.411-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"GF0uPgG1","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"34"}}
|
||||
{"__type":"$$EventMessageRunner","id":"7095603d-0ad8-4414-a77e-1991b23a6d91","ts":"2026-02-14T19:17:39.469-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"GF0uPgG1","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"34"}}
|
||||
{"__type":"$$EventMessageNode","id":"96f789e4-9c32-4396-b4a5-d6def55bfae2","ts":"2026-02-14T19:17:39.469-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"34","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"2c5f98a7-9bc6-426b-a870-e63d6029fe32","ts":"2026-02-14T19:17:39.475-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"34","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"f030adfc-8822-45d6-852c-d8b95ed5edfa","ts":"2026-02-14T19:17:39.549-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"34","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"9c8b0ca9-454e-48cf-a58e-45f358d8b4c5","ts":"2026-02-14T19:17:39.550-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"34","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"8ddafa75-05e8-4bc2-966b-1f6c2a48d601","ts":"2026-02-14T19:19:25.577-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"c2b41941-44b2-4fd5-9b4a-242f14cd0328","ts":"2026-02-14T19:19:27.572-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"2c14d7c4-07c4-4519-89cc-347918f045a0","ts":"2026-02-14T19:20:30.609-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"6462c413-941d-4f47-894e-5e39b4e5ffc0","ts":"2026-02-14T19:20:42.613-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"d0af5296-0bdd-4001-9fca-ddd9d23b09c0","ts":"2026-02-14T19:20:56.942-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"35","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"1411cc3b-497d-4d1e-a1ac-7c0bf769873f","ts":"2026-02-14T19:20:56.943-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"35","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"fb7961de-f6c0-493f-9d9b-cb40add56730","ts":"2026-02-14T19:20:56.944-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"35","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"dd663b80-ab35-4fc1-ac97-bc5e91794176","ts":"2026-02-14T19:20:56.947-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"zOXMLRsd","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"35"}}
|
||||
{"__type":"$$EventMessageRunner","id":"14af5a9b-ef65-486a-8e59-6aad16018c57","ts":"2026-02-14T19:20:57.003-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"zOXMLRsd","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"35"}}
|
||||
{"__type":"$$EventMessageNode","id":"c0274d29-e2e5-43ec-93df-1716bb671133","ts":"2026-02-14T19:20:57.003-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"35","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"ffd8ab53-de72-4e04-a49d-6dc86efa6c32","ts":"2026-02-14T19:20:57.009-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"35","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"76584705-2a62-47f1-8860-26382d394eed","ts":"2026-02-14T19:20:57.064-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"35","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"b6fe000b-ee40-4986-b081-d330ec89eea2","ts":"2026-02-14T19:20:57.066-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"35","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"02fbcd73-91af-47c4-bf24-d8ece5be0e0c","ts":"2026-02-14T19:22:00.354-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"aea81adc-3814-4e67-8ca4-fc2ca6eb1751","ts":"2026-02-14T19:22:17.335-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"c3889e7a-0098-4e81-8c6f-2d3a0430768c","ts":"2026-02-14T19:22:17.576-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"36","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"16d955d5-bd1c-4318-bfc0-ca94c081800a","ts":"2026-02-14T19:22:17.577-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"36","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"223baff6-e2ea-495b-9d8a-66806bccab30","ts":"2026-02-14T19:22:17.578-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"36","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"3ee02e49-afae-4a67-b22a-aab021b64f7a","ts":"2026-02-14T19:22:17.580-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"lKGVrE-q","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"36"}}
|
||||
{"__type":"$$EventMessageRunner","id":"9d36ccfe-1b92-4264-97fe-01ffd55dd172","ts":"2026-02-14T19:22:17.632-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"lKGVrE-q","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"36"}}
|
||||
{"__type":"$$EventMessageNode","id":"7e476f2d-d016-4616-96c2-9f05ae34dca7","ts":"2026-02-14T19:22:17.633-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"36","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"746f54ad-201a-4c68-8761-e186f5bf095b","ts":"2026-02-14T19:22:17.639-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"36","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"57a1bcaf-7c62-436b-896e-649df6d099c0","ts":"2026-02-14T19:22:17.682-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"36","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"75bd4a30-d1df-4f3d-b669-d9f764cc39b0","ts":"2026-02-14T19:22:17.682-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"36","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"de283afc-35db-4db5-9a17-3c81f70f9793","ts":"2026-02-14T19:22:17.684-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"36","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"a8b51fa2-d381-4a34-95ba-b62b6ad8a5a2","ts":"2026-02-14T19:22:17.684-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"36","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"c298ce44-d72b-45a2-b674-71c23c2edf6f","ts":"2026-02-14T19:22:53.435-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"0a66e6ea-b1c1-48a5-9b79-94fc9eade352","ts":"2026-02-14T19:22:59.354-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"37","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"872f9421-3665-4b6e-be23-6803f948d715","ts":"2026-02-14T19:22:59.355-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"37","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"ee66f833-9eaf-4fea-918e-d30e4b5d26d1","ts":"2026-02-14T19:22:59.356-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"37","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"ed71f99e-5a3d-4679-a6aa-352264d752c7","ts":"2026-02-14T19:22:59.359-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"dPQ6-CQE","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"37"}}
|
||||
{"__type":"$$EventMessageRunner","id":"7f71a6c8-f100-4996-966a-ef400c96fef3","ts":"2026-02-14T19:22:59.406-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"dPQ6-CQE","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"37"}}
|
||||
{"__type":"$$EventMessageNode","id":"d0c65143-1052-4310-8ecd-88b6b377229e","ts":"2026-02-14T19:22:59.407-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"37","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"d066fbd9-057f-40bd-92bb-bc2e8b6d9e97","ts":"2026-02-14T19:22:59.411-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"37","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"b17788e8-6197-4274-8b08-cb74b389cc83","ts":"2026-02-14T19:22:59.450-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"37","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"6a1cb3c6-21ce-4314-82f7-9eb1866783ab","ts":"2026-02-14T19:22:59.451-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"37","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"9e62d0de-1cf9-4fce-b97c-04741fc20859","ts":"2026-02-14T19:22:59.451-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"37","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"0a01a889-d517-4346-8a04-66d69361c8d4","ts":"2026-02-14T19:22:59.452-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"37","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"93d4e103-9501-4d28-83a8-6637604a47bc","ts":"2026-02-14T19:23:08.053-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"f80dc75b-7aad-4e94-a4f8-348a879794d3","ts":"2026-02-14T19:23:08.245-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"38","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"c7d624ac-5f87-477d-8c68-77472231092f","ts":"2026-02-14T19:23:08.245-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"38","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"ddc3cc6b-5ad5-4ff4-a53b-7839eacd5c92","ts":"2026-02-14T19:23:08.246-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"38","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"78d8367c-6755-43ba-a28b-7657b0676dfe","ts":"2026-02-14T19:23:08.248-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"nukUxiSj","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"38"}}
|
||||
{"__type":"$$EventMessageRunner","id":"101bd4c0-be93-4e90-bd66-5b46eadfcdfd","ts":"2026-02-14T19:23:08.307-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"nukUxiSj","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"38"}}
|
||||
{"__type":"$$EventMessageNode","id":"8fa9896a-be5a-4678-840b-8497807c4a29","ts":"2026-02-14T19:23:08.307-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"38","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"51d745f0-9076-4e51-91c7-0c06032a34d7","ts":"2026-02-14T19:23:08.313-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"38","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"fe36bf49-98fa-45c0-992f-05f55e1d4394","ts":"2026-02-14T19:23:08.352-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"38","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"6441dc1f-d008-45f3-bcdc-9b1e808fd954","ts":"2026-02-14T19:23:08.353-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"38","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"295bd675-4a0d-4cb6-b2ad-0f6b0216950a","ts":"2026-02-14T19:23:08.354-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"38","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"7aafb097-3f6a-43cf-a6a8-9d51aeb26979","ts":"2026-02-14T19:23:08.355-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"38","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"24ba491b-e346-47a6-9d95-7584a5133d26","ts":"2026-02-14T19:23:15.007-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"3f0f6cde-1c82-46a1-bcef-57827a0a764c","ts":"2026-02-14T19:23:17.758-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"cdbc3c61-ecd8-43de-8b72-8ad51da22fb3","ts":"2026-02-14T19:23:21.919-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"39","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"78440af1-c937-4f0b-bd2b-5737883a2899","ts":"2026-02-14T19:23:21.920-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"39","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"33705212-ff58-483a-b273-363c7e4bffca","ts":"2026-02-14T19:23:21.921-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"39","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"ae6e7c4b-53a8-4e6e-8825-2c50b8e848aa","ts":"2026-02-14T19:23:21.924-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"hb5XzItq","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"39"}}
|
||||
{"__type":"$$EventMessageRunner","id":"4ebc8d27-2279-4264-a3c6-0059c249b7c8","ts":"2026-02-14T19:23:21.975-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"hb5XzItq","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"39"}}
|
||||
{"__type":"$$EventMessageNode","id":"7174c264-5019-437d-9654-5505e01cedf8","ts":"2026-02-14T19:23:21.976-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"39","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"49a0cad3-33ac-4b3f-811c-58df24916542","ts":"2026-02-14T19:23:21.981-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"39","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"bd42d021-b453-47b6-b924-b6d8dca4d244","ts":"2026-02-14T19:23:22.019-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"39","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"a252efd0-43e5-4fb3-876d-9a30403616e5","ts":"2026-02-14T19:23:22.020-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"39","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"960b612a-cb9b-4eca-a247-74f02aa72484","ts":"2026-02-14T19:23:22.020-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"39","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"b2e19719-fae3-4881-a8c3-3dc6f90078b0","ts":"2026-02-14T19:23:22.022-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"39","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"815de0f4-64c0-4e14-93b9-70937acec49c","ts":"2026-02-14T19:23:22.370-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"bc2956b5-b275-49f4-96ee-40443957a926","ts":"2026-02-14T19:24:00.518-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"8bcaf347-33b2-427e-ab99-c6b88df882ae","ts":"2026-02-14T19:24:48.923-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"355d6391-1902-499f-9b7a-7382044a7b34","ts":"2026-02-14T19:24:50.810-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"ddab95bf-fa53-46e2-8434-7c6f92e4b86d","ts":"2026-02-14T19:25:01.433-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"a8fb95f7-7c63-4d6f-a327-a83d94fad5a1","ts":"2026-02-14T19:25:01.743-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"40","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"cbbe81bf-5796-4243-8ace-16bfbfd07e23","ts":"2026-02-14T19:25:01.744-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"40","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"517e33a7-ce32-4226-847d-79db0ba8783b","ts":"2026-02-14T19:25:01.745-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"40","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"4795ea85-c9eb-4d95-9327-793a0a5c98fd","ts":"2026-02-14T19:25:01.748-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"A0etMNPy","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"40"}}
|
||||
{"__type":"$$EventMessageRunner","id":"3e9a11aa-c2af-4bf9-ab06-4a05d03e83f8","ts":"2026-02-14T19:25:01.800-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"A0etMNPy","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"40"}}
|
||||
{"__type":"$$EventMessageNode","id":"f70d0374-b06d-4214-8cc1-d68ca5962d63","ts":"2026-02-14T19:25:01.801-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"40","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"492d70d1-2b77-485e-be2c-02564aefaefa","ts":"2026-02-14T19:25:01.806-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"40","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"bc845d1f-0525-4138-93f3-3107dc7ba8d5","ts":"2026-02-14T19:25:01.846-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"40","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"86b024cf-0fd2-4eb3-9749-41064fffb394","ts":"2026-02-14T19:25:01.847-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"40","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"66d33457-7859-4035-aff5-6d75c43cfb03","ts":"2026-02-14T19:25:06.406-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"d86357d8-bc0a-49fd-bdf7-0ca0c2bd2d85","ts":"2026-02-14T19:25:08.886-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"41","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"29a9992a-4b7d-47a6-9af9-1c5c68b16f8d","ts":"2026-02-14T19:25:08.887-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"41","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"3255d0e6-f1d6-485f-99ef-85f4fb01b5cf","ts":"2026-02-14T19:25:08.888-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"41","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"e7ff66f4-5f6f-4335-8dee-c07aacbce539","ts":"2026-02-14T19:25:08.892-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"eyClpGUr","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"41"}}
|
||||
{"__type":"$$EventMessageRunner","id":"e26731d5-f2b9-4640-bc63-e0974e02aa0d","ts":"2026-02-14T19:25:08.937-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"eyClpGUr","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"41"}}
|
||||
{"__type":"$$EventMessageNode","id":"d0718e41-edf4-411c-a511-c64e4255c44a","ts":"2026-02-14T19:25:08.938-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"41","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"55e6a449-88fb-4978-a5be-0665091351ce","ts":"2026-02-14T19:25:08.944-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"41","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"9d25a223-38c8-49dd-85c6-191575090b70","ts":"2026-02-14T19:25:08.973-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"41","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"dc87a504-86a9-4c3a-992b-f193d9a9e38e","ts":"2026-02-14T19:25:08.974-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"41","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"4a7f02a5-7dc9-4909-8825-4b569d79ac34","ts":"2026-02-14T19:25:08.974-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"41","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"dd28111a-ae5a-43cd-a94e-4baa5a1160af","ts":"2026-02-14T19:25:08.975-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"41","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"1c72db37-7cdc-4ed3-8aca-9cd932a99f6f","ts":"2026-02-14T19:27:05.491-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"3b591a4a-3c3d-4e01-8663-bff7cf36db57","ts":"2026-02-14T19:27:39.078-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"af76b173-b732-4ef8-9daa-7d02a275df32","ts":"2026-02-14T19:27:43.308-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"42","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"8bd55b0d-fcf0-4d2f-b977-a03e4fd1e650","ts":"2026-02-14T19:27:43.309-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"42","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"b42a4247-2b3d-4f42-93b1-b8641f0eb5e4","ts":"2026-02-14T19:27:43.310-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"42","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"ac38e18c-05f3-4a1e-918a-c5417558553b","ts":"2026-02-14T19:27:43.313-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"ptZotiS7","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"42"}}
|
||||
{"__type":"$$EventMessageRunner","id":"2523767d-d19a-486c-9f6a-2f9ccd278e1f","ts":"2026-02-14T19:27:43.363-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"ptZotiS7","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"42"}}
|
||||
{"__type":"$$EventMessageNode","id":"a09af45a-6cc7-4477-b576-286e0738f59a","ts":"2026-02-14T19:27:43.364-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"42","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"0b73059a-5838-4698-9683-888f8a8417e6","ts":"2026-02-14T19:27:43.370-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"42","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"20b1f59d-cf15-4706-af9f-dd80d5be1923","ts":"2026-02-14T19:27:43.405-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"42","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"0caef885-dfb0-4e22-8c5f-cbc79cb66fdd","ts":"2026-02-14T19:27:43.406-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"42","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"b76576c7-c6c7-49aa-abf1-c67c76838a55","ts":"2026-02-14T19:27:43.407-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"42","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"4ac9682b-35d1-490f-a84d-0588dbcb5deb","ts":"2026-02-14T19:27:43.407-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"42","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageRunner","id":"f884bd2c-116d-478d-b24b-856cfae01b8e","ts":"2026-02-14T19:27:43.408-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"mjnoQD3U","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"42"}}
|
||||
{"__type":"$$EventMessageNode","id":"0472b27e-f7eb-42f9-9736-07f137f9b78e","ts":"2026-02-14T19:27:43.435-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"42","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"ea286ebe-73ae-40f0-9918-9faca88f9edb","ts":"2026-02-14T19:27:43.437-05:00","eventName":"n8n.workflow.failed","message":"n8n.workflow.failed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"42","success":false,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","lastNodeExecuted":"Code in JavaScript1","errorMessage":"item is not defined [line 2]"}}
|
||||
{"__type":"$$EventMessageAudit","id":"f1bcc4e2-e43b-46a7-95fd-7ff1cfcaeda8","ts":"2026-02-14T19:29:07.457-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"4db656ec-fc9e-4836-b54d-faa872e4332d","ts":"2026-02-14T19:29:07.935-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"43","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"d16ac747-5f76-4bfd-85dd-e68fe25bf073","ts":"2026-02-14T19:29:07.935-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"43","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"d7d26429-e64a-46c7-a489-be21816fb13a","ts":"2026-02-14T19:29:07.937-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"43","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"c9100d04-1fe2-4d2b-a35b-ee37cbf65102","ts":"2026-02-14T19:29:07.939-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"u9QPBtvo","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"43"}}
|
||||
{"__type":"$$EventMessageRunner","id":"0110dd92-0307-406a-b131-42b34386ff32","ts":"2026-02-14T19:29:07.995-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"u9QPBtvo","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"43"}}
|
||||
{"__type":"$$EventMessageNode","id":"d4050257-81bb-41aa-8f6f-193473bad858","ts":"2026-02-14T19:29:07.995-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"43","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"68151441-eb01-4911-8efe-c1f9015d3ff1","ts":"2026-02-14T19:29:08.001-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"43","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"5391c200-4cd3-4997-a6a7-96897715f1c2","ts":"2026-02-14T19:29:08.040-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"43","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"03f20266-20fd-4601-858b-ea03a9c07ab8","ts":"2026-02-14T19:29:08.041-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"43","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"244a5637-818e-4890-8c2f-df0f52da9cb7","ts":"2026-02-14T19:29:08.042-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"43","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"6fc2d269-9365-4a9f-9de7-cb37b1493743","ts":"2026-02-14T19:29:08.043-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"43","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageRunner","id":"ce24de19-85ab-49ff-8c43-9ede9dce7c05","ts":"2026-02-14T19:29:08.044-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"ePHzT-N3","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"43"}}
|
||||
{"__type":"$$EventMessageRunner","id":"9e289a7a-e4a5-43de-86e9-5efeb195592f","ts":"2026-02-14T19:29:08.054-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"ePHzT-N3","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"43"}}
|
||||
{"__type":"$$EventMessageNode","id":"bc519240-c055-4de1-9225-de3717459e35","ts":"2026-02-14T19:29:08.055-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"43","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"d491c9e8-d7ac-4691-9db3-a84359f9add5","ts":"2026-02-14T19:29:08.056-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"43","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"947ab9ed-5655-4601-9fe0-4c61fa89e228","ts":"2026-02-14T19:30:00.692-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"44","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"ed9274ba-ce85-4fa0-8c20-39771ec404df","ts":"2026-02-14T19:30:00.692-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"44","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"88d8c2dc-99b8-43f3-b35a-a18febdba092","ts":"2026-02-14T19:30:00.693-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"44","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"478886b2-0275-4641-9561-1b72fb8280a3","ts":"2026-02-14T19:30:00.695-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"aNOkY1kM","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"44"}}
|
||||
{"__type":"$$EventMessageRunner","id":"e6cd758b-db0c-4f5e-bfca-a5bec18b6bbc","ts":"2026-02-14T19:30:00.746-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"aNOkY1kM","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"44"}}
|
||||
{"__type":"$$EventMessageNode","id":"70f63f0c-e91a-469a-8e8f-dd96c1ae1170","ts":"2026-02-14T19:30:00.747-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"44","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"524881cc-7296-4468-a9f6-c2353a41a324","ts":"2026-02-14T19:30:00.753-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"44","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"640bef7b-2269-40d9-a273-5966a27284fd","ts":"2026-02-14T19:30:00.786-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"44","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"a4f6cf77-9d64-4be5-ab35-c2249c57edc5","ts":"2026-02-14T19:30:00.787-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"44","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"bb5e322b-32a4-44ea-853c-fb0ba443c14d","ts":"2026-02-14T19:30:00.787-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"44","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"524c81ea-91d3-4a0f-9c74-88e36e7d951c","ts":"2026-02-14T19:30:00.788-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"44","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageRunner","id":"e580273a-eccc-4216-a414-7d28bdf9706e","ts":"2026-02-14T19:30:00.789-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"ZU1z_J3D","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"44"}}
|
||||
{"__type":"$$EventMessageRunner","id":"a84db632-bf60-4329-909a-bc4b8d933813","ts":"2026-02-14T19:30:00.806-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"ZU1z_J3D","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"44"}}
|
||||
{"__type":"$$EventMessageNode","id":"f981aed6-f748-43b5-87cd-161795645db7","ts":"2026-02-14T19:30:00.806-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"44","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"53b8d2bb-1fb2-47d7-8f24-256da88a2f03","ts":"2026-02-14T19:30:00.807-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"44","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"8f72b6cf-2577-449a-a839-273a62670c50","ts":"2026-02-14T19:31:28.463-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"45","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"da087b62-593f-4b12-bff1-20016766ec68","ts":"2026-02-14T19:31:28.464-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"45","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"b3c44f86-923b-4b3d-97f7-59f5c94355c9","ts":"2026-02-14T19:31:28.465-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"45","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"c24d54e0-7cb7-4446-ba2f-48c00edf4413","ts":"2026-02-14T19:31:28.467-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"k-76NVt4","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"45"}}
|
||||
{"__type":"$$EventMessageRunner","id":"d9ec34cd-b0ff-4faf-a2eb-830ec07ff68b","ts":"2026-02-14T19:31:28.514-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"k-76NVt4","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"45"}}
|
||||
{"__type":"$$EventMessageNode","id":"ae7fa026-e449-4377-ae1a-5f7c58bc428b","ts":"2026-02-14T19:31:28.515-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"45","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"a85b7b11-7b44-407c-a4ef-51f55ade6abc","ts":"2026-02-14T19:31:28.521-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"45","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"8f6a0d31-1b13-44b2-851c-c0948c7b5fd8","ts":"2026-02-14T19:31:28.557-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"45","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"68c1599a-a9f6-4700-9c01-a0123f90f922","ts":"2026-02-14T19:31:28.558-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"45","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"9a060c42-228f-4ef2-8f8d-abefc352e501","ts":"2026-02-14T19:31:28.561-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"45","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"d5787cda-0c96-426e-900a-685b7ec5ad08","ts":"2026-02-14T19:31:28.561-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"45","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageRunner","id":"7133b1a0-1c8b-4e2b-b92e-3c0dca5ee586","ts":"2026-02-14T19:31:28.562-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"vy40OpXM","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"45"}}
|
||||
{"__type":"$$EventMessageRunner","id":"6c1ff876-18df-4fdd-81b4-e7a8a6c4e08b","ts":"2026-02-14T19:31:28.578-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"vy40OpXM","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"45"}}
|
||||
{"__type":"$$EventMessageNode","id":"8a50d35f-d1d0-41e1-8b23-9d14dd488218","ts":"2026-02-14T19:31:28.578-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"45","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"665a45ac-57d4-4402-8874-bf65416cbb6c","ts":"2026-02-14T19:31:28.579-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"45","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"29071081-ba9a-4bc5-88d1-3a90a7e9334b","ts":"2026-02-14T19:31:29.212-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"646a23a2-cef3-4057-b8a4-8048575660a0","ts":"2026-02-14T19:35:08.748-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"9d179d52-c0c4-43f3-a5be-37221ae0f091","ts":"2026-02-14T19:35:08.898-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"46","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"ff977fef-b6f1-4319-8063-ede1431c90ef","ts":"2026-02-14T19:35:08.899-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"46","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"34c0ff62-c17c-49e7-8b2c-d68fcc622101","ts":"2026-02-14T19:35:08.900-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"46","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"e94f9203-fee5-4aaf-a5a0-00167cdb095e","ts":"2026-02-14T19:35:08.903-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"i4zWqeIN","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"46"}}
|
||||
{"__type":"$$EventMessageRunner","id":"bb0e2e99-3498-4ed6-b949-8cd9f09575b1","ts":"2026-02-14T19:35:08.953-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"i4zWqeIN","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"46"}}
|
||||
{"__type":"$$EventMessageNode","id":"1d693c3c-b973-443a-9612-e34fe2c7615f","ts":"2026-02-14T19:35:08.953-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"46","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"98000f5a-581c-4fba-8f12-1ab3fef78492","ts":"2026-02-14T19:35:08.958-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"46","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"e8d72597-307e-4857-b2f1-231489e1be5d","ts":"2026-02-14T19:35:08.995-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"46","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"78b15d82-830c-4cc6-8dae-75fec96ae7f5","ts":"2026-02-14T19:35:08.996-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"46","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"456217e2-847b-45d7-8376-988077cfef65","ts":"2026-02-14T19:35:08.996-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"46","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"5249826b-5e54-499b-87ef-99d9b44ef6f0","ts":"2026-02-14T19:35:08.997-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"46","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageRunner","id":"73b3b670-6b34-4e63-980c-d5217c849b0e","ts":"2026-02-14T19:35:09.002-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"4qb7CrXF","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"46"}}
|
||||
{"__type":"$$EventMessageRunner","id":"90e68362-6785-4de1-b9f4-b66c4fa696d3","ts":"2026-02-14T19:35:09.077-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"4qb7CrXF","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"46"}}
|
||||
{"__type":"$$EventMessageNode","id":"4d21f751-b74f-415f-ae9e-78df1bc1ebac","ts":"2026-02-14T19:35:09.078-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"46","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"b44613b4-2cfa-4a2b-b974-40b920cc03bd","ts":"2026-02-14T19:35:09.082-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"46","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"126cc823-d958-4119-bd94-d334f651f183","ts":"2026-02-14T19:36:20.863-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"671ef520-5053-40ed-9455-a13d22c952f4","ts":"2026-02-14T19:36:25.669-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"226571d0-a943-4024-8a77-bb94d66faadc","ts":"2026-02-14T19:37:08.386-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"cdb9579c-4cd0-4467-9730-7aaa67423e61","ts":"2026-02-14T19:37:14.414-05:00","eventName":"n8n.audit.workflow.updated","message":"n8n.audit.workflow.updated","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"97f284ca-74d6-41da-b193-3f30c5a64dfe","ts":"2026-02-14T19:37:48.390-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"47","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"00288d57-3c5c-4d87-91ab-91804fb858df","ts":"2026-02-14T19:37:48.390-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"47","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"cdf82349-62ea-44d5-8af7-3855c9994bcc","ts":"2026-02-14T19:37:48.391-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"47","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"be26c409-bb18-41c6-8881-766451a6ec53","ts":"2026-02-14T19:37:48.393-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"O1361oJS","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"47"}}
|
||||
{"__type":"$$EventMessageRunner","id":"ac5cd0c6-9d51-4241-9e2f-c2d12bf31128","ts":"2026-02-14T19:37:48.442-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"O1361oJS","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"47"}}
|
||||
{"__type":"$$EventMessageNode","id":"366c37c1-ac1d-4110-91ac-9389bee3ebe0","ts":"2026-02-14T19:37:48.442-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"47","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"1c37ed7f-0118-487f-a1f6-3ce7d6ce1ca1","ts":"2026-02-14T19:37:48.448-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"47","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"80a251da-f2f8-4879-9e51-4f392a9bc73e","ts":"2026-02-14T19:37:48.486-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"47","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"268c771f-39a6-4c2c-bbeb-20ba62b66a63","ts":"2026-02-14T19:37:48.487-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"47","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"3e2fd2a5-bb51-40bb-8c2c-4b5d82f18a31","ts":"2026-02-14T19:37:48.488-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"47","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"7acb6106-223d-4c36-8ec4-833e60dd9769","ts":"2026-02-14T19:37:48.488-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"47","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageRunner","id":"bc2caefb-fb5c-4700-81b3-e1e7bab48c41","ts":"2026-02-14T19:37:48.489-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"G_oanKfN","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"47"}}
|
||||
{"__type":"$$EventMessageRunner","id":"8c74ab0b-78af-4d35-b5cd-2282d1aa3874","ts":"2026-02-14T19:37:48.558-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"G_oanKfN","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"47"}}
|
||||
{"__type":"$$EventMessageNode","id":"354bec36-df6f-4a8d-a62a-eea1f62e0e5b","ts":"2026-02-14T19:37:48.559-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"47","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageNode","id":"b87c3eda-ac7c-48a9-8247-fadc1230a458","ts":"2026-02-14T19:37:48.561-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"47","nodeType":"n8n-nodes-base.postgres","nodeName":"Execute a SQL query","nodeId":"2d92f41f-baea-47ac-9340-54b40ad343a6"}}
|
||||
{"__type":"$$EventMessageNode","id":"02b81ec5-8027-4a65-bdd4-18750dc8a1cc","ts":"2026-02-14T19:37:48.684-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"47","nodeType":"n8n-nodes-base.postgres","nodeName":"Execute a SQL query","nodeId":"2d92f41f-baea-47ac-9340-54b40ad343a6"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"990d53ac-8cc6-48b8-b2b7-5ce0da736501","ts":"2026-02-14T19:37:48.686-05:00","eventName":"n8n.workflow.failed","message":"n8n.workflow.failed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"47","success":false,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","lastNodeExecuted":"Execute a SQL query","errorNodeType":"n8n-nodes-base.postgres","errorMessage":"permission denied for table catalog_discovery"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"f93ba421-f604-448a-ad1c-e79758e92b86","ts":"2026-02-14T19:40:00.381-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"48","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"3d4cb2a2-8983-4dc3-86de-5371ff056c42","ts":"2026-02-14T19:40:00.381-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"48","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"043ae25e-7d8d-4e68-8ff6-8995dd1c2671","ts":"2026-02-14T19:40:00.382-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"48","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"c656c676-2121-4cb4-bf96-eb6e5d8f79b1","ts":"2026-02-14T19:40:00.384-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"hv6uWpW3","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"48"}}
|
||||
{"__type":"$$EventMessageRunner","id":"675a5d55-8a72-4b2f-9bff-2e19f96222e5","ts":"2026-02-14T19:40:00.428-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"hv6uWpW3","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"48"}}
|
||||
{"__type":"$$EventMessageNode","id":"01a9cf62-4fa1-43ad-8186-91e2a962c6e8","ts":"2026-02-14T19:40:00.428-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"48","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"df9e7132-c40a-4fa9-9347-5a3c0fa09eb3","ts":"2026-02-14T19:40:00.434-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"48","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"5fce15d1-ba5e-4f2b-b3b0-09ed241372af","ts":"2026-02-14T19:40:00.470-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"48","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"75edd6f4-6424-4201-ac21-44d4512078f2","ts":"2026-02-14T19:40:00.470-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"48","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"fc5b52c4-03e1-436d-a384-fe37b3dec44b","ts":"2026-02-14T19:40:00.472-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"48","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"eda6d295-d4c4-457a-a317-1c375549433f","ts":"2026-02-14T19:40:00.473-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"48","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageRunner","id":"d01c4667-a4af-4a29-a7c1-08ebcced3313","ts":"2026-02-14T19:40:00.474-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"xhOSvWvS","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"48"}}
|
||||
{"__type":"$$EventMessageRunner","id":"a2e5c94f-caec-4f3d-abfa-6377cad3cad9","ts":"2026-02-14T19:40:00.531-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"xhOSvWvS","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"48"}}
|
||||
{"__type":"$$EventMessageNode","id":"10b60953-0422-49db-b82a-c6a3ef2dd452","ts":"2026-02-14T19:40:00.532-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"48","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageNode","id":"e773e4cb-58ef-428e-b1ae-98c641726fbc","ts":"2026-02-14T19:40:00.534-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"48","nodeType":"n8n-nodes-base.postgres","nodeName":"Execute a SQL query","nodeId":"2d92f41f-baea-47ac-9340-54b40ad343a6"}}
|
||||
{"__type":"$$EventMessageNode","id":"7692b2bf-811f-4811-9a8f-7e7cd57d758f","ts":"2026-02-14T19:40:00.664-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"48","nodeType":"n8n-nodes-base.postgres","nodeName":"Execute a SQL query","nodeId":"2d92f41f-baea-47ac-9340-54b40ad343a6"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"60152d8b-2d17-4695-a31f-b1ed659afc5a","ts":"2026-02-14T19:40:00.668-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"48","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"14339d78-0184-45ee-b954-bee60af83d19","ts":"2026-02-14T19:40:57.346-05:00","eventName":"n8n.workflow.started","message":"n8n.workflow.started","payload":{"executionId":"49","workflowId":"g3yuktNVnNC6OqUt","isManual":false,"workflowName":"Market Discovery Pipeline"}}
|
||||
{"__type":"$$EventMessageAudit","id":"39ec9840-29c1-4d41-ab82-c81aea3c9c82","ts":"2026-02-14T19:40:57.346-05:00","eventName":"n8n.audit.workflow.executed","message":"n8n.audit.workflow.executed","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","_email":"kincses@gmail.com","_firstName":"Zsolt","_lastName":"Gyongyossy","globalRole":"global:owner","workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"49","source":"user-manual"}}
|
||||
{"__type":"$$EventMessageNode","id":"2c91cee5-7733-473a-9b33-063bec8a8cf4","ts":"2026-02-14T19:40:57.347-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"49","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageRunner","id":"733dcdfb-949b-4dd5-b11b-b8760572927e","ts":"2026-02-14T19:40:57.349-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"zNrKb4XJ","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"49"}}
|
||||
{"__type":"$$EventMessageRunner","id":"176fb88d-c371-4e7b-b803-39726430732e","ts":"2026-02-14T19:40:57.396-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"zNrKb4XJ","nodeId":"396b714c-a809-4623-974c-06173c445c64","workflowId":"g3yuktNVnNC6OqUt","executionId":"49"}}
|
||||
{"__type":"$$EventMessageNode","id":"507318b3-d7b9-486f-becb-c572442d3544","ts":"2026-02-14T19:40:57.396-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"49","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript","nodeId":"396b714c-a809-4623-974c-06173c445c64"}}
|
||||
{"__type":"$$EventMessageNode","id":"06df90a8-dc85-47e6-a2d9-7cdb5601f8db","ts":"2026-02-14T19:40:57.403-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"49","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"51f1cfae-4773-4851-91f5-22b97acc84cb","ts":"2026-02-14T19:40:57.440-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"49","nodeType":"n8n-nodes-base.html","nodeName":"HTML","nodeId":"12a5aa30-9500-4808-9d81-83682ba1a990"}}
|
||||
{"__type":"$$EventMessageNode","id":"106ad46e-7d82-45f6-bfec-56015e099336","ts":"2026-02-14T19:40:57.441-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"49","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"9ae3bf81-ce6f-4f30-b141-84a081a6efa8","ts":"2026-02-14T19:40:57.441-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"49","nodeType":"n8n-nodes-base.splitOut","nodeName":"Split Out","nodeId":"8e0871e2-af94-4a6d-9b44-76e732b51a15"}}
|
||||
{"__type":"$$EventMessageNode","id":"2ee88d59-be92-4297-91be-d1f32328c31f","ts":"2026-02-14T19:40:57.442-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"49","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageRunner","id":"d19926bc-9bd6-4402-a8f2-050ed54b099b","ts":"2026-02-14T19:40:57.443-05:00","eventName":"n8n.runner.task.requested","message":"n8n.runner.task.requested","payload":{"taskId":"5wxIWF7i","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"49"}}
|
||||
{"__type":"$$EventMessageRunner","id":"6d21e237-e8d1-4d70-85c3-bae5f25dc585","ts":"2026-02-14T19:40:57.512-05:00","eventName":"n8n.runner.response.received","message":"n8n.runner.response.received","payload":{"taskId":"5wxIWF7i","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408","workflowId":"g3yuktNVnNC6OqUt","executionId":"49"}}
|
||||
{"__type":"$$EventMessageNode","id":"f1863211-22d8-4d12-9a71-eca6fcd55804","ts":"2026-02-14T19:40:57.513-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"49","nodeType":"n8n-nodes-base.code","nodeName":"Code in JavaScript1","nodeId":"78726a29-919c-451d-a4a2-e9a76aa46408"}}
|
||||
{"__type":"$$EventMessageNode","id":"4dca0bde-fb2a-4a40-96c3-a29dab684206","ts":"2026-02-14T19:40:57.514-05:00","eventName":"n8n.node.started","message":"n8n.node.started","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"49","nodeType":"n8n-nodes-base.postgres","nodeName":"Execute a SQL query","nodeId":"2d92f41f-baea-47ac-9340-54b40ad343a6"}}
|
||||
{"__type":"$$EventMessageNode","id":"2e82f24c-37a6-4f79-87f4-3be1a0cdb2ed","ts":"2026-02-14T19:40:57.630-05:00","eventName":"n8n.node.finished","message":"n8n.node.finished","payload":{"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline","executionId":"49","nodeType":"n8n-nodes-base.postgres","nodeName":"Execute a SQL query","nodeId":"2d92f41f-baea-47ac-9340-54b40ad343a6"}}
|
||||
{"__type":"$$EventMessageWorkflow","id":"655184c6-e578-42d7-8c8a-df700ef9feca","ts":"2026-02-14T19:40:57.633-05:00","eventName":"n8n.workflow.success","message":"n8n.workflow.success","payload":{"userId":"07cbc1c9-f562-4c77-88d0-c0c8faff3e82","executionId":"49","success":true,"isManual":true,"workflowId":"g3yuktNVnNC6OqUt","workflowName":"Market Discovery Pipeline"}}
|
||||
|
||||
12
seed_discovery.py
Normal file
12
seed_discovery.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# seed_discovery.py
|
||||
async def seed():
|
||||
# Az RDW-től lekérjük az ÖSSZES egyedi márkát
|
||||
url = "https://opendata.rdw.nl/resource/m9d7-ebf2.json?$select=distinct%20merk&$limit=50000"
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(url)
|
||||
makes = resp.json()
|
||||
async with SessionLocal() as db:
|
||||
for item in makes:
|
||||
m = item['merk'].upper()
|
||||
await db.execute(text("INSERT INTO data.catalog_discovery (make, model, source, status) VALUES (:m, 'ALL', 'global_seed', 'pending') ON CONFLICT DO NOTHING"), {"m": m})
|
||||
await db.commit()
|
||||
Reference in New Issue
Block a user