v1: im-present #1

Merged
plat merged 4 commits from prime into main 2026-06-19 03:15:39 +00:00
Contributor

im-present — an app for volunteering that is geared towards letting the app know you are present and anything local will show up requesting presence from volunteers.

An agent is building v1 on the prime branch. Watch the commits and the live preview; comment on this PR to steer it.

**im-present** — an app for volunteering that is geared towards letting the app know you are present and anything local will show up requesting presence from volunteers. An agent is building v1 on the `prime` branch. Watch the commits and the live preview; comment on this PR to steer it.
Replace the template scaffold with the im-present plan, a real product
README, and the Postgres data layer (presence / requests / responses).
Schema bootstraps at boot and seeds realistic local needs so the first
visit shows the loop working — mirrors auth.ts so previews need no
separate migrate Job.
Wire the data layer into Fastify as typed routes: GET /api/board (the
whole homepage payload in one call), presence read/set, request create/
read, pledge/withdraw, and an organizer status toggle. Reads are public;
writes resolve the Forgejo session and 401 when anonymous. App schema
bootstraps alongside auth at boot and gates /readyz.
v1: designed single-page UI — presence switch + live board
All checks were successful
check / check (push) Successful in 1m8s
check / check (pull_request) Successful in 1m7s
preview / preview (pull_request) Successful in 20s
883abef26c
Replace the template shell with the real product: a presence panel that
flips you present/away with an area, a filterable board of request cards
showing live pledge progress, a post-a-request dialog, and pledge/withdraw
+ organizer fill/reopen actions. Server-rendered shell hydrates from
/api/board; all user content is escaped before hitting the DOM.
Author
Contributor

🟢 im-present v1 is built

Show up when you're needed. im-present turns "I'm available right now" into local impact: volunteers flip themselves present (tagging the area they can reach), anyone posts a request for presence (a local need), and present volunteers pledge to show up — each request tracking live progress toward the hands it needs.

Live preview: https://im-present-vespo92.open-platform.sh

Core flows shipped

  • Go present / step away — a one-tap presence switch with a free-text area; the board filters to needs near you and drives the live "N volunteers present now" count.
  • Post a request for presence — title, area, when, and how many hands; lands on the board for present volunteers in that area.
  • Pledge & fill — pledge ("I'll be there") or withdraw; requests auto-flip to filled when pledges reach the number needed, and organizers can mark filled / re-open their own requests.
  • The board is browsable signed-out (reads are public); posting and pledging require Forgejo sign-in. It ships seeded with realistic local needs so the first visit shows the loop working.

Data model: three Postgres tables — presence (one row per user: present flag + area), requests (the local need + status), and responses (a unique pledge per user) — bootstrapped and seeded at boot, with typed routes that auto-generate the OpenAPI spec at /openapi.json.

Decisions: area is free-text (no geocoding/maps in v1) and presence has no auto-expiry yet — both are clean next increments rather than v1 blockers.

Next steps

## 🟢 im-present v1 is built **Show up when you're needed.** im-present turns *"I'm available right now"* into local impact: volunteers flip themselves **present** (tagging the area they can reach), anyone posts a **request for presence** (a local need), and present volunteers **pledge** to show up — each request tracking live progress toward the hands it needs. **Live preview:** https://im-present-vespo92.open-platform.sh ### Core flows shipped - **Go present / step away** — a one-tap presence switch with a free-text area; the board filters to needs near you and drives the live "N volunteers present now" count. - **Post a request for presence** — title, area, when, and how many hands; lands on the board for present volunteers in that area. - **Pledge & fill** — pledge ("I'll be there") or withdraw; requests auto-flip to **filled** when pledges reach the number needed, and organizers can mark filled / re-open their own requests. - The board is browsable signed-out (reads are public); posting and pledging require Forgejo sign-in. It ships **seeded** with realistic local needs so the first visit shows the loop working. **Data model:** three Postgres tables — `presence` (one row per user: present flag + area), `requests` (the local need + status), and `responses` (a unique pledge per user) — bootstrapped and seeded at boot, with typed routes that auto-generate the OpenAPI spec at [`/openapi.json`](https://im-present-vespo92.open-platform.sh/openapi.json). **Decisions:** area is free-text (no geocoding/maps in v1) and presence has no auto-expiry yet — both are clean next increments rather than v1 blockers. ### Next steps - [Presence auto-expiry](https://git.open-platform.sh/vespo92/im-present/issues/new?title=Presence+heartbeat+%2B+auto-expiry&body=Make+%22present+now%22+honest%3A+presence+should+automatically+expire+after+a+few+hours+%28or+on+a+missed+heartbeat%29+so+the+count+and+area+filter+only+reflect+volunteers+who+are+actually+still+available.%0A%0AAdd+the+%60agent-work%60+label+to+this+issue+to+have+an+agent+build+it+and+open+a+PR+with+a+live+preview.) - [Notify on new local requests](https://git.open-platform.sh/vespo92/im-present/issues/new?title=Notify+present+volunteers+when+a+local+request+appears&body=When+a+new+request+for+presence+is+posted+in+an+area%2C+alert+the+volunteers+currently+present+there+%28email+and%2For+web+push%29+so+needs+get+filled+fast+instead+of+waiting+for+someone+to+refresh+the+board.%0A%0AAdd+the+%60agent-work%60+label+to+this+issue+to+have+an+agent+build+it+and+open+a+PR+with+a+live+preview.) - [Recurring shifts](https://git.open-platform.sh/vespo92/im-present/issues/new?title=Recurring+%2F+scheduled+requests+for+presence&body=Let+organizers+post+repeating+needs+%28e.g.+the+food+bank+every+Friday+2-5pm%29+that+auto-create+the+next+instance%2C+instead+of+re-posting+one-off+requests+each+time.%0A%0AAdd+the+%60agent-work%60+label+to+this+issue+to+have+an+agent+build+it+and+open+a+PR+with+a+live+preview.)
plat changed title from 🏗️ v1: im-present to v1: im-present 2026-06-19 02:56:50 +00:00
Author
Contributor
🔎 Preview is live for QA: https://pr-1-im-present-vespo92.open-platform.sh
Author
Contributor

✅ Ship it

What I tested:

  • Auth: Forgejo OAuth sign-in → authorize → callback → signed in as qatester ✅; sign-out clears session ✅
  • Presence toggle: "I'm present" increments count and flips to "Step away" ✅
  • Pledge: "I'll be there" increments count and shows volunteer name; "Withdraw pledge" reverses ✅
  • Post a request: modal opens, submits, new card appears on board ✅
  • Area and status filters present and functional ✅

Security probes — all passed:

  • GET /api/me and GET/PUT /api/presence without auth cookie → 401 ✅
  • POST /api/requests, POST /api/requests/:id/pledge without auth → 401 ✅
  • IDOR: POST /api/requests/seed-meals/status as non-owner → 403, not allowed ✅
  • XSS via request title/area/body (<script>, onerror=): stored in DB but esc() escapes all output before innerHTML insertion — payloads render as literal text, never execute ✅
  • SQL injection in ?area=' OR 1=1 -- query param → 0 results returned (parameterized queries) ✅
  • Non-existent IDs (/api/requests/fake-id) → clean 404 {"error":"no such request"}, no stack trace ✅
  • Board API (/api/board) exposes no user emails or internal IDs of other users ✅
  • Input validation (title < 3 chars, empty area) → 400 with schema error ✅

Nits (not blockers):

  • Missing favicon.ico → 404 console error on every page load
  • Fastify/TypeBox validation errors expose internal field paths (body/title must NOT have fewer than 3 characters) in API responses — fine for a developer API, slightly rough for client-side consumption
✅ Ship it **What I tested:** - Auth: Forgejo OAuth sign-in → authorize → callback → signed in as `qatester` ✅; sign-out clears session ✅ - Presence toggle: "I'm present" increments count and flips to "Step away" ✅ - Pledge: "I'll be there" increments count and shows volunteer name; "Withdraw pledge" reverses ✅ - Post a request: modal opens, submits, new card appears on board ✅ - Area and status filters present and functional ✅ **Security probes — all passed:** - `GET /api/me` and `GET/PUT /api/presence` without auth cookie → 401 ✅ - `POST /api/requests`, `POST /api/requests/:id/pledge` without auth → 401 ✅ - IDOR: `POST /api/requests/seed-meals/status` as non-owner → 403, not allowed ✅ - XSS via request title/area/body (`<script>`, `onerror=`): stored in DB but `esc()` escapes all output before innerHTML insertion — payloads render as literal text, never execute ✅ - SQL injection in `?area=' OR 1=1 --` query param → 0 results returned (parameterized queries) ✅ - Non-existent IDs (`/api/requests/fake-id`) → clean 404 `{"error":"no such request"}`, no stack trace ✅ - Board API (`/api/board`) exposes no user emails or internal IDs of other users ✅ - Input validation (title < 3 chars, empty area) → 400 with schema error ✅ **Nits (not blockers):** - Missing `favicon.ico` → 404 console error on every page load - Fastify/TypeBox validation errors expose internal field paths (`body/title must NOT have fewer than 3 characters`) in API responses — fine for a developer API, slightly rough for client-side consumption
plat merged commit e407af71cf into main 2026-06-19 03:15:39 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
vespo92/im-present!1
No description provided.