Pages and actions
Every address the app serves a page on, and every form action behind it — read from the route tree, so a page added or an action renamed shows up here on the next build.
An action is what a <form method="post"> posts to. They are the app's
own write surface, the way the endpoints in the API are the
write surface for everything else; both end up calling the same
services.
37 pages, 153 actions.
| Page | Actions |
|---|---|
/ |
createDiaryEntry, saveWins, setLayout, resetLayout |
/admin |
unban, blockForever, unblockForever, dismissReport, setRole, retryMail, dismissMail |
/admin/[id] |
setRole, setPlanEnd, grantTrial, resendVerification, impersonate |
/buy |
— |
/data/[slug] |
— |
/diary |
create, createWins, update, delete |
/diary/notebooks |
— |
/diary/notebooks/[id] |
— |
/diary/people |
create, update, delete |
/goals |
createArea, deleteArea, create, update, setProgress, close, setLinks, remove |
/health/habits |
create, update, delete, logOccurrence, toggleOccurrence, updateOccurrence, deleteOccurrence |
/ideas |
create, update, delete, toggleApplied, updateAppliedNote, toggleFavorite |
/kitchen/meals |
— |
/kitchen/recipes |
— |
/kitchen/recipes/[id] |
— |
/legal/privacy |
— |
/legal/terms |
— |
/login |
signIn, signUp, requestReset, signOut |
/login/reset |
reset |
/login/verify |
resend |
/offline |
— |
/planner/activities |
create, update, toggleActive, delete, createCategory, updateCategory, deleteCategory |
/planner/board |
setStatus, setTiming, reorder, schedule, promote, demote, createTodo, setRatings, remind, unremind, editInstance, resolveActivity, deleteInstance, deleteTodo |
/planner/history |
— |
/planner/plan |
create, update, toggleActive, delete, bulkDelete, copyToWeekdays, clearAll, addCalendar, removeCalendar, applyTemplate, saveScheme, loadScheme, deleteScheme, renameScheme, scheduleTodo, unscheduleBlock, convertRepeat, moveOccurrence, suppress, unsuppress, createExceptional, updateExceptional, deleteExceptional, importCsv |
/planner/review |
saveLines, keepStale, completeStale, dropStale, resolve, carry |
/planner/todo |
create, remind, unremind, update, setStatus, schedule, delete, delegate |
/search |
— |
/settings/account |
changeEmail, changePassword, revokeSession, signOutEverywhere, delete |
/settings/billing |
checkout, switchInterval |
/settings/instance |
setRegistration, setEmailChange, setClientErrors, createInvite, revokeInvite |
/settings/integrations |
createToken, calendarLink, revokeToken, updateStream, deleteStream, createWebhook, deleteWebhook, reviveWebhook |
/settings/integrations/widget |
connect |
/settings/preferences |
setErrorReports, saveCurrency, saveGridHours, setSections, setLayout, resetLayout, addQuote, importQuotes, deleteQuote, setStyle, setTheme, saveWeek |
/shopping |
saveCategories, createCategory, create, update, toggleBought, paid, delete, restock, toggleSnoozed |
/start |
checkout |
/welcome |
default |
What these pages do
Only the ones whose code says — the comment at the top of the route file, and the comment above each action. Write it there and it turns up here; the rest are named for what they do.
/admin/[id]
setPlanEnd
The operator's clock: end the plan on a chosen date.
grantTrial
A trial for an account that predates billing — see grantTrial.
resendVerification
Send the confirmation link again, for somebody who never got the first.
impersonate
Sign in as somebody else, with the session marked as borrowed.
Recorded against both accounts before it happens: the point of the log is that the person whose account it is can see it too.
/buy
The one page that loads the payment provider's script.
A checkout action mints a transaction and lands here with ?_ptxn=…;
Paddle.js reads that itself and opens its overlay. The page is only the
overlay's backdrop — the terms were already read on /start or the
billing page, so nothing here competes with the payment window.
/diary/notebooks
The query value that stands for the orphaned notes rather than a notebook.
/diary/notebooks/[id]
One notebook, with nothing else on the page.
The index shows a notebook beside the list of them, which is the right shape for moving between subjects and the wrong one for sitting inside a single one. This is the same notebook with the whole width.
/kitchen/meals
The seven days from a date, as YYYY-MM-DD.
/login
signUp
Register, if this instance is taking anybody.
The check is repeated here rather than left to the hook in
hooks.server.ts: this action calls better-auth in-process, so the
request never passes the hook. Two doors, one rule.
requestReset
Ask for a reset link.
Always reports the same thing whether or not the address exists — the response is otherwise a way to enumerate who has an account here.
/login/verify
Signed in, address unconfirmed — the one page such an account can reach
while ONTOPLANO_REQUIRE_VERIFIED_EMAIL=true (the gate is in
hooks.server.ts). It says so plainly and offers exactly one act: sending
the mail again.
/offline
Public on purpose.
The layout guard sends signed-out visitors to /login, but this page is what a failed navigation falls back to — including one where the session could not be checked because there is no network.
/planner/board
Next sensible start time on a day.
Today gets the next half hour from now so a promoted todo lands ahead of you rather than in the past; another day starts at nine.
setTiming
Correct when something actually happened. See setInstanceTiming.
reorder
Where a card sits within its column.
Only todos have a position to remember — an occurrence's place is its time of day, and letting a drag override that would put the board and the calendar into disagreement over the same task.
schedule
Dragging between the two tabs: a todo gains a day, or gives one up.
promote
Turn a todo into a real scheduled task.
A todo pulled onto a day stops being a todo: it becomes a one-off block with a time, which is what makes it show up on the grid, in the tracker, and against a goal. The row moves rather than being copied, so there is never a todo and a task that are secretly the same thing.
demote
The reverse: a one-off goes back to being an undated todo.
remind
"Remind me before this one." A lead time, not a clock reading.
resolveActivity
Which activity a category-shaped block turned out to be.
/planner/history
Last week by default: this week is what the tracker is for.
/planner/plan
How much of the plan is on screen.
A week is the default because that is what the plan is. A day is what a phone can show honestly, and a month is for looking rather than editing — six rows so every month fits whatever weekday it starts on.
scheduleTodo
Drop an undated todo onto the grid: it becomes a block at that hour.
unscheduleBlock
A block dragged off the grid and back onto the todo strip.
The reverse of scheduleTodo, and the reason the strip is a drop target:
scheduling used to be one-way, so changing your mind meant deleting the
block and typing it in again.
/planner/review
Last week by default.
You review a week once it is over; landing on the current one would invite writing three lines about a Wednesday.
resolve
Done, or skipped — the two answers that are not "carry it forward".
/planner/todo
remind
A nudge at a time.
A todo has no time on it — that is what makes it a todo — so this is a clock reading rather than a lead time, unlike a block's.
/settings/account
better-auth's messages are already user-facing; anything else is a bug.
changeEmail
Ask to move the account to another address, where the instance allows it.
Nothing changes here: better-auth mails a confirmation and the swap happens when the link is followed. The current address stays the one that signs in until then.
changePassword
Change the password, and sign every other session out.
Someone changing their password is often doing it because they think somebody else is logged in, so the other sessions go with it.
revokeSession
Sign one device out. Its next request finds nothing to authenticate with.
signOutEverywhere
Sign out everywhere, this browser included.
Keeping the current session alive would be friendlier and wrong: someone clicking this has usually decided they do not know who else is logged in, and the answer to that is nobody.
delete
Deleting an account is irreversible, so it asks for the account's own email address rather than a yes/no — the point is to make it impossible to do by reflex, not to add a step.
/settings/billing
What this account is on, and what it is using.
A self-hosted instance sells nothing, so the page says so and stops — the same answer the Telegram bot and the deployment settings give.
/settings/instance
Deployment settings: bind host, port, database path, and who may register.
These describe the machine, not the account, so they are only readable and writable on a self-hosted instance by its owner. Anyone else gets a 404 — "not yours" and "not there" are the same answer. This page moves to /admin once roles land.
/settings/integrations
calendarLink
Mint another calendar link.
Several are allowed — a phone, a laptop, a partner's calendar — because one per account meant that wanting it in a second place cost you the first. Each is revoked on its own, in the list below, which is what makes "I pasted that one somewhere I should not have" recoverable without breaking the calendars that are fine.
/settings/integrations/widget
Where the phone widget connects itself.
The widget used to ask for an address and a pasted token, which is asking a person to do a key exchange by hand. Now its Connect button opens this page in the browser — where a session already exists — one tap mints the key, and the app link on the way back carries it home. Nobody sees a token.
/settings/preferences
Everything on this page belongs to the account, never to the instance (I9).
/shopping
Every action here is the same shape: read the form, call the service, map errors.
saveCategories
Which categories hold food, and therefore what can be an ingredient.
createCategory
Making a category is its own act, and needs its own action.
It used to be a second pair of fields inside saveCategories, so one Save
meant two things. Splitting the form was right and left this behind: the
new form posted here and there was nothing here to post to, so the dialog
simply did nothing and said nothing about it.
paid
What you actually paid. Never part of the tick, which has to stay one press.
/start
The card step of the funnel: register → confirm → here.
The billing-hold gate in hooks.server.ts routes a verified account with no plan yet to this page, so the terms are read BEFORE any payment window opens — /buy is just the overlay's backdrop. Yearly leads; it is the one worth taking.