Skip to content

Commit 3330c72

Browse files
committed
Add frontend CosmoView
1 parent 188cf99 commit 3330c72

4 files changed

Lines changed: 101 additions & 20 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,27 @@ jobs:
1313
PYTHON_BIN: ${{ secrets.EC2_PYTHON_BIN }}
1414
SERVICE_NAME: ${{ secrets.EC2_SERVICE_NAME }}
1515
UVICORN_PORT: ${{ secrets.EC2_UVICORN_PORT }}
16+
EC2_HOST: ${{ secrets.EC2_HOST }}
17+
EC2_USER: ${{ secrets.EC2_USER }}
1618
steps:
1719
- name: Checkout repository
1820
uses: actions/checkout@v4
1921

22+
- name: Set up Node.js
23+
uses: actions/setup-node@v4
24+
with:
25+
node-version: "20"
26+
cache: "npm"
27+
cache-dependency-path: CosmoView/package-lock.json
28+
29+
- name: Install frontend dependencies
30+
working-directory: CosmoView
31+
run: npm ci
32+
33+
- name: Build frontend bundle
34+
working-directory: CosmoView
35+
run: npm run build
36+
2037
- name: Start SSH agent
2138
uses: webfactory/ssh-agent@v0.9.0
2239
with:
@@ -25,15 +42,15 @@ jobs:
2542
- name: Add EC2 host to known_hosts
2643
run: |
2744
mkdir -p ~/.ssh
28-
ssh-keyscan -H "${{ secrets.EC2_HOST }}" >> ~/.ssh/known_hosts
45+
ssh-keyscan -H "${{ env.EC2_HOST }}" >> ~/.ssh/known_hosts
2946
3047
- name: Ensure remote application directory exists
3148
env:
3249
REMOTE_APP_DIR: ${{ env.APP_DIR }}
3350
run: |
3451
set -euo pipefail
3552
APP_DIR="${REMOTE_APP_DIR:-/opt/nasa-sky-explorer}"
36-
ssh "${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }}" "sudo mkdir -p ${APP_DIR}"
53+
ssh "${{ env.EC2_USER }}@${{ env.EC2_HOST }}" "sudo mkdir -p ${APP_DIR}"
3754
3855
- name: Sync repository to EC2
3956
env:
@@ -44,16 +61,17 @@ jobs:
4461
TEMP_DIR="/tmp/nasa-sky-explorer-deploy-$$"
4562
4663
# Sync to temp directory first
47-
ssh "${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }}" "mkdir -p ${TEMP_DIR}"
64+
ssh "${{ env.EC2_USER }}@${{ env.EC2_HOST }}" "mkdir -p ${TEMP_DIR}"
4865
rsync -az --delete \
4966
--exclude ".git" \
5067
--exclude ".github/" \
5168
--exclude ".venv/" \
69+
--exclude "CosmoView/node_modules/" \
5270
--exclude "logs/" \
53-
./ "${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }}:${TEMP_DIR}/"
71+
./ "${{ env.EC2_USER }}@${{ env.EC2_HOST }}:${TEMP_DIR}/"
5472
5573
# Move from temp to final location with sudo
56-
ssh "${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }}" "sudo rsync -a --delete ${TEMP_DIR}/ ${APP_DIR}/ && rm -rf ${TEMP_DIR}"
74+
ssh "${{ env.EC2_USER }}@${{ env.EC2_HOST }}" "sudo rsync -a --delete ${TEMP_DIR}/ ${APP_DIR}/ && rm -rf ${TEMP_DIR}"
5775
5876
- name: Install Python dependencies and restart the service
5977
env:
@@ -68,5 +86,5 @@ jobs:
6886
SERVICE_NAME="${REMOTE_SERVICE:-nasaspaceapps}"
6987
UVICORN_PORT="${REMOTE_PORT:-80}"
7088
71-
ssh "${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }}" \
89+
ssh "${{ env.EC2_USER }}@${{ env.EC2_HOST }}" \
7290
"cd '${APP_DIR}' && sudo APP_DIR='${APP_DIR}' PYTHON_BIN='${PYTHON_BIN}' SERVICE_NAME='${SERVICE_NAME}' UVICORN_PORT='${UVICORN_PORT}' bash deploy/remote_deploy.sh"

README.md

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,30 @@ A FastAPI-powered prototype that serves an interactive Aladin Lite interface for
44

55
## Quickstart
66

7-
1. Create a virtual environment and install the dependencies:
7+
1. Build the CosmoView frontend (repeat whenever you change the React app):
88

99
```bash
10-
python -m venv .venv
10+
cd CosmoView
11+
npm install
12+
npm run build
13+
cd ..
14+
```
15+
16+
2. Create a virtual environment and install the FastAPI dependencies:
17+
18+
```bash
19+
python3 -m venv .venv
1120
source .venv/bin/activate
1221
pip install -r requirements.txt
1322
```
1423

15-
2. Launch the development server:
24+
3. Launch the development server:
1625

1726
```bash
1827
uvicorn src.server:app --reload
1928
```
2029

21-
3. Open <http://127.0.0.1:8000/> in your browser and click **Launch the viewer.** The FITS explorer lives at <http://127.0.0.1:8000/aladin>.
30+
4. Open <http://127.0.0.1:8000/> in your browser. The CosmoView landing page now lives at the root route with an **Explore the Universe** button that jumps directly to the Aladin viewer at <http://127.0.0.1:8000/aladin>.
2231

2332
### Working with FITS datasets
2433

@@ -42,12 +51,14 @@ ruff check .
4251

4352
```
4453
NASASpaceAppsChallenge2025/
54+
├── CosmoView/ # React + Vite front-end project
55+
│ ├── client/src/ # UI components and pages
56+
│ └── dist/public/ # Production build served by FastAPI
4557
├── requirements.txt # FastAPI and Uvicorn dependencies
4658
├── src/
4759
│ ├── __init__.py
48-
│ └── server.py # FastAPI application serving the HTML page
60+
│ └── server.py # FastAPI application that serves both front-ends
4961
├── web/
50-
│ ├── index.html # Landing page served at the root route
5162
│ ├── aladin.html # FITS explorer with Aladin Lite integration
5263
│ └── styles.css # Styling for the viewer interface
5364
├── deploy/
@@ -70,12 +81,19 @@ Every push to `main` triggers the GitHub Actions workflow in `.github/workflows/
7081
pipeline performs the following steps:
7182

7283
1. Checks out the latest code.
73-
2. Copies the repository to `/opt/nasa-sky-explorer` on your EC2 instance via `rsync`.
74-
3. Creates a dedicated service user (`nasaapp`) if it doesn't exist.
75-
4. Sets proper ownership and permissions for the application directory.
76-
5. Installs Python dependencies in a virtual environment owned by the service user.
77-
6. Applies necessary capabilities to bind to port 80 (if running on a privileged port).
78-
7. Restarts the systemd service or launches Uvicorn as a background process.
84+
2. Installs Node.js dependencies for the CosmoView frontend and builds the production bundle.
85+
3. Copies the repository to `/opt/nasa-sky-explorer` on your EC2 instance via `rsync` (skipping
86+
local build artefacts such as `node_modules/`).
87+
4. Creates a dedicated service user (`nasaapp`) if it doesn't exist.
88+
5. Sets proper ownership and permissions for the application directory.
89+
6. Installs Python dependencies in a virtual environment owned by the service user.
90+
7. Installs CosmoView dependencies on the EC2 host and rebuilds the Vite bundle to guarantee fresh
91+
assets.
92+
8. Applies necessary capabilities to bind to port 80 (if running on a privileged port).
93+
9. Restarts the systemd service or launches Uvicorn as a background process.
94+
95+
> **Prerequisite:** Ensure Node.js (v20 or newer recommended) is available on the EC2 instance so
96+
> the deployment script can run `npm install` and `npm run build` inside `CosmoView/`.
7997
8098
### Required GitHub secrets
8199

deploy/remote_deploy.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ PYTHON_BIN="${PYTHON_BIN:-/usr/bin/python3}"
66
SERVICE_NAME="${SERVICE_NAME:-nasaspaceapps}"
77
UVICORN_PORT="${UVICORN_PORT:-80}"
88
APP_USER="${APP_USER:-nasaapp}"
9+
FRONTEND_DIR="${FRONTEND_DIR:-CosmoView}"
10+
NPM_BIN="${NPM_BIN:-npm}"
11+
12+
cd "${APP_DIR}"
913

1014
# Create dedicated service user if it doesn't exist
1115
if ! id "${APP_USER}" >/dev/null 2>&1; then
@@ -31,6 +35,32 @@ pip install -r requirements.txt
3135
deactivate || true
3236
EOSCRIPT
3337

38+
# Build the frontend bundle
39+
FRONTEND_PATH="${APP_DIR}/${FRONTEND_DIR}"
40+
if [ ! -d "${FRONTEND_PATH}" ]; then
41+
echo "Error: Frontend directory ${FRONTEND_PATH} not found."
42+
exit 1
43+
fi
44+
45+
if ! command -v "${NPM_BIN}" >/dev/null 2>&1; then
46+
echo "Error: npm command '${NPM_BIN}' not found. Install Node.js/npm or set NPM_BIN." >&2
47+
exit 1
48+
fi
49+
50+
echo "Installing frontend dependencies with ${NPM_BIN}..."
51+
sudo -u "${APP_USER}" bash -c "cd '${FRONTEND_PATH}' && ${NPM_BIN} install"
52+
53+
echo "Building frontend production bundle..."
54+
sudo -u "${APP_USER}" bash -c "cd '${FRONTEND_PATH}' && ${NPM_BIN} run build"
55+
56+
FRONTEND_BUILD_DIR="${FRONTEND_PATH}/dist/public"
57+
if [ ! -d "${FRONTEND_BUILD_DIR}" ]; then
58+
echo "Error: Frontend build directory ${FRONTEND_BUILD_DIR} was not created." >&2
59+
exit 1
60+
fi
61+
62+
chown -R "${APP_USER}:${APP_USER}" "${FRONTEND_PATH}"
63+
3464
# Apply capability for port binding if needed (for systemd < 229)
3565
# Modern systemd (>= 229) uses AmbientCapabilities in the service file
3666
if [ "${UVICORN_PORT}" -lt 1024 ]; then

src/server.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
from fastapi.staticfiles import StaticFiles
88

99
BASE_DIR = Path(__file__).resolve().parent.parent
10+
FRONTEND_DIR = BASE_DIR / "CosmoView" / "dist" / "public"
1011
WEB_DIR = BASE_DIR / "web"
11-
INDEX_PATH = WEB_DIR / "index.html"
12+
INDEX_PATH = FRONTEND_DIR / "index.html"
1213
ALADIN_PATH = WEB_DIR / "aladin.html"
1314
FAVICON_SVG = (
1415
"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'>\n"
@@ -18,8 +19,22 @@
1819
"</svg>"
1920
)
2021

22+
if not INDEX_PATH.exists():
23+
raise RuntimeError(
24+
"Frontend bundle not found. Run 'npm run build' in the CosmoView directory "
25+
"to generate dist/public before starting the API server."
26+
)
27+
28+
ASSETS_DIR = FRONTEND_DIR / "assets"
29+
if not ASSETS_DIR.exists():
30+
raise RuntimeError(
31+
"Frontend assets directory missing. Ensure the CosmoView build succeeded "
32+
"and dist/public/assets is present."
33+
)
34+
2135
app = FastAPI(title="NASA Sky Explorer Prototype")
22-
app.mount("/static", StaticFiles(directory=WEB_DIR), name="static")
36+
app.mount("/assets", StaticFiles(directory=ASSETS_DIR), name="frontend-assets")
37+
app.mount("/static", StaticFiles(directory=WEB_DIR), name="legacy-static")
2338

2439

2540
def _read_html(path: Path) -> str:

0 commit comments

Comments
 (0)