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
18 changes: 9 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Each **destination** has:

**`data/config.json`** may include **`parkingPrivateUnknown`** (`lotAssumedDollars`, `garageAssumedDollars`, **`cardCopy`**) for assumed private-lot/garage dollars when OSM items lack `pricing`—used where the app shows planning estimates for private pins.

Parking JSON lives under **`data/parking/public/`** (Grand Rapids Visitor Parking ArcGIS map via `scripts/fetch_car_parking_arcgis.py` for **`garages-arcgis.json`** and **`lots-arcgis.json`**; meters; OSM bike racks via `scripts/fetch_bike_parking.py`) and **`data/parking/private/`** (**`garages-osm.json`** and **`lots-osm.json`** from OpenStreetMap via `scripts/fetch_car_parking_osm.py`; **`garages-ellis.json`** / **`lots-ellis.json`** from `scripts/fetch_car_parking_ellis.py` — loaded as **`ellisGarages`** / **`ellisLots`**. After overrides, pins with **`manager`: `"AirGarage"`** are split from OSM into **`airGarageGarages`** / **`airGarageLots`** in **`appData`** (still used for `#/visit` and the modes page); **`#/data/parking`** merges OSM + AirGarage + Ellis into one **Private Parking Garages** and one **Private Parking Lots** dataset in the dropdown (`dataset=osmGarages` / `osmLots`). **`#/visit`** merges OSM + AirGarage for private pins under **`private-garage` / `private-lot`** toggles. Lime micromobility via `scripts/fetch_lime_parking.py`. OSM drive **garages** (resp. **lots**) within **~0.06 mi** (Haversine) of a public ArcGIS **garage** (resp. **lot**) centroid are omitted in **`loadData()`** and when regenerating private JSON, so official names/pricing win over near-duplicate OSM pins of the same facility type (a surface lot beside a ramp is kept). Lime snapshot buckets stay in `data/parking/.lime/`. `loadData()` merges these into **`appData.parking`** and the **data** view (`#/data/parking`) shows them with a map and mode filters. Each category applies to one or more transport **modes** (`drive`, `bike`, `micromobility`).
Parking JSON lives under **`data/parking/public/`** (Grand Rapids Visitor Parking ArcGIS map via `scripts/fetch_car_parking_arcgis.py` for **`garages-arcgis.json`** and **`lots-arcgis.json`**; meters; OSM bike racks via `scripts/fetch_bike_parking.py`) and **`data/parking/private/`** (**`garages-osm.json`** and **`lots-osm.json`** from OpenStreetMap via `scripts/fetch_car_parking_osm.py`; **`garages-ellis.json`** / **`lots-ellis.json`** from `scripts/fetch_car_parking_ellis.py` — loaded as **`ellisGarages`** / **`ellisLots`**. After overrides, pins with **`owner`: `"AirGarage"`** are split from OSM into **`airGarageGarages`** / **`airGarageLots`** in **`appData`** (still used for `#/visit` and the modes page); **`#/data/parking`** merges OSM + AirGarage + Ellis into one **Private Parking Garages** and one **Private Parking Lots** dataset in the dropdown (`dataset=osmGarages` / `osmLots`). **`#/visit`** merges OSM + AirGarage for private pins under **`private-garage` / `private-lot`** toggles. Lime micromobility via `scripts/fetch_lime_parking.py`. OSM drive **garages** (resp. **lots**) within **~0.06 mi** (Haversine) of a public ArcGIS **garage** (resp. **lot**) centroid are omitted in **`loadData()`** and when regenerating private JSON, so official names/pricing win over near-duplicate OSM pins of the same facility type (a surface lot beside a ramp is kept). Lime snapshot buckets stay in `data/parking/.lime/`. `loadData()` merges these into **`appData.parking`** and the **data** view (`#/data/parking`) shows them with a map and mode filters. Each category applies to one or more transport **modes** (`drive`, `bike`, `micromobility`).

### Schema

Expand All @@ -80,14 +80,14 @@ Each parking file has:

Each **item** (parking location) has:

| Attribute | Type | Required | Description |
| -------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `location` | object | yes | Coordinates: `{ "latitude": number, "longitude": number }`. |
| `name` | string | no | Display name for the map and popup (e.g. "Arena Place Garage"). |
| `address` | string | no | Street address. |
| `pricing` | object | no | Price info; shown in map popups. See below. |
| `availability` | string | no | e.g. "Good availability". |
| `manager` | string | no | Who operates the facility (e.g. **AirGarage** on a private lot). Official public **`garages`** / **`lots`** from ArcGIS default to **`City`** in `loadData()` when omitted. The **`#/visit`** map shows **`(manager)`** after the category line only for **private** garages and lots when set. |
| Attribute | Type | Required | Description |
| -------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `location` | object | yes | Coordinates: `{ "latitude": number, "longitude": number }`. |
| `name` | string | no | Display name for the map and popup (e.g. "Arena Place Garage"). |
| `address` | string | no | Street address. |
| `pricing` | object | no | Price info; shown in map popups. See below. |
| `availability` | string | no | e.g. "Good availability". |
| `owner` | string | no | Who owns or operates the facility (e.g. **AirGarage** on a private lot). Official public **`garages`** / **`lots`** from ArcGIS default to **`City`** in `loadData()` when omitted. The **`#/visit`** map shows **`(owner)`** after the category line only for **private** garages and lots when set. |

**`pricing`** (optional): an object. **Dollar tiers** are stored as JSON **numbers** (dollars) or **`[low, high]`** arrays for ranges—not `"$…"` strings. **`hourly`** is always **per hour** (Ellis half-hour source rates are stored ×2). Optional metadata: **`rateLabel`**, **`rateNote`**, **`hourlyFreeWhen`**. Per-unit source rates (e.g. half-hour) are stored on **`hourly`** (×2 when needed) at fetch time; **`rate`** is for labeled flat tiers such as early bird. Non-price keys on meters: **`maxDuration`**, **`enforcement`**, **`free`**. Display formatting lives in **`src/shared/parking-pricing.mjs`**. The **data view** lists tiers in order: `events`, `evening`, `hourly`, `rate`, `daily`. The **`#/visit`** popup prefers **`events`**, then **`daily`**, **`evening`**, **`rate`**, with **`hourly`** in parentheses when paired. If none are present, private OSM shows **"Not listed"**; other categories show **"Free"**. Example: `{ "daily": 27, "evening": 30, "events": [27, 30], "hourly": 6 }`.

Expand Down
10 changes: 5 additions & 5 deletions data/overrides.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"longitude": -85.67193
},
"name": "Downtown Grand Rapids Parking",
"manager": "AirGarage",
"owner": "AirGarage",
"address": "45 Ottawa Ave NW, Grand Rapids, MI 49503",
"pricing": {
"hourly": 4.0,
Expand All @@ -71,7 +71,7 @@
"longitude": -85.646478
},
"name": "East Hills Cherry Street Parking",
"manager": "AirGarage",
"owner": "AirGarage",
"address": "946 Cherry St SE, Grand Rapids, MI 49506",
"pricing": {
"hourly": 4.99,
Expand All @@ -86,7 +86,7 @@
"longitude": -85.677352
},
"name": "Swift Printing Parking",
"manager": "AirGarage",
"owner": "AirGarage",
"address": "349 Mt Vernon Ave NW, Grand Rapids, MI 49504",
"pricing": {
"hourly": 4.99,
Expand All @@ -101,7 +101,7 @@
"longitude": -85.681926
},
"name": "Bridge Street Parking",
"manager": "AirGarage",
"owner": "AirGarage",
"address": "433 Bridge St NW, Grand Rapids, MI 49504",
"pricing": {
"hourly": 4.99,
Expand All @@ -116,7 +116,7 @@
"longitude": -85.679696
},
"name": "Red Lion Lot",
"manager": "AirGarage",
"owner": "AirGarage",
"address": "412 Bridge St NW, Grand Rapids, MI 49504",
"pricing": {
"hourly": 4.99,
Expand Down
16 changes: 8 additions & 8 deletions data/parking/private/garages-ellis.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"latitude": 42.967794,
"longitude": -85.668944
},
"manager": "Ellis",
"owner": "Ellis",
"name": "210 Ionia",
"address": "210 Ionia Ave NW, Grand Rapids, MI, 49503",
"availability": "Grand Rapids; 204 spaces; Monthly from $210; North of Commerce Building corner of Lyon and Ionia Early Bird Discount program available, please call (616) 458-1179 for details. Residential Rate : $245 (24/7 access) Monthly Rate: $210 (Monday - Friday 6am - 6pm) ",
Expand All @@ -23,7 +23,7 @@
"latitude": 42.964667,
"longitude": -85.667546
},
"manager": "Ellis",
"owner": "Ellis",
"name": "9-17 Library",
"address": "Grand Rapids, MI",
"availability": "Grand Rapids; 125 spaces; Monthly from $195; Corner of Library and Division Monthly parking is on a Waiting list, call (616) 458-1179 for details",
Expand All @@ -38,7 +38,7 @@
"latitude": 42.961379,
"longitude": -85.672669
},
"manager": "Ellis",
"owner": "Ellis",
"name": "Arena Place",
"address": "55 Ottawa Ave SW, Grand Rapids, MI, 49503",
"availability": "Grand Rapids; 250 spaces; Located near the Van Andel Arena",
Expand All @@ -53,7 +53,7 @@
"latitude": 42.954605,
"longitude": -85.670565
},
"manager": "Ellis",
"owner": "Ellis",
"name": "Downtown Market",
"address": "435 Ionia Ave SW, Grand Rapids, MI, 49503",
"availability": "Grand Rapids; 225 spaces; Surface parking lot  1st 1/2 hour free $3.00 per half upto a $24.00 Max",
Expand All @@ -68,7 +68,7 @@
"latitude": 42.971496,
"longitude": -85.672041
},
"manager": "Ellis",
"owner": "Ellis",
"name": "Michigan State University Innovation Park (GRIP)",
"address": "432 Monroe Ave NW, Grand Rapids, MI, 49503",
"availability": "Grand Rapids; 600 spaces; Monthly from $168.83; Please call to be added to the waitlist 616-458-1179",
Expand All @@ -83,7 +83,7 @@
"latitude": 42.966771,
"longitude": -85.671237
},
"manager": "Ellis",
"owner": "Ellis",
"name": "Midtown Parking Garage",
"address": "130 Lyon Street NW, Grand Rapids, MI, 49503",
"availability": "Grand Rapids; 665 spaces; Monthly from $240; Midtown Multi-Level Parking Garage Behind Waters Buliding Entrances off both Pearl and Lyon Street between Monroe and Ottawa. Overnight Parking:  $38.00 per 24 hour period  No in/out p rivileges   Monthly Rate: $240 (Monda\u2026",
Expand All @@ -98,7 +98,7 @@
"latitude": 42.965954,
"longitude": -85.670936
},
"manager": "Ellis",
"owner": "Ellis",
"name": "Sears",
"address": "Grand Rapids, MI",
"availability": "Grand Rapids; 56 spaces; On Pearl Between Ledyard and McKay Tower   Overnight Parking:  $38.00 per 24 hour period  No in/out p rivileges  ",
Expand All @@ -113,7 +113,7 @@
"latitude": 42.966456,
"longitude": -85.67011
},
"manager": "Ellis",
"owner": "Ellis",
"name": "Warner Ramp",
"address": "151 Ionia Ave NW, Grand Rapids, MI, 49503",
"availability": "Grand Rapids; 125 spaces; Entrance on Ionia    Overnight Max: $38.00 per 24 hour period",
Expand Down
32 changes: 16 additions & 16 deletions data/parking/private/lots-ellis.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"latitude": 42.96016,
"longitude": -85.673232
},
"manager": "Ellis",
"owner": "Ellis",
"name": "100 Grandville",
"address": "Grand Rapids, MI",
"availability": "Grand Rapids; 22 spaces; Across from the Intersection Lounge Event Parking Only",
Expand All @@ -21,7 +21,7 @@
"latitude": 42.960635,
"longitude": -85.670101
},
"manager": "Ellis",
"owner": "Ellis",
"name": "120 South Ionia",
"address": "120 South Ionia, Grand Rapids, Michigan, 49503",
"availability": "Grand Rapids; 25 spaces; 120 South Ionia Event Parking Only",
Expand All @@ -34,7 +34,7 @@
"latitude": 42.96239,
"longitude": -85.669971
},
"manager": "Ellis",
"owner": "Ellis",
"name": "28 Ionia",
"address": "28 Ionia Ave, Grand Rapids, MI",
"availability": "Grand Rapids; 18 spaces; Corner of Ionia and Weston Event Parking only",
Expand All @@ -48,7 +48,7 @@
"latitude": 42.961369,
"longitude": -85.674391
},
"manager": "Ellis",
"owner": "Ellis",
"name": "90 Market",
"address": "Grand Rapids, MI",
"availability": "Grand Rapids; 180 spaces; Monthly from $220; Overnight Parking:  $35.00 per 24 hour period  No in/out p rivileges   No Trailers allowed in the Lot Call for Monthly parking details 616-458-1179",
Expand All @@ -63,7 +63,7 @@
"latitude": 42.970861,
"longitude": -85.67718
},
"manager": "Ellis",
"owner": "Ellis",
"name": "Bridgewater Place",
"address": "Grand Rapids, MI",
"availability": "Grand Rapids; 1650 spaces; Corner of Bridge and Scribner",
Expand All @@ -78,7 +78,7 @@
"latitude": 42.968184,
"longitude": -85.671215
},
"manager": "Ellis",
"owner": "Ellis",
"name": "Fifth Third",
"address": "Grand Rapids, MI",
"availability": "Grand Rapids; 650 spaces; Between Ottawa and Monroe",
Expand All @@ -93,7 +93,7 @@
"latitude": 42.968624,
"longitude": -85.669348
},
"manager": "Ellis",
"owner": "Ellis",
"name": "Frey",
"address": "Grand Rapids, MI",
"availability": "Grand Rapids; 100 spaces; Between County Courthouse and State of Michigan Building",
Expand All @@ -108,7 +108,7 @@
"latitude": 42.96071,
"longitude": -85.673747
},
"manager": "Ellis",
"owner": "Ellis",
"name": "G.W.L.",
"address": "Grand Rapids, MI",
"availability": "Grand Rapids; 20 spaces; Across street south of Grand Woods Lodge Event Parking Only",
Expand All @@ -121,7 +121,7 @@
"latitude": 42.969997,
"longitude": -85.677395
},
"manager": "Ellis",
"owner": "Ellis",
"name": "GR Ford Museum",
"address": "Grand Rapids, MI",
"availability": "Grand Rapids; 240 spaces; Monthly from $100; Corner of Bridge and Scribner Monday - Friday Monthly rate $100 24/7 monthly rate $150.00",
Expand All @@ -136,7 +136,7 @@
"latitude": 42.966268,
"longitude": -85.665894
},
"manager": "Ellis",
"owner": "Ellis",
"name": "GRCC Bostwick",
"address": "Grand Rapids, MI",
"availability": "Grand Rapids; 2200 spaces; Corner of Bostwick and Lyon Radier card Rate $3.50 per use",
Expand All @@ -151,7 +151,7 @@
"latitude": 42.965217,
"longitude": -85.658601
},
"manager": "Ellis",
"owner": "Ellis",
"name": "GRCC DeVos Campus",
"address": "432 Fountain, Grand Rapids, Michigan, 49503",
"availability": "Grand Rapids; 250 spaces; GRCC DeVos Campus 432 Fountain Street, NE   Raider Card Rate $3.50 per use",
Expand All @@ -166,7 +166,7 @@
"latitude": 42.967666,
"longitude": -85.666859
},
"manager": "Ellis",
"owner": "Ellis",
"name": "GRCC Lyon",
"address": "Grand Rapids, MI",
"availability": "Grand Rapids; 768 spaces; Corner of Lyon and Bostwick   Raider Card Rate  $3.50 per use",
Expand All @@ -181,7 +181,7 @@
"latitude": 42.964761,
"longitude": -85.67394
},
"manager": "Ellis",
"owner": "Ellis",
"name": "Oldtown",
"address": "Grand Rapids, MI",
"availability": "Grand Rapids; 145 spaces; Monthly from $0; On Louis-Campau across from Z's",
Expand All @@ -198,7 +198,7 @@
"latitude": 42.960923,
"longitude": -85.672366
},
"manager": "Ellis",
"owner": "Ellis",
"name": "Studio Park(ing) Ramp",
"address": "120 Ottawa Ave SW, Grand Rapids, MI, 49503",
"availability": "Grand Rapids; 933 spaces; Monthly from $185; 1st 4 hours of Movie Parking is free with a ticket purchase and validation form inside the Theater. This location has ChargePoint EV chargers in the Ramp.      ",
Expand All @@ -213,7 +213,7 @@
"latitude": 42.961259,
"longitude": -85.670593
},
"manager": "Ellis",
"owner": "Ellis",
"name": "West Michigan Community Bank",
"address": "Grand Rapids, MI",
"availability": "Grand Rapids; 22 spaces; On Ionia behind arena. Event Parking Only for Nights and Weekends.",
Expand All @@ -226,7 +226,7 @@
"latitude": 42.970437,
"longitude": -85.654811
},
"manager": "Ellis",
"owner": "Ellis",
"name": "Womens Health Center",
"address": "Grand Rapids, MI",
"availability": "Grand Rapids; 440 spaces; Monthly from $150; Womens Health Center at Michigan and Union",
Expand Down
Loading
Loading