Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
- **api:** fail closed auth gate and secure exports ([b11cbf7](https://github.com/cyclonite69/shadowcheck-web/commit/b11cbf774205eaf9eaca7707d175620399e294de))
- **api:** make v2 filtered manufacturer fields schema-compatible and add regression tests ([2bd4e9f](https://github.com/cyclonite69/shadowcheck-web/commit/2bd4e9fa73a3b63c2f43cf48fc50ffdb0ffe26c9))
- **api:** normalize OBS radio_type values in radio filter expression ([d51065e](https://github.com/cyclonite69/shadowcheck-web/commit/d51065e965a92b76b2058cfbb6866bc759d8200e))
- **api:** normalize observations endpoint timestamp type to float8 ([519bd4a](https://github.com/cyclonite69/shadowcheck-web/commit/519bd4a41a55233d52e956c8403983593377db5c))
- **api:** optimize filtered network-only queries and notes predicate ([782e59d](https://github.com/cyclonite69/shadowcheck-web/commit/782e59dfd342be44af8b8de63b1244c4dda7b52d))
- **api:** prevent filtered dashboard metrics fallback to zeros ([7a0c94f](https://github.com/cyclonite69/shadowcheck-web/commit/7a0c94fb5dc2c69343f8314b69fb5724641c8ca0))
- **api:** qualify sort columns with ne. alias to prevent 500 ambiguity errors ([dbf0db2](https://github.com/cyclonite69/shadowcheck-web/commit/dbf0db21f582d06af77b08362c47750a37ed9aec))
Expand Down Expand Up @@ -234,7 +235,7 @@
- **deps:** bump axios to 1.15.0 ([494b337](https://github.com/cyclonite69/shadowcheck-web/commit/494b3376f5326ae01500b4288153429a5f507b1d))
- **deps:** downgrade @vitejs/plugin-react to 5.0.3 to fix Node 22 build failure ([a539ad9](https://github.com/cyclonite69/shadowcheck-web/commit/a539ad9af823c8467e16e9227523ce0d57612d81))
- **deps:** pin fast-xml-parser to 5.5.8 to restore AWS SDK XML parsing ([0942fac](https://github.com/cyclonite69/shadowcheck-web/commit/0942fac65022e0929fc37a047d44b26d153fbd08)), closes [#xD](https://github.com/cyclonite69/shadowcheck-web/issues/xD)
- **deps:** restore @playwright/test (lost during react-dom merge conflict resolution) ([09474d1](https://github.com/cyclonite69/shadowcheck-web/commit/09474d1490b99fd67ffb2a646f6f3110fb884820))
- **deps:** restore @playwright/test (lost during react-dom merge conflict resolution) ([aa983f6](https://github.com/cyclonite69/shadowcheck-web/commit/aa983f68dbd30f337017d9b65de17ba50cfef857))
- **dev:** add docker-cli, aws-cli, postgresql-client, curl to Dockerfile builder stage ([23b0399](https://github.com/cyclonite69/shadowcheck-web/commit/23b03991276bafe870e0870fa1a5380b7c549a01))
- **dev:** set REDIS_HOST=redis in dev compose to fix api_dev DNS resolution ([cc631ab](https://github.com/cyclonite69/shadowcheck-web/commit/cc631abe0b824c4becff04c34a4df10c337d69b1))
- disable weather routes to unblock server startup ([c853217](https://github.com/cyclonite69/shadowcheck-web/commit/c85321793ed0af677410ac260dbdf9cd1fa00d89))
Expand Down Expand Up @@ -1015,6 +1016,7 @@
- **wigle:** restore tooltip on WiGLE v2 and v3 map point click ([fe66827](https://github.com/cyclonite69/shadowcheck-web/commit/fe66827c63b4a1b01d3d7c65fee45881c8163bb2))
- **wigle:** restore v2/v3 toggle refresh and add encryption filtering ([8016359](https://github.com/cyclonite69/shadowcheck-web/commit/801635931a8d15d215c505de16192552248a4b10))
- **wigle:** restore WiGLE-only and local-match badges on map tooltips ([4b84f0d](https://github.com/cyclonite69/shadowcheck-web/commit/4b84f0d54d2e941b9d2e3cfcc1d09f24b4080060))
- **wigle:** return numeric epoch times for Explorer WiGLE observations ([e3cdff6](https://github.com/cyclonite69/shadowcheck-web/commit/e3cdff60538888562095d2105da33f149e3cf6ca))
- **wigle:** run import loop in background to prevent HTTP 504 timeouts ([4c7aba3](https://github.com/cyclonite69/shadowcheck-web/commit/4c7aba3bf255ea38b4773c2dae80b1daec84e496))
- **wigle:** seed field data bssids when wigle datasets are off ([3e33420](https://github.com/cyclonite69/shadowcheck-web/commit/3e33420b848c91033d5c7008f51b2b1e648eadbf))
- **wigle:** serve cached detail before live lookup ([e86cb52](https://github.com/cyclonite69/shadowcheck-web/commit/e86cb52ef3506ab988727f67e7d9fe8d349bdb1c))
Expand Down
58 changes: 3 additions & 55 deletions client/src/components/wigle/mapHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const attachClickHandlers = (
if (!props || !e.lngLat) return;

const netid = String(props.netid || props.bssid || '');

const featureData: Record<string, any> = {
...(props as Record<string, any>),
netid: String(props.netid || props.bssid || ''),
Expand All @@ -32,28 +33,7 @@ export const attachClickHandlers = (
wigle_source: props.wigle_source === 'wigle-v3' ? 'wigle-v3' : 'wigle-v2',
};

// ── INSTRUMENTATION: Stage 1 — feature properties at click ──────────────
console.log('[popup:1:feature]', netid, {
lasttime: featureData.lasttime,
observed_at: featureData.observed_at,
first_seen: featureData.first_seen,
last_seen: featureData.last_seen,
wigle_v3_first_seen: featureData.wigle_v3_first_seen,
wigle_v3_last_seen: featureData.wigle_v3_last_seen,
wigle_source: featureData.wigle_source,
});

const initialNormalized = normalizeTooltipData(featureData, [e.lngLat.lng, e.lngLat.lat]);

// ── INSTRUMENTATION: Stage 2 — normalizer output for initial render ──────
console.log('[popup:2:initial-normalized]', netid, {
time: initialNormalized.time,
first_seen: initialNormalized.first_seen,
last_seen: initialNormalized.last_seen,
timespan_days: initialNormalized.timespan_days,
wigle_observation_count: initialNormalized.wigle_observation_count,
});

const initialHTML = renderNetworkTooltip(initialNormalized);

const anchor = getPopupAnchor(map, e.lngLat, initialHTML);
Expand All @@ -77,15 +57,6 @@ export const attachClickHandlers = (

const { wigle, localLinkage } = pageResponse;

// ── INSTRUMENTATION: Stage 3 — raw enrichment API response ─────────
console.log('[popup:3:api-response]', netid, {
wigle_v3_first_seen: wigle.wigle_v3_first_seen,
wigle_v3_last_seen: wigle.wigle_v3_last_seen,
wigle_v3_observation_count: wigle.wigle_v3_observation_count,
wigle_v2_lasttime: wigle.wigle_v2_lasttime,
wigle_v2_lastupdt: wigle.wigle_v2_lastupdt,
wigle_source: wigle.wigle_source,
});
// Build merged object: WiGLE-truth fields from structured `wigle` section only.
// Local linkage maps to the existing flat fields the normalizer already reads.
const mergedData: Record<string, any> = {
Expand Down Expand Up @@ -148,33 +119,10 @@ export const attachClickHandlers = (
local_last_seen: localLinkage.local_last_seen,
};

// ── INSTRUMENTATION: Stage 4 — mergedData before normalizer ────────
console.log('[popup:4:merged]', netid, {
lasttime: mergedData.lasttime,
observed_at: mergedData.observed_at,
wigle_v3_first_seen: mergedData.wigle_v3_first_seen,
wigle_v3_last_seen: mergedData.wigle_v3_last_seen,
wigle_v2_lasttime: mergedData.wigle_v2_lasttime,
timespan_days: mergedData.timespan_days,
wigle_v3_observation_count: mergedData.wigle_v3_observation_count,
});

const enrichedNormalized = normalizeTooltipData(mergedData);

// ── INSTRUMENTATION: Stage 5 — normalizer output for enriched render
console.log('[popup:5:enriched-normalized]', netid, {
time: enrichedNormalized.time,
first_seen: enrichedNormalized.first_seen,
last_seen: enrichedNormalized.last_seen,
timespan_days: enrichedNormalized.timespan_days,
wigle_observation_count: enrichedNormalized.wigle_observation_count,
});

popup.setHTML(renderNetworkTooltip(enrichedNormalized));
popup.setHTML(renderNetworkTooltip(normalizeTooltipData(mergedData)));
})
.catch((err) => {
// ── INSTRUMENTATION: enrichment request failure ────────────────────
console.warn('[popup:enrichment-failed]', netid, err);
console.warn('[wigle-tooltip] enrichment fetch failed', err);
});
}

Expand Down
3 changes: 3 additions & 0 deletions docs/API_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ List networks with pagination and filtering.

Get all observations for a network.

**Response:** `observations[].time` is a JavaScript-safe numeric epoch timestamp in
milliseconds.

### GET /api/networks/search/:ssid

Search by SSID.
Expand Down
38 changes: 20 additions & 18 deletions docs/ai/decisions/20260707_vite_build_mode_nodejs_env_bleed.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ by `process.env.NODE_ENV` in the Vite process itself at build time. From Vite 8'
(`node_modules/vite/dist/node/chunks/node.js`):

```javascript
const isProduction = process.env.NODE_ENV === "production";
const isProduction = process.env.NODE_ENV === 'production';
```

`isProduction` controls the `DEV` and `PROD` values baked into the bundle.
Expand All @@ -51,10 +51,10 @@ console.log('[ENV_PROBE]', {

Two builds, different `NODE_ENV`, identical `--mode production`:

| Build command | Compiled output |
|---|---|
| Build command | Compiled output |
| --------------------------------------------------- | ---------------------------------------------- |
| `NODE_ENV=development vite build --mode production` | `{DEV: true, PROD: false, MODE: "production"}` |
| `NODE_ENV=production vite build --mode production` | `{DEV: false, PROD: true, MODE: "production"}` |
| `NODE_ENV=production vite build --mode production` | `{DEV: false, PROD: true, MODE: "production"}` |

The second build also correctly eliminated the `window.__wigleHandleUnclustered` assignment
from the bundle. The first did not.
Expand All @@ -77,7 +77,7 @@ eliminated and the assignment became a bare statement in every production Docker

```javascript
// Minified output (production container) — NO guard, NO if()
window.__wigleHandleUnclustered=i;
window.__wigleHandleUnclustered = i;
```

`window.__wigleHandleUnclustered` has been exposed on the global window object in every
Expand All @@ -90,7 +90,7 @@ const isDev = import.meta.env.DEV;

function shouldLog(level: LogLevel) {
if (levelOrder[level] < minLevel) return false;
if (!isDev && (level === 'debug' || level === 'info')) return false; // ← suppressed in prod
if (!isDev && (level === 'debug' || level === 'info')) return false; // ← suppressed in prod
return true;
}
```
Expand All @@ -109,8 +109,8 @@ Note: `debug` logs were already suppressed regardless of `DEV` — the first gua
Both use a double gate:

```typescript
import.meta.env.DEV && import.meta.env.VITE_SIBLING_TOPOLOGY_DEBUG === 'true'
import.meta.env.DEV && import.meta.env.VITE_SIBLING_DEBUG === 'true'
import.meta.env.DEV && import.meta.env.VITE_SIBLING_TOPOLOGY_DEBUG === 'true';
import.meta.env.DEV && import.meta.env.VITE_SIBLING_DEBUG === 'true';
```

The second operand (`=== 'true'`) evaluated to `false` because neither env var is set by
Expand Down Expand Up @@ -139,10 +139,10 @@ not independently confirm which value was substituted for `DEV`.
A temporary `console.log` of `import.meta.env.DEV/PROD/MODE` was added to `mapHandlers.ts`
and two builds were compared:

| Build command | Compiled output |
|---|---|
| Build command | Compiled output |
| --------------------------------------------------- | ---------------------------------------------- |
| `NODE_ENV=development vite build --mode production` | `{DEV: true, PROD: false, MODE: "production"}` |
| `NODE_ENV=production vite build --mode production` | `{DEV: false, PROD: true, MODE: "production"}` |
| `NODE_ENV=production vite build --mode production` | `{DEV: false, PROD: true, MODE: "production"}` |

The second build also eliminated the `window.__wigleHandleUnclustered` assignment from the
bundle. The first did not.
Expand All @@ -156,9 +156,11 @@ can be updated from "evidence indicates" to "confirmed by rebuilt artifact."

**4. Vite 8 source confirms the mechanism.**
`node_modules/vite/dist/node/chunks/node.js` line ~34582:

```javascript
const isProduction = process.env.NODE_ENV === "production";
const isProduction = process.env.NODE_ENV === 'production';
```

`isProduction` controls the `DEV`/`PROD` values baked into the bundle. `--mode production`
sets `MODE` and loads `.env.production` files but does not set `process.env.NODE_ENV`.
These are independent concerns in Vite 8's internals.
Expand Down Expand Up @@ -208,12 +210,12 @@ invocation only, not to the entire stage.

## Blast radius of the fix

| Location | Current behavior (broken) | Fixed behavior | Impact |
|---|---|---|---|
| `mapHandlers.ts` | `window.__wigleHandleUnclustered` exposed unconditionally | Eliminated from bundle (dead code) | Seam removed from production |
| `clientLogger.ts` | `info` logs fire in production console | `info` logs suppressed in production | Production console quieter |
| `siblingTopologyDebug.ts` | No change (double-gated, already off) | No change | None |
| `NetworkExplorerSection.tsx` | No change (double-gated, already off) | No change | None |
| Location | Current behavior (broken) | Fixed behavior | Impact |
| ---------------------------- | --------------------------------------------------------- | ------------------------------------ | ---------------------------- |
| `mapHandlers.ts` | `window.__wigleHandleUnclustered` exposed unconditionally | Eliminated from bundle (dead code) | Seam removed from production |
| `clientLogger.ts` | `info` logs fire in production console | `info` logs suppressed in production | Production console quieter |
| `siblingTopologyDebug.ts` | No change (double-gated, already off) | No change | None |
| `NetworkExplorerSection.tsx` | No change (double-gated, already off) | No change | None |

The logger change is a behavioral change that ops/dev users may notice (production browser
console loses `[INFO]` output). This is the intended behavior that has never correctly
Expand Down
8 changes: 4 additions & 4 deletions docs/metrics/lines-of-code.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# LOC Metrics

_Generated: Wed Jul 8 03:16:41 PM EDT 2026 | SHA: 09474d14_
_Generated: Wed Jul 8 05:58:18 PM EDT 2026 | SHA: 2ff30228_

| cloc | github.com/AlDanial/cloc v 2.06 T=3.99 s (462.8 files/s, 161808.9 lines/s) |
| cloc | github.com/AlDanial/cloc v 2.06 T=4.35 s (425.1 files/s, 148577.8 lines/s) |
| ---- | -------------------------------------------------------------------------- |

| Language | files | blank | comment | code |
| :--------- | -------: | -------: | -------: | -------: |
| SQL | 340 | 4533 | 6245 | 414867 |
| TypeScript | 1474 | 24231 | 8284 | 182592 |
| TypeScript | 1475 | 24245 | 8301 | 182694 |
| JavaScript | 32 | 486 | 237 | 3908 |
| CSS | 1 | 47 | 27 | 276 |
| -------- | -------- | -------- | -------- | -------- |
| SUM: | 1847 | 29297 | 14793 | 601643 |
| SUM: | 1848 | 29311 | 14810 | 601745 |
5 changes: 3 additions & 2 deletions docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1175,8 +1175,9 @@ components:
signal:
type: integer
time:
type: integer
format: int64
type: number
format: double
description: Epoch timestamp in milliseconds, returned as a JSON number.
acc:
type: number
alt:
Expand Down
8 changes: 4 additions & 4 deletions server/src/api/routes/v1/wigle/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ const validateWigleNetworksQuery = validateQuery({
* the wigle_networks_enriched view for v2-only imports.
*/
router.get(
'/page/network/:netid',
'/page/network/:bssid',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The route param was renamed from :netid to :bssid here, but the corresponding references in client/src/config/apiTestEndpoints.ts, docs/API_REFERENCE.md, docs/api/route-inventory.md, and tests/unit/wigleDatabase.test.ts still use :netid. While the URL path itself is unchanged (so clients still work), the inconsistency across the codebase will confuse future maintainers and may cause test/config mismatches if someone searches by param name.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/src/api/routes/v1/wigle/database.ts, line 73:

<comment>The route param was renamed from `:netid` to `:bssid` here, but the corresponding references in `client/src/config/apiTestEndpoints.ts`, `docs/API_REFERENCE.md`, `docs/api/route-inventory.md`, and `tests/unit/wigleDatabase.test.ts` still use `:netid`. While the URL path itself is unchanged (so clients still work), the inconsistency across the codebase will confuse future maintainers and may cause test/config mismatches if someone searches by param name.</comment>

<file context>
@@ -70,15 +70,15 @@ const validateWigleNetworksQuery = validateQuery({
  */
 router.get(
-  '/page/network/:netid',
+  '/page/network/:bssid',
   macParamMiddleware,
   asyncHandler(async (req: Request, res: Response) => {
</file context>

macParamMiddleware,
asyncHandler(async (req: Request, res: Response) => {
const { netid } = req.params;
const { bssid } = req.params;
// Try MV first (single-row read); fall back to live 4-query fan-out if MV
// is unavailable (pre-migration deployment) or returns no row.
let network = await wigleService.getWiglePageNetworkFromMv(netid);
let network = await wigleService.getWiglePageNetworkFromMv(bssid);
if (!network) {
network = await wigleService.getWiglePageNetwork(netid);
network = await wigleService.getWiglePageNetwork(bssid);
Comment on lines +73 to +81

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Cross-file contract drift: param rename not propagated to client config, docs, or route inventory.

The route param rename from :netid to :bssid is server-internal and doesn't change the URL path, so existing clients continue to work. However, multiple downstream artifacts still reference :netid:

  • client/src/config/apiTestEndpoints.ts:1081-1086 — path and params still use netid
  • docs/API_REFERENCE.md:943-951 — documents :netid
  • docs/api/route-inventory.md:306-310 — lists :netid
  • tests/unit/wigleDatabase.test.ts:52-63 — describe block still uses :netid

Per coding guidelines, every endpoint requires an entry in client/src/config/apiTestEndpoints.ts and a JSDoc comment on the route handler. While the JSDoc was updated, the client config and documentation were not, creating inconsistency that will confuse future maintainers and API consumers.

As per coding guidelines: "Every new endpoint requires: entry in client/src/config/apiTestEndpoints.ts, JSDoc comment on route handler, and note in relevant docs/schema/ file if touching DB schema."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/api/routes/v1/wigle/database.ts` around lines 73 - 81, The route
handler now uses the updated `:bssid` parameter in `wigle/database.ts`, but the
client-facing and documentation artifacts still reference `:netid`. Propagate
the rename in `client/src/config/apiTestEndpoints.ts`, `docs/API_REFERENCE.md`,
`docs/api/route-inventory.md`, and the `tests/unit/wigleDatabase.test.ts`
describe block so all endpoint metadata stays consistent with the `page/network`
route and its `macParamMiddleware`/handler contract. Ensure the client config
entry, docs, and test names all match the current route param name used by
`getWiglePageNetworkFromMv` and `getWiglePageNetwork`.

Source: Coding guidelines

Comment on lines +73 to +81

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. api_endpoints still uses :netid 📘 Rule violation ≡ Correctness

The WiGLE DB page route parameter was renamed from :netid to :bssid, but the Admin API Testing
endpoint registry/preset still references the old :netid path. This leaves the testing UI out of
sync with the backend and causes Bulk Endpoint Verification to generate non-matching/invalid URLs
that consistently fail MAC validation, violating the compliance requirement to register modified API
routes.
Agent Prompt
## Issue description
The WiGLE DB Page endpoint preset in the Admin API Testing registry is out of sync with the backend: the backend route now uses `:bssid` and the MAC validation middleware reads `req.params.bssid`, but the registry/preset still uses `:netid`. This mismatch breaks the compliance requirement to register modified API routes and makes Bulk Endpoint Verification generate invalid URLs (often substituting `'1'`) that fail MAC validation and report false failures.

## Issue Context
- Backend route changed to `/api/wigle/page/network/:bssid` (previously `:netid`).
- `macParamMiddleware` validates `req.params.bssid`, so requests using `:netid` placeholders won’t map correctly.
- Admin bulk tester fills missing path params via `FALLBACK_PARAMS[paramName] || '1'`; because the preset still uses `netid`, it can fall back to `'1'`, producing `/api/wigle/page/network/1` and consistent 400 failures from MAC validation.

## Fix Focus Areas
- server/src/api/routes/v1/wigle/database.ts[72-82]
- client/src/config/apiTestEndpoints.ts[1074-1086]
- client/src/components/admin/hooks/useApiTesting.ts[220-267]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

}
if (!network) {
return res.status(404).json({ error: 'Network not found in WiGLE database' });
Expand Down
6 changes: 3 additions & 3 deletions server/src/services/observationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export async function getObservationsByBSSID(
const { rows } = await query(
`SELECT ROW_NUMBER() OVER (ORDER BY o.time) as id, o.bssid,
COALESCE(NULLIF(o.ssid, ''), '(hidden)') as ssid, o.radio_type as type,
o.lat, o.lon, o.level as signal, EXTRACT(EPOCH FROM o.time)::BIGINT * 1000 as time,
o.lat, o.lon, o.level as signal, (EXTRACT(EPOCH FROM o.time) * 1000)::float8 as time,
COALESCE(o.accuracy, 3.79) as acc, o.altitude as alt,
gc.address as geocoded_address, gc.city as geocoded_city, gc.state as geocoded_state,
gc.poi_name as geocoded_poi_name,
Expand Down Expand Up @@ -92,7 +92,7 @@ export async function getWigleObservationsByBSSID(bssid: string): Promise<any[]>
FROM app.wigle_v3_observations w
WHERE UPPER(w.netid) = $1 AND w.latitude IS NOT NULL AND w.longitude IS NOT NULL
)
SELECT we.bssid, we.lat, we.lon, EXTRACT(EPOCH FROM we.time) * 1000 as time,
SELECT we.bssid, we.lat, we.lon, (EXTRACT(EPOCH FROM we.time) * 1000)::float8 as time,
we.level, we.ssid, we.frequency, we.channel, we.encryption, we.altitude, we.accuracy,
we.is_matched,
CASE
Expand Down Expand Up @@ -149,7 +149,7 @@ export async function getWigleObservationsBatch(bssids: string[]): Promise<any[]
FROM app.wigle_v3_observations w
WHERE UPPER(w.netid) = ANY($1) AND w.latitude IS NOT NULL AND w.longitude IS NOT NULL
)
SELECT we.bssid, we.lat, we.lon, EXTRACT(EPOCH FROM we.time) * 1000 as time,
SELECT we.bssid, we.lat, we.lon, (EXTRACT(EPOCH FROM we.time) * 1000)::float8 as time,
we.level, we.ssid, we.frequency, we.channel, we.encryption, we.altitude, we.accuracy,
we.is_matched,
CASE
Expand Down
Loading
Loading