尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗A mobile-first web app showing what's in the Cornell Food Recovery Network community freedge (free fridge) right now. Built by KTP x FRN.
People currently coordinate over GroupMe, so anyone who hasn't checked the chat doesn't know what's available. This app answers "what's in the freedge?" at a glance and lets anyone keep that answer accurate.
Contributors:
servings, items, containers, or bags). The name box suggests
common foods and what's already in the fridge.undo_action).emptied_at timestamp so history isn't lost.| Tier | Technology | Why we chose it |
|---|---|---|
| Frontend (client) | Plain HTML, CSS, JavaScript | No framework or build step, so every line is readable. One page doesn't need React. |
| Database (hosted) | Supabase (Postgres) | A free hosted database everyone's phone talks to, so an item added on one phone shows up on all of them. It uses real SQL and pushes live updates, and we don't have to run a server. |
| iPhone app (coming next) | Capacitor + Xcode | Wraps these same web files into an iOS app we can test with TestFlight. |
Only one person needs to do this.
supabase/schema.sql, and click Run. This creates the items table,
its rules, and live updates.public/config.js, then commit it.
(The anon key is meant to be public. Never commit the service_role
key.)git clone https://github.com/claregartz/KTPhoodRecovery.git
cd KTPhoodRecovery
The app is just files in public/, so any static file server works. If you
have Node.js (version 20 or newer):
npm start
Open the address it prints (usually http://localhost:3000). No Node? Use
python3 -m http.server 3000 --directory public and open
http://localhost:3000.
Everyone shares the same database, so items you add are real and show up for everyone. Open the app in two browser windows to watch live updates.
Try it on your phone: with your phone on the same Wi-Fi as your laptop,
find your laptop's local IP (Mac: System Settings → Wi-Fi → Details) and open
http://<that-ip>:3000 on your phone. Campus Wi-Fi (eduroam) may block this.
If it does, use your browser's mobile view instead (Chrome: right-click →
Inspect → phone icon).
See or edit the data directly: Supabase dashboard → Table Editor → items. Feedback is under Table Editor → feedback.
┌──────────────────┐ HTTPS (supabase-js) ┌───────────────────────────┐
│ Frontend │ ──────────────────────► │ Supabase (Postgres) │
│ (phone/browser) │ ◄────────────────────── │ items table + functions │
│ public/ │ live updates │ supabase/schema.sql │
└──────────────────┘ └───────────────────────────┘
index.html, styles.css, config.js, and app.js.app.js reads the list straight from the items table.app.js calls a database function (add_item,
take_item, empty_item, undo_action, submit_feedback). The
function checks the input, updates the table, and returns an undo code,
or an error message the app shows as-is.Key design decisions:
config.js is visible to anyone who looks. So the database
only lets the public read the table (a row level security policy).
All writes go through the functions, which do the real checks. The
frontend's checks only give quick feedback.quantity = quantity - 2 each time,
giving 6 (right).actions table that stores the codes
can't be read by the app.status column. An item is empty exactly when
quantity = 0, so the two values can never disagree.KTPhoodRecovery/
├── README.md ← you are here
├── package.json ← project info and the `npm start` script
├── .gitignore ← files git should ignore
├── supabase/
│ └── schema.sql ← table, permissions, and functions. Run in Supabase's SQL Editor
└── public/ ← the app itself
├── index.html ← page structure
├── styles.css ← mobile-first styling in FRN colors (always light mode)
├── config.js ← Supabase project URL + anon key
├── app.js ← reads/writes the database, draws the list, handles buttons
└── images/ ← FRN logo, Cornell FRN bear, favicon, home-screen icon
The look matches cornellfoodrecoverynetwork.com:
the FRN wordmark centered in the header, white background, FRN green
(#5e9516), gray text, Arvo headings and Varela Round for buttons
and labels (loaded from Google Fonts), and "—— Heading ——" section titles.
The Cornell FRN bear shows when the fridge is empty, and its dark red
(#8b1a2b) is used for "Empty" buttons and error messages.
All colors are variables at the top of public/styles.css. Change them there
and the whole app follows. The app is always light, like the website, even
when a phone is set to dark mode.
Buttons use a slightly darker green (#4b7a10) than the logo so white
button text stays easy to read.
items| Column | Type | Notes |
|---|---|---|
id | bigint, primary key | Auto-numbered |
name | text | 1–100 characters |
quantity | integer | ≥ 0. 0 means empty |
unit | text | servings, items, containers, or bags |
created_at | timestamptz | When it was added |
updated_at | timestamptz | When it last changed |
emptied_at | timestamptz or null | When it hit 0 |
allergens | text[] or null | null = not sure, {} = none of these, {milk,gluten} = contains those. Keys: peanuts, tree_nuts, milk, eggs, gluten, soy, fish, shellfish, sesame |
diet | text or null | null = not marked, vegan, or vegetarian. Vegan can't be combined with milk, eggs, fish, or shellfish; vegetarian can't be combined with fish or shellfish |
actionsA log of every add, take, and empty, used for undo. The app can't read it.
| Column | Type | Notes |
|---|---|---|
id | bigint, primary key | Auto-numbered |
item_id | bigint | The item changed. Deleted along with the item |
kind | text | add (new item), stack (added to an existing item), take, or empty |
amount | integer | How many were added, taken, or emptied |
undo_token | uuid | The secret undo code |
created_at | timestamptz | When it happened |
undone_at | timestamptz or null | When it was undone |
feedbackWhat people send with the Feedback button. The app can't read, change, or
delete it, only add to it through submit_feedback. Read it in the
Supabase dashboard (Table Editor → feedback).
| Column | Type | Notes |
|---|---|---|
id | bigint, primary key | Auto-numbered |
category | text | general, wrong_info, missing_food, bug, or idea |
rating | integer or null | 1–5, "how useful has the Freedge been?" |
message | text or null | Up to 2000 characters |
email | text or null | Only if they want a reply. Stored lowercase |
created_at | timestamptz | When it was sent |
Every row has a rating, a message, or both. There's no link to an item: feedback is about the app, and undo can delete items.
A second table, feedback_throttle, keeps a scrambled (hashed) copy of the
sender's IP address for an hour, only to limit spam (see submit_feedback).
To change the allergen list: edit ALLERGENS in public/app.js and the
two lists in supabase/schema.sql (the items_allergens_check constraint
and add_item), then re-run the schema file.
To add a unit: add it to UNITS in public/app.js and to the three
places in supabase/schema.sql that list units. Because the table already
exists, also run this in the SQL Editor (with your new list):
alter table public.items drop constraint items_unit_check;
alter table public.items add constraint items_unit_check
check (unit in ('servings', 'items', 'containers', 'bags', 'trays'));
The app calls these with db.rpc('name', { ...args }). The first three
return an undo code to pass to undo_action (add_item returns
{ undo_token, item }). Any of them can fail with a plain-English error
message.
| Function | Arguments | Does | Errors |
|---|---|---|---|
add_item | p_name, p_quantity, p_unit, p_allergens (optional, defaults to null = not sure), p_diet (optional, defaults to null = not marked) | Adds a new item, or adds to a matching one already in the fridge (see Food stacks) | Bad name, quantity, unit, allergen, or diet; diet that contradicts the allergens |
take_item | p_id, p_amount | Subtracts p_amount | Bad amount, more than is left, already empty, no such item |
empty_item | p_id | Sets quantity to 0. Returns null (nothing to undo) if already empty | No such item |
submit_feedback | p_category, p_rating, p_message, p_email (all but the category optional) | Saves feedback. Returns nothing. Limited to 5 per 10 minutes per IP address and 100 per hour in total | Bad category, rating, or email; no rating or message; message over 2000 characters; too many recently |
undo_action | p_token | Reverses that change: removes an added item, takes back a stacked amount, adds a take back, or restores an emptied amount | Older than 15 minutes, already undone, someone emptied it since (undo take), someone changed it since (undo add), not enough left (undo stack) |
Reading the list doesn't need a function: the app selects from items where
quantity > 0, newest first.
Example item:
{
"id": 1,
"name": "Lasagna",
"quantity": 8,
"unit": "servings",
"created_at": "2026-10-05T20:06:29.123+00:00",
"updated_at": "2026-10-05T20:31:02.456+00:00",
"emptied_at": null,
"allergens": ["milk", "gluten"],
"diet": "vegetarian"
}
We're all learning git, so this section covers both the rules we follow and how to actually do them.
main. main should always hold working
code.feature/undo-empty, fix/take-button-mobile, docs/readme-setup.main.main before starting new work, so you build on the latest code.| Term | Meaning |
|---|---|
| Repository (repo) | The project folder plus its full history. |
| Commit | A saved snapshot of your changes with a message explaining them. |
| Branch | A separate line of work. Your changes stay off main until merged. |
origin | The copy of the repo on GitHub. |
| Push | Upload your commits to GitHub. |
| Pull | Download others' commits from GitHub into your local copy. |
| Pull Request (PR) | A request on GitHub to merge your branch into main. Teammates review it there. |
| Merge | Combine a branch's commits into another branch. |
| Merge conflict | Two branches changed the same lines, so git asks you to choose. |
# 1. Start from an up-to-date main
git checkout main
git pull
# 2. Create a branch for your work
git checkout -b feature/short-description
# 3. Make changes, then see what changed
git status # which files changed
git diff # the actual line-by-line changes
# 4. Stage and commit (repeat as you go: small commits are better)
git add public/app.js # stage specific files
git commit -m "Add undo for emptied items"
# 5. Push your branch to GitHub (first push of a new branch)
git push -u origin feature/short-description
# later pushes on the same branch: just `git push`
# 6. Open a Pull Request (see below)
# 7. After the PR is merged, clean up
git checkout main
git pull
git branch -d feature/short-description
A teammate should understand what changed and why without opening the code.
| ✅ Good | ❌ Not helpful |
|---|---|
Add "Take…" button to choose an amount | changes |
Fix quantity going negative on double tap | fixed stuff |
Update README with phone testing steps | asdf / final version 2 |
For a commit with a body, run git commit with no -m. Your editor opens:
write the summary line, a blank line, then the details.
On the website (easiest):
git push, go to the repo on GitHub. A yellow banner offers
Compare & pull request. Click it. (Or go to the Pull requests
tab → New pull request.)main ← compare: your-branch.npm start, add an item, tap Take 1, check the
quantity drops").From the terminal (optional): install the GitHub CLI
(brew install gh, then gh auth login) and run:
gh pr create --base main --title "Add undo for emptied items" --body "What / why / how to test"
git fetch
git checkout their-branch-name
npm start
| Situation | What to do |
|---|---|
| "Which branch am I on?" | git status (first line) or git branch |
I made changes on main by accident (not committed yet) | git checkout -b feature/new-branch: your changes come with you |
| I want to undo changes to a file (not committed) | git restore path/to/file. This throws away your edits |
| I staged a file I didn't mean to | git restore --staged path/to/file |
| Typo in my last commit message (not pushed yet) | git commit --amend -m "Better message" |
git push is rejected | Someone pushed to your branch first. Run git pull, then git push |
My branch is behind main | git checkout main && git pull && git checkout my-branch && git merge main |
| Merge conflict | Open the files git lists, find the <<<<<<< / ======= / >>>>>>> markers, keep the right code, delete the markers, then git add the file and git commit. Ask a teammate if unsure! |
| Something's broken and I'm confused | Stop, run git status, and ask. Avoid --force or reset --hard unless you know exactly what they do: they can delete work. |
feedback