The app library and landing page for the GEOGLOWS initiative. Connects researchers and water professionals to open-access tools for river forecasting, groundwater monitoring, and water intelligence.
Production: apps.geoglows.org
- Vanilla JS, Vite 6, Tailwind CSS v4
- Supabase Auth (via @aquaveo/geoglows-auth)
- anime.js v4 (scroll animations)
- Vercel (hosting, sub-app rewrites)
- Node.js 18+
- npm 9+
- A Supabase project with Auth enabled (shared across portal + sub-apps)
git clone git@github.com:Aquaveo/apps.geoglows.git
cd apps.geoglows
npm installCopy the example env file and fill in your Supabase credentials:
cp .env.example .env.local| Variable | Description |
|---|---|
VITE_SUPABASE_URL |
Supabase project URL (Settings > API) |
VITE_SUPABASE_PUBLISHABLE_KEY |
Supabase anon/publishable key |
For local development with a full Supabase stack (auth, database, RLS policies), use the Supabase CLI with Docker:
# Install the CLI (if not already)
npm install -g supabase
# Start the local Supabase stack (requires Docker)
supabase startThis spins up Postgres, Auth, Storage, and the API gateway in Docker containers. On first run it applies all migrations from supabase/migrations/. The CLI prints local credentials on startup:
API URL: http://127.0.0.1:54321
anon key: eyJ...
DB URL: postgresql://postgres:postgres@127.0.0.1:54322/postgres
Studio: http://127.0.0.1:54323
Point your .env.local at the local instance:
VITE_SUPABASE_URL=http://127.0.0.1:54321
VITE_SUPABASE_PUBLISHABLE_KEY=<anon key from supabase start output>Common commands:
supabase start # start all services
supabase stop # stop and keep data
supabase stop --no-backup # stop and reset data
supabase db reset # re-run all migrations from scratch
supabase migration new <name> # create a new migration file
supabase db diff --schema core # generate migration from schema changesMigrations live in supabase/migrations/ and run in filename order. The core schema holds the profiles table and RLS policies. See supabase/config.toml for the full local configuration.
Studio (local dashboard) is available at http://127.0.0.1:54323 for inspecting data, testing queries, and managing auth users.
npm run dev # dev server at localhost:5173
npm run build # production build to dist/
npm run preview # serve production build locally
npm test # vitest under jsdomRequires Docker. Tests Chrome, Safari (WebKit), and Firefox across phone, tablet, and desktop viewports using Playwright.
npm run build
npm run screenshots # test local build
npm run screenshots:live # test production (apps.geoglows.org)Screenshots are saved to /tmp/pw-screenshots/.
src/
main.js App entry, state, routing, render
ui/
landingPage.js Scroll-driven landing page + app grid
profilePage.js User profile (view/edit)
footer.js Footer
auth.js Supabase Auth adapter
events.js DOM event handlers
recentApps.js localStorage recent app tracking
disclaimer.js First-visit disclaimer modal
style.css Tailwind theme, animations, components
public/
showcase/ Hero and app screenshot images
scripts/
playwright-screenshots.js Cross-browser test matrix
docs/
plans/ Engineering plans
solutions/ Documented learnings (bugs, patterns)
designs/ Sub-app design proposals
Sub-apps are separate Vercel projects that get proxied through the portal using Vercel rewrites. This makes them appear under apps.geoglows.org/hydroviewer, apps.geoglows.org/grace-groundwater, etc., even though each app is deployed independently.
All apps share the same origin (apps.geoglows.org), which means:
- SSO works automatically. Supabase Auth stores its session token in
localStoragescoped to the origin. Since the portal and all sub-apps share the same origin, a user who signs in on the portal is already signed in on every sub-app. - No CORS issues. API calls from sub-apps to Supabase go through the same origin.
- Clean URLs. Users see
apps.geoglows.org/hydroviewerinstead ofrfs-v2-hydroviewer.vercel.app.
Each sub-app needs three rewrite rules in vercel.json (bare path, trailing slash, and wildcard for assets/routes):
{
"rewrites": [
{ "source": "/hydroviewer", "destination": "https://rfs-v2-hydroviewer.vercel.app/" },
{ "source": "/hydroviewer/", "destination": "https://rfs-v2-hydroviewer.vercel.app/" },
{ "source": "/hydroviewer/:path+", "destination": "https://rfs-v2-hydroviewer.vercel.app/:path+" }
]
}The sub-app's Vite config must set base to the portal path so asset URLs resolve correctly. For example, the GRACE app sets VITE_BASE_PATH=/grace-groundwater/ on Vercel Production, which makes its built assets load from /grace-groundwater/assets/... instead of /assets/....
- Deploy the sub-app as its own Vercel project (it gets a
.vercel.appURL) - Add three rewrite rules to
vercel.jsonin this repo - Add the app entry to
apps.json(name, description, path, icon, tags) - Set
VITE_BASE_PATH=/<portal-path>/on the sub-app's Vercel Production environment - Push both repos; the portal redeploy picks up the new rewrites
| App | Portal path | Vercel project | Repo |
|---|---|---|---|
| Hydroviewer RFS v2 | /hydroviewer |
rfs-v2-hydroviewer | rfs-v2-hydroviewer |
| GRACE Groundwater | /grace-groundwater |
grace-groundwater-dashboard | grace-groundwater-dashboard |
| Aquifer Analyst | /aquifer-analyst |
aquiferx | aquiferx |
Push to main triggers Vercel production deployment automatically. Preview deploys are created for pull request branches.
Environment variables must be set per-environment on Vercel (Production + Preview + Development). Setting only Production silently breaks preview deploys.
This project uses Claude Code for development. AI configuration files are organized under dotfiles to keep the project root clean.
.claude/
CLAUDE.md Project instructions (loaded automatically each session)
commands/ Slash commands (e.g. /screenshots)
.agents/
context/
PRODUCT.md Product context, users, brand, design principles
DESIGN.md Design system tokens, typography, color, components
| Command | Description |
|---|---|
/screenshots |
Run cross-browser Playwright screenshot matrix (local build) |
/screenshots live |
Same matrix against production |
| Plugin | Purpose |
|---|---|
| compound-engineering | /ce:plan, /ce:debug, /ce:compound for planning, debugging, and documenting solutions |
| impeccable | /impeccable polish, /impeccable critique for design review and UI polish |
Past solutions are captured in docs/solutions/ with YAML frontmatter for searchability. Grep here before reinventing a pattern that was already solved:
grep -r "tags:.*safari" docs/solutions/
grep -r "module:.*apps.geoglows" docs/solutions/Engineering plans live in docs/plans/. Sub-app design proposals are in docs/designs/.
See geoglows.org for terms.