Datasynk og cache

Hvorfor cache brukes

For å gi raske svar og redusere databasebelastning, bygges en lokal JSON-cache per klubb.

Synkprosess

  1. Les master-DB (Clubs-tabell)
  2. Finn alle klubber med DB-tilkobling
  3. Koble til hver klubbdatabase
  4. Hent data fra tillatte tabeller
  5. Rens tomme felt og serialiser verdier
  6. Skriv cachefil: cache/<KLUBB>_context.json

Godkjent datakilde-liste til JSON-cache

Dette er fasit for hva som skal hentes til cache i V1-oppsett/drift.

Kilde 1 - Master (hvilke klubber som synkes)

  • Database: master-databasen konfigurert via miljøvariabler.
  • Tabell: Clubs.
  • Felter brukt for synk:
    • clubFolder
    • dbName
    • dbUser
    • dbPwd
  • Synk skjer kun for rader der dbName og dbUser finnes.

Kilde 2 - Klubbdatabase (tillatt tabelliste)

Kun tabellene under er tillatt i cache-bygging:

  1. Activities
  2. Activities_PriceGroups
  3. Activities_Prices
  4. Contacts
  5. Course_Guide_Hole
  6. Courses
  7. Courses_Par
  8. Courses_Tees
  9. Departments
  10. Documents
  11. FAQ
  12. Functions
  13. Memberships
  14. Memberships_Vtg
  15. News
  16. Pages
  17. Pro_Register
  18. Restaurant_Menuitems
  19. Setup_Basic
  20. Shop_Products
  21. Status_CourseClub
  22. Status_Info
  23. Statusboard
  24. Tournaments

Filer og mapper i flyten

  • Synk alle klubber: api/sync_worker.py
  • Synk testklubb (SKI): api/sync_worker_ski_only.py
  • Cachemål: api/cache/{clubFolder}_context.json
  • Prompt bygger fra cache: api/app.py

SQL-sporringer i synk (for belastningssjekk)

Denne seksjonen beskriver hvilke SQL-sporringer scriptet faktisk kjører, og hvorfor de normalt ikke skal belaste SQL unodvendig.

1) Master-oppslag av klubber

Kjøres i sync_worker.py før synk starter:

SELECT clubFolder, dbName, dbUser, dbPwd
FROM Clubs
WHERE dbName IS NOT NULL
    AND dbUser IS NOT NULL

Kjøres i sync_worker_ski_only.py for testklubb:

SELECT clubFolder, dbName, dbUser, dbPwd
FROM Clubs
WHERE clubFolder = ?
    AND dbName IS NOT NULL
    AND dbUser IS NOT NULL

Belastning: - Liten tabell i master-DB. - Ingen join-operasjoner. - Lett å indeksere på clubFolder ved behov.

2) Eksistenssjekk per tillatt tabell

For hver tabell i allowlist kjøres en rask metadata-sjekk:

SELECT 1
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = '<table_name>'

Belastning: - Treffer metadata, ikke store datamengder. - Brukes for å unngå feil mot klubber med ulike skjema-versjoner.

3) Datauthenting per tabell (med hard cap)

Når tabellen finnes, hentes et begrenset antall rader:

  • Kurs-tabeller (Course*):
SELECT TOP 300 * FROM <table_name>
  • Tidsstyrte innholdstabeller (News, Activities, Tournaments, Pages, Documents):
SELECT TOP 15 *
FROM <table_name>
ORDER BY 1 DESC
  • Øvrige tillatte tabeller:
SELECT TOP 50 * FROM <table_name>

Belastning: - TOP begrenser lesning og nettverkstrafikk. - Unngår full tabellscan av store historiske tabeller i normal drift.

Hvorfor dette normalt er skånsomt mot SQL

  1. Ingen tunge joins i synk-script.
  2. Hard begrensning på antall rader per tabell.
  3. Kjøres batch-vis (typisk nattlig), ikke kontinuerlig.
  4. SKI-only script finnes for trygg testing uten full flerklubb-belastning.

Risiko og anbefalte forbedringer

Følgende punkter er viktige for ekstra trygghet:

  1. ORDER BY 1 DESC er teknisk fallback og kan sortere på feil kolonne i noen tabeller.
  2. Uten eksplisitt dato-kolonne kan gamle rader i verste fall bli valgt som "siste".
  3. SELECT * henter flere kolonner enn nødvendig.

Anbefalt forbedring (neste steg):

  1. Definer per tabell hvilken dato/versjonskolonne som er fasit for "nyeste".
  2. Bytt ut ORDER BY 1 DESC med eksplisitt ORDER BY <datofelt> DESC.
  3. Innfør valgfri tidsgrense (for eksempel kun siste 6-12 måneder) for nyheter og aktiviteter.
  4. Vurder å hente eksplisitt kolonneliste i stedet for * for de største tabellene.

Datavern og blokkering

Ikke tillatt i cache-kontekst til AI

  • Private kontaktfelt utenfor Setup_Basic, inkludert feltnavn som inneholder:
    • epost, email, mail
    • telefon, phone, mobil, tlf

Felter som filtreres bort som standard støy/internt

  • Feltnavn som inneholder id
  • date_created
  • created_by
  • modified_by
  • sortnum
  • boolarchive

Prinsipp

  • Setup_Basic er unntaket for offisiell klubbkontakt.
  • Private persondata skal ikke eksponeres i chat-svar.

Regler for ferskeste informasjon (anti-gammel-data)

Målet er å hindre at gamle priser/nyheter får høyere vekt enn fersk status.

Prioritet 1 - Driftsstatus

  • Ved spørsmål om banestatus skal Setup_Basic.course_condition brukes som primær sannhet.
  • Gyldighetsfelt ccond_validfrom og ccond_validto skal tolkes sammen med statusen.
  • Dersom News/Pages motsier dette, skal course_condition vinne.

Prioritet 2 - Tidsstyrt innhold

  • For nyheter, aktiviteter, turneringer, sider og dokumenter brukes et begrenset sett ferske rader i cache.
  • Dagens tekniske fallback er TOP 15 med ORDER BY 1 DESC.

Prioritet 3 - Stamdata/priser

  • Stamdata (kurs, medlemskap, shop, menyer) brukes som faktagrunnlag, men må ikke overstyre prioritet 1 ved konflikt.
  • Hvis prisinnhold mangler tydelig gyldighetsdato, skal svar være forsiktige og be om dobbeltsjekk ved tvil.

Anbefalt hard-regel for rekkefølge (for utvikler)

For tabeller med tidsdata skal sortering være eksplisitt etter dato-felt, ikke ORDER BY 1 alene. Anbefalt sortering i prioritert rekkefølge:

  1. valid_from eller publish_from (DESC)
  2. publish_date, news_date, event_date (DESC)
  3. modified_date eller updated_at (DESC)
  4. Primærnøkkel-ID (DESC) kun som siste fallback

Dette skal dokumenteres per tabell før utrulling til flere klubber.

Viktig driftsregel

  • Produksjon skal bruke sync_worker.py (alle klubber)
  • SKI-only script er kun for lokal test

Driftsfrekvens

Anbefalt:

  • Nattlig synk via Scheduled Task
  • Manuell synk etter store admin-endringer

Kvalitetskontroll

  • Kontroller last_updated i cache metadata
  • Verifiser at kritiske felter finnes (setup_basic, banestatus)