50a261e05e
- POST /operations/{id}/field-data/sync: тянет GET /api/v1/vector/areas-checked
→ идемпотентный upsert в areas_checked (dedupe по contour_area_id:
geom/checked_at/result/coverage_pct/team_label, source=contour)
- GET /operations/{id}/areas-checked: теперь из локальной БД после sync
(source=db), фолбэк на живой прокси КОНТУРа если пусто (source=contour/empty)
- миграция 011_b17_field_data: areas_checked +contour_area_id/team_label/source
(+check ck_areas_checked_source)
- аудит field_data_sync; лог vector.contour field_sync_*
- фронт: кнопка «⟳ Синхронизировать полевые данные» в КОНТУР-панели,
слой проверенных квадратов на карте (зелёный=clear ≥99.5%, жёлтый=partial)
- тесты: +9 (267 passed) — sync/идемпотентность/502/аудит/локальное чтение
37 lines
1.3 KiB
Python
37 lines
1.3 KiB
Python
"""B17/E5: ингестия полевых данных КОНТУРа (колонки areas_checked).
|
|
|
|
Revises: 010_b23_policy
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
from sqlalchemy.dialects import postgresql as pg
|
|
|
|
revision = '011_b17_field_data'
|
|
down_revision = '010_b23_policy'
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.add_column('areas_checked',
|
|
sa.Column('contour_area_id', sa.String(64), nullable=True))
|
|
op.add_column('areas_checked',
|
|
sa.Column('team_label', sa.String(100), nullable=True))
|
|
op.add_column('areas_checked',
|
|
sa.Column('source', sa.String(20),
|
|
server_default='manual', nullable=False))
|
|
op.create_index('idx_areas_checked_contour_area',
|
|
'areas_checked', ['contour_area_id'])
|
|
op.create_check_constraint(
|
|
'ck_areas_checked_source', 'areas_checked',
|
|
"source IN ('manual','contour')")
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_constraint('ck_areas_checked_source', 'areas_checked', type_='check')
|
|
op.drop_index('idx_areas_checked_contour_area', table_name='areas_checked')
|
|
op.drop_column('areas_checked', 'source')
|
|
op.drop_column('areas_checked', 'team_label')
|
|
op.drop_column('areas_checked', 'contour_area_id') |