From 2c49d7cd5c6d1a5db863523e129bcf93fec61e08 Mon Sep 17 00:00:00 2001 From: Duncan Auld Date: Mon, 30 Jun 2025 05:17:50 +0000 Subject: [PATCH] base sys done. shift to vs code --- .env | 3 + backend/Dockerfile | 8 +++ backend/app/__pycache__/main.cpython-311.pyc | Bin 0 -> 1699 bytes backend/app/main.py | 65 +++++++++++++++++ db/schema.sql | 44 ++++++++++++ docker-compose.yml | 43 ++++++++++++ frontend/public/app.js | 56 +++++++++++++++ frontend/public/config.js | 2 + frontend/public/index.html | 69 +++++++++++++++++++ worker/fetch.py | 2 + 10 files changed, 292 insertions(+) create mode 100644 .env create mode 100644 backend/Dockerfile create mode 100644 backend/app/__pycache__/main.cpython-311.pyc create mode 100644 backend/app/main.py create mode 100644 db/schema.sql create mode 100644 docker-compose.yml create mode 100644 frontend/public/app.js create mode 100644 frontend/public/config.js create mode 100644 frontend/public/index.html create mode 100644 worker/fetch.py diff --git a/.env b/.env new file mode 100644 index 0000000..8a75e01 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +POSTGRES_DB=spacecom +POSTGRES_USER=spacecom +POSTGRES_PASSWORD=spacecom \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..f274166 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.11-slim + +WORKDIR /app +COPY . . + +RUN pip install fastapi uvicorn + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/backend/app/__pycache__/main.cpython-311.pyc b/backend/app/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2de66ad86419a2166152d07ae11c5074b3b0fc29 GIT binary patch literal 1699 zcmZ8hOKclO7@paeo%oT|Hg?>a;#NuN@&B1yCmN#4UGwWX6Z83Jqg9%h)F*is-WL$V}CULbi=AR{dW_~Mp9PHq`3bce65+4e@+^7W- zxsK30)1T}nmLO`;^e5`|$!=w;K6P=T{_4ckYfJU|<)}7l&yg2^Z;1Hp^o@n-xf|E^ zWG0CC%-pqwrJ3p3Ztl5oIZdOI;|heapMU)bMZF02u1Ie9t6PYb=TOhFw=TI4-?I>V zbF0tE%x2#eZE*b6=R(P$KY-i3gnMHvy2vxfr@Z4@rVnSFwp#GV{kAQ#$M~zX#VHkO zPFE?XPLp2eQW~9h+-6%0G))fLG1J+Tw@zrhwPIGZ-j)x5;pIM56fw|Y>(p9gT^QeV zEthwPCZ{@n*)tt)!lRt63hnyL?ChQtKp1b$FD=dA6oW@=O!buc`{3Z9VhGKr>%P!d zUB?%?=Wke4B;7UNVh(+u5x*_c@cVq$G_Cn4l|>?2etvb;qkhHUG9USnTq$YZHkoCv zFpK#cBHnR5CM6Mi#|15f4lZiRJJ*D@Aa}S1qrlc=qI)vy%1?)DW~UQ1+hk6)vmw$g z>Ms+SWXm#+Ux2tgH19`%O%%pa_QfD~E+~}3m^LsNA_+;9Ee5$WLFvZs_=Vv7Sa9~` zpjZnP<8&rON03Ms(;<>jLZ{2SxsyAkYOjW>axxR@dLH}|(x`YY7^wusmxA({;OzKr zuDm_D-P|67z;Y%`4ah(VwKH-H5>jJHWAp023m7FwwzZwa=%d8w)8|3jQ(F=XvK6;C)O_zHdo@FFd&`YFELYDt`3l%hrgnEGZ zMTp|B06dLfv0bue(Kq<(U`oBc?*T#;V;mX?mv+#pXKR4QcaGNpP3;`7yGClW^(ni{ zHdQ%=_B+b_hBASc*^N(vHdzDM!l@ve|8g{fa0ub-6BNhFKN7+SMv$U^Uihr=Md=aF YKgRh`8OP^B1n@*fO5qq2(b1v)0~l-9IRF3v literal 0 HcmV?d00001 diff --git a/backend/app/main.py b/backend/app/main.py new file mode 100644 index 0000000..f906b11 --- /dev/null +++ b/backend/app/main.py @@ -0,0 +1,65 @@ +# backend/main.py + +from fastapi import FastAPI +from fastapi.responses import JSONResponse +from fastapi.middleware.cors import CORSMiddleware + +app = FastAPI() + + +app.add_middleware( + CORSMiddleware, + allow_origins=[ + "http://aegis.sbln.bxl.skynav.cloud:8080" + ], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + + +@app.get("/czml/test") +def get_dummy_czml(): + czml = [ + { + "id": "document", + "name": "Dummy orbit test", + "version": "1.0" + }, + { + "id": "sat1", + "name": "TestSat-001", + "availability": "2025-06-29T00:00:00Z/2025-06-29T00:04:00Z", + "position": { + "interpolationAlgorithm": "LAGRANGE", + "interpolationDegree": 5, + "referenceFrame": "INERTIAL", + "epoch": "2025-06-29T00:00:00Z", + "cartesian": [ + 0, 7000000, 0, 0, + 60, 7050000, 20000, 0, + 120, 7100000, 40000, 0, + 180, 7150000, 60000, 0, + 240, 7200000, 80000, 0 + ] + }, + "point": { + "pixelSize": 10, + "color": { + "rgba": [0, 255, 255, 255] + } + }, + "label": { + "text": "TestSat-001", + "font": "12pt sans-serif", + "style": "FILL", + "outlineWidth": 2, + "verticalOrigin": "BOTTOM", + "pixelOffset": { + "cartesian2": [0, -20] + } + } + } + ] + return JSONResponse(content=czml) diff --git a/db/schema.sql b/db/schema.sql new file mode 100644 index 0000000..6d2699e --- /dev/null +++ b/db/schema.sql @@ -0,0 +1,44 @@ +-- Enable extensions +CREATE EXTENSION IF NOT EXISTS postgis; +CREATE EXTENSION IF NOT EXISTS timescaledb; + +-- Main object catalog (replaces 'satellites') +CREATE TABLE objects ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + norad_id INT UNIQUE NOT NULL, + intl_designator TEXT, + launch_date DATE, + orbit_type TEXT +); + +CREATE TABLE orbits ( + object_id INT REFERENCES objects(id), + ts TIMESTAMPTZ NOT NULL, + position GEOGRAPHY(POINT, 4326), + altitude_km DOUBLE PRECISION, + velocity_kms DOUBLE PRECISION, + PRIMARY KEY (object_id, ts) +); +SELECT create_hypertable('orbits', 'ts', if_not_exists => TRUE); + +-- Conjunction Data Messages / alerts +CREATE TABLE conjunctions ( + id SERIAL PRIMARY KEY, + primary_object INT REFERENCES objects(id), + secondary_object INT, + tca TIMESTAMPTZ, -- Time of Closest Approach + miss_distance_km DOUBLE PRECISION, + risk_level TEXT, + poc DOUBLE PRECISION -- Probability of Collision +); + +-- Re-entry prediction windows and footprints +CREATE TABLE reentry_predictions ( + id SERIAL PRIMARY KEY, + object_id INT REFERENCES objects(id), + window_start TIMESTAMPTZ, + window_end TIMESTAMPTZ, + footprint GEOGRAPHY(POLYGON, 4326), + notes TEXT +); diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..dd61a17 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,43 @@ +version: '3.8' + +services: + frontend: + image: nginx:alpine + container_name: spacecom-frontend + volumes: + - ./frontend/public:/usr/share/nginx/html:ro + ports: + - "8080:80" + restart: unless-stopped + + backend: + build: ./backend + container_name: spacecom-backend + ports: + - "8000:8000" + depends_on: + - db + environment: + - DB_URL=postgresql://spacecom:spacecom@db:5432/spacecom + volumes: + - ./backend:/app + restart: unless-stopped + + + db: + image: timescaledev/timescaledb-ha:pg17 + container_name: spacecom-db + ports: + - "5432:5432" + environment: + POSTGRES_DB: spacecom + POSTGRES_USER: spacecom + POSTGRES_PASSWORD: uCV4@YUCuR9kX.MQaxp2 + volumes: + - pgdata:/var/lib/postgresql/data + - ./db/schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro + restart: unless-stopped + + +volumes: + pgdata: diff --git a/frontend/public/app.js b/frontend/public/app.js new file mode 100644 index 0000000..631298c --- /dev/null +++ b/frontend/public/app.js @@ -0,0 +1,56 @@ +// app.js +import { API_BASE_URL } from "./config.js"; + +console.log('🔥 app.js loaded'); + +// Optional: set Ion token (if using Ion) +Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJkZjk0MDM3OC1kZDE1LTRhMjItODg3NC1iMjUzNmI1NzUwMjgiLCJpZCI6MzE2ODE3LCJpYXQiOjE3NTEyMzM5OTh9.UDLPRYrMOcLAjuCWAZa2f159W0bULWSMNv3iiQcAAP8'; + + + +// Create empty viewer with no base layer +const viewer = new Cesium.Viewer("cesiumContainer", { + imageryProvider: false, + baseLayerPicker: false, + terrainProvider: new Cesium.EllipsoidTerrainProvider() +}); + +console.log('✅ Viewer created:', viewer); + +// Create OSM imagery layer +const osmLayer = new Cesium.ImageryLayer( + new Cesium.UrlTemplateImageryProvider({ + url: "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png", + credit: "© OpenStreetMap contributors" + }) +); + +// Add imagery layer manually +viewer.imageryLayers.add(osmLayer); + +console.log('✅ OSM Layer Added:', osmLayer); +console.log('✅ Imagery Layers:', viewer.imageryLayers.length); + + + +// Load CZML from FastAPI endpoint +fetch(`${API_BASE_URL}/czml/test`) + .then(response => { + if (!response.ok) { + throw new Error("Network response was not ok"); + } + return response.json(); + }) + .then(czmlData => { + // Load the CZML data into a Cesium data source + const czmlSource = new Cesium.CzmlDataSource(); + czmlSource.load(czmlData).then(() => { + viewer.dataSources.add(czmlSource); + viewer.zoomTo(czmlSource); + }); + }) + .catch(error => { + console.error("Failed to load CZML:", error); + }); + + diff --git a/frontend/public/config.js b/frontend/public/config.js new file mode 100644 index 0000000..a09dbb3 --- /dev/null +++ b/frontend/public/config.js @@ -0,0 +1,2 @@ +// config.js +export const API_BASE_URL = "http://aegis.sbln.bxl.skynav.cloud:8000"; diff --git a/frontend/public/index.html b/frontend/public/index.html new file mode 100644 index 0000000..b073e73 --- /dev/null +++ b/frontend/public/index.html @@ -0,0 +1,69 @@ + + + + + SkyNav SpaceCom + + + + + + + + + + + + +
+

🛰️ SkyNav SpaceCom

+

Real-Time Orbit & Re-entry Monitoring Platform

+
+ +
+ + + + + diff --git a/worker/fetch.py b/worker/fetch.py new file mode 100644 index 0000000..e992ae4 --- /dev/null +++ b/worker/fetch.py @@ -0,0 +1,2 @@ +# Placeholder for TLE or CDM ingestion logic +print("Worker fetch script ready. Implement data polling here.") \ No newline at end of file