Document current state: backlog from overnight session, CLAUDE.md refresh
Deploy to Dev / Deploy & Smoke Test (push) Successful in 20s
Deploy to Dev / Deploy & Smoke Test (push) Successful in 20s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,9 @@ LisiLou Photography Portfolio — a photography booking and portfolio site for E
|
|||||||
Built as a zero-framework SPA with a Node.js/Express booking API, deployed on a homelab Proxmox cluster.
|
Built as a zero-framework SPA with a Node.js/Express booking API, deployed on a homelab Proxmox cluster.
|
||||||
|
|
||||||
**Live dev URL:** http://192.168.1.192:8080 (CT114, lisilou-dev LXC)
|
**Live dev URL:** http://192.168.1.192:8080 (CT114, lisilou-dev LXC)
|
||||||
**Gitea repo:** https://git.jerodrigged.com/jhodgkin/lisilou-portfolio
|
**Production URL:** https://lisilou.jerodrigged.com (CT111 via Cloudflare tunnel → NPM CT102)
|
||||||
|
**Gitea repo:** https://git.jerodrigged.com/jhodgkin/lisilou-portfolio (deploys dev, CT114)
|
||||||
|
**GitHub mirror:** https://github.com/jhodgkin/lisilou-portfolio (deploys prod, CT111 — push here too or prod drifts!)
|
||||||
|
|
||||||
## Technology Stack
|
## Technology Stack
|
||||||
|
|
||||||
@@ -18,7 +20,7 @@ Built as a zero-framework SPA with a Node.js/Express booking API, deployed on a
|
|||||||
| Portfolio server | Nginx Alpine |
|
| Portfolio server | Nginx Alpine |
|
||||||
| Booking API | Node.js 20 / Express / better-sqlite3 |
|
| Booking API | Node.js 20 / Express / better-sqlite3 |
|
||||||
| Deployment | Docker Compose (two services: `portfolio` + `api`) |
|
| Deployment | Docker Compose (two services: `portfolio` + `api`) |
|
||||||
| CI/CD | Gitea Actions → auto-deploys to CT114 on push to `main` |
|
| CI/CD | Gitea Actions → CT114 (dev); GitHub Actions → CT111 (prod) on push to `main` |
|
||||||
| Image hosting | Immich (immich.jerodrigged.com) |
|
| Image hosting | Immich (immich.jerodrigged.com) |
|
||||||
|
|
||||||
## Development Commands
|
## Development Commands
|
||||||
@@ -67,7 +69,7 @@ All content is loaded at runtime — no rebuild needed:
|
|||||||
|
|
||||||
```
|
```
|
||||||
site.json
|
site.json
|
||||||
├── site — title, tagline, logo, favicon
|
├── site — title, tagline, logo, favicon, heroImage (optional hero photo)
|
||||||
├── photographer — name, bio, profile image
|
├── photographer — name, bio, profile image
|
||||||
├── contact — email, phone
|
├── contact — email, phone
|
||||||
├── social — instagram, facebook, etc.
|
├── social — instagram, facebook, etc.
|
||||||
@@ -157,14 +159,19 @@ Every push to `main`:
|
|||||||
|
|
||||||
| Step | Feature | Issue | Status |
|
| Step | Feature | Issue | Status |
|
||||||
|------|---------|-------|--------|
|
|------|---------|-------|--------|
|
||||||
| 1 | Date picker | #3 | Shell done; Google Calendar availability pending |
|
| 1 | Date picker | #3 | Done — Google Calendar busy dates (graceful when unconfigured) |
|
||||||
| 2 | Session type | #4 | Done — config-driven from `sessionTypes[]` |
|
| 2 | Session type | #4 | Done — config-driven from `sessionTypes[]` |
|
||||||
| 3 | Session length | #4 | Done — mini/full with pricing from config |
|
| 3 | Session length | #4 | Done — mini/full with pricing from config |
|
||||||
| 4 | Location picker | #5 | Done — photo cards with detail expand panel |
|
| 4 | Location picker | #5 | Done — photo cards with detail expand panel |
|
||||||
| 5 | Contract e-signature | #6 | Shell placeholder; PDF.js + pdf-lib pending |
|
| 5 | Contract e-signature | #6 | Done — PDF.js viewer + canvas pad; needs `api/contracts/model-release.pdf` on volume |
|
||||||
| 6 | Venmo payment | #7 | Shell placeholder; deep link + QR pending |
|
| 6 | Venmo payment | #7 | Done — deep link + server-generated QR |
|
||||||
| 7 | Confirm & submit | — | Done — summary + POST /api/bookings |
|
| 7 | Confirm & submit | — | Done — summary + POST /api/bookings |
|
||||||
|
|
||||||
|
Also done: n8n webhooks (#8), admin dashboard at `/dashboard` (#11), Authentik OIDC
|
||||||
|
login (#10, needs Authentik-side setup), client portal at `/my-bookings` (#13).
|
||||||
|
Auth lives in `api/auth.js` (zero-dep OIDC + HMAC cookie sessions); admin routes
|
||||||
|
accept an OIDC admin session or the legacy `ADMIN_SECRET` bearer.
|
||||||
|
|
||||||
### Booking JS Functions (in `src/index.html`)
|
### Booking JS Functions (in `src/index.html`)
|
||||||
|
|
||||||
| Function | Purpose |
|
| Function | Purpose |
|
||||||
@@ -181,17 +188,10 @@ Every push to `main`:
|
|||||||
| `populateSummary()` | Fills step 7 confirm rows from bookingState + config labels |
|
| `populateSummary()` | Fills step 7 confirm rows from bookingState + config labels |
|
||||||
| `submitBooking()` | POST /api/bookings; shows success state |
|
| `submitBooking()` | POST /api/bookings; shows success state |
|
||||||
|
|
||||||
## Pending Issues
|
## Pending Work
|
||||||
|
|
||||||
| # | Feature |
|
All original wizard issues (#3–#13) are code-complete. Remaining items — mostly
|
||||||
|---|---------|
|
infrastructure setup, secrets, and content — are catalogued in
|
||||||
| #3 | Google Calendar availability (real date picker with blocked dates) |
|
`docs/BACKLOG-2026-07-16.md` and should be transferred to Gitea issues.
|
||||||
| #6 | Contract e-signature (PDF.js viewer + HTML5 canvas signature pad) |
|
|
||||||
| #7 | Venmo payment step (deep link + QR code) |
|
|
||||||
| #8 | n8n email notifications on new booking |
|
|
||||||
| #10 | Authentik OIDC (photographer admin + client self-registration) |
|
|
||||||
| #11 | Management dashboard with payment status |
|
|
||||||
| #12 | Authentik client self-registration enrollment flow |
|
|
||||||
| #13 | Client portal /my-bookings |
|
|
||||||
|
|
||||||
Issues are tracked at: https://git.jerodrigged.com/jhodgkin/homelab/issues
|
Issues are tracked at: https://git.jerodrigged.com/jhodgkin/homelab/issues
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
# Backlog from overnight session — 2026-07-16
|
||||||
|
|
||||||
|
Written to the repo because the available Gitea credential (`write:repository` only)
|
||||||
|
cannot create issues. **Transfer these to Gitea once a token with
|
||||||
|
`read:issue` + `write:issue` scope exists.**
|
||||||
|
|
||||||
|
## Blockers needing Jerod's input
|
||||||
|
|
||||||
|
### B1. Gitea API token for agent workflows
|
||||||
|
The stored git credential can push code but not read/create issues
|
||||||
|
(`required=[read:issue], token scope=write:repository`). Create a token at
|
||||||
|
git.jerodrigged.com/user/settings/applications with `read:user`, `write:issue`,
|
||||||
|
`write:repository` and set it as `GITEA_TOKEN` (user env var) on this machine.
|
||||||
|
|
||||||
|
### B2. Production (CT111) api/.env is a blank template
|
||||||
|
The GitHub deploy now auto-creates `api/.env` from `.env.example`, which is why the
|
||||||
|
new stack runs — but every secret is empty. Until real values are set on CT111 at
|
||||||
|
`/opt/lisilou-portfolio/api/.env`:
|
||||||
|
- admin dashboard login is disabled (no `ADMIN_SECRET`)
|
||||||
|
- **new bookings send no n8n notification — real clients could book silently**
|
||||||
|
- calendar availability shows all dates free (no Google creds)
|
||||||
|
- SSO/client portal sign-in is inactive (no `OIDC_*` / `SESSION_SECRET`)
|
||||||
|
Copy working values from CT114:`/opt/…/api/.env` (adjust `SITE_URL` / `CORS_ORIGIN`
|
||||||
|
to https://lisilou.jerodrigged.com), then `docker compose restart api`.
|
||||||
|
|
||||||
|
### B3. Authentik provider + groups (issues #10/#12)
|
||||||
|
Code for OIDC login and the client portal is deployed and tested, but Authentik
|
||||||
|
needs one-time admin setup (see header comment in `api/auth.js`):
|
||||||
|
1. OAuth2/OpenID provider (confidential; redirect URIs for both dev and prod
|
||||||
|
`/api/auth/callback`), application "LisiLou Portfolio"
|
||||||
|
2. `lisilou-admin` group with Elysse (grants dashboard access)
|
||||||
|
3. Enrollment flow for client self-registration (#12) — Authentik-side config only
|
||||||
|
4. Fill `OIDC_*` + `SESSION_SECRET` in both instances' `api/.env`
|
||||||
|
|
||||||
|
### B4. Decide the deploy topology (dev vs prod)
|
||||||
|
Discovered overnight: `lisilou.jerodrigged.com` → NPM (CT102) → **CT111**, deployed
|
||||||
|
by **GitHub** Actions from github.com/jhodgkin/lisilou-portfolio; the Gitea repo
|
||||||
|
deploys to **CT114** (dev). The public site was 20 commits stale because pushes
|
||||||
|
stopped reaching GitHub. I've synced GitHub main and both pipelines are green, but:
|
||||||
|
- keeping two remotes in sync manually will drift again (mirror Gitea→GitHub, or
|
||||||
|
point NPM at CT114, or move prod deploy to Gitea Actions)
|
||||||
|
- CT111 and CT114 have separate SQLite DBs — real bookings live on CT111 only
|
||||||
|
- `homelab/docs/infrastructure.md` is stale (lists CT114 as Keycloak; CT111 notes
|
||||||
|
don't mention the GitHub runner deploy chain)
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
### S1. Signed-contract download is unauthenticated and enumerable
|
||||||
|
`GET /api/bookings/:id/contract` serves any signed contract by numeric id (kept
|
||||||
|
because n8n email links use it). Replace with HMAC-signed URLs
|
||||||
|
(`?token=…`, using SESSION_SECRET) and update the n8n workflow template.
|
||||||
|
|
||||||
|
### S2. Dev ADMIN_SECRET committed in playwright.config.js
|
||||||
|
`9yPu…` is in git history and matches the dev instance. Rotate the dev secret and
|
||||||
|
inject via env/Gitea secret instead of a hardcoded default.
|
||||||
|
|
||||||
|
## Content (needed to look professional — code is ready, assets are missing)
|
||||||
|
|
||||||
|
### C1. Real photography on the prod volume
|
||||||
|
- `/images/hero.jpg` — new: homepage hero photo (soft scrim applied automatically)
|
||||||
|
- portfolio category covers (`/images/portfolio/*-cover.jpg`) or working Immich
|
||||||
|
album links — cards currently show the styled placeholder
|
||||||
|
- location photos (`/images/locations/<id>/hero.jpg`, `1.jpg`, `2.jpg`)
|
||||||
|
- `/images/logo.png`, `/images/favicon.ico`, profile photo
|
||||||
|
Verify the Immich share albums referenced in `site.json` resolve on prod.
|
||||||
|
|
||||||
|
### C2. Contract template PDF
|
||||||
|
`api/contracts/model-release.pdf` is absent on both instances — the e-sign step
|
||||||
|
falls back and no PDF gets stamped. Drop the real contract on the volumes.
|
||||||
|
|
||||||
|
### C3. Confirm public contact details
|
||||||
|
`site.json` has `hello@lisilou.com` and an empty phone; Venmo username
|
||||||
|
`LisiLouPhoto` — confirm all are real before promoting the site.
|
||||||
|
|
||||||
|
## Nice-to-haves spotted during the walkthrough
|
||||||
|
- Portfolio lightbox: verify Immich proxy flow end-to-end on prod (couldn't test
|
||||||
|
without albums)
|
||||||
|
- `/dashboard` and `/my-bookings` aren't linked from anywhere for the photographer;
|
||||||
|
consider a footer link or bookmark
|
||||||
|
- Add `robots.txt` + real meta description / OpenGraph tags for sharing
|
||||||
|
- The "designer plugin" requested for the design review doesn't exist in this
|
||||||
|
Claude Code environment — the pass was done manually (screenshots + fixes);
|
||||||
|
if there's a specific plugin to install, add it to `.claude/settings.json`
|
||||||
Reference in New Issue
Block a user