# Generated by Django 5.2.7 on 2026-01-02 04:45

import django.contrib.postgres.fields
import django.contrib.postgres.indexes
import django.core.validators
import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
        ('scan', '0001_initial'),
        ('targets', '0001_initial'),
    ]

    operations = [
        migrations.CreateModel(
            name='AssetStatistics',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('total_targets', models.IntegerField(default=0, help_text='目标总数')),
                ('total_subdomains', models.IntegerField(default=0, help_text='子域名总数')),
                ('total_ips', models.IntegerField(default=0, help_text='IP地址总数')),
                ('total_endpoints', models.IntegerField(default=0, help_text='端点总数')),
                ('total_websites', models.IntegerField(default=0, help_text='网站总数')),
                ('total_vulns', models.IntegerField(default=0, help_text='漏洞总数')),
                ('total_assets', models.IntegerField(default=0, help_text='总资产数（子域名+IP+端点+网站）')),
                ('prev_targets', models.IntegerField(default=0, help_text='上次目标总数')),
                ('prev_subdomains', models.IntegerField(default=0, help_text='上次子域名总数')),
                ('prev_ips', models.IntegerField(default=0, help_text='上次IP地址总数')),
                ('prev_endpoints', models.IntegerField(default=0, help_text='上次端点总数')),
                ('prev_websites', models.IntegerField(default=0, help_text='上次网站总数')),
                ('prev_vulns', models.IntegerField(default=0, help_text='上次漏洞总数')),
                ('prev_assets', models.IntegerField(default=0, help_text='上次总资产数')),
                ('updated_at', models.DateTimeField(auto_now=True, help_text='最后更新时间')),
            ],
            options={
                'verbose_name': '资产统计',
                'verbose_name_plural': '资产统计',
                'db_table': 'asset_statistics',
            },
        ),
        migrations.CreateModel(
            name='StatisticsHistory',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('date', models.DateField(help_text='统计日期', unique=True)),
                ('total_targets', models.IntegerField(default=0, help_text='目标总数')),
                ('total_subdomains', models.IntegerField(default=0, help_text='子域名总数')),
                ('total_ips', models.IntegerField(default=0, help_text='IP地址总数')),
                ('total_endpoints', models.IntegerField(default=0, help_text='端点总数')),
                ('total_websites', models.IntegerField(default=0, help_text='网站总数')),
                ('total_vulns', models.IntegerField(default=0, help_text='漏洞总数')),
                ('total_assets', models.IntegerField(default=0, help_text='总资产数')),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('updated_at', models.DateTimeField(auto_now=True, help_text='更新时间')),
            ],
            options={
                'verbose_name': '统计历史',
                'verbose_name_plural': '统计历史',
                'db_table': 'statistics_history',
                'ordering': ['-date'],
                'indexes': [models.Index(fields=['date'], name='statistics__date_1d29cd_idx')],
            },
        ),
        migrations.CreateModel(
            name='Directory',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('url', models.CharField(help_text='完整请求 URL', max_length=2000)),
                ('status', models.IntegerField(blank=True, help_text='HTTP 响应状态码', null=True)),
                ('content_length', models.BigIntegerField(blank=True, help_text='响应体字节大小（Content-Length 或实际长度）', null=True)),
                ('words', models.IntegerField(blank=True, help_text='响应体中单词数量（按空格分割）', null=True)),
                ('lines', models.IntegerField(blank=True, help_text='响应体行数（按换行符分割）', null=True)),
                ('content_type', models.CharField(blank=True, default='', help_text='响应头 Content-Type 值', max_length=200)),
                ('duration', models.BigIntegerField(blank=True, help_text='请求耗时（单位：纳秒）', null=True)),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('target', models.ForeignKey(help_text='所属的扫描目标', on_delete=django.db.models.deletion.CASCADE, related_name='directories', to='targets.target')),
            ],
            options={
                'verbose_name': '目录',
                'verbose_name_plural': '目录',
                'db_table': 'directory',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['-created_at'], name='directory_created_2cef03_idx'), models.Index(fields=['target'], name='directory_target__e310c8_idx'), models.Index(fields=['url'], name='directory_url_ba40cd_idx'), models.Index(fields=['status'], name='directory_status_40bbe6_idx'), django.contrib.postgres.indexes.GinIndex(fields=['url'], name='directory_url_trgm_idx', opclasses=['gin_trgm_ops'])],
                'constraints': [models.UniqueConstraint(fields=('target', 'url'), name='unique_directory_url_target')],
            },
        ),
        migrations.CreateModel(
            name='DirectorySnapshot',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('url', models.CharField(help_text='目录URL', max_length=2000)),
                ('status', models.IntegerField(blank=True, help_text='HTTP状态码', null=True)),
                ('content_length', models.BigIntegerField(blank=True, help_text='内容长度', null=True)),
                ('words', models.IntegerField(blank=True, help_text='响应体中单词数量（按空格分割）', null=True)),
                ('lines', models.IntegerField(blank=True, help_text='响应体行数（按换行符分割）', null=True)),
                ('content_type', models.CharField(blank=True, default='', help_text='响应头 Content-Type 值', max_length=200)),
                ('duration', models.BigIntegerField(blank=True, help_text='请求耗时（单位：纳秒）', null=True)),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('scan', models.ForeignKey(help_text='所属的扫描任务', on_delete=django.db.models.deletion.CASCADE, related_name='directory_snapshots', to='scan.scan')),
            ],
            options={
                'verbose_name': '目录快照',
                'verbose_name_plural': '目录快照',
                'db_table': 'directory_snapshot',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['scan'], name='directory_s_scan_id_c45900_idx'), models.Index(fields=['url'], name='directory_s_url_b4b72b_idx'), models.Index(fields=['status'], name='directory_s_status_e9f57e_idx'), models.Index(fields=['content_type'], name='directory_s_content_45e864_idx'), models.Index(fields=['-created_at'], name='directory_s_created_eb9d27_idx'), django.contrib.postgres.indexes.GinIndex(fields=['url'], name='dir_snap_url_trgm', opclasses=['gin_trgm_ops'])],
                'constraints': [models.UniqueConstraint(fields=('scan', 'url'), name='unique_directory_per_scan_snapshot')],
            },
        ),
        migrations.CreateModel(
            name='Endpoint',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('url', models.TextField(help_text='最终访问的完整URL')),
                ('host', models.CharField(blank=True, default='', help_text='主机名（域名或IP地址）', max_length=253)),
                ('location', models.TextField(blank=True, default='', help_text='重定向地址（HTTP 3xx 响应头 Location）')),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('title', models.TextField(blank=True, default='', help_text='网页标题（HTML <title> 标签内容）')),
                ('webserver', models.TextField(blank=True, default='', help_text='服务器类型（HTTP 响应头 Server 值）')),
                ('response_body', models.TextField(blank=True, default='', help_text='HTTP响应体')),
                ('content_type', models.TextField(blank=True, default='', help_text='响应类型（HTTP Content-Type 响应头）')),
                ('tech', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=100), blank=True, default=list, help_text='技术栈（服务器/框架/语言等）', size=None)),
                ('status_code', models.IntegerField(blank=True, help_text='HTTP状态码', null=True)),
                ('content_length', models.IntegerField(blank=True, help_text='响应体大小（单位字节）', null=True)),
                ('vhost', models.BooleanField(blank=True, help_text='是否支持虚拟主机', null=True)),
                ('matched_gf_patterns', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=100), blank=True, default=list, help_text='匹配的GF模式列表，用于识别敏感端点（如api, debug, config等）', size=None)),
                ('response_headers', models.TextField(blank=True, default='', help_text='原始HTTP响应头')),
                ('target', models.ForeignKey(help_text='所属的扫描目标（主关联字段，表示所属关系，不能为空）', on_delete=django.db.models.deletion.CASCADE, related_name='endpoints', to='targets.target')),
            ],
            options={
                'verbose_name': '端点',
                'verbose_name_plural': '端点',
                'db_table': 'endpoint',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['-created_at'], name='endpoint_created_44fe9c_idx'), models.Index(fields=['target'], name='endpoint_target__7f9065_idx'), models.Index(fields=['url'], name='endpoint_url_30f66e_idx'), models.Index(fields=['host'], name='endpoint_host_5b4cc8_idx'), models.Index(fields=['status_code'], name='endpoint_status__5d4fdd_idx'), models.Index(fields=['title'], name='endpoint_title_29e26c_idx'), django.contrib.postgres.indexes.GinIndex(fields=['tech'], name='endpoint_tech_2bfa7c_gin'), django.contrib.postgres.indexes.GinIndex(fields=['response_headers'], name='endpoint_resp_headers_trgm_idx', opclasses=['gin_trgm_ops']), django.contrib.postgres.indexes.GinIndex(fields=['url'], name='endpoint_url_trgm_idx', opclasses=['gin_trgm_ops']), django.contrib.postgres.indexes.GinIndex(fields=['title'], name='endpoint_title_trgm_idx', opclasses=['gin_trgm_ops'])],
                'constraints': [models.UniqueConstraint(fields=('url', 'target'), name='unique_endpoint_url_target')],
            },
        ),
        migrations.CreateModel(
            name='EndpointSnapshot',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('url', models.TextField(help_text='端点URL')),
                ('host', models.CharField(blank=True, default='', help_text='主机名（域名或IP地址）', max_length=253)),
                ('title', models.TextField(blank=True, default='', help_text='页面标题')),
                ('status_code', models.IntegerField(blank=True, help_text='HTTP状态码', null=True)),
                ('content_length', models.IntegerField(blank=True, help_text='内容长度', null=True)),
                ('location', models.TextField(blank=True, default='', help_text='重定向位置')),
                ('webserver', models.TextField(blank=True, default='', help_text='Web服务器')),
                ('content_type', models.TextField(blank=True, default='', help_text='内容类型')),
                ('tech', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=100), blank=True, default=list, help_text='技术栈', size=None)),
                ('response_body', models.TextField(blank=True, default='', help_text='HTTP响应体')),
                ('vhost', models.BooleanField(blank=True, help_text='虚拟主机标志', null=True)),
                ('matched_gf_patterns', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=100), blank=True, default=list, help_text='匹配的GF模式列表', size=None)),
                ('response_headers', models.TextField(blank=True, default='', help_text='原始HTTP响应头')),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('scan', models.ForeignKey(help_text='所属的扫描任务', on_delete=django.db.models.deletion.CASCADE, related_name='endpoint_snapshots', to='scan.scan')),
            ],
            options={
                'verbose_name': '端点快照',
                'verbose_name_plural': '端点快照',
                'db_table': 'endpoint_snapshot',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['scan'], name='endpoint_sn_scan_id_6ac9a7_idx'), models.Index(fields=['url'], name='endpoint_sn_url_205160_idx'), models.Index(fields=['host'], name='endpoint_sn_host_577bfd_idx'), models.Index(fields=['title'], name='endpoint_sn_title_516a05_idx'), models.Index(fields=['status_code'], name='endpoint_sn_status__83efb0_idx'), models.Index(fields=['webserver'], name='endpoint_sn_webserv_66be83_idx'), models.Index(fields=['-created_at'], name='endpoint_sn_created_21fb5b_idx'), django.contrib.postgres.indexes.GinIndex(fields=['tech'], name='endpoint_sn_tech_0d0752_gin'), django.contrib.postgres.indexes.GinIndex(fields=['response_headers'], name='ep_snap_resp_hdr_trgm', opclasses=['gin_trgm_ops']), django.contrib.postgres.indexes.GinIndex(fields=['url'], name='ep_snap_url_trgm', opclasses=['gin_trgm_ops']), django.contrib.postgres.indexes.GinIndex(fields=['title'], name='ep_snap_title_trgm', opclasses=['gin_trgm_ops'])],
                'constraints': [models.UniqueConstraint(fields=('scan', 'url'), name='unique_endpoint_per_scan_snapshot')],
            },
        ),
        migrations.CreateModel(
            name='HostPortMapping',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('host', models.CharField(help_text='主机名（域名或IP）', max_length=1000)),
                ('ip', models.GenericIPAddressField(help_text='IP地址')),
                ('port', models.IntegerField(help_text='端口号（1-65535）', validators=[django.core.validators.MinValueValidator(1, message='端口号必须大于等于1'), django.core.validators.MaxValueValidator(65535, message='端口号必须小于等于65535')])),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('target', models.ForeignKey(help_text='所属的扫描目标', on_delete=django.db.models.deletion.CASCADE, related_name='host_port_mappings', to='targets.target')),
            ],
            options={
                'verbose_name': '主机端口映射',
                'verbose_name_plural': '主机端口映射',
                'db_table': 'host_port_mapping',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['target'], name='host_port_m_target__943e9b_idx'), models.Index(fields=['host'], name='host_port_m_host_f78363_idx'), models.Index(fields=['ip'], name='host_port_m_ip_2e6f02_idx'), models.Index(fields=['port'], name='host_port_m_port_9fb9ff_idx'), models.Index(fields=['host', 'ip'], name='host_port_m_host_3ce245_idx'), models.Index(fields=['-created_at'], name='host_port_m_created_11cd22_idx')],
                'constraints': [models.UniqueConstraint(fields=('target', 'host', 'ip', 'port'), name='unique_target_host_ip_port')],
            },
        ),
        migrations.CreateModel(
            name='HostPortMappingSnapshot',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('host', models.CharField(help_text='主机名（域名或IP）', max_length=1000)),
                ('ip', models.GenericIPAddressField(help_text='IP地址')),
                ('port', models.IntegerField(help_text='端口号（1-65535）', validators=[django.core.validators.MinValueValidator(1, message='端口号必须大于等于1'), django.core.validators.MaxValueValidator(65535, message='端口号必须小于等于65535')])),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('scan', models.ForeignKey(help_text='所属的扫描任务（主关联）', on_delete=django.db.models.deletion.CASCADE, related_name='host_port_mapping_snapshots', to='scan.scan')),
            ],
            options={
                'verbose_name': '主机端口映射快照',
                'verbose_name_plural': '主机端口映射快照',
                'db_table': 'host_port_mapping_snapshot',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['scan'], name='host_port_m_scan_id_50ba0b_idx'), models.Index(fields=['host'], name='host_port_m_host_e99054_idx'), models.Index(fields=['ip'], name='host_port_m_ip_54818c_idx'), models.Index(fields=['port'], name='host_port_m_port_ed7b48_idx'), models.Index(fields=['host', 'ip'], name='host_port_m_host_8a463a_idx'), models.Index(fields=['scan', 'host'], name='host_port_m_scan_id_426fdb_idx'), models.Index(fields=['-created_at'], name='host_port_m_created_fb28b8_idx')],
                'constraints': [models.UniqueConstraint(fields=('scan', 'host', 'ip', 'port'), name='unique_scan_host_ip_port_snapshot')],
            },
        ),
        migrations.CreateModel(
            name='Subdomain',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('name', models.CharField(help_text='子域名名称', max_length=1000)),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('target', models.ForeignKey(help_text='所属的扫描目标（主关联字段，表示所属关系，不能为空）', on_delete=django.db.models.deletion.CASCADE, related_name='subdomains', to='targets.target')),
            ],
            options={
                'verbose_name': '子域名',
                'verbose_name_plural': '子域名',
                'db_table': 'subdomain',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['-created_at'], name='subdomain_created_e187a8_idx'), models.Index(fields=['name', 'target'], name='subdomain_name_60e1d0_idx'), models.Index(fields=['target'], name='subdomain_target__e409f0_idx'), models.Index(fields=['name'], name='subdomain_name_d40ba7_idx'), django.contrib.postgres.indexes.GinIndex(fields=['name'], name='subdomain_name_trgm_idx', opclasses=['gin_trgm_ops'])],
                'constraints': [models.UniqueConstraint(fields=('name', 'target'), name='unique_subdomain_name_target')],
            },
        ),
        migrations.CreateModel(
            name='SubdomainSnapshot',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('name', models.CharField(help_text='子域名名称', max_length=1000)),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('scan', models.ForeignKey(help_text='所属的扫描任务', on_delete=django.db.models.deletion.CASCADE, related_name='subdomain_snapshots', to='scan.scan')),
            ],
            options={
                'verbose_name': '子域名快照',
                'verbose_name_plural': '子域名快照',
                'db_table': 'subdomain_snapshot',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['scan'], name='subdomain_s_scan_id_68c253_idx'), models.Index(fields=['name'], name='subdomain_s_name_2da42b_idx'), models.Index(fields=['-created_at'], name='subdomain_s_created_d2b48e_idx'), django.contrib.postgres.indexes.GinIndex(fields=['name'], name='subdomain_snap_name_trgm', opclasses=['gin_trgm_ops'])],
                'constraints': [models.UniqueConstraint(fields=('scan', 'name'), name='unique_subdomain_per_scan_snapshot')],
            },
        ),
        migrations.CreateModel(
            name='Vulnerability',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('url', models.CharField(help_text='漏洞所在的URL', max_length=2000)),
                ('vuln_type', models.CharField(help_text='漏洞类型（如 xss, sqli）', max_length=100)),
                ('severity', models.CharField(choices=[('unknown', '未知'), ('info', '信息'), ('low', '低'), ('medium', '中'), ('high', '高'), ('critical', '危急')], default='unknown', help_text='严重性（未知/信息/低/中/高/危急）', max_length=20)),
                ('source', models.CharField(blank=True, default='', help_text='来源工具（如 dalfox, nuclei, crlfuzz）', max_length=50)),
                ('cvss_score', models.DecimalField(blank=True, decimal_places=1, help_text='CVSS 评分（0.0-10.0）', max_digits=3, null=True)),
                ('description', models.TextField(blank=True, default='', help_text='漏洞描述')),
                ('raw_output', models.JSONField(blank=True, default=dict, help_text='工具原始输出')),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('target', models.ForeignKey(help_text='所属的扫描目标', on_delete=django.db.models.deletion.CASCADE, related_name='vulnerabilities', to='targets.target')),
            ],
            options={
                'verbose_name': '漏洞',
                'verbose_name_plural': '漏洞',
                'db_table': 'vulnerability',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['target'], name='vulnerabili_target__755a02_idx'), models.Index(fields=['vuln_type'], name='vulnerabili_vuln_ty_3010cd_idx'), models.Index(fields=['severity'], name='vulnerabili_severit_1a798b_idx'), models.Index(fields=['source'], name='vulnerabili_source_7c7552_idx'), models.Index(fields=['url'], name='vulnerabili_url_4dcc4d_idx'), models.Index(fields=['-created_at'], name='vulnerabili_created_e25ff7_idx')],
            },
        ),
        migrations.CreateModel(
            name='VulnerabilitySnapshot',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('url', models.CharField(help_text='漏洞所在的URL', max_length=2000)),
                ('vuln_type', models.CharField(help_text='漏洞类型（如 xss, sqli）', max_length=100)),
                ('severity', models.CharField(choices=[('unknown', '未知'), ('info', '信息'), ('low', '低'), ('medium', '中'), ('high', '高'), ('critical', '危急')], default='unknown', help_text='严重性（未知/信息/低/中/高/危急）', max_length=20)),
                ('source', models.CharField(blank=True, default='', help_text='来源工具（如 dalfox, nuclei, crlfuzz）', max_length=50)),
                ('cvss_score', models.DecimalField(blank=True, decimal_places=1, help_text='CVSS 评分（0.0-10.0）', max_digits=3, null=True)),
                ('description', models.TextField(blank=True, default='', help_text='漏洞描述')),
                ('raw_output', models.JSONField(blank=True, default=dict, help_text='工具原始输出')),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('scan', models.ForeignKey(help_text='所属的扫描任务', on_delete=django.db.models.deletion.CASCADE, related_name='vulnerability_snapshots', to='scan.scan')),
            ],
            options={
                'verbose_name': '漏洞快照',
                'verbose_name_plural': '漏洞快照',
                'db_table': 'vulnerability_snapshot',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['scan'], name='vulnerabili_scan_id_7b81c9_idx'), models.Index(fields=['url'], name='vulnerabili_url_11a707_idx'), models.Index(fields=['vuln_type'], name='vulnerabili_vuln_ty_6b90ee_idx'), models.Index(fields=['severity'], name='vulnerabili_severit_4eae0d_idx'), models.Index(fields=['source'], name='vulnerabili_source_968b1f_idx'), models.Index(fields=['-created_at'], name='vulnerabili_created_53a12e_idx')],
            },
        ),
        migrations.CreateModel(
            name='WebSite',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('url', models.TextField(help_text='最终访问的完整URL')),
                ('host', models.CharField(blank=True, default='', help_text='主机名（域名或IP地址）', max_length=253)),
                ('location', models.TextField(blank=True, default='', help_text='重定向地址（HTTP 3xx 响应头 Location）')),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('title', models.TextField(blank=True, default='', help_text='网页标题（HTML <title> 标签内容）')),
                ('webserver', models.TextField(blank=True, default='', help_text='服务器类型（HTTP 响应头 Server 值）')),
                ('response_body', models.TextField(blank=True, default='', help_text='HTTP响应体')),
                ('content_type', models.TextField(blank=True, default='', help_text='响应类型（HTTP Content-Type 响应头）')),
                ('tech', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=100), blank=True, default=list, help_text='技术栈（服务器/框架/语言等）', size=None)),
                ('status_code', models.IntegerField(blank=True, help_text='HTTP状态码', null=True)),
                ('content_length', models.IntegerField(blank=True, help_text='响应体大小（单位字节）', null=True)),
                ('vhost', models.BooleanField(blank=True, help_text='是否支持虚拟主机', null=True)),
                ('response_headers', models.TextField(blank=True, default='', help_text='原始HTTP响应头')),
                ('target', models.ForeignKey(help_text='所属的扫描目标（主关联字段，表示所属关系，不能为空）', on_delete=django.db.models.deletion.CASCADE, related_name='websites', to='targets.target')),
            ],
            options={
                'verbose_name': '站点',
                'verbose_name_plural': '站点',
                'db_table': 'website',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['-created_at'], name='website_created_c9cfd2_idx'), models.Index(fields=['url'], name='website_url_b18883_idx'), models.Index(fields=['host'], name='website_host_996b50_idx'), models.Index(fields=['target'], name='website_target__2a353b_idx'), models.Index(fields=['title'], name='website_title_c2775b_idx'), models.Index(fields=['status_code'], name='website_status__51663d_idx'), django.contrib.postgres.indexes.GinIndex(fields=['tech'], name='website_tech_e3f0cb_gin'), django.contrib.postgres.indexes.GinIndex(fields=['response_headers'], name='website_resp_headers_trgm_idx', opclasses=['gin_trgm_ops']), django.contrib.postgres.indexes.GinIndex(fields=['url'], name='website_url_trgm_idx', opclasses=['gin_trgm_ops']), django.contrib.postgres.indexes.GinIndex(fields=['title'], name='website_title_trgm_idx', opclasses=['gin_trgm_ops'])],
                'constraints': [models.UniqueConstraint(fields=('url', 'target'), name='unique_website_url_target')],
            },
        ),
        migrations.CreateModel(
            name='WebsiteSnapshot',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('url', models.TextField(help_text='站点URL')),
                ('host', models.CharField(blank=True, default='', help_text='主机名（域名或IP地址）', max_length=253)),
                ('title', models.TextField(blank=True, default='', help_text='页面标题')),
                ('status_code', models.IntegerField(blank=True, help_text='HTTP状态码', null=True)),
                ('content_length', models.BigIntegerField(blank=True, help_text='内容长度', null=True)),
                ('location', models.TextField(blank=True, default='', help_text='重定向位置')),
                ('webserver', models.TextField(blank=True, default='', help_text='Web服务器')),
                ('content_type', models.TextField(blank=True, default='', help_text='内容类型')),
                ('tech', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=100), blank=True, default=list, help_text='技术栈', size=None)),
                ('response_body', models.TextField(blank=True, default='', help_text='HTTP响应体')),
                ('vhost', models.BooleanField(blank=True, help_text='虚拟主机标志', null=True)),
                ('response_headers', models.TextField(blank=True, default='', help_text='原始HTTP响应头')),
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='创建时间')),
                ('scan', models.ForeignKey(help_text='所属的扫描任务', on_delete=django.db.models.deletion.CASCADE, related_name='website_snapshots', to='scan.scan')),
            ],
            options={
                'verbose_name': '网站快照',
                'verbose_name_plural': '网站快照',
                'db_table': 'website_snapshot',
                'ordering': ['-created_at'],
                'indexes': [models.Index(fields=['scan'], name='website_sna_scan_id_26b6dc_idx'), models.Index(fields=['url'], name='website_sna_url_801a70_idx'), models.Index(fields=['host'], name='website_sna_host_348fe1_idx'), models.Index(fields=['title'], name='website_sna_title_b1a5ee_idx'), models.Index(fields=['-created_at'], name='website_sna_created_2c149a_idx'), django.contrib.postgres.indexes.GinIndex(fields=['tech'], name='website_sna_tech_3d6d2f_gin'), django.contrib.postgres.indexes.GinIndex(fields=['response_headers'], name='ws_snap_resp_hdr_trgm', opclasses=['gin_trgm_ops']), django.contrib.postgres.indexes.GinIndex(fields=['url'], name='ws_snap_url_trgm', opclasses=['gin_trgm_ops']), django.contrib.postgres.indexes.GinIndex(fields=['title'], name='ws_snap_title_trgm', opclasses=['gin_trgm_ops'])],
                'constraints': [models.UniqueConstraint(fields=('scan', 'url'), name='unique_website_per_scan_snapshot')],
            },
        ),
    ]
