Easy-to-manage touch screens
무료 오픈소스 터치스크린으로 USB 설정 가이드, 드래그‑드롭 편집기, 로컬 제어를 제공하며 Home Assistant용으로 제작되었습니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Common Ground: a private roommate hub for shared plans, chores, shopping, and house notes
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A warm, private roommate hub built with Next.js, React, TypeScript, and Supabase. Designed for Vercel. The home screen is a kitchen noticeboard with warm paper, soft sage, terracotta, and a taped fridge note.README 전문 보기 ↗A warm, private roommate hub built with Next.js, React, TypeScript, and Supabase. Designed for Vercel. The home screen is a kitchen noticeboard with warm paper, soft sage, terracotta, and a taped fridge note.
Apply migrations 031–037 before deploying this release. Set SUPABASE_SERVICE_ROLE_KEY and a new HOUSEHOLD_OWNER_SETUP_SECRET of at least 8 characters in the server environment; a longer random secret is recommended. The production build gate waits for migration 037 and these settings. The owner enters the household code, chooses their name, then enters the setup secret and a personal password on first sign-in. In Our household, the owner creates a one-time invitation for each other person. Share the household code and invitation privately. Existing accounts sign in with their own password; choosing another name requires that person's password. The shared-screen option remains read-only. Treat the owner setup secret as an enrollment credential and rotate it after owner enrollment if it was exposed.
Maintenance requests now have due dates, a dated follow-up trail, and morning reminders for due or overdue assigned requests. To-dos and shopping order synchronize across devices. Reservations use the configured household time zone, appear on the in-app and subscribed calendars, and can carry a 30-minute calendar reminder. Shopping purchases can record a partial quantity and actual total price while leaving the remainder open; the ledger posts the purchased portion once. The Budget panel shows six months of grocery and utility totals and remaining target amounts. Expenses can create weekly or monthly rules from an existing charge; each new cycle creates a draft that must be posted or skipped, with possible duplicates flagged. The owner can download a JSON household backup and restore missing records to the same household. The backup includes shared plans, chores, shopping, handbook text, planning records, and the owner's private entries; it excludes other members' private entries and file blobs. Back up handbook files, maintenance photos, and receipts separately from private storage.
The overview opens with the date and one sentence about what the house needs today: chores that have come due, the nearest unpaid bill within the week — nearest by distance from today, so an old bill nobody ticked off never hides the rent that is actually coming up, and a tie goes to the overdue one — and what is on the shopping list ("One thing to do, rent in 5 days, and olive oil to grab."). Each card is a different piece of paper: a calendar leaf for plans, an index card for chores, receipt paper for shopping, and the taped fridge note; the To-dos, Shopping, and Expenses pages carry the same papers. The homepage and calendar fit the available viewport without page scrolling. Home cards adapt their item count to the space; a "See all" link on each card opens the full tab when more items exist. A repeating chore or plan takes one row on the overview — its next turn, plus anything overdue — while the full tab still lists every occurrence. Complete chores or mark purchases directly, or use the To-do / Item / Plan shortcuts. Calendar rows resize to fit even six-week months; crowded days open a detail dialog. On phones, navigation stays at the bottom and the calendar becomes a paginated monthly agenda.
Choose Display mode in the top bar for a monitor/TV, or bookmark /?display=1. It fills the browser viewport with four cards, a clock, and no scrolling. Each card fits as many rows as its own space allows, measured per row, so a tall entry in one card no longer decides how many the others show and a bigger screen genuinely shows more. Extra items and notes rotate every 20 seconds; the bottom controls let you pause, change pages, enter full screen, or exit. Long titles and notes are shown as concise previews; open the normal app for full details.
Display mode uses the same signed-in household session and refreshes shared records every 15 seconds. It does not create a public sharing link or grant extra access. The URL keeps the display preference across reloads. Set the TV/computer's sleep settings separately if you want an always-on display.
Controls use Radix UI primitives and Motion, styled to match the house: sliding filter highlights, tactile buttons, drawn checkmarks, and gentle entrances. A living windowsill illustration appears across the app: tap the cat to make it stretch, or complete a to-do to get a small reaction. The cat breathes and flicks its tail, the plant sways, and clouds drift past. On phones the cat sits in the top bar; on a TV the scene sits beside the clock. The TV button has a soft idle shimmer, and display mode has slowly drifting background color. Use Motion on/off in display mode or household settings to pause ambient effects; the choice stays on this device. Idle effects stop in hidden tabs, and system reduced-motion preferences are respected.
Lists and undo notices animate out while writes continue in the background. Surviving rows move into place; dialog closes preserve focus and keyboard dismissal. Notes and expense editors share a transition with their source card or row. Reduced motion removes these transitions.
The To-dos and Shopping lists open with whatever is waiting on you — your own unfinished chores and the items you said you'd grab — the way the overview already puts your chores first. Anything done, or belonging to your housemate, keeps the order it had, and a shared screen with nobody signed in reorders nothing. To-dos and shopping rows have drag handles: use a pointer or focus the handle and press Up/Down (Home/End also work). Arranging a list by hand replaces that opening order for good on this device. Shared list order synchronizes across devices. It does not change the household's due dates. Row menus offer edit and delete; the usual undo still works. A to-do or shopping item can be filed as Personal — yours rather than the house's, like renewing renters insurance or buying your own shampoo. It keeps off the overview, wall display, shared shopping message, and morning and evening digests, and waits under the relevant Personal filter instead. It is the entry's category, so the editor can set it and anything added while Personal is on show is filed there for you. A personal item's estimate is charged only to the person it is for when someone marks it bought. The other person can still open that filter and see it, so it is a quieter lane, not a locked drawer. House notes have a quick composer, member-colored paper, individual tilts, and crumpling exits. A note's menu offers Pin to the top: a pinned note stays first on the fridge card, the notes board, and the wall, so the Wi-Fi password or the house rules never scroll away under newer notes (it is the note's category, so the editor can set it too). The menu also offers Take down: it leaves the fridge, the notes board, and the wall, and waits under "Taken down" at the foot of House notes, where it can be put back up or thrown out. In household settings, hover or focus a member magnet for their open chore count and balance; a repeating chore counts once there, as it does on the overview.
The home greeting highlights a recent action by another housemate. “Lately at home” in household settings shows the latest 20 completed chores, purchases, bill payments, reopened items, and notes. Actions are saved with the person who performed them and the actual time, and appear across devices. Activity starts after migration 012; older entries are not given invented completion times.
Completing items releases paper scraps; finishing the last chore gets an all-done message. Paid bills receive a stamp, repayments get a short transfer illustration, and expense totals count to their new values. Activity is grouped by month, with older months collapsed. Repayment feedback indicates a ledger entry, not a money transfer.
The cat window follows local device time and the commute strip's weather reading. Wall display changes its palette in the morning/evening and dims from 22:00–06:00. Weather particles, seasonal leaves/snow, a subtle card spotlight, and a one-pixel drift all follow the existing ambient gate. Ambient pause also stops automatic board paging and flip animation; actual time and household data stay current. Decorative loops pause in hidden tabs. Seasonal decoration follows the device's calendar month; it is not a forecast.
The Expenses tab records shared purchases, who paid, and even splits among selected housemates. Amounts are calculated in whole cents; any remainder is assigned consistently so shares always add up to the total. Adjust shares in the split box turns the even amounts into inputs, for the night one person had the wine: type each share (0 is allowed), the hint says what is left to assign, and the save is refused until they add up. An expense saved that way reopens with its shares as typed (unless they happen to be the even split, which reopens as one). Balances show who owes whom, with a Venmo handoff and a copyable Zelle/general payment note that names the payer, recipient, amount, and household. These links help housemates pay outside Common Ground; Record paid remains a separate bookkeeping action and does not transfer money. Repayments reduce the balance without increasing monthly spending. A new entry is read out to the people in it ("Alex logged a purchase — “Groceries” $82.50, your share $27.50"; "Sam paid you back — $40.00, recorded on the ledger"), with the same quiet hours as a nudge; edits and deletions stay quiet. Purchases and repayments can be edited or deleted from Activity. Entries save optimistically and refresh across devices.
Expenses use migration 006_expenses.sql and a separate household-scoped gateway. I paid is a reminder check only. Log my share to Expenses records your original share paid by you, without creating debt. I covered the whole bill (or I covered the remaining shares) logs only unpaid original shares and checks those people off. Migration 021 links these postings: retries cannot duplicate them, deleting the expense reverses only checks it created, and monetary edits require deleting and re-logging the linked expense. The home board shows who owes whom from the ledger. None of these actions transfers money.
House notes can be turned into a to-do, plan, or shopping item: open the note and pick a new type in the edit dialog. The entry keeps its title, details, and author; turning one into a rent or bill event adds payment checks for everyone.
Household life groups five shared tools:
house-maintenance bucket and authenticated, short-lived links.Apply migrations through 024_household_life_membership.sql before deploying this update. Photo attachments additionally need the existing server-only SUPABASE_SERVICE_ROLE_KEY; records work without photo storage. All writes use the household token gateway and selected member identity. Shared screens can read these tools. Updates refresh through existing change broadcasts and a 15-second fallback poll. Sample-household changes last until reload.
A device can sign in as the household instead of as a person: pick This is a shared screen on the "Who's this?" step. It is meant for the kitchen tablet or the wall display, which is nobody in particular.
Such a device is read-only. It shows the house by name with no "you"
anywhere, no yours-first ordering, and none of the controls that would author a
change — no quick add, no checkboxes, no row menus, no note composer, no
expense editor, no add-housemate form. This is not only a UI choice: every
gateway function in the migrations requires an actor that is a real housemate
(name <> 'Housemates') and refuses the shared identity, so the house's own
records always say which person did a thing. Pick a person from Change person
on this device to check things off again.
Signed-in devices join a Supabase Realtime broadcast channel and ping each other after every successful save, so a change made on one phone appears on the other phone and the wall display within a moment. The pings carry no household data — just "something changed" and which board — and the channel name is a secret derived server-side, handed only to signed-in sessions. The 15-second poll stays on as the safety net, so nothing is lost if the channel drops; the wall footer says "updates live" while the channel is connected. A device ignores its own pings, since a successful write already updated its screen.
The site is an installable web app: manifest.webmanifest plus home-screen
icons rendered from the house cat. On iPhone or iPad use Share → Add to Home
Screen; Android and desktop Chrome offer their own install prompts. A long
press on the installed icon (Android and desktop Chrome) offers Add a
to-do, Shopping list, and Wall display; the links behind them,
/?tab=To-dos&add=task, /?tab=Shopping%20list, and /?display=1, work
from anywhere, and an add waits for you to be signed in as a housemate.
Morning reminders send one push notification per subscribed device at the person’s chosen morning time in the household timezone: the day's chores for whoever the device belongs to (unassigned chores go to both people), any bill whose check that person hasn't ticked within three days of its date, the house's plans for the day, and a count of needed shopping items. When a digest is going out anyway, it ends with what the ledger says about you ("You owe Alex $12", "Sam owes you $5", at most two lines); a balance on its own doesn't wake anyone. Nothing due means no notification. Evening heads-ups go out at the selected evening time: tomorrow's chores and plans and any bill due tomorrow that person hasn't checked off, plus whatever of today's is still open. Nothing tomorrow and nothing left today means no notification — except on Sunday, when the evening one ends with the week's recap ("4 chores done this week — Alex 2, Sam 1, shared 1", "$106.50 spent together this week"), counting done chores by their due day. Separately, a new house note is read out to everyone else's subscribed phones the moment it's pinned ("Sam left a note on the fridge — Friends coming over this weekend?…"), except during quiet hours, when the note simply waits on the fridge. A plan or a bill going onto the calendar is read out the same way ("Sam put a plan on the calendar — “House dinner” is on Saturday", "Sam added a bill — “Internet” ($80, $40 each) is due Sep 15"), once for a repeating one. And when someone else ticks off a to-do or picks up an item you added, your phone hears it ("Alex took care of “Take out recycling”"), same quiet hours. Each device opts in from Our household → Reminders, which also has a "send today's digest now" button for checking the pipeline end to end. On iOS the app must be installed to the Home Screen first; the settings section says so when it detects that state.
Setup needs four server-side pieces:
008_push_subscriptions.sql (verify with
supabase/tests/push-subscriptions.sql in a disposable database).npx web-push generate-vapid-keys and set
NEXT_PUBLIC_VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY (plus an optional
VAPID_SUBJECT, a mailto: address) in Vercel and .env.local.CRON_SECRET to a random value; Vercel sends it as a bearer token when
invoking the cron route.026_feature_improvements.sql. The daily Vercel cron in
vercel.json provides a roll-forward fallback compatible with Hobby hosting.
For custom delivery times, configure .github/workflows/reminders.yml with the
repository variable REMINDER_APP_URL (the HTTPS production origin) and a
repository secret REMINDER_SCHEDULER_SECRET; put the same secret in Vercel's
production environment and redeploy. The workflow calls /api/reminders/custom
every five minutes. An external scheduler can instead use CRON_SECRET.
Do not also enable the older morning/evening digest cron jobs.
Delivery happens after the chosen time at the next available scheduler run;
GitHub Actions can delay scheduled jobs. A one-hour catch-up window and
persistent per-device claims tolerate delays without resending a digest.
Quiet hours suppress automatic pushes; the explicit “send today’s digest now”
test ignores the schedule and quiet hours.Subscriptions live in the push_subscriptions table behind the same
token-gated gateway pattern as everything else, tied to the person using the
device. Change person on this device moves the subscription with them, so
the morning digest never keeps arriving for the housemate who used the phone
last; choosing the shared screen clears it, since a kitchen display gets no
personal reminders. Dead endpoints are pruned automatically when a push
bounces.
Migration 026 persists delivery claims per subscribed device, edition, and household-local date. Interrupted claims expire after five minutes and failed deliveries can be retried. Our household → Household reliability shows interrupted/failed/partial deliveries and lets a housemate retry outside quiet hours. A retry skips devices whose success was recorded. A push accepted just before the database fails may still be resent; this is not an exactly-once guarantee across the push provider and database. Fan-out isolates individual failures and has a bounded concurrency/time budget. The five-minute scheduler also appends gym sessions and chore rotations when their horizon is within two weeks, even if push is not configured. They preserve existing entries, swaps, skips, and workout logs. Nudge/thanks cooldowns are stored in SQL, so a cold instance does not reset them.
A band above the noticeboard shows the current weather beside the next few departures, on both the home screen and the wall display. PATH and subway arrivals are interleaved so one busy station cannot crowd out the other, and each departure names the station it leaves from so the two are never confused.
Departures carry an absolute arrival time, so the minutes count down on their own between the 30-second polls instead of freezing on whatever the last response said, and a train that has gone drops off without waiting for a refresh. Anything a minute out is highlighted, since that is the one you might still catch. How many departures appear is measured from the space available, and never falls below one per station you added. On a phone the departures stack under the weather instead, three deep (two on shorter phones), and the band is dropped on screens under 700px tall.
When an agency feed cannot be reached the board keeps its last known times but marks itself Not live rather than passing them off as current; the same marker appears when one station of several fails. The refresh button reloads the weather and departures immediately; hover it to see when the board last updated. It appears in display mode too, which otherwise refreshes departures every 30 seconds on its own.
Subway service alerts that are in effect right now — delays, reroutes, active planned work — appear as a quiet line under the departures, limited to the routes serving your saved stations (and to your chosen route filters). Live disruptions sort before planned work. The alerts come from the MTA's public alerts feed, cached for five minutes; if it can't be reached the line simply disappears rather than flagging the board. PATH has no comparable feed, so its free-text delay notes on individual trains remain the only PATH signal.
Each station can also carry a walk time, set in the gear panel. Departures from that station then show "leave in 4 min" next to the destination, counting down locally like the arrival times do, and the highlighted train becomes the one you must leave for now rather than the one arriving next — an arriving train you can no longer reach is not worth running for.
The gear button opens a managed list of stations. One search box covers both systems, so "14 st" finds PATH's 14th Street and the MTA's 14 St platforms together. Add up to six stops, reorder them, or remove them; the weather follows whichever station sits first in the list.
Expand a station to choose which of its trains you actually care about. A subway stop offers its routes and its two platform directions, so W 4 St can show only the A downtown. PATH has one line, so it offers destinations instead, letting Journal Square show World Trade Center trains and skip the 33rd Street ones.
Each row starts on All. Clicking a named option selects just that option, and further clicks add to the selection; clicking All, deselecting the last option, or selecting every option all return to showing everything. A stop can never end up blank.
The subway's options come from the station list; PATH's come from its live board, since only the feed knows which destinations are running. Anything already saved is folded into the options, so a filter set for a train that is not running right now stays visible and undoable. Filtering happens in the browser, so every household shares one cached upstream response no matter how differently they have each set things up.
The list is saved in localStorage, per device, so the TV and each phone can
show different stops. The wall display is read only apart from refresh, so set
its stations before switching into display mode.
Three upstream sources are used, none of which needs an API key:
| Data | Source | Notes |
|---|---|---|
| Weather | Open-Meteo | Current conditions plus the day's high, low, and chance of rain. |
| PATH | panynj.gov/bin/portauthority/ridepath.json | The endpoint behind the RidePATH app. Unofficial and undocumented; it can change without notice. |
| NYC Subway | MTA GTFS-realtime | Protocol buffer feeds, split by line group. No key required. |
Requests go through route handlers in app/api/ rather than the browser: the
subway feeds are protobuf and are not reachable directly from a page. Responses
are cached in memory for 20 seconds (10 minutes for weather) and concurrent
requests are coalesced, so a TV polling all day makes about three upstream
requests a minute regardless of how many housemates have the page open. When an
upstream fails, the last good board keeps showing instead of going blank.
These are third-party requests. The servers involved see your deployment's IP address and the station and coordinates being asked about; no household data is sent. The PATH widget is the most likely to break, so treat it as a nicety rather than something to catch a train by, and check the platform clock.
lib/subway-stations.json holds the 496 subway stations and is committed so
the app never depends on data.ny.gov at request time. It is read only by
lib/subway-data.ts, which the route handlers import; keeping it out of
lib/transit.ts is deliberate, since that module reaches the browser and the
station file would otherwise be bundled with it. Regenerate it when the MTA
opens or re-routes a station:
node scripts/build-subway-stations.mjs
Departure predictions come from the agencies and are only as good as their feeds. Service changes, skipped stops, and planned diversions are not shown.
Requires Node.js 22+ and npm.
npm install
npm run dev
Open the localhost address printed by Next.js. Without Supabase environment variables, the app opens an interactive sample household. Demo changes stay in memory and reset when you reload; no private information should be stored in the demo.
Household supplies: toilet paper, soap, paper towels — is shown as that heading with the things under it laid out beside each other, on the list, the overview, the wall display, and the shared list; the overview's opening sentence names it by its heading alone, so one entry cannot swallow the line; it stays one entry that is ticked off as a unit. A title needs a colon and at least two comma-separated things, so Costco: olive oil and Dinner at 7:30 stay ordinary titles. Tap the hand on a household row to say I’ll grab it; the row, the overview, and the wall display then say who is getting it, and tapping again lets it go. Your own claims and chores read as “you” on your screens; the wall display keeps names, since the whole house reads it. Share list in the tab heading hands the open household items, with prices and who is getting what, to your phone's share sheet (or copies them on a laptop) for whoever is already at the store; a title written as its own list sends its things one per line under the heading, so they can be bought one at a time. A bought item's menu offers Need again, which puts a fresh copy back on the list and leaves the old purchase logged. With the app installed, it also shows up in the phone's share sheet: share a product page from a store app or the browser and the shopping dialog opens with the link and name filled in, ready to save (Android and desktop Chrome; iOS share sheets don't offer web apps). The add box is a notepad: type or paste one thing per line, and Enter adds every line as its own item, exactly as written, while the cursor stays put (Shift+Enter for a new line).The household code is the only authentication. After entering it, choose Amane
or Barnatt. The choice is stored in an HTTP-only cookie for 30 days and can be
changed from the sidebar footer or, on a phone, from Our household →
Switch person. It controls attribution and the Mine filter;
it does not grant different access rights. Existing entries keep their original
creator, including the legacy shared Housemates identity. That identity is a
members row created by migration 002, not a person: it is never offered as an
assignee, payer, or person to switch to, and it is not listed or counted as a
housemate.
For a fresh database, apply migrations in order: 001_household.sql,
002_shared_code.sql (using psql with -v gateway_hash=<SHA-256 of your gateway token>),
003_recurring_entries.sql, 004_device_identity.sql, 005_chores_bills_undo.sql,
006_expenses.sql, 007_covered_bills_note_conversion.sql,
008_push_subscriptions.sql, 009_cover_expense_and_attempt_clear.sql,
010_push_subscribe_hardening.sql, 011_revoke_legacy_multi_user.sql,
012_house_activity.sql, 013_pinned_notes.sql, 014_personal_todos.sql,
015_agreements.sql, 016_house_handbook.sql, 017_timed_house_status.sql,
019_daily_life_gaps.sql, 020_edit_undo.sql,
021_household_reliability.sql, 022_household_life.sql,
023_house_coordination.sql, 024_household_life_membership.sql, and
025_search_offline_chore_bill_splits.sql.
For an existing installation, apply only the migrations newer than the last installed migration.
Use npm run migrate with pg_connection_url in .env or a server-only
MIGRATION_DATABASE_URL. It applies pending files in order, one transaction per
file, with an advisory lock and SHA-256 checksums recorded in the private
household_schema_migrations table. npm run migrate -- --check reports pending
or changed migrations. Never edit an applied migration.
Legacy installations have no ledger: verify the actual installed schema first,
then explicitly baseline it, for example npm run migrate -- --baseline 016
only if 001–016 are already installed. This records that asserted baseline
and applies newer migrations; it does not replay historical DDL. The runner
refuses to replay migration 001 onto an existing household. If direct Supabase
IPv6 is unreachable, set MIGRATION_POOLER_HOST to the project's verified
session-pooler hostname from Supabase; the runner uses port 5432 and the project
qualified user. Connection passwords/tokens are not printed.
Migration 021 bounds home RPC pages to 500 entries (open items plus a date window)
and exposes 50-row historical pages. Calendar navigation loads its selected
month; older bought shopping remains saved in Household history, not deleted.
It also temporarily disables adding a third real member in both the UI and SQL.
Personal records are excluded from calendar exports/subscriptions; the shared
feed still includes bill amounts, and signing out does not revoke its URL.
Attachment availability is shown in settings. Signing still uses the server-only
storage key, which must never be exposed to browser code.
Migration 017 adds event end times and the Away, Guest, and Quiet hours
categories. It also persists event times through the household gateway and
expands an away or guest date range into a bounded daily series. Verify it with
supabase/tests/timed-house-status.sql in a disposable database.
Migration 016 adds structured handbook entries, private attachment metadata, and
the private house-handbook Storage bucket. Set the server-only
SUPABASE_SERVICE_ROLE_KEY to enable uploads and signed downloads; handbook
text still works without it. Verify the gateway with
supabase/tests/house-handbook.sql in a disposable database.
Migration 015 adds the house and gym agreements: the signed documents, amendments,
relief requests (swaps, skips, reschedules, gym PTO), generated gym sessions with a
time of day, and per-person workout logs. Apply it before deploying this
frontend; without it the Agreements section cannot load and gym sessions cannot
be placed on the calendar. Existing entries are untouched. Verify it with
supabase/tests/agreements.sql in a disposable database.
Migration 014 lets a to-do or shopping item's category be “Personal”. Apply it
before deploying personal entries; without it the category is refused. Verify
it with in a disposable database.
Migration 013 lets a note's category be “Pinned”. Apply it before deploying
pinned notes; without it a pin is refused and the note stays where it was.
Verify it with in a disposable database.
Migration 012 adds the private “Lately at home” feed and records the actual actor
and completion time from successful changes. Apply it before deploying this
frontend. Existing entries are untouched; activity starts with new actions.
Migration 004 adds Amane and Barnatt if absent, validates the selected household
member on writes, and returns saved entry IDs with create responses. It preserves existing entries and members.
Configure the variables listed in .env.example: the Supabase URL and
publishable key, HOUSEHOLD_ACCESS_CODE, HOUSEHOLD_SESSION_SECRET, and
HOUSEHOLD_DATA_TOKEN. Keep the last three server-only. Add the server-only
SUPABASE_SERVICE_ROLE_KEY when handbook attachments are enabled. The data
token must match the hash supplied to migration 002. Code rotation invalidates
existing sessions; sign-out clears both authentication and person cookies.
Entry creation, edits, check-offs, and deletion appear immediately. Background writes run in order so rapid clicks cannot arrive out of order, and polling waits for them to finish. Successful changes need no follow-up GET. A failed write shows a brief notice and quietly reloads after the queue drains. Normal cross-device updates arrive live, every 15 seconds, and on focus. Task and shopping pages also support typing a title and pressing Enter to add it.
Apply migration 005 before deploying this batch. It adds payment and rotation
fields, backfills existing rent participants without marking anyone paid, and
adds a private table for short-lived deletion snapshots. Verify it with
supabase/tests/chores-bills-undo.sql in the disposable database described below.
Apply migration 007 before deploying covered bills and note conversion. It
lets the payment operation check off every payer at once and lets updates
change an entry's kind, managing payment checks when an entry enters or leaves
bill status. Verify it with supabase/tests/covered-bills-note-conversion.sql
in the disposable database described below.
The Vercel CLI is included as a development dependency. Deploy directly from this folder; no extra repository clone is needed:
npx vercel login
npx vercel link
npx vercel env add NEXT_PUBLIC_SUPABASE_URL production
npx vercel env add NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY production
npx vercel --prod
Use the HTTPS Supabase project URL for NEXT_PUBLIC_SUPABASE_URL, never a PostgreSQL connection string. The local .env file does not configure Vercel's hosted environment. Configure all server-only household variables and apply the migrations described above before deploying for household use.
Alternatively, import the GitHub repository through Vercel's website:
NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY as Vercel environment variables for the desired environments.This repository does not create cloud accounts, remote Git repositories, or paid resources. No live Supabase project or Vercel deployment is provisioned by the local scaffold. Google Fonts are loaded from Google with local fallback fonts if unavailable.
npm run typecheck
npm test
SQL_TEST_DATABASE_URL=postgresql://postgres:[email protected]:5432/postgres npm run test:sql
npm run build
With the development server running and Google Chrome installed, run npm run test:browser for desktop/mobile interaction tests. Set PW_BROWSER_CHANNEL=chromium to use bundled Playwright Chromium. CI runs type generation, typecheck, unit tests, all staged SQL suites, production build, and the mocked reliability browser tests (including Agreements signing and handbook file opening).
The SQL harness creates its own uniquely named database on a local admin
database postgres, bootstraps the minimal Supabase-compatible auth/storage
definitions, and runs each suite at its required migration version. It refuses
remote URLs and never drops the supplied database. On success its own database
is dropped; on failure it is retained for diagnosis. PostgreSQL and psql must
be installed locally. Never point SQL tests at production.
Calendar tests cover all-day date boundaries, escaping of user text, UTF-8 line folding, filtering of exported records, and safe external links. supabase/tests/isolation.sql verifies RLS and write restrictions inside a transaction that rolls back its fixtures; run it against a disposable database with the schema installed. The local test harness requires a local PostgreSQL server and Supabase-compatible auth.users, auth.uid(), anon, and authenticated definitions.
Push subscription storage has its own check, supabase/tests/push-subscriptions.sql,
run the same way with migrations 001–008 installed.
The new database regression check is supabase/tests/device-identity.sql.
Run it only in a disposable database with migrations 001–004 and the gateway
hash set to SHA-256 of test-gateway. It checks creator attribution, returned
series IDs, valid member edits, invalid member rejection, and gateway access.
For the mocked shared-code browser checks, start the app with its public Supabase variables set, then run:
PW_SHARED_API=1 npx playwright test tests/browser/optimistic.spec.ts tests/browser/reliability.spec.ts
These tests intercept session and household requests; they never modify the live household. The other browser tests use the demo app (start with both public Supabase variables empty).
Suggested order:
SUPABASE_SERVICE_ROLE_KEY on the server to enable them.Chore reminders and push notifications shipped as the daily morning digest; shared expenses shipped as the Expenses tab. Data amounts are USD; events can be timed or all-day, and weekly, biweekly, and monthly recurring entries are supported. Reminder times, timezone, quiet hours and notification topics are configurable. Home/history and ledger/agreements return bounded RPC pages; expenses retain full-ledger balance and monthly-summary aggregates while older activity loads on demand.
Apply migrations 019_daily_life_gaps.sql and 020_edit_undo.sql before deploying
this update. Migration 021 adds the household reliability work after those
changes; 019 and 020 also work directly after 017. The history wrappers preserve gateway
validation, and edit undo stores private, expiring snapshots rather than accepting
restoration data from clients.
Verify with tests/daily-life-gaps.test.ts, supabase/tests/daily-life-gaps.sql,
and tests/browser/daily-life-gaps.spec.ts. The older isolation.sql targets
legacy authenticated-user functions revoked by migration 011; gateway isolation
is exercised by the current SQL tests.
Apply 026_feature_improvements.sql before deploying this release. The Vercel
ignore command checks the production schema and holds deployments until schema
026 is available; the current app stays live. This release also requires migration 027. After applying the migrations,
redeploy the merged commit. Preview and demo builds proceed normally. It adds
shared household time settings and chore templates; person-specific reminder
preferences; shopping quantities, units and stores; checklist progress and effort;
expense categories, retained percentage splits, receipt metadata and history
pagination; private entry visibility; coverage approvals; and replay receipts.
The scheduler keeps recurring agreements rolling forward even without push keys.
Receipt uploads use the private expense-receipts bucket and the existing
SUPABASE_SERVICE_ROLE_KEY. Save a purchase, then reopen it to attach PDF,
JPEG, PNG or WebP receipts (up to 10 MB each). Downloads use two-minute signed URLs.
Percentages accept up to two decimals, must total 100%, and use deterministic
largest-remainder rounding so shares always add up to the purchase in cents.
Repayments never count toward the monthly spending summary. Shopping estimates
refer to the whole row including its quantity. Bundled Heading: Item, Item
entries split atomically into independently checkable rows; per-item estimates
start empty rather than inventing prices.
Personal items remain visible to housemates by default. Optional private personal chores/shopping items are returned only for their creator’s selected identity. Private actions stay out of shared activity, calendar feeds, boards and digests; earlier activity created while an item was shared remains visible. Each person signs in with a password. First-time owner enrollment requires a separate setup secret; other members need an owner-issued one-time invitation. The household code alone opens a read-only view. Private shopping purchases are not automatically posted to the shared ledger. Shared screens remain read-only and receive no private entries.
Offline support saves previously opened boards, expenses, handbook and agreement information on this device for up to 30 days, plus the app shell and static assets. Chore/shopping and ledger create/edit/delete changes queue locally, with stable IDs, ordered replay and database mutation receipts. Synced expenses update full balances and summaries even when history is paginated. Person changes require syncing or discarding the current queue first; sign-out clears saved household records and queued changes. Unopened information, receipt transfers, payments, short-lived Undo actions, settings and agreement/coverage decisions need a connection. The banner shows queued changes, retry failures and discard controls. An unavailable or rejected replay pauses the queue for review. Existing server permissions and validations remain authoritative; ordinary queued edits use the same overwrite behavior as online edits.
The search button checks saved records in demo/offline mode and all household chores, notes, expenses and handbook records (including older history) online. Every search response caps at 51 results; the UI displays 50 and asks for a more specific query when needed. Guest visits conflicting with household quiet hours or shared calendar plans require a review check before saving. Away-aware coverage suggestions never reassign a chore automatically: the two involved housemates approve one occurrence, and the server rechecks availability and the original assignment before changing it.
Validation: tests/feature-improvements.test.ts,
supabase/tests/feature-improvements.sql, and
tests/browser/feature-improvements.spec.ts, alongside existing unit, SQL,
production-build and household reliability browser checks.
Apply migrations through 024_household_life_membership.sql before rolling out this update. Migration 022 for household life was already applied when coordination reached main, so its contents are preserved and the previously unapplied coordination migration follows as 023. Migration 024 connects membership removal to polls, repair assignments, and future meal plans.
House planning brings together weekly reviews, shared reservations, and moving
checklists. A review lists unpaid bills and unfinished shared chores through the
end of next week, including overdue and undated work, plus proposed agreements,
open amendments, relief requests, and household decisions. Save review notes for
the current Monday-based household week (New York time); the previous twelve
reviews remain available. Personal tasks stay outside the review.
Reserve Laundry, Parking spot, Shared workspace, or a custom resource, using the household time zone. Reservations appear on the calendar and its feed, with optional 30-minute reminders. Reservations may last up to 24 hours and start within 180 days. Database row locks prevent overlapping reservations even when two devices save together; adjacent slots are allowed. Each housemate cancels their own reservations. Move-in and move-out checklists keep keys, deposits, meter readings, cleaning, and final balances with item notes and completion checks. Amounts in checklist notes do not post to Expenses. Shared screens can read all three features but cannot change them.
In Our household, the owner adds a housemate's name and privately shares the existing household code. Households support larger rosters after migration 027; recurring chores and agreements include every current housemate. Migration 022 assigns a legacy shared-screen owner to the first named housemate in alphabetical order; existing named owners remain owners. Ownership must be transferred before the owner leaves. Removing or leaving archives membership, stops reminders, cancels future bookings, and unassigns unfinished shared chores. Past expenses, outstanding balances, completed work, and moving checklists remain, and final repayments can still name a former housemate.
A roster change archives signed/proposed agreements, cancels unfinished future
generated obligations, closes pending agreement decisions, and returns live
agreements to draft for review with the new housemate. The original terms and
signatures remain readable in House planning. Member actions require that person's password; an owner issues invitations for new accounts. To revoke a departed person's household access, rotate
HOUSEHOLD_ACCESS_CODE in the hosting settings and redeploy; this invalidates
existing sessions and the calendar subscription link.
Validation includes tests/coordination.test.ts,
supabase/tests/house-coordination.sql, and
tests/browser/coordination.spec.ts (demo desktop/mobile flows and mocked
shared-household permissions and membership).
Apply 025_search_offline_chore_bill_splits.sql before deploying. The top-bar
Search the household button searches current and older entries, expenses,
handbook values and attachment filenames, agreements, household life and house
planning records. Every word must match, accents are ignored, and More results
loads the next 50 matches. Open a result for details and its relevant tab;
entries open their own editor for housemates. Personal and completed records
remain searchable by everyone holding the household session.
Shopping offers Open saved list for offline shopping. Opening the app online saves this household's shopping snapshot on the device. The separate checklist opens and reloads without a signal after its public shell is installed. Check-offs stay in a durable queue and sync on reconnect or Sync now, using the same selected person. Purchases with estimates log their expense atomically, once, with the normal household/personal split. Reopening keeps any existing expense. Changed or removed items show a conflict; Use latest household version discards that local check-off. Signing out or changing person clears the snapshot and queue. Shared screens can read their saved list but cannot author check-offs. Only the public checklist shell is cached by the service worker; household API responses and signed-in pages remain network-served. Demo check-offs stay local.
To-do rows show Last done with the actual completion time and person, including previous occurrences of recurring chores outside the visible date window. Reopening preserves that history. Completion timestamps recorded since 021 are retained; old completions without a known timestamp or actor stay unknown.
Rent and bill editors offer Adjust each person’s share in dollars, including zero. Shares must sum exactly to the total in cents. Recurring creation and series edits carry the split to each occurrence while preserving payment checks. Checks, reminders, calendar exports, Log my share and partial/whole bill covers use those saved shares. Linked expenses must be deleted before changing their bill's split; edit undo and delete undo preserve shares.
Validation: tests/search-offline-chore-bill-splits.test.ts,
supabase/tests/search-offline-chore-bill-splits.sql, and
tests/browser/search-offline-chore-bill-splits.spec.ts.
Apply 027_fair_chores_household_setup.sql with npm run migrate before
deploying this release. The production build gate requires schema version 027.
To-dos shows Monday–Sunday chore workload in estimated minutes, alongside completed minutes credited to the person who checked off each occurrence in the household timezone. Week arrows show earlier and upcoming schedules. Personal work, undated chores, and chores outside the selected week are excluded; missing estimates are flagged rather than counted as zero-effort chores. Suggestions distribute larger pending chores first, respect away dates, and keep completed work fixed. Review opens the chore editor; save explicitly to change that occurrence. Suggestions recalculate after every saved assignment.
Owners can invite more than two housemates. Recurring chores can rotate through any selected set of at least two current housemates, with the first assignee going first. Agreement bundles rotate through the complete roster with staggered starting assignments; over a full rotation everyone holds each bundle equally. Every current housemate must sign agreements and approve amendments. Chore swap and cover requests name a recipient; only that recipient can answer. Joint gym reschedules require every other housemate’s acceptance. Invitations archive existing signed agreements and reset them to draft for the new roster, while preserving past completions and payment history. Existing bill shares stay as originally recorded; new bills include the current roster.
Our household includes a live setup checklist for invitations, recurring bills, recurring chores with effort and rotations, and notification choices. The checklist opens prefilled recurring bill and chore forms, or jumps to the member and notification settings. Saved notification choices complete that step even when reminders are disabled; enabling push on a device is separate. Shared screens can read setup and workload but cannot make changes.
Each page has a bookmarkable URL, for example /?tab=calendar,
/?tab=expenses, and /?tab=attention. Refresh restores that page; Back and
Forward follow page changes. Existing named-tab shortcuts and share-sheet
arrivals still work, and display mode keeps its URL flag.
The overview, calendar, overdue labels, bill posting dates, expense forms and monthly totals, agreement scheduling, and attention list use the timezone in household reminder settings. The household clock updates at minute boundaries and when a device returns to the app, including across midnight and DST changes.
“Needs your attention” shows the selected person's open to-dos, unpaid bill shares, proposed agreements, incoming amendments/requests, and coverage decisions. It keeps every overdue occurrence and the next upcoming occurrence of each series. Review opens the item or exact agreement; chores and bill shares can be completed directly, and the receiving housemate can approve or decline coverage. Shared screens do not have personal actions. Failed request loads are shown as an incomplete list with a retry action.
Personal visibility restricts an item to its creator's signed-in account. A shared-code session has read-only household access. New accounts require the owner setup secret or an owner-issued invitation before a password can be set.
Apply migration 028 before production deployment. It updates server posting dates, check-in weeks, schedule maintenance, and agreement history windows to use the household timezone. The deployment gate holds production until 028 is confirmed.
Apply migration 029_anonymous_house_polls.sql before deploying anonymous polls. It also anonymizes responses for existing polls and saved decisions; the production deployment gate requires schema 029.
.ics calendar export and per-event Google Calendar links, which create snapshots/copies. Subscribe on your phone in household settings gives a private feed URL instead: Apple, Google, or Outlook Calendar polls it on its own schedule, so plans and dated chores stay current without re-exporting. The feed and the export both carry the household's name, so the phone lists it as "The Maple House" rather than the URL it came from, and the feed asks to be re-read hourly rather than leaving the cadence to the phone. The link is a secret derived from the household code and session secret, so it is never stored, and changing the household code revokes every subscription at once. On the phone a chore reads as “Dishes — Alex” (“✓ Dishes — Alex” once done) and a bill as “Rent — $2,400”, with each person's share and who has paid in its notes. It reads the calendar only; nothing writes back.supabase/tests/personal-todos.sqlsupabase/tests/pinned-notes.sql