# Generated by Django 5.2.9 on 2025-12-08 03:33 import django.core.validators import django.db.models.deletion import uuid from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='Website', fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for the website', primary_key=True, serialize=False)), ('url', models.URLField(help_text='The normalized URL of the website', max_length=2048, unique=True, validators=[django.core.validators.URLValidator(schemes=['http', 'https'])])), ('domain', models.CharField(db_index=True, help_text='The domain extracted from the URL', max_length=255)), ('created_at', models.DateTimeField(auto_now_add=True, help_text='When the website was first added')), ('last_scanned_at', models.DateTimeField(blank=True, help_text='When the website was last scanned', null=True)), ], options={ 'db_table': 'websites', 'ordering': ['-created_at'], 'indexes': [models.Index(fields=['domain'], name='websites_domain_9fabc6_idx'), models.Index(fields=['-last_scanned_at'], name='websites_last_sc_15be22_idx')], }, ), migrations.CreateModel( name='Scan', fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for the scan', primary_key=True, serialize=False)), ('status', models.CharField(choices=[('pending', 'Pending'), ('running', 'Running'), ('done', 'Completed'), ('failed', 'Failed'), ('partial', 'Partially Completed')], db_index=True, default='pending', help_text='Current status of the scan', max_length=20)), ('celery_task_id', models.CharField(blank=True, help_text='Celery task ID for tracking', max_length=255, null=True)), ('created_at', models.DateTimeField(auto_now_add=True, help_text='When the scan was created')), ('started_at', models.DateTimeField(blank=True, help_text='When the scan started running', null=True)), ('completed_at', models.DateTimeField(blank=True, help_text='When the scan completed', null=True)), ('performance_score', models.IntegerField(blank=True, help_text='Lighthouse performance score (0-100)', null=True)), ('accessibility_score', models.IntegerField(blank=True, help_text='Lighthouse accessibility score (0-100)', null=True)), ('seo_score', models.IntegerField(blank=True, help_text='Lighthouse SEO score (0-100)', null=True)), ('best_practices_score', models.IntegerField(blank=True, help_text='Lighthouse best practices score (0-100)', null=True)), ('security_score', models.IntegerField(blank=True, help_text='Computed security score based on issues (0-100)', null=True)), ('overall_score', models.IntegerField(blank=True, help_text='Overall health score (0-100)', null=True)), ('error_message', models.TextField(blank=True, help_text='Error message if scan failed', null=True)), ('raw_lighthouse_data', models.JSONField(blank=True, help_text='Raw Lighthouse report data', null=True)), ('raw_zap_data', models.JSONField(blank=True, help_text='Raw OWASP ZAP report data', null=True)), ('raw_playwright_data', models.JSONField(blank=True, help_text='Raw Playwright analysis data', null=True)), ('raw_headers_data', models.JSONField(blank=True, help_text='Raw HTTP headers analysis data', null=True)), ('website', models.ForeignKey(help_text='The website that was scanned', on_delete=django.db.models.deletion.CASCADE, related_name='scans', to='websites.website')), ], options={ 'db_table': 'scans', 'ordering': ['-created_at'], }, ), migrations.CreateModel( name='Metric', fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('name', models.CharField(db_index=True, help_text="Name of the metric (e.g., 'first_contentful_paint_ms')", max_length=100)), ('display_name', models.CharField(help_text='Human-readable name for display', max_length=200)), ('value', models.FloatField(help_text='Numeric value of the metric')), ('unit', models.CharField(choices=[('ms', 'Milliseconds'), ('s', 'Seconds'), ('bytes', 'Bytes'), ('kb', 'Kilobytes'), ('mb', 'Megabytes'), ('score', 'Score (0-1)'), ('percent', 'Percentage'), ('count', 'Count')], help_text='Unit of measurement', max_length=20)), ('source', models.CharField(choices=[('lighthouse', 'Google Lighthouse'), ('owasp_zap', 'OWASP ZAP'), ('playwright', 'Playwright'), ('header_check', 'HTTP Header Check'), ('tls_check', 'TLS/SSL Check')], help_text='Tool that provided this metric', max_length=30)), ('score', models.FloatField(blank=True, help_text='Lighthouse score for this metric (0-1)', null=True)), ('created_at', models.DateTimeField(auto_now_add=True)), ('scan', models.ForeignKey(help_text='The scan that measured this metric', on_delete=django.db.models.deletion.CASCADE, related_name='metrics', to='websites.scan')), ], options={ 'db_table': 'metrics', 'ordering': ['name'], 'indexes': [models.Index(fields=['scan', 'name'], name='metrics_scan_id_c4cc62_idx'), models.Index(fields=['source'], name='metrics_source_71e403_idx')], 'constraints': [models.UniqueConstraint(fields=('scan', 'name'), name='unique_metric_per_scan')], }, ), migrations.CreateModel( name='Issue', fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('category', models.CharField(choices=[('performance', 'Performance'), ('security', 'Security'), ('headers', 'HTTP Headers'), ('tls', 'TLS/SSL'), ('cors', 'CORS'), ('accessibility', 'Accessibility'), ('seo', 'SEO'), ('best_practices', 'Best Practices'), ('content', 'Content'), ('resources', 'Resources')], db_index=True, help_text='Category of the issue', max_length=30)), ('severity', models.CharField(choices=[('critical', 'Critical'), ('high', 'High'), ('medium', 'Medium'), ('low', 'Low'), ('info', 'Informational')], db_index=True, help_text='Severity level of the issue', max_length=20)), ('tool', models.CharField(choices=[('lighthouse', 'Google Lighthouse'), ('owasp_zap', 'OWASP ZAP'), ('playwright', 'Playwright'), ('header_check', 'HTTP Header Check'), ('tls_check', 'TLS/SSL Check')], help_text='Tool that detected this issue', max_length=30)), ('title', models.CharField(help_text='Brief title of the issue', max_length=500)), ('description', models.TextField(help_text='Detailed description of the issue')), ('affected_url', models.URLField(blank=True, help_text='Specific URL affected by this issue', max_length=2048, null=True)), ('remediation', models.TextField(blank=True, help_text='Suggested fix or remediation', null=True)), ('raw_data', models.JSONField(blank=True, help_text='Raw data from the scanner for this issue', null=True)), ('created_at', models.DateTimeField(auto_now_add=True)), ('scan', models.ForeignKey(help_text='The scan that found this issue', on_delete=django.db.models.deletion.CASCADE, related_name='issues', to='websites.scan')), ], options={ 'db_table': 'issues', 'ordering': ['severity', '-created_at'], 'indexes': [models.Index(fields=['scan', 'category'], name='issues_scan_id_e7f389_idx'), models.Index(fields=['scan', 'severity'], name='issues_scan_id_c92ffd_idx'), models.Index(fields=['tool'], name='issues_tool_78d942_idx')], }, ), migrations.AddIndex( model_name='scan', index=models.Index(fields=['status'], name='scans_status_dc5ad7_idx'), ), migrations.AddIndex( model_name='scan', index=models.Index(fields=['-created_at'], name='scans_created_7db2e5_idx'), ), migrations.AddIndex( model_name='scan', index=models.Index(fields=['website', '-created_at'], name='scans_website_6dae4d_idx'), ), ]