marco/PROJECT_STATUS.md

102 lines
7.0 KiB
Markdown

# Project Status: Marco
**Last Updated:** Wed Jan 21 2026
## Project Context
We are building **Marco**, a decentralized maps application using **Ember.js** (Octane/Polaris edition with GJS/GLIMMER), **Vite**, and **OpenLayers**. The core feature is storing place bookmarks in **RemoteStorage.js**, using a custom module structure.
## What We Have Done
### 1. Map Integration
- Set up OpenLayers in `app/components/map.gjs` (class-based component).
- Switched tiles to **OpenFreeMap Liberty** style (supports vector POIs).
- Implemented a hybrid click handler:
- Detects clicks on visual vector tiles.
- Falls back to fetching authoritative data from an **Overpass API** service.
- Uses a **heuristic** (distance + type matching) to link visual clicks to API results (handling data desynchronization).
- **Optimization:** Added **10px hit tolerance** for easier tapping on mobile devices.
- **Visuals:** Increased bookmark marker size (Radius 9px) and added a subtle drop shadow.
- **Feedback:** Implemented a "pulse" animation (via OpenLayers Overlay) at the click location to visualize the search radius (30m/50m).
- **Mobile UX:**
- Disabled browser tap highlights (`-webkit-tap-highlight-color: transparent`) to prevent blue flashing on Android.
- Disabled "pull-to-refresh" (`overscroll-behavior: none`) on the body to prevent accidental reloads while keeping the sidebar scrollable (`contain`).
- **Auto-Pan:** On mobile screens, if a selected pin is obscured by the bottom sheet, the map automatically pans to center the pin in the visible top half of the screen.
- **Geolocation ("Locate Me"):**
- Implemented a "Locate Me" button with robust tracking logic.
- **Dynamic Zoom:** Automatically zooms to a level where the accuracy circle covers ~10% of the map (fallback logic handles missing accuracy data).
- **Smart Pulse:** Displays a pulsing blue circle during the search phase.
- **Auto-Stop:** Pulse and tracking automatically stop when high accuracy (≤20m) is achieved or after a 10s timeout.
- **Persistence:** Saves and restores map center and zoom level using `localStorage` (key: `marco:map-view`).
- **Controls:** Enabled standard OpenLayers Rotate control (re-north) and custom Locate control.
- **Pin Animation:** Selected pins are highlighted with a custom **Red Pin** overlay that drops in with an animation. The center dot is styled as a solid dark red circle (`#b31412`).
### 2. RemoteStorage Module (`@remotestorage/module-places`)
- Created a custom TypeScript module in `vendor/remotestorage-module-places/`.
- **Schema:** `place` object containing `id` (ULID), `title`, `lat`, `lon`, `geohash`, `osmId`, `url`, etc.
- **Storage Path:** Nested `<2-char>/<2-char>/<id>` (based on geohash) for scalability.
- **API:**
- `getPlaces(prefixes?)`: efficient partial loading of specific sectors (or full recursive scan if no prefixes provided).
- Uses `getListing` for directory traversal and `getAll` for object retrieval.
- configured with `maxAge: false` to ensure data freshness.
- **Dependencies:** Uses `ulid` and `latlon-geohash` internally.
### 3. App Infrastructure
- **Services:**
- `storage.js`: Initializes RemoteStorage, claims access, enables caching, and sets up the widget. Consumes the new `getPlaces` API.
- **Optimization:** Implemented **Debounced Reload** (200ms) for bookmark updates to handle rapid change events efficiently.
- **Optimization:** Correctly handles deletion/updates by clearing stale data for reloaded geohash sectors.
- `osm.js`: Fetches nearby POIs from Overpass API.
- **Reliability:** Implemented `fetchWithRetry` to handle HTTP 504/502/503 timeouts and 429 rate limits, in addition to network errors.
- **UI Components:**
- `places-sidebar.gjs`: Displays a list of nearby POIs.
- **Layout:** Responsive design that transforms into a **Bottom Sheet** (50% height) on mobile screens (`<=768px`) with rounded corners and upward shadow.
- `place-details.gjs`: Dedicated component for displaying rich place information.
- **Features:** Icons (via `feather-icons`), Address, Phone, Website, Opening Hours, Cuisine, Wikipedia.
- **Layout:** Polished UI with distinct sections for Actions and Meta info.
- **Geo Utils:**
- `app/utils/geo.js`: Haversine distance calculations.
- `app/utils/geohash-coverage.js`: Logic to calculate required 4-char geohash prefixes for a given bounding box.
### 4. Routing & Data Optimization
- **Explicit URLs:** Implemented routing support for specific OSM entities via `/place/osm:node:<id>` and `/place/osm:way:<id>`, distinguishing them from local bookmarks (ULIDs).
- **Smart Linking:** The `showPlaces` action intercepts search results and automatically resolves them to existing **Bookmarks** if a match is found (via `storage.findPlaceById`). This ensures the app navigates to the persistent Bookmark URL (ULID) and correctly reflects the "Saved" status in the UI instead of treating it as a new generic OSM place.
- **Data Normalization:** Refactored `OsmService` to return normalized objects (`osmTags`, `osmType`) for all queries. This ensures consistent data structures between fresh Overpass results and saved bookmarks throughout the app.
- **Performance:** Optimized navigation to prevent redundant network requests. Clicking a map pin passes the existing data object to the route, skipping the `model` hook (no re-fetch) while maintaining correct deep-linkable URLs via a custom `serialize` hook in `PlaceRoute`.
## Current State
- **Repo:** The app runs via `pnpm start`.
- **Workflow:**
1. User pans map -> `moveend` triggers `storage.loadPlacesInBounds`.
2. User clicks map -> "Pulse" animation -> hybrid hit detection (Visual Tile vs Overpass).
3. **Navigation:** Selected place is checked against bookmarks; if found, it uses the Bookmark object. Otherwise, it uses the OSM object.
4. Sidebar displays details via `<PlaceDetails>` component (Bottom sheet on mobile).
5. User clicks "Save Bookmark" -> Stores JSON in RemoteStorage.
6. RemoteStorage change event -> Debounced reload updates the map reactive-ly.
## Files Currently in Focus
- `app/styles/app.css`: Responsive sidebar styles and mobile optimizations.
- `app/components/map.gjs`: Map rendering, interaction, and mobile auto-panning.
- `app/templates/application.gjs`: Root template handling place selection logic.
- `app/services/storage.js`: Data sync logic.
## Next Steps & Pending Tasks
1. **App Header:** Implement a transparent header bar with the App Logo (left) and Login/User Info (right).
2. **Edit Bookmarks:** Allow users to edit the title and description of saved places.
3. **Linting & Code Quality:** Fix remaining CSS errors, remove inline styles in `map.gjs`, and address unused variables/runloop usage.
4. **Performance:** Monitor performance with large datasets (thousands of bookmarks).
5. **Testing:** Add automated tests for the geohash coverage and retry logic.
## Technical Constraints
- **Template Style:** Strict Mode GJS (`<template>`).
- **Package Manager:** `pnpm` for the main app, `npm` for the vendor module.
- **Visuals:** No Tailwind/Bootstrap; using custom CSS in `app/styles/app.css`.