What each screen of the SPA shows and does, and the conventions every
screen shares. styling.md covers how things look;
architecture.md covers where code goes. Each section
names the view (src/views/) and the feature code behind it, so you can
go from a screen to its source.
features/shell/AppShell.vue wraps every signed-in screen.
md): the TopBar at the top, the page, and the
BottomNav at the bottom.md): the SideNav on the left (icons;
icons and labels from lg), with the TopBar and the page beside it.TopBar (components/layout/TopBar.vue) has three zones:
Tabs (BottomNav and SideNav): Overview (/app/), Budgets
(/app/budgets/), Transactions (/app/transactions/), Account
(/app/account/).
Account switcher (components/shared/AccountSwitcher.vue): a sheet
listing the user’s bank accounts with their balances; the active one is
checked. Choosing one makes it the active account, and every screen
scoped to an account reloads for it. “Manage accounts” opens the
Account tab.
/app/login/, LoginView, features/auth/useLogin.ts):
email and password; “Forgot password?” goes to the password-reset
flow. On success the user lands on the page named in ?next=, or the
Overview./app/email-change/...): the result of following a verification or
“this wasn’t me” link from an email. Public, since the user arrives
from their mail client./app/ path no route matches, with a link to the
Overview./app/, OverviewView, features/overview/useOverview.ts.
List (/app/budgets/, BudgetsView,
features/budgets/useBudgetList.ts):
BudgetCard shows the name, balance, target, progress, schedule
and status. A recurring budget with a fill-up goal carries the goal’s
FillUpBand inside its card; fill-up goals never appear as budgets of
their own. The Unallocated budget is not listed (its balance is in the
TopBar).Detail (/app/budgets/:id/, BudgetDetailView,
features/budgets/useBudgetDetail.ts):
MoveMoneySheet) that transfers between this
budget (or its fill-up goal) and another budget of the account.BudgetEditSheet); the bank
account and the budget type cannot change.useBudgetTransactions, paged from
GET /api/v1/transactions/?budget=<id>), grouped by date, with
infinite scroll, search over loaded and older rows, a toggle to
include transfers, and a per-row “remove from this budget”.Create (/app/budgets/create/, BudgetCreateView + BudgetForm):
choose the type (Goal, Recurring, Capped), then its fields. A recurring
budget can have a fill-up goal, which the backend creates. The
SchedulePicker edits a funding schedule or refresh cycle: weekly,
monthly or yearly, with the days, and a plain-English preview.
List (/app/transactions/, TransactionsView,
features/transactions/useTransactionList.ts):
useInfiniteList). Each row’s
allocations come embedded in the page.TransactionRow shows the party, amount, running balance, type and
its allocation: one budget with that budget’s new balance, a split, or
“Unallocated”. A pending transaction is marked PENDING; a transaction
still to assign has the unallocated left rule.useMergedSearch).Detail (/app/transactions/:id/, TransactionDetailView,
features/transactions/useTransactionDetail.ts):
SplitEditorDialog), which shows what
is left to allocate and assigns any remainder to Unallocated. A
pending transaction’s allocations cannot change until it posts.Hub (/app/account/, AccountView,
features/settings/useAccountHub.ts): the profile card (opens Profile);
the bank accounts with posted, available and unallocated balances and
the next funding event (“Add bank account” at the end); settings: the
default account, Security & Notifications, and Sign out.
Profile (/app/account/profile/, UserProfileView): name and
timezone; the email address is changed through a verification email to
the new address and a notice to the old one. An account without a
password (created by invitation) is told how to set one first.
Security & Notifications (/app/account/settings/,
AccountSettingsView): change password; API keys (create, shown once;
revoke one, or all active keys at once, with confirmation; “Revoke all
keys” is disabled when none is active); notification delivery per kind and the email
digest frequency; pending co-owner invitations the user sent, across
accounts.
Bank account detail (/app/account/bank-accounts/:id/,
BankAccountDetailView): balances; details (the account number, masked,
is editable, as is the name); owners and co-owner invitations; a link to
the account’s budgets; funding (data freshness, the next event, the
automatic-funding switch, “Run funding now”); Delete account, with
confirmation.
Create bank account (/app/account/bank-accounts/create/,
BankAccountCreateView): type, name, bank, account number, currency and
opening balances. Balances cannot change after creation; an Unallocated
budget is created with the account.
BaseSkeleton placeholders shaped
like the content; loading the next page of a long list shows a small
spinner at its end.BaseBanner, never a browser alert; a field’s
error sits under the field.EmptyState, with an action where there is one to
take.ConfirmSheet. One that is easily redone
(removing a transaction from a budget, removing a split, cancelling an
invitation) acts at once.The screens are single-column at every width; wider screens only swap the BottomNav for the SideNav and show sheets as centred cards. Planned for tablets and desktops: