Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/check-vm-prereqs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Check VM Prerequisites

on:
pull_request:
branches:
- main
workflow_dispatch:

permissions:
contents: read

jobs:
check-vm-prereqs:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v4

- name: Validate prerequisite checker syntax
run: bash -n food-planner/deploy/check-vm-prereqs.sh

- name: Setup SSH
run: |
sudo apt-get update
sudo apt-get install -y sshpass
mkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keyscan -H ${{ secrets.REMOTE_HOST }} >> ~/.ssh/known_hosts

- name: Check VM prerequisites
env:
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
REMOTE_USER: ${{ secrets.REMOTE_USER }}
REMOTE_PASS: ${{ secrets.REMOTE_PASS }}
run: |
sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no "$REMOTE_USER@$REMOTE_HOST" 'bash -s' < food-planner/deploy/check-vm-prereqs.sh
38 changes: 18 additions & 20 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,12 @@ jobs:
echo "Files in build directory"
ls ${{ github.workspace }}/public

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Build Valentine App
- name: Validate Food Planner
run: |
cd valentine
npm ci
npm run build
echo "Valentine app built:"
ls dist/
python3 -m py_compile food-planner/app.py food-planner/smoke_test.py
python3 food-planner/smoke_test.py
bash -n food-planner/deploy/install.sh
bash -n food-planner/deploy/check-vm-prereqs.sh

- name: Setup SSH
run: |
Expand All @@ -67,28 +61,32 @@ jobs:
run: |
echo "Deploying to server..."

# Prepare temporary upload directories before scp.
sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no "$REMOTE_USER@$REMOTE_HOST" \
"rm -rf /tmp/deploy_temp /tmp/food_planner_release && mkdir -p /tmp/deploy_temp /tmp/food_planner_release"

# Clear existing files on server (with sudo if needed)
sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no "$REMOTE_USER@$REMOTE_HOST" \
"sudo rm -rf /var/www/html/* || rm -rf /var/www/html/*"
"sudo mkdir -p /var/www/html && sudo rm -rf /var/www/html/* || rm -rf /var/www/html/*"

# Copy Zola site to server
sshpass -p "$REMOTE_PASS" scp -r -o StrictHostKeyChecking=no \
${{ github.workspace }}/public/* "$REMOTE_USER@$REMOTE_HOST:/tmp/deploy_temp/"

# Move files from temp to final destination with proper permissions
sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no "$REMOTE_USER@$REMOTE_HOST" \
"sudo mkdir -p /tmp/deploy_temp && sudo mv /tmp/deploy_temp/* /var/www/html/ && sudo chown -R www-data:www-data /var/www/html/ && sudo chmod -R 755 /var/www/html/"

# Deploy Valentine app
echo "Deploying Valentine app..."
sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no "$REMOTE_USER@$REMOTE_HOST" \
"sudo rm -rf /var/www/valentine && sudo mkdir -p /var/www/valentine"
"sudo mv /tmp/deploy_temp/* /var/www/html/ && sudo chown -R root:root /var/www/html/ && sudo chmod -R 755 /var/www/html/"

# Deploy Food Planner app and backend service.
echo "Deploying Food Planner app..."
sshpass -p "$REMOTE_PASS" scp -r -o StrictHostKeyChecking=no \
${{ github.workspace }}/valentine/dist/* "$REMOTE_USER@$REMOTE_HOST:/tmp/valentine_temp/"
${{ github.workspace }}/food-planner/* "$REMOTE_USER@$REMOTE_HOST:/tmp/food_planner_release/"

sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no "$REMOTE_USER@$REMOTE_HOST" \
"cd /tmp/food_planner_release && sudo bash deploy/install.sh"

sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no "$REMOTE_USER@$REMOTE_HOST" \
"sudo mkdir -p /tmp/valentine_temp && sudo mv /tmp/valentine_temp/* /var/www/valentine/ && sudo chown -R www-data:www-data /var/www/valentine/ && sudo chmod -R 755 /var/www/valentine/"
"curl -fsS http://127.0.0.1:8010/api/bootstrap >/dev/null && curl -fsS https://rahulreddy.in/food-planner/api/bootstrap >/dev/null"

- name: Job Status
run: echo "🍏 This job's status is ${{ job.status }}."
8 changes: 6 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
.DS_Store
/public
/scripts
/valentine/node_modules
/valentine/dist
/archive/valentine/node_modules
/archive/valentine/dist
/food-planner/data
/food-planner/__pycache__
/food-planner/**/*.pyc
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
64 changes: 64 additions & 0 deletions food-planner/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Couple Meal Planner

A small single-page meal planning app for a couple, backed by SQLite and served by Python's standard library. No build step and no package install are required.

## Run Locally

```bash
python3 app.py
```

Open `http://localhost:8000`.

The SQLite database is created at `data/meal_planner.sqlite3` on first run and is preloaded with 20 starter meals.

## VM Hosting In `website-hell`

The repository deploys this app behind Caddy at `https://rahulreddy.in/food-planner/`.

GitHub Actions copies this directory to the VM, runs `deploy/install.sh`, and installs:

- `/opt/food-planner/current` for app code
- `/var/lib/food-planner/meal_planner.sqlite3` for persistent SQLite data
- `/etc/systemd/system/food-planner.service` for the backend service
- a Caddy route that reverse proxies `/food-planner/*` to `127.0.0.1:8010`

For manual VM hosting, run from this directory on the VM:

```bash
sudo bash deploy/install.sh
```

For ad-hoc local testing, run:

```bash
HOST=0.0.0.0 PORT=8000 python3 app.py
```

To store the database somewhere else during ad-hoc runs:

```bash
MEAL_PLANNER_DB=/var/lib/food-planner/meal_planner.sqlite3 python3 app.py
```

## Backup And Restore

In the app, open `Library` and use:

- `Export JSON` to download a full backup.
- `Import JSON` to restore from a prior export. Import replaces the current database.

API endpoints are also available:

```bash
curl http://localhost:8000/api/export > meal-planner-backup.json
curl -X POST -H 'Content-Type: application/json' --data @meal-planner-backup.json http://localhost:8000/api/import
```

## Verify

```bash
python3 smoke_test.py
```

The smoke test initializes a temporary database, verifies seed data, creates a plan cell, generates a shopping list, archives a week, and validates JSON export/import shape.
Loading
Loading