LCTX
Globe Tracker.
Why it exists
Pazator ingests structured entity data, but location data is fundamentally different — it's continuous, time-bound, and comes from a completely separate pipeline (GPS pings, cell tower logs, etc.). The LCTX tracker keeps location data separate from entity profiles, linked only by a shared alias. This means you can have rich location history for a person without polluting the entity data model with hundreds of timestamped coordinates.
The globe visualisation gives you a "God's eye" view — satellite imagery, path lines, and automatic spin so you can watch movement patterns emerge without touching the keyboard.
Architecture
The tracker runs on a Supabase backend with a single locations
table. Pazator connects via the Supabase JavaScript client with an anon key — no server-side
middleware needed. Configuration is stored in localStorage.LCTXTrackerConfig
and can be set through the "Configure tracker server" button in the tracker tab.
Supabase locations table schema
id uuid / serial (primary key) name text (person alias, used for linking) latitude float8 longitude float8 timestamp timestamptz ip text region text country text device text platform text user_agent text speed float8 heading float8
How It Works
1. Configuration
Click "Configure tracker server" to enter your Supabase project URL and anon key. The key is
stored in localStorage and used to create a Supabase client via
supabase.createClient(url, key). The tracker won't initialise until
valid credentials are provided. On first visit, it prompts automatically.
2. Loading people
On map load, fetchTrackerPeople() queries the locations
table with .select('name').order('timestamp', { ascending: false }),
then groups by name with a point count. The result is rendered as a list in the sidebar —
each item shows the name and number of data points.
3. Viewing a person's path
Click a person in the sidebar. showTrackerPersonLocations(name) fetches
all rows for that name sorted ascending by timestamp, then:
- Adds a LineString GeoJSON source (
tracker-path) for the path trace - Adds a Point GeoJSON source (
tracker-markers) for individual pings flyTo()the latest coordinate at zoom 15, pitch 60- Reverse-geocodes the latest point via Nominatim and displays the address + available metadata (IP, device, platform, country, region)
4. Globe controls
- Spin — continuous
requestAnimationFramerotation at configurable degrees/second (default 10°/s, max 60). Speed persisted across sessions. - Street labels — toggles an OSM raster overlay on top of the satellite imagery.
- Angle / Top-down — sets pitch to 60° (isometric) or 0° (flat).
- Reset view — flyTo [0,0] at zoom 2, pitch 60, bearing 0.
- Filter toggle — visual CSS filter toggle on the map container (presentational, not a query filter).
5. Person linking
The tracker integrates with Pazator's entity model. You can connect a human entity to a tracker
alias from the tracker tab itself (using the "Connect" dropdown), or from the entity detail slide
panel. When linked, the human record gets trackerAlias and
trackerLinkedAt fields. The detail panel then shows the latest known
location for that alias, fetched live from Supabase.
Debug & Status
A #trackerDebug status line at the bottom of the sidebar shows what the tracker is
doing: "Fetching tracker people...", "Found 1420 tracker points across 34 people.", or "Tracker
disabled until you configure a Supabase connection." This is the main feedback channel since
Supabase operations are async.
Danger Zone
The "Purge" button calls purgeTrackerData() which fires a
DELETE FROM locations WHERE id != 0 on Supabase after a confirmation
dialog. No undo.
What's Missing
No real-time subscriptions. The tracker polls Supabase on demand — it doesn't use Supabase's real-time features at all. Location history for linked entities is limited to the latest point; there's no timeline view showing all historical pings for a linked human. The tracker also doesn't push location updates to the entity graph or trigger alerts on proximity or geofence events.
Reverse geocoding is done client-side via Nominatim's free API, which has usage limits and no caching. If you click through many people in quick succession, you'll get HTTP 429 responses.