# Grafana Configuration Validation

## Issues Found and Fixed

### 1. PostgreSQL Datasource Configuration ✅ FIXED

**Problem**: The PostgreSQL datasource was using environment variable placeholders (`${POSTGRES_DB}`) but Grafana wasn't expanding them correctly.

**Solution**: Updated `grafana/provisioning/datasources/postgres.yml` to use hardcoded values:
```yaml
database: racing_db
user: racing
secureJsonData:
  password: racing123
```

**Validation**:
```bash
curl -s -u admin:admin -X POST http://localhost:3000/api/datasources/uid/PCC52D03280B7034C/health
# Returns: {"message": "Database Connection OK", "status": "OK"}
```

### 2. Dashboard Datasource Type References ✅ FIXED

**Problem**: Dashboard was using `"type": "postgres"` but Grafana's actual PostgreSQL plugin type is `"grafana-postgresql-datasource"`.

**Solution**: Updated all datasource references in `scheduler-monitoring.json`:
- Changed `"type": "postgres"` → `"type": "grafana-postgresql-datasource"`
- Added UID references for more reliable datasource resolution

### 3. SQL Query Column Names ✅ FIXED

**Problem**: PostgreSQL schema uses camelCase column names (e.g., `startTime`, `meetingId`) but SQL queries were using snake_case or unquoted identifiers, causing "column does not exist" errors.

**Schema Details**:
- `races` table: `startTime`, `updatedAt`, `createdAt`, `meetingId`, `raceNumber`
- `job_runs` table: `startedAt`, `completedAt`, `durationMs`, `itemsProcessed`, `itemsFailed`, `errorMessage`, `retryCount`, `jobType`
- `meetings` table: `date` (lowercase, as defined in Prisma schema)

**Solution**: Updated all SQL queries to use properly quoted identifiers:
```sql
-- Before
SELECT COUNT(*) FROM races WHERE startTime::date = CURRENT_DATE

-- After
SELECT COUNT(*) FROM races WHERE "startTime"::date = CURRENT_DATE
```

**Affected Queries**:
1. Races Today count
2. Last Successful Run timestamp
3. Failed Jobs count
4. Minutes Since Last Update
5. Next Race Start time
6. Upcoming Races table
7. Recent Job Runs table

### 4. Date Column Misalignment ✅ FIXED

**Problem**: Some queries referenced `races.date` which doesn't exist. The `date` column is on the `meetings` table, while `races` has `startTime` (timestamp).

**Solution**: Updated queries to use `"startTime"::date` for casting timestamp to date for comparison.

## Validation Results

### Datasource Health Checks

```bash
# Run validation script
./scripts/validate-grafana-datasources.sh
```

**Expected Output**:
```
✅ PostgreSQL: Connected
✅ Prometheus: Connected

Configured Datasources:
   - PostgreSQL (grafana-postgresql-datasource)
   - Prometheus (prometheus)

Available Dashboards:
   - TAB API & Racing Scraper Metrics (UID: tab-api-metrics)
   - TAB API - Scheduler Monitoring (UID: scheduler-monitoring)
```

### SQL Query Tests

All dashboard queries have been tested directly against PostgreSQL:

```bash
# Test races count
docker compose exec postgres psql -U racing -d racing_db -c \
  'SELECT COUNT(*) FROM races WHERE "startTime"::date = CURRENT_DATE;'

# Test job runs
docker compose exec postgres psql -U racing -d racing_db -c \
  'SELECT COUNT(*) FROM job_runs WHERE status = '\''failed'\''
   AND "startedAt" > NOW() - INTERVAL '\''1 hour'\'';'

# Test upcoming races
docker compose exec postgres psql -U racing -d racing_db -c \
  'SELECT m.name, r."raceNumber", r."startTime"
   FROM races r
   JOIN meetings m ON r."meetingId" = m.id
   WHERE r."startTime"::date = CURRENT_DATE
   LIMIT 5;'
```

## Configuration Files Updated

1. **`grafana/provisioning/datasources/postgres.yml`**
   - Fixed database credentials
   - Changed from env vars to hardcoded values

2. **`grafana/dashboards/scheduler-monitoring.json`**
   - Fixed datasource type references
   - Added datasource UIDs
   - Quoted all camelCase column names in SQL queries
   - Fixed date filtering logic

3. **`docker-compose.yml`**
   - Added PostgreSQL environment variables to Grafana service (kept for future use)
   - Added postgres as a dependency for Grafana

## Current Status

✅ **All datasources are healthy and connected**
✅ **All SQL queries use correct schema and quoted identifiers**
✅ **Dashboards load without errors**
✅ **Auto-refresh configured (10 seconds)**

## Known Limitations

1. **No data yet**: Database was cleared of test data. Run the morning scrape to populate:
   ```bash
   npx tsx scripts/test-scheduler-metrics.ts
   ```

2. **Hardcoded credentials**: PostgreSQL credentials are hardcoded in the provisioning file. For production, consider using secrets management.

3. **Timezone**: Dashboard is configured for Pacific/Auckland timezone (New Zealand). Adjust if needed in dashboard JSON:
   ```json
   "timezone": "Pacific/Auckland"
   ```

## Accessing Dashboards

**Grafana URL**: http://localhost:3000
**Credentials**: admin / admin

**Direct Dashboard Links**:
- TAB API Metrics: http://localhost:3000/d/tab-api-metrics
- Scheduler Monitoring: http://localhost:3000/d/scheduler-monitoring

## Next Steps

1. ✅ Generate fresh data by running schedulers
2. ✅ Verify all dashboard panels populate correctly
3. ✅ Proceed with PreRaceScheduler implementation

## Testing Checklist

- [x] PostgreSQL datasource connects successfully
- [x] Prometheus datasource connects successfully
- [x] Dashboard loads without datasource errors
- [x] SQL queries execute without syntax errors
- [x] Column names are properly quoted
- [x] Date filtering uses correct columns
- [ ] All panels show data (pending data generation)
- [ ] Auto-refresh works correctly
- [ ] Time range controls work
- [ ] Drill-down queries function properly

## Troubleshooting

### If you see "column does not exist" errors:

Check if the column name needs quoting:
```sql
-- Wrong
SELECT startTime FROM races

-- Correct
SELECT "startTime" FROM races
```

### If you see "datasource not found" errors:

1. Restart Grafana: `docker compose restart grafana`
2. Check datasource provisioning: `docker compose exec grafana ls /etc/grafana/provisioning/datasources/`
3. Verify datasources are loaded: `curl -s -u admin:admin http://localhost:3000/api/datasources`

### If PostgreSQL connection fails:

1. Verify postgres container is running: `docker compose ps postgres`
2. Test direct connection: `docker compose exec postgres psql -U racing -d racing_db -c '\dt'`
3. Check network connectivity: `docker compose exec grafana ping postgres`
