Two PCs exchanging changes through a folder must be able to name the SAME contact in both logs. "the QSO with M0ABC at 14:32" is a guess and the two machines can disagree about which row that is, so an edit or a deletion cannot be addressed at all without an identity that travels with the record. A real indexed column, not a key inside extras_json: the identity is resolved once per incoming change, and scanning JSON for it would turn every sync into a full read of a 120 000-QSO logbook. A column costs one migration; the JSON would cost a scan every time. That was the decision to confirm, and it is confirmed. It follows the award_refs pattern — read in selectCols, absent from columnList, written only through its own methods. So an ordinary edit cannot clobber it, which matters: another machine addresses the contact by that id, and losing it makes the same QSO arrive again as a new one. Pinned by a test that saves an edit with the field deliberately blanked. Existing contacts are stamped in batches inside one transaction rather than one commit each — on a remote MySQL the round trip dominates, and 120 000 commits is the difference between a minute and an afternoon. And a dedupe-key map lets two machines that already hold the same imported log recognise each other's contacts instead of copying 120 000 of them across. MySQL nearly lost its logbook to this. It cannot index a TEXT column without a prefix length: the migration would fail with error 1170 and fail again on every startup, with no way out from the interface. The translator only emits VARCHAR for names listed by hand in varcharColumns. sync_uid is now listed — and a test reads the migrations, works out which indexed columns are TEXT, and fails if the list does not cover them, so the next one cannot reach a shared logbook.
4.3 KiB
4.3 KiB
QRZ.com XML API — what a free account returns, and what a subscription adds
Captured 2026-08-02 on F4BPO's two accounts, same callsign looked up twice within a minute. Kept because the difference is the answer to a question that comes back regularly: "someone told me their logger gets the 6-character locator from QRZ without paying". It does not.
Free account — SubExp: non-subscriber
<Callsign>
<call>F4BPO</call>
<fname>Gregory</fname>
<name>Salaun</name>
<addr2>Veigy-Foncenex</addr2>
<country>France</country>
</Callsign>
<Session>
<SubExp>non-subscriber</SubExp>
<Message>A subscription is required to access the complete record.</Message>
</Session>
Five fields. No grid, no lat/lon, no dxcc, no zones, no email, no
street, no image.
Subscriber — SubExp: Sat Jul 3 21:45:38 2027
<Callsign>
<call>F4BPO</call> <dxcc>227</dxcc> <nickname>Greg</nickname>
<fname>Gregory</fname> <name>Salaun</name>
<addr2>Veigy-Foncenex</addr2><zip>74140</zip> <country>France</country>
<lat>46.103333</lat> <lon>6.290000</lon> <grid>JN36dc</grid>
<ccode>97</ccode> <land>France</land> <class>2</class>
<codes>E</codes> <qslmgr>Lotw, Buro, Direct</qslmgr>
<email>…</email> <u_views>56966</u_views>
<bio>4414</bio> <biodate>2026-07-08 15:30:58</biodate>
<image>https://cdn-xml.qrz.com/o/f4bpo/F4BPO_Greg_png.jpg</image>
<imageinfo>800:1200:221041</imageinfo>
<moddate>2025-08-24 19:55:31</moddate>
<eqsl>0</eqsl> <mqsl>1</mqsl> <lotw>1</lotw>
<cqzone>14</cqzone> <ituzone>27</ituzone>
<geoloc>user</geoloc> <name_fmt>Gregory "Greg" Salaun</name_fmt>
<serial>1000134</serial>
</Callsign>
<QRZDatabase xmlns="http://xmldata.qrz.com" version="1.36">
<div id="in-page-channel-node-id" data-channel-name="in_page_channel_ogW01U"/>
<Callsign>
<call>F5IRH</call>
<dxcc>227</dxcc>
<fname>AVRILLON</fname>
<name>Max</name>
<addr1>La Grand Prairie</addr1>
<addr2>Le Palais BELLE-ILE-EN-MER</addr2>
<zip>56360</zip>
<country>France</country>
<lat>47.339686</lat>
<lon>-3.156500</lon>
<grid>IN87ki</grid>
<ccode>97</ccode>
<land>France</land>
<codes>TP</codes>
<qslmgr>VIA BURO</qslmgr>
<email>[email protected]</email>
<u_views>8005</u_views>
<bio>2463</bio>
<biodate>2015-07-16 00:29:49</biodate>
<image>https://cdn-xml.qrz.com/h/f5irh/qsl_F5IRH_111-3.JPG</image>
<imageinfo>518:799:105108</imageinfo>
<moddate>2010-08-05 01:05:37</moddate>
<eqsl>0</eqsl>
<mqsl>0</mqsl>
<cqzone>14</cqzone>
<iota>EU-048</iota>
<lotw>0</lotw>
<geoloc>user</geoloc>
<name_fmt>AVRILLON Max</name_fmt>
<serial>1570698</serial>
</Callsign>
<Session>
<Key>e5ca5b3e7f88d733408ab7677e605270</Key>
<Count>161639</Count>
<SubExp>Sat Jul 3 21:45:38 2027</SubExp>
<GMTime>Sun Aug 16 21:14:40 2026</GMTime>
<Remark>cpu: 0.073s</Remark>
</Session>
</QRZDatabase>
Consequences
- A free QRZ account can never fill the locator, the coordinates, the zones
or the e-mail. If someone reports a logger doing it on a free account, they
are either using HamQTH (free, returns a 6-character
grid) or they hold an XML subscription without realising it — the QRZ.com account and the "XML Logbook Data" subscription are sold separately.SubExpin the session block settles it in one request. - Profile edits take a few minutes to reach the XML feed. Changing the grid on the website and looking the callsign up immediately returns the OLD value, which looks exactly like a stale cache. Re-test after a few minutes before suspecting the logger. (This cost an hour on 2026-08-02.)
Fields OpsLog does not use yet
qrz.go maps call, name, addr1/2, zip, state, county, country, grid, lat, lon,
dxcc, cqzone, ituzone, cont, email, qslmgr and image. Left on the table:
geoloc—userwhen the operator entered the position by hand, versus a geocoded value derived from the postal address. This is a direct statement of how much the coordinates and the locator can be trusted, and it is exactly the question the grid-precision rule in App.tsx tries to answer by comparing string lengths. Worth wiring if the locator ever misbehaves again.eqsl/mqsl/lotw— the station's QSL preferences as flags, more reliable than parsing the free-textqslmgr.nickname/name_fmt,class,moddate,bio.