""" Mobile App Models für React Native API """ from django.db import models from django.contrib.auth.models import User from django.utils import timezone import uuid class MobileDevice(models.Model): """Mobile Device Registration für Push Notifications""" DEVICE_TYPE_CHOICES = [ ('ios', 'iOS'), ('android', 'Android'), ('web', 'Web'), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='mobile_devices') device_token = models.CharField(max_length=255, unique=True) device_type = models.CharField(max_length=20, choices=DEVICE_TYPE_CHOICES) device_name = models.CharField(max_length=100, blank=True) device_model = models.CharField(max_length=100, blank=True) os_version = models.CharField(max_length=50, blank=True) app_version = models.CharField(max_length=20, blank=True) is_active = models.BooleanField(default=True) last_seen = models.DateTimeField(auto_now=True) created_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['-created_at'] verbose_name = 'Mobile Device' verbose_name_plural = 'Mobile Devices' def __str__(self): return f"{self.user.username} - {self.device_type} ({self.device_name})" class PushNotification(models.Model): """Push Notification Tracking""" NOTIFICATION_TYPE_CHOICES = [ ('order_status', 'Order Status'), ('auction_update', 'Auction Update'), ('chat_message', 'Chat Message'), ('promotion', 'Promotion'), ('system', 'System'), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='push_notifications') device = models.ForeignKey(MobileDevice, on_delete=models.CASCADE, related_name='notifications') notification_type = models.CharField(max_length=20, choices=NOTIFICATION_TYPE_CHOICES) title = models.CharField(max_length=200) message = models.TextField() data = models.JSONField(default=dict) # Additional data for deep linking sent_at = models.DateTimeField(auto_now_add=True) delivered_at = models.DateTimeField(null=True, blank=True) opened_at = models.DateTimeField(null=True, blank=True) is_sent = models.BooleanField(default=False) is_delivered = models.BooleanField(default=False) is_opened = models.BooleanField(default=False) class Meta: ordering = ['-sent_at'] verbose_name = 'Push Notification' verbose_name_plural = 'Push Notifications' def __str__(self): return f"{self.notification_type}: {self.title}" class OfflineSync(models.Model): """Offline Sync Tracking für Mobile App""" SYNC_STATUS_CHOICES = [ ('pending', 'Pending'), ('syncing', 'Syncing'), ('completed', 'Completed'), ('failed', 'Failed'), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='offline_syncs') device = models.ForeignKey(MobileDevice, on_delete=models.CASCADE, related_name='syncs') sync_type = models.CharField(max_length=50) # 'orders', 'products', 'auctions' data = models.JSONField() # Data to sync status = models.CharField(max_length=20, choices=SYNC_STATUS_CHOICES, default='pending') error_message = models.TextField(blank=True) created_at = models.DateTimeField(auto_now_add=True) synced_at = models.DateTimeField(null=True, blank=True) class Meta: ordering = ['-created_at'] verbose_name = 'Offline Sync' verbose_name_plural = 'Offline Syncs' def __str__(self): return f"{self.user.username} - {self.sync_type} ({self.get_status_display()})" class MobileAnalytics(models.Model): """Mobile App Analytics""" id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='mobile_analytics') device = models.ForeignKey(MobileDevice, on_delete=models.CASCADE, related_name='analytics') event_type = models.CharField(max_length=50) # 'app_open', 'product_view', 'purchase' event_data = models.JSONField(default=dict) session_id = models.CharField(max_length=100, blank=True) screen_name = models.CharField(max_length=100, blank=True) timestamp = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['-timestamp'] verbose_name = 'Mobile Analytics' verbose_name_plural = 'Mobile Analytics' def __str__(self): return f"{self.user.username} - {self.event_type}" class MobileCache(models.Model): """Mobile App Cache für Offline Support""" CACHE_TYPE_CHOICES = [ ('products', 'Products'), ('categories', 'Categories'), ('auctions', 'Auctions'), ('user_data', 'User Data'), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='mobile_caches') cache_type = models.CharField(max_length=20, choices=CACHE_TYPE_CHOICES) cache_key = models.CharField(max_length=255) cache_data = models.JSONField() expires_at = models.DateTimeField() created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ['-updated_at'] verbose_name = 'Mobile Cache' verbose_name_plural = 'Mobile Caches' unique_together = ['user', 'cache_type', 'cache_key'] def __str__(self): return f"{self.user.username} - {self.cache_type}: {self.cache_key}" @property def is_expired(self): """Prüfen ob Cache abgelaufen ist""" return timezone.now() > self.expires_at class MobileSession(models.Model): """Mobile App Session Tracking""" id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='mobile_sessions') device = models.ForeignKey(MobileDevice, on_delete=models.CASCADE, related_name='sessions') session_id = models.CharField(max_length=100, unique=True) started_at = models.DateTimeField(auto_now_add=True) ended_at = models.DateTimeField(null=True, blank=True) duration = models.IntegerField(default=0) # in seconds is_active = models.BooleanField(default=True) class Meta: ordering = ['-started_at'] verbose_name = 'Mobile Session' verbose_name_plural = 'Mobile Sessions' def __str__(self): return f"{self.user.username} - {self.session_id}" def end_session(self): """Session beenden""" self.ended_at = timezone.now() self.is_active = False self.duration = int((self.ended_at - self.started_at).total_seconds()) self.save() class MobileError(models.Model): """Mobile App Error Tracking""" ERROR_LEVEL_CHOICES = [ ('debug', 'Debug'), ('info', 'Info'), ('warning', 'Warning'), ('error', 'Error'), ('critical', 'Critical'), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='mobile_errors') device = models.ForeignKey(MobileDevice, on_delete=models.CASCADE, related_name='errors') error_level = models.CharField(max_length=20, choices=ERROR_LEVEL_CHOICES) error_type = models.CharField(max_length=100) error_message = models.TextField() stack_trace = models.TextField(blank=True) app_version = models.CharField(max_length=20, blank=True) os_version = models.CharField(max_length=50, blank=True) device_info = models.JSONField(default=dict) created_at = models.DateTimeField(auto_now_add=True) is_resolved = models.BooleanField(default=False) class Meta: ordering = ['-created_at'] verbose_name = 'Mobile Error' verbose_name_plural = 'Mobile Errors' def __str__(self): return f"{self.error_type}: {self.error_message[:50]}"