Sync Ops

Grupper Synkronisering

Oversikt

Grupper (lokallag) synkroniseres fra Cornerstone (kilde) til ClickUp og WordPress (mål). Systemet bruker entity_map som eneste kilde for global synkronisering.

Sync-retning

Cornerstone → ClickUp → WordPress

Cornerstone er kilden for gruppedata. Endringer i Cornerstone synkroniseres til ClickUp og WordPress.

Entity Mapping System

Hver gruppe har en entity_uuid som kobler sammen: - cornerstone_id - ID i Cornerstone - clickup_id - Task ID i ClickUp - wp_post_id - Post ID i WordPress - display_name - Visningsnavn

Global Sync Flyt

Trigger

Global sync kan trigges på tre måter: 1. Scheduled: Daglig kl 02:00 (via scheduler) 2. Manual: POST /lokallag/global-sync 3. Webhook: POST /webhook?task_id={id}

Prosess

flowchart TD
    Start[Global Sync Start] --> FetchEntities[Hent alle group entities fra entity_map]
    FetchEntities --> FetchCS[Fetch Cornerstone groups EN GANG]
    FetchCS --> BuildMap[Bygg lookup map: cornerstone_id → payload]
    BuildMap --> LoopStart[For hver entity]
    LoopStart --> CheckCS{Har cornerstone_id?}
    CheckCS -->|Nei| Skip1[Skip - log warning]
    CheckCS -->|Ja| FindGroup{Finnes i Cornerstone?}
    FindGroup -->|Nei| Skip2[Skip - log warning]
    FindGroup -->|Ja| ComputeHash[Beregn hash over synced fields]
    ComputeHash --> CompareHash{Hash endret?}
    CompareHash -->|Nei| Skip3[Skip - ingen endringer]
    CompareHash -->|Ja| SyncEngine[SyncEngine.sync_entity]
    SyncEngine --> FetchData[LokallagHandler.fetch_source_data]
    FetchData --> Transform[Transform data]
    Transform --> SyncClickUp[Sync til ClickUp]
    SyncClickUp --> SyncWP[Sync til WordPress]
    SyncWP --> UpdateHash[Oppdater hash og timestamps]
    UpdateHash --> Success[Success]
    Skip1 --> NextEntity[Neste entity]
    Skip2 --> NextEntity
    Skip3 --> NextEntity
    Success --> NextEntity
    NextEntity --> MoreEntities{Flere entities?}
    MoreEntities -->|Ja| LoopStart
    MoreEntities -->|Nei| End[Sync ferdig]

Steg-for-steg

  1. Hent entities: Få alle entity_type='group' fra entity_map
  2. Fetch Cornerstone: En enkelt GraphQL-spørring for alle grupper (optimalisert)
  3. Bygg lookup map: cornerstone_id → group payload
  4. Iterer over entities:
  5. Skip hvis mangler cornerstone_id
  6. Skip hvis gruppe ikke finnes i Cornerstone
  7. Beregn hash for å oppdage endringer
  8. Skip hvis uendret (hash match)
  9. Kall SyncEngine.sync_entity() med source='cornerstone'
  10. Spor resultater: Tell prosesserte, suksesser, feil

Sync Engine Flyt

LokallagHandler

sequenceDiagram
    participant GS as Global Sync
    participant SE as SyncEngine
    participant LH as LokallagHandler
    participant CS as Cornerstone
    participant CU as ClickUp
    participant WP as WordPress
    participant EM as Entity Map

    GS->>SE: sync_entity(entity_uuid, source='cornerstone')
    SE->>EM: get_entity_by_uuid()
    EM-->>SE: entity (med entity_type='group')
    SE->>LH: fetch_source_data(entity, 'cornerstone')
    LH->>CS: fetch_graphql_data()
    CS-->>LH: group data
    LH-->>SE: source_data
    SE->>LH: transform_data(source_data)
    LH-->>SE: transformed_data (clickup + wordpress)
    SE->>LH: sync_to_targets(entity, data)
    LH->>CU: Update custom fields
    CU-->>LH: success
    LH->>WP: Update via registry API
    WP-->>LH: success
    LH-->>SE: success
    SE-->>GS: SyncResult(success=True)

Data Transformasjon

Fra Cornerstone:

{
  "id": "123",
  "name": "Lokallag Navn",
  "bankAccountNo": "12345678901",
  "leader": {
    "email": "leder@example.com",
    "name": "Leder Navn",
    "mobile": "12345678"
  },
  "annualReports": [{
    "membersAccepted": 50
  }]
}

Til ClickUp: - bank_account → Custom field - email → Custom field - name → Custom field - mobile → Custom field - members_accepted → Custom field - entity_uuid → Custom field

Til WordPress: - cornerstone_group_id → Meta field - clickup_task_id → Meta field - entity_uuid → Meta field - display_name → Post title - telefon, epost, hovedleder, antall_medlemmer → Meta fields

Incremental Sync

Systemet bruker hash-basert endringsdeteksjon: - Beregner hash over alle synced fields - Sammenligner med lagret cornerstone_source_hash - Skipper uendrede entities (hash match) - Oppdaterer last_seen_at timestamp

Dette reduserer unødvendige API-kall og forbedrer ytelsen.

Individual Sync

Enkelt gruppe kan synkroniseres via: - POST /applications/sync-lokallag/{task_id}

Flyt: 1. Hent task data fra ClickUp 2. Sjekk om entity finnes i entity_map 3. Hvis ikke: Opprett ny lokallag i alle systemer 4. Hvis ja: Bruk SyncEngine for å synkronisere

Error Handling

Manglende Cornerstone ID

  • Logger warning til sync_errors
  • Skipper entity (fortsetter med andre)
  • Oppdaterer last_seen_at for debugging

Manglende Cornerstone Payload

  • Group ID finnes i entity_map men ikke i Cornerstone
  • Logger warning med kontekst
  • Registrerer last-seen forsøk

Sync-feil

  • Logger feil med entity-kontekst
  • Fortsetter prosessering av andre entities
  • Oppdaterer ClickUp sync status til 'error'

Monitoring

  • Sporer sync history i sync_history tabell
  • Logger feil med entity-kontekst
  • Oppdaterer entity stamps etter vellykket sync
  • Oppdaterer ClickUp sync status field

Performance

  • Prosesserer entities sekvensielt
  • En enkelt Cornerstone-fetch per run
  • Hash-basert endringsdeteksjon
  • Skipper uendrede entities