No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗See how many solar panels fit on your roof, and what they'd produce, without leaving the browser. Find your house on a satellite map of the Philippines, click its roof (or trace it yourself), and the app lays out 550 W panels on the real roof outline, sizes a system for your electric bill and estimates production month by month.
| Layer | Technology |
|---|---|
| App | Next.js 16 (App Router, TypeScript), React 19 |
| Database | Supabase PostgreSQL + PostGIS, via Prisma 7 (@prisma/adapter-pg) |
| Auth | Supabase Auth (@supabase/ssr) |
| Map | Google Maps JavaScript API (satellite view) |
| Building outlines | OpenStreetMap via OpenFreeMap vector tiles, with the Overpass API as fallback; cached in the database |
| Solar estimates | NREL PVWatts v8 |
developer.nrel.gov to developer.nlr.gov)git clone https://github.com/AaronPublic/SoLax.git
cd SoLax
npm install # also runs `prisma generate`
cp .env.example .env # then fill in the values (see below)
npm run db:migrate # enables PostGIS, creates the tables, turns on row-level security
npm run dev # http://localhost:3000
If npm reports blocked install scripts, run npm approve-scripts --allow-scripts-pending, then
npx prisma generate.
All settings live in .env, which is git-ignored. Never commit it. .env.example documents every variable.
| Variable | Where it's used | Notes |
|---|---|---|
DATABASE_URL | Server | Supabase transaction pooler URL (port 6543, ?pgbouncer=true) |
DIRECT_URL | Prisma CLI | Supabase session/direct URL (port 5432), used for migrations |
NREL_API_KEY | Server | PVWatts key. DEMO_KEY works for quick tests but is heavily rate-limited |
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY | Browser | Public by design. Restrict it by HTTP referrer in Google Cloud |
NEXT_PUBLIC_SUPABASE_URL | Browser + server | Your project URL |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY | Browser + server | The publishable/anon key, never the secret/service-role key |
NEXT_PUBLIC_MAP_BOUNDS, NEXT_PUBLIC_MAP_CENTER | Browser | Optional; default to the whole Philippines / Manila |
OVERPASS_URLS | Server | Optional comma-separated Overpass servers for the fallback |
If your database password contains special characters (@ # / ?), URL-encode them in both URLs.
In the Supabase dashboard:
http://localhost:3000
in development) and add http://localhost:3000/** (and your production URL) to Redirect URLs,
so confirmation emails return to /auth/callback./api/buildings for outlines in ~550 m tiles. The server serves
them from the BuildingTile cache, or reads OpenFreeMap's z14 vector tiles (falling back to
Overpass), splits them into individual roofs and caches them.lib/panel-fit.ts). One PostGIS query projects the roof to its UTM zone, finds
its long axis (ST_OrientedEnvelope), removes a 0.5 m setback, tries 8 candidate grids (2 panel
orientations × 4 half-step offsets), keeps panels fully inside the roof (ST_CoveredBy) and
returns them sorted from the centre out.lib/sizing.ts sizes any system from that profile, on the
server and instantly in the browser.POST /api/plans recomputes the plan on the server (it never trusts numbers from the
browser) and stores it with the roof outline.| Method & path | Auth | Purpose |
|---|---|---|
GET /api/buildings?tiles=<ix>_<iy>,… | — | Building outlines for map tiles |
POST /api/calculate-solar | — | Fit panels and estimate production for a roof |
POST /api/plans | Required | Save a plan (recomputed server-side) |
GET /api/plans/:id | Owner | Open a saved plan |
DELETE /api/plans/:id | Owner | Delete a saved plan |
POST /api/calculate-solar body:
{ "geometry": { "type": "Polygon", "coordinates": [[[121.07, 14.65], "…"]] }, "monthlyKwh": 450 }
The response shape is CalculateSolarResponse in lib/types.ts. Roofs larger than 5,000 m², with
more than 500 vertices, or outside the Philippines are rejected.
This is the beginning of the README. Read the rest at the original. Read the full README ↗