lucky-vanilla

(WIP) Experimenting with the Lucky framework and custom elements

alt text

Vanilla Expense Tracker

What

Vanilla Splits is a web-based expense tracker which is designed for two people to split monthly expenses. Each user can log into the application, and enter the expenses they want to split for a given month. At the end of the month, the application will email each user the total expenses for that month, and who owes who how much.

Why

There's two main motivations for this application:

Guiding Tech Principles

Limitations

Development

Prerequisites

  • Podman (Linux, macOS, or WSL on Windows)

Quick start

./containers/dev/build.sh

This auto-generates secrets, builds the API and scheduler images, pre-labels SELinux volumes (if applicable), and starts the pod. Visit http://localhost:8888.

The frontend uses bun in watch mode — any changes to src/ts/ recompile automatically. The Lucky API server also hot-reloads on file changes.

Logs

podman pod logs -f --color --names vanilla-dev

Alternatively, you can use Podman Desktop or even LazyJournal.

Stop / Start

podman pod stop vanilla-dev
podman pod start vanilla-dev

Clean rebuild

Remove the pod, then re-run build.sh:

podman pod rm vanilla-dev
./containers/dev/build.sh

Production

CI

Pushing to main triggers a GitHub Actions workflow that runs checks and specs, then builds and pushes images to ghcr.io/mikebelanger/lucky-vanilla/.

VPS deployment

The production stack runs on a VPS with rootless Podman and Quadlets. Reference files are in containers/systemd/:

  • vanilla-app.kube — Pod spec pointing at containers/prod/pod.yml and the ConfigMaps

The containers/prod/pod.yml containers carry the io.containers.autoupdate=registry label so that Podman's built-in auto-update mechanism handles pulling fresh images from GHCR and restarting the pod automatically.

One-time VPS setup

# Copy the containers directory to the VPS (replace host/port as needed)
scp -r containers deploy@hostname.com:/home/deploy/vanilla-app/

# SSH into the VPS
ssh deploy@hostname.com

# Generate the production ConfigMaps (config.yml is committed, secrets.yml
# is gitignored and auto-generated by this script). Cross-reference the
# database auth credentials (DATABASE_URL, POSTGRES_DB, POSTGRES_USER,
# POSTGRES_PASSWORD) against config/database.cr to make sure they match:
./containers/prod/build.sh

# Log into GHCR with a personal access token (read:packages scope)
podman login ghcr.io

# Create named volumes (Podman creates these on first use, but doing it
# explicitly avoids permission issues with postgres data and Caddy certs)
podman volume create vanilla_prod_pg_data
podman volume create vanilla_prod_caddy_data

# Install the Quadlet file (copies to ~/.config/containers/systemd/)
podman quadlet install --replace containers/systemd/vanilla-app.kube

# The .kube file uses ../add-subdir/ as a deliberate placeholder.
# Edit it to absolute paths matching your server layout, e.g.:
#   Yaml=/path/to/containers/prod/pod.yml
#   ConfigMap=/path/to/containers/prod/config.yml
#   ConfigMap=/path/to/containers/prod/secrets.yml
nano ~/.config/containers/systemd/vanilla-app.kube

# Start the pod
systemctl --user daemon-reload
systemctl --user start vanilla-app.service

# Enable Podman's built-in auto-update timer (runs daily, checks for newer
# images and restarts the pod if any were pulled):
systemctl --user enable --now podman-auto-update.timer

# To customize the schedule (e.g. 2am EST), create an override:
# mkdir -p ~/.config/systemd/user/podman-auto-update.timer.d
# cat > ~/.config/systemd/user/podman-auto-update.timer.d/override.conf << 'EOF'
# [Timer]
# OnCalendar=*-*-* 02:00:00 America/New_York
# EOF
# systemctl --user daemon-reload

# Open firewall ports
sudo firewall-cmd --permanent --add-port=80/tcp --add-port=443/tcp
sudo firewall-cmd --reload

If systemctl --user start vanilla-app.service fails because rootless Podman can't bind to ports 80/443, you need to lower the unprivileged port floor:

# Check current value
sysctl net.ipv4.ip_unprivileged_port_start    # default is 1024

# Set it to 80 (or lower) so rootless Podman can publish low ports
echo 'net.ipv4.ip_unprivileged_port_start = 80' | sudo tee /etc/sysctl.d/99-rootless-podman.conf
sudo sysctl --system
Repository

lucky-vanilla

Owner
Statistic
  • 0
  • 0
  • 0
  • 0
  • 10
  • 1 day ago
  • July 27, 2025
License

Links
Synced at

Sun, 02 Aug 2026 16:07:23 GMT

Languages