Skip to content

Commit 824d02e

Browse files
committed
feat: mission control dashboard, changelog, and timeline endpoint
- CHANGELOG.md: full project history (v1.0.0 β†’ v1.1.0) documenting all 7 PRs (isro#65–isro#71) in Keep a Changelog format; Unreleased section for today's work - index.html: complete rewrite β€” space-themed mission control dashboard; live Chart.js visualisations (orbit distribution, mission status, vehicle families, top countries by satellite count); animated counters fed from /api/stats; responsive star-field background; endpoint quick-reference cards - style.css: full rewrite with CSS custom properties; dark space palette (#080818 bg, #06b8ee accent); responsive grid at 900 px and 600 px breakpoints - api/timeline.js: GET /api/timeline β€” aggregates launch dates from spacecraft_missions, spacecrafts, and customer_satellites into a unified chronological event stream; supports ?date=MM-DD, ?month=YYYY-MM, ?year=YYYY, ?range=YYYY,YYYY query params - isro_api_plan.md: big-picture vision document (10 major platform moves) - social_posts.md: LinkedIn posts and X thread for all 7 PRs
1 parent e8e4e93 commit 824d02e

6 files changed

Lines changed: 1169 additions & 139 deletions

File tree

β€ŽCHANGELOG.mdβ€Ž

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Changelog
2+
3+
All notable changes to this project are documented here.
4+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5+
6+
---
7+
8+
## [Unreleased]
9+
10+
### Added
11+
- Interactive dashboard landing page with live Chart.js visualisations
12+
- `CHANGELOG.md` β€” this file
13+
14+
---
15+
16+
## [1.1.0] β€” 2026-03-12
17+
18+
Seven pull requests submitted. All backward-compatible β€” existing routes,
19+
wrapper keys, and record counts are unchanged.
20+
21+
### Added β€” Data
22+
- `data/spacecraft_missions.json` β€” normalised to a consistent 17-field schema:
23+
- ISO 8601 dates (was: 15+ ad-hoc formats)
24+
- Numeric `mass_kg` (was: 9+ field name variants)
25+
- Numeric `power_watts` extracted from complex strings
26+
- `orbit_type` classification: LEO / SSO / GEO / Lunar / Interplanetary / Failed
27+
- `status` inferred from launch date + mission life: active / decommissioned / failed / unknown
28+
- `data/spacecrafts.json` β€” 73 of 113 records enriched from missions cross-reference
29+
(was: only `id` + `name`)
30+
- `data/launchers.json` β€” `vehicle_family` added: SLV / ASLV / PSLV / GSLV / LVM-3 / RLV / Scramjet-TD
31+
- `data/customer_satellites.json` β€” ISO dates, numeric mass, normalised country names
32+
- `data/centres.json` β€” consistent lowercase field names (`place`, `state`)
33+
- `scripts/normalize_data.py` β€” idempotent Python normalisation pipeline
34+
- `isro_scrape/isro_spacecrafts_scraper_output.json` β€” fresh scraper output merged into data
35+
36+
### Added β€” API endpoints
37+
- `GET /api/stats` β€” aggregate analytics: counts, orbit/status distributions,
38+
country breakdown, vehicle family counts; all computed at runtime ([PR #66](https://github.com/isro/api/pull/66))
39+
- `GET /api/spacecrafts/:id` β€” individual spacecraft lookup ([PR #67](https://github.com/isro/api/pull/67))
40+
- `GET /api/launchers/:id` β€” individual launcher lookup ([PR #67](https://github.com/isro/api/pull/67))
41+
- `GET /api/customer_satellites/:id` β€” individual customer satellite lookup ([PR #67](https://github.com/isro/api/pull/67))
42+
- `GET /api/centres/:id` β€” individual centre lookup ([PR #67](https://github.com/isro/api/pull/67))
43+
- `GET /api/spacecraft_missions/:id` β€” individual mission lookup ([PR #67](https://github.com/isro/api/pull/67))
44+
- Query parameter filtering on all collection endpoints ([PR #68](https://github.com/isro/api/pull/68)):
45+
- `/api/spacecrafts?status=active&orbit_type=GEO`
46+
- `/api/spacecraft_missions?mission_type=Remote+Sensing&orbit_type=SSO`
47+
- `/api/customer_satellites?country=Germany`
48+
- `/api/launchers?vehicle_family=PSLV`
49+
- `/api/centres?state=Karnataka`
50+
- `_links` object on `/api/spacecrafts/:id` and `/api/spacecraft_missions/:id`
51+
with `self` and cross-reference URLs ([PR #69](https://github.com/isro/api/pull/69))
52+
- `schemas/` β€” JSON Schema definitions for all five data files ([PR #70](https://github.com/isro/api/pull/70))
53+
- `scripts/validate_schemas.js` β€” local schema validation (`npm run validate`) ([PR #70](https://github.com/isro/api/pull/70))
54+
- `.github/workflows/validate_data.yml` β€” CI validation on PRs touching `data/` ([PR #70](https://github.com/isro/api/pull/70))
55+
- `tests/` β€” Jest test suite: 58 tests across API handlers, ID endpoints, stats,
56+
and data integrity ([PR #71](https://github.com/isro/api/pull/71))
57+
- `.github/workflows/test.yml` β€” CI test workflow on every PR ([PR #71](https://github.com/isro/api/pull/71))
58+
59+
### Fixed β€” API handlers ([PR #65](https://github.com/isro/api/pull/65))
60+
- Removed unused `fs` import from all 6 handlers
61+
- Fixed misleading variable names (`launchers` β†’ `customerSatellites`, `spacecraftMissions`)
62+
- Added `Content-Type: application/json` header to all responses
63+
- Sanitised error responses (no longer leak internal objects)
64+
- `GET /api` now returns a JSON endpoint directory instead of an HTML string
65+
66+
### Fixed β€” Landing page ([PR #65](https://github.com/isro/api/pull/65))
67+
- Added missing `/api/spacecraft_missions` endpoint link
68+
- Removed hotlinked external images
69+
70+
### Changed
71+
- `README.md` rewritten: endpoint table with record counts, full schema
72+
documentation, data pipeline instructions, contributing guide
73+
74+
---
75+
76+
## [1.0.0] β€” 2021 (initial release)
77+
78+
Original API with five static JSON endpoints:
79+
`/api/spacecrafts`, `/api/launchers`, `/api/customer_satellites`,
80+
`/api/centres`, `/api/spacecraft_missions`.

β€Žapi/timeline.jsβ€Ž

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
const spacecraftMissions = require("../data/spacecraft_missions.json");
2+
const spacecrafts = require("../data/spacecrafts.json");
3+
const customerSatellites = require("../data/customer_satellites.json");
4+
5+
function buildEvents() {
6+
const events = [];
7+
8+
for (const m of spacecraftMissions.spacecraft_missions) {
9+
if (m.launch_date) {
10+
events.push({
11+
date: m.launch_date,
12+
name: m.name,
13+
type: "mission",
14+
collection: "spacecraft_missions",
15+
id: m.id,
16+
orbit_type: m.orbit_type || null,
17+
status: m.status,
18+
});
19+
}
20+
}
21+
22+
// Add spacecrafts that don't have a mission entry (avoid duplicates)
23+
const missionNames = new Set(
24+
spacecraftMissions.spacecraft_missions.map((m) => m.name.toLowerCase())
25+
);
26+
for (const s of spacecrafts.spacecrafts) {
27+
if (s.launch_date && !missionNames.has(s.name.toLowerCase())) {
28+
events.push({
29+
date: s.launch_date,
30+
name: s.name,
31+
type: "spacecraft",
32+
collection: "spacecrafts",
33+
id: s.id,
34+
orbit_type: s.orbit_type || null,
35+
status: s.status || null,
36+
});
37+
}
38+
}
39+
40+
for (const c of customerSatellites.customer_satellites) {
41+
if (c.launch_date) {
42+
events.push({
43+
date: c.launch_date,
44+
name: c.id + (c.country ? " (" + c.country + ")" : ""),
45+
type: "customer_satellite",
46+
collection: "customer_satellites",
47+
id: c.id,
48+
country: c.country || null,
49+
launcher: c.launcher || null,
50+
});
51+
}
52+
}
53+
54+
events.sort((a, b) => a.date.localeCompare(b.date));
55+
return events;
56+
}
57+
58+
const ALL_EVENTS = buildEvents();
59+
60+
module.exports = async (req, res) => {
61+
try {
62+
res.setHeader("Content-Type", "application/json");
63+
const { date, month, year, range } = req.query;
64+
let results = ALL_EVENTS;
65+
66+
if (date) {
67+
// date=04-19 or date=04-19 β†’ match month-day across all years
68+
const parts = date.split("-");
69+
const mm = parts[0].padStart(2, "0");
70+
const dd = parts[1] ? parts[1].padStart(2, "0") : null;
71+
results = results.filter((e) => {
72+
if (dd) return e.date.slice(5) === mm + "-" + dd;
73+
return e.date.slice(5, 7) === mm;
74+
});
75+
} else if (month) {
76+
// month=2023-07 β†’ all events in that month
77+
results = results.filter((e) => e.date.startsWith(month));
78+
} else if (year) {
79+
// year=1975 β†’ all events in that year
80+
results = results.filter((e) => e.date.startsWith(year));
81+
} else if (range) {
82+
// range=1975,2000 β†’ all events from 1975 to 2000 inclusive
83+
const [from, to] = range.split(",");
84+
results = results.filter((e) => {
85+
const y = e.date.slice(0, 4);
86+
return y >= from && y <= to;
87+
});
88+
}
89+
90+
res.send({
91+
count: results.length,
92+
events: results,
93+
});
94+
} catch (error) {
95+
res.status(500);
96+
res.send({ error: error.message });
97+
}
98+
};

0 commit comments

Comments
Β (0)