Skip to content

Commit 86f6e5a

Browse files
feat(routeFinder): selettore 'ottimizza per' end-to-end + cleanup post-merge
Nuova feature --------------- - Aggiunto selettore pill 'ottimizza per' (tempo/cambi/a piedi) nella pagina route-finder con persistenza su localStorage. - searchState.optimize viene propagato a /api/plan-route via query param. - ApiController::planRoute() applica il sort dopo il post-processing delle walking legs: * transfers: route diretti prima, tie-break su duration * walking: somma distanze leg walking, tie-break su duration * time: ordine nativo del RoutePlanner - StopCard.js: hardening con String(stop.id) per evitare TypeError su id numerici. - stationSelector.css: stato visuale .stop-card.selected con check verde. Cleanup post-merge ------------------ - public/sw.js: pre-cache aggiornato con notifications.js, widget.js, delayHistory.js, offline.js, delayStats.css per supporto offline completo delle nuove pagine introdotte dalle PR #5/#6/#8/#9. - public/routes.php: rotte riorganizzate in 3 sezioni (Pagine, API, API GTFS) per leggibilita'. - ApiController::planRoute(): rimossi commenti rumorosi lasciati dall'agente AI durante il refactoring iniziale. - composer.json: aggiunto script 'composer test' -> pest. - .phpunit.cache/test-results: rimosso dal tracking (era gia' in .gitignore ma tracciato per errore). - app/views/home.php.backup: file backup eliminato. Documentazione -------------- - README.md: aggiunta sezione TODO con problemi noti prioritizzati emersi dall'analisi del codice (push reali, widget CORS, format adapter gtfs-passages, console.log debug, ecc.).
1 parent f67a0cd commit 86f6e5a

14 files changed

Lines changed: 264 additions & 360 deletions

File tree

.phpunit.cache/test-results

Lines changed: 0 additions & 1 deletion
This file was deleted.

CLAUDE.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
**actv-live** is a web application for Venice's public transport (ACTV). It provides real-time bus/water bus tracking, route planning, and stop information using GTFS data. The app is built with plain PHP (no framework) and vanilla JavaScript.
8+
9+
## Tech Stack
10+
11+
- **Backend**: PHP 8.4+ (plain PHP, no framework)
12+
- **Frontend**: Vanilla JavaScript, no build tool
13+
- **Database**: MySQL (GTFS data stored in tables: `stops`, `routes`, `trips`, `stop_times`, `calendar`, `shapes_refined`, `logs`)
14+
- **Testing**: Pest (PHP) + Jest (JavaScript)
15+
- **Dependencies**: Composer (Pest, symfony/var-dumper), npm (Jest, jest-environment-jsdom)
16+
17+
## Key Commands
18+
19+
```bash
20+
# Install dependencies
21+
composer install
22+
npm install
23+
24+
# Run PHP tests (Pest)
25+
vendor/bin/pest
26+
27+
# Run a single PHP test
28+
vendor/bin/pest tests/Unit/RouterTest.php
29+
30+
# Run JavaScript tests (Jest)
31+
npm test
32+
33+
# Run a single JS test
34+
npx jest --testPathPattern=routeFinder
35+
```
36+
37+
## Architecture
38+
39+
### Request Flow
40+
41+
1. `public/index.php` — entry point, starts session, creates Router
42+
2. `public/routes.php` — defines all routes (URL → controller + action)
43+
3. `public/functions.php` / `public/imports.php` — utility functions and common imports
44+
4. `app/Router.php` — simple URL-keyed router that instantiates controllers and calls actions
45+
5. Controllers load views from `app/views/`
46+
47+
### Directory Structure
48+
49+
```
50+
app/
51+
controllers/ Controller.php (page rendering), ApiController.php (JSON API endpoints)
52+
models/ databaseConnector.php (PDO singleton), GTFS models (gtfsStops, gtfsPassages, etc.)
53+
services/ Logger.php (DB logging), RoutePlanner.php (GTFS-based routing), GTFSParser.php
54+
views/ PHP templates for each page (home, routeFinder, stopList, admin/*, etc.)
55+
public/
56+
index.php Entry point
57+
routes.php Route definitions
58+
functions.php Global helper functions
59+
js/ Client-side JS per page (routeFinder.js, liveBusMap.js, etc.)
60+
components/ Reusable JS components (StopCard.js, StopListItem.js)
61+
tests/
62+
Unit/ PHP unit tests (Pest)
63+
Feature/ Feature tests (Pest)
64+
jest/ JavaScript tests (Jest)
65+
data/gtfs/cache/ Parsed GTFS JSON cache (stops.json, routes.json, stop_times per route)
66+
scripts/ CLI utilities for GTFS processing and DB management
67+
```
68+
69+
### Key Components
70+
71+
- **Router**: Simple array-based router in `app/Router.php`. Routes defined in `public/routes.php`.
72+
- **databaseConnector**: PDO singleton wrapper with prepared statements. `app/models/databaseConnector.php`.
73+
- **RoutePlanner**: GTFS-based route finder (direct + 1 transfer). Uses JSON cache files from `data/gtfs/cache/`, not the database. See `app/services/RoutePlanner.php`.
74+
- **GTFSParser**: Downloads and parses ACTV GTFS zip feed into JSON cache files. See `app/services/GTFSParser.php`.
75+
- **Logger**: Logs PHP/JS errors to the `logs` database table. See `app/services/Logger.php`.
76+
- **ApiController**: All API endpoints return JSON. Handles GTFS queries, route planning, bus positions, and error logging.
77+
78+
### Configuration
79+
80+
- Environment variables in `.env`: `DB_HOST`, `DB_USER`, `DB_PASS`, `DB_NAME`
81+
- Constants defined in `app/bootstrap.php`: `BASE_PATH`, `ENV`, `URL_PATH`
82+
- Session management with expiration check
83+
84+
### CI
85+
86+
GitHub Actions (`.github/workflows/test.yml`) runs on push/PR:
87+
- Jest on Node 20
88+
- Pest on PHP 8.4

README.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,28 @@ composer install
2323

2424
## Configurazione Docker
2525

26-
[non ancora implementato]
26+
[non ancora implementato]
27+
28+
## TODO / Da fare
29+
30+
### 🔴 Priorità alta
31+
- [ ] **Notifiche push reali**: l'attuale implementazione (`public/js/notifications.js`) fa polling locale dell'API ACTV e mostra notifiche solo a tab aperto. Per vere push in background servono:
32+
- Generazione e configurazione chiavi VAPID
33+
- Endpoint `/api/push/subscribe` per salvare le subscription dei client
34+
- Cron/job lato server che pusha quando rileva ritardi
35+
- Chiamata `pushManager.subscribe()` in `notifications.js`
36+
- In alternativa: rinominare la feature in "Avvisi ritardi (mentre l'app è aperta)"
37+
38+
### 🟡 Priorità media
39+
- [ ] **Widget embed CORS**: `app/views/widget.php` chiama direttamente `https://oraritemporeale.actv.it/...`. In contesti embed su domini terzi potrebbe rompersi. Valutare proxy `/api/widget-passages` con CORS aperto.
40+
- [ ] **Format adapter `/api/gtfs-passages`**: in `public/js/stop.js:111` c'è un `//todo:correct format` — il fallback locale ritorna le righe raw di `stop_times` invece del formato `{line, destination, time, real}` di ACTV. Serve un mapper.
41+
- [ ] **Rimuovere `console.log` di debug** in produzione (sono volutamente lasciati per ora):
42+
- `public/js/stop.js:237`
43+
- `public/js/liveBusMap.js:317, 324, 391, 446`
44+
- `app/views/stopList.php:163`
45+
46+
### 🟢 Pulizia / quality
47+
- [ ] **CSS empty rulesets** pre-esistenti in `public/css/stop.css` (linee 2, 58, 79)
48+
- [ ] **Documentazione Docker** (sezione sopra è vuota)
49+
- [ ] **Pre-cache GTFS in SW**: la funzione `cacheGtfsData()` in `sw.js` è già pronta ma nessuno invia il messaggio `CACHE_GTFS` al SW
50+
- [ ] **Bottone widget in home**: la feature widget è scoperta solo dal pulsante share nella pagina fermata; valutare punto di accesso più visibile

app/controllers/ApiController.php

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,16 @@ function favorite() {
9595
require_once BASE_PATH . '/app/models/addToFavorites.php';
9696
}
9797

98-
// Moved from Controller::planRoute
9998
function planRoute() {
100-
// This service likely uses local files (RoutePlanner), keeping as is per plan/User request scope (Controllers only)
10199
require_once BASE_PATH . '/app/services/RoutePlanner.php';
102100

103101
$origin = $_GET['from'] ?? '';
104102
$dest = $_GET['to'] ?? '';
105103
$time = $_GET['time'] ?? date('H:i:s');
104+
$optimize = $_GET['optimize'] ?? 'time';
105+
if (!in_array($optimize, ['time', 'transfers', 'walking'], true)) {
106+
$optimize = 'time';
107+
}
106108

107109
// Ensure time is in HH:MM:SS format
108110
if (strlen($time) == 5) {
@@ -111,12 +113,6 @@ function planRoute() {
111113

112114
try {
113115
$planner = new RoutePlanner();
114-
// ... Logic from Controller.php ...
115-
// Since the logic is long and depends on RoutePlanner, we just copy the body.
116-
// But wait, the user asked to "remove LOCAL GTFS calls" from Controllers.
117-
// planRoute logic in Controller.php handles logic "around" RoutePlanner.
118-
119-
// Re-implementing the logic from Controller::planRoute
120116
$startWalk = null;
121117
$endWalk = null;
122118
$planningOrigin = $origin;
@@ -200,9 +196,34 @@ function planRoute() {
200196
];
201197
}
202198
}
199+
unset($route);
200+
201+
// Apply user-selected optimization sort
202+
if ($optimize !== 'time') {
203+
usort($routes, function($a, $b) use ($optimize) {
204+
if ($optimize === 'transfers') {
205+
$ta = ($a['type'] ?? '') === 'transfer' ? 1 : 0;
206+
$tb = ($b['type'] ?? '') === 'transfer' ? 1 : 0;
207+
if ($ta !== $tb) return $ta - $tb;
208+
return ($a['duration'] ?? 0) - ($b['duration'] ?? 0);
209+
}
210+
if ($optimize === 'walking') {
211+
$wa = 0; $wb = 0;
212+
foreach ($a['legs'] ?? [] as $l) {
213+
if (($l['type'] ?? '') === 'walking') $wa += (int)($l['distance'] ?? 0);
214+
}
215+
foreach ($b['legs'] ?? [] as $l) {
216+
if (($l['type'] ?? '') === 'walking') $wb += (int)($l['distance'] ?? 0);
217+
}
218+
if ($wa !== $wb) return $wa - $wb;
219+
return ($a['duration'] ?? 0) - ($b['duration'] ?? 0);
220+
}
221+
return 0;
222+
});
223+
}
203224

204225
header('Content-Type: application/json');
205-
echo json_encode(['success' => true, 'routes' => $routes]);
226+
echo json_encode(['success' => true, 'routes' => $routes, 'optimize' => $optimize]);
206227

207228
} catch (Exception $e) {
208229
header('Content-Type: application/json');

0 commit comments

Comments
 (0)