Gastverificatieflow
Deze handleiding legt uit hoe je de lijst met aanwezige gasten in een captive portal gebruikt: wat de gast invoert matchen met de lijst, wanneer de wifi-sessie moet eindigen, hoe vaak je de lijst vernieuwt en welke velden je bewaart voor de registratie volgens de Turkse Wet nr. 5651.
Wat je op het portal vraagt#
Omdat de lijst kamer- en identiteitsgegevens samen levert, is het meest gebruikte formulier kamernummer + achternaam. Alleen het kamernummer is niet genoeg; iedereen die het nummer van een naburige kamer kent, zou dan kunnen inloggen. Alternatieven zijn kamernummer + identiteits-/paspoortnummer of achternaam + geboortedatum; houd die laatste achter de hand voor gasten van wie het identiteitsnummer leeg is.
Matchregels#
Normaliseer beide kanten voordat je vergelijkt wat de gast heeft ingevoerd met de waarden in de lijst:
- Kamernummer: verwijder witruimte aan begin en eind en zet om naar hoofdletters.
roomNameis een string (bijvoorbeeld"104","A-12"of"Villa 3"); zet het niet om naar een getal en verwijder geen voorloopnullen. - Achternaam: zet om naar hoofdletters (let op de Turkse omzetting
i → İ) en vervang herhaalde spaties door één spatie. De waarden in de lijst zijn meestal in hoofdletters van het identiteitsbewijs overgenomen. - Identiteitsnummer: verwijder spaties en zet om naar hoofdletters. Een Turks nationaal identiteitsnummer heeft 11 cijfers; een paspoortnummer bestaat uit letters en cijfers.
- Geboortedatum: de lijst geeft
DD.MM.YYYY; zet de waarde om als je formulier een ander formaat gebruikt.
const norm = (s) => String(s ?? "")
.replace(/\s+/g, " ")
.trim()
.toLocaleUpperCase("tr-TR");
function findGuest(list, room, lastName) {
return list.find((g) =>
norm(g.roomName) === norm(room) && norm(g.lastName) === norm(lastName)
) || null;
}
const guest = findGuest(data.otelde, form.room, form.lastName);
if (!guest) {
// "Kamernummer en achternaam komen niet overeen" — tel mislukte pogingen, beperk na 5
}De waarde unique van het gevonden record is de identiteit van de hotspotgebruiker. Logt dezelfde gast in vanaf een tweede apparaat, gebruik dan het account dat aan deze waarde gekoppeld is in plaats van een nieuw account aan te maken, en handhaaf de apparaatlimiet op dat account.
Sessieduur#
checkout is de geplande uitcheckdatum en wijst naar 00:00 (UTC) van die dag; er zit geen tijdstip in. Open je de sessie tot dat moment, dan verliest de gast de toegang in de ochtend van vertrek. Bereken het einde van de sessie door de uitchecktijd van het hotel bij de datum op te tellen:
const CHECKOUT_TIME = "12:00"; // uitchecktijd van het hotel
const day = new Date(guest.checkout * 1000)
.toLocaleDateString("en-CA", { timeZone: "UTC" }); // "2026-09-10"
const sessionEnd = new Date(`${day}T${CHECKOUT_TIME}:00+03:00`);Vertrekt de gast vóór de uitchecktijd, dan verdwijnt hij uit de lijst; sluit het account bij de volgende synchronisatie. Wordt het verblijf verlengd, dan verandert checkout; vergelijk dit veld tijdens de synchronisatie en werk het einde van de sessie bij. Bij laat uitchecken is het veiliger de toegang open te houden zolang de gast in de lijst staat.
Periodieke synchronisatie#
De lijst is een momentopname; er is geen melding bij wijzigingen (webhook). Haal de lijst op met een vast interval en vergelijk hem op unique met de vorige:
- Interval: 5 minuten is voor de meeste hotels genoeg. Moeten gasten direct na het inchecken online kunnen, dan kun je naar 1–2 minuten gaan; ga niet onder 1 minuut.
- Nieuwe
unique: bereid het account voor; de gast wordt bij de eerste login op het portal gematcht. - Ontbrekende
unique: de gast is uitgecheckt of de reservering is geannuleerd. Beëindig de sessie en sluit het account. - Zelfde
unique, andereroomNameofcheckout: een kamerwissel of een verlenging. Werk het account bij. - Mislukt verzoek: bij een time-out,
401of5xxbehoud je de laatste geslaagde lijst; sluit nooit accounts op basis van een foutantwoord.
async function sync(prev) {
const res = await fetch(BASE + "/public/json/customer/inhotel", {
method: "POST",
headers: { "ApiKey": process.env.HMS_API_KEY, "HotelCode": HOTEL_CODE }
});
if (!res.ok) return prev; // 401 / 5xx: oude lijst behouden
const { success, otelde } = await res.json();
if (success !== 1) return prev;
const next = new Map(otelde.map((g) => [g.unique, g]));
for (const [id] of prev) {
if (!next.has(id)) await closeAccount(id); // uitgecheckt
}
for (const [id, g] of next) {
const old = prev.get(id);
if (!old) await openAccount(g); // nieuwe gast
else if (old.checkout !== g.checkout || old.roomName !== g.roomName) await updateAccount(g);
}
return next;
}Meerdere gasten in één kamer#
Elke gast in een kamer is een apart record: rezervasyon_id is gelijk, unique verschilt. Open accounts per gast in plaats van per kamer, zodat elke gast een eigen apparaat, sessie en registratie volgens Wet nr. 5651 heeft. Een zoekopdracht op kamernummer + achternaam kan bij gasten met dezelfde achternaam (een gezin) meer dan één record opleveren; neem dan niet zomaar de eerste match, maar maak onderscheid op voornaam of geboortedatum, of open een gedeeld account voor hen.
Registratie volgens Wet nr. 5651#
De verplichting om toegangslogs bij te houden volgens de Turkse Wet nr. 5651 ligt bij het hotspotsysteem; HMS levert alleen de identiteitsgegevens. Sla bij het openen van een sessie de volgende velden op, samen met het MAC-/IP-adres en de timestamp: unique, rezervasyon_id, firstName, lastName, identityNumber, birthDate, roomName, checkin, checkout. Zodra een gast uit de lijst verdwijnt, levert HMS deze gegevens niet meer; bewaar het record aan jouw kant.