About Principles
This is an internal engineering document, published unedited. It is the checklist every notification, badge and piece of copy in the app is reviewed against before it ships. It is here so that the claim on the about page — that nothing here is designed to make you feel worse — is something you can check rather than something you have to take on trust.
Engagement principles
Debito is a debt app. The people using it are, by definition, under financial pressure, and a meaningful share of them are under emotional pressure too. Every engagement mechanic we ship is a lever on someone's behaviour with money they may not have. A streak that works beautifully in a language-learning app can, here, be the thing that talks somebody into an overdraft.
This document is the review gate. Every new string, badge, notification, and email in the engagement surface gets checked against it before it ships. If a rule below and a growth metric disagree, the rule wins.
1. The qualifying action is looking, never paying
A week counts if the user opened the dashboard, logged a payment, or updated a balance. That is the complete list.
Nothing about the amount of a payment ever feeds a streak, a milestone, a badge, or a nudge. Logging a $5 payment counts exactly as much as logging a $500 one. Someone who opens Debito, sees a number they can't change this month, and closes it again has done the thing we are asking for.
This is the rule the others exist to protect. The moment a mechanic rewards paying more, we have built an incentive to skip an emergency fund, or to take a cash advance on one card to keep a number alive on another.
2. Streaks are weekly
Never daily. Debt moves monthly: statements cut monthly, minimums are due monthly, paydays are fortnightly at best. A daily streak on a monthly quantity manufactures daily anxiety about something the user cannot act on daily, and the only way to relieve it is to do something unnecessary.
Weekly is slow enough to be honest about the underlying rhythm and frequent enough to be a habit.
Amendment, 17 August 2026 — visual state may fade continuously
A purely visual, non-numeric state may fade on a continuous scale, provided it:
- has a floor it cannot fall below, and that floor is a state a thing is allowed to be in rather than a damaged one;
- carries no number — no day count, no percentage, no "last seen", in the UI or anywhere else;
- is restored in full by a single action, not incrementally and not in proportion to how long somebody was away.
Decided knowingly, and worth writing down rather than treating as an exception. The reason for the weekly rule is daily anxiety about a monthly quantity — a number that ticks, that can be lost, and that can only be protected by doing something unnecessary with money. A floored visual with no count attached does not create that pressure: there is nothing to lose, nothing to protect, and one tap undoes any amount of absence.
The streak itself stays weekly. This clause covers scenery, not scoring. See
docs/companion-plan.md for the design it was written for, and §4 below,
which is unchanged: this permits a fade, not a countdown, and certainly not a
thing that can die.
3. A miss pauses; two misses restart, gently
- One missed week pauses the streak. It does not reset. The count is held.
- Two consecutive missed weeks reset to 1 on the next check-in.
- The user is never told what they lost.
The copy on return is "Welcome back." It is never "You lost your 14-week streak", never "Your streak ended", never a number with a strikethrough through it. Someone who stopped opening a debt app for two weeks was very likely having a bad two weeks. The product's job on their return is to be easy to walk back into.
4. No comparison, no countdown, no audience
- No leaderboards.
- No percentile, cohort, or "users like you" framing.
- No social feed, no follower count, no public profile.
- No countdown timers, no "3 days left to keep…", no expiring anything.
Debt is not a competition and the comparison set is invisible anyway: another user's $400 month may be heroic or trivial depending on facts we will never have. Ranking people by it is both cruel and wrong.
5. Nothing is ever gated on an amount
No feature, view, celebration, or piece of content unlocks because a payment was large enough. Entitlements are gated on plan tier and nothing else.
6. We are willing to say "slow down"
safeBufferWarning in @debito/domain/calculator is the concrete expression of
this. When a proposed extra payment would leave the user with no monthly slack,
or would pull their savings below one month of must-pays, we say so, right next
to the button.
It is non-blocking. We inform, we do not veto: it is their money and they may have context we don't. But we do not let them walk into it silently, and we never celebrate the decision afterward.
Being the debt app that tells you to slow down is a real differentiator. An ad-funded competitor cannot ship this, because the behaviour it discourages is the behaviour their revenue depends on.
7. Informal debt costs a relationship, not a fee
A reminder about a Chase card is a reminder about money. A reminder about the twenty thousand from a father-in-law is a reminder about a person, and the cost of getting it wrong is a Christmas dinner rather than a late fee.
A reminder about an informal debt must never imply the counterparty is waiting, disappointed, or owed an explanation. State the number and the date. Nothing else. No "you promised", no "they're expecting this", no "it's been three months".
The rule holds from both sides. Money owed to the user is the same problem seen from the other end: nothing in the app may characterise the person who owes them. No "overdue", no "chasing", no red, no counting how many months somebody has been slow. A projected settle date is a projection and says so.
Two consequences already in the code. createDebtFromBalance refuses to
estimate a rate or a minimum for a debt with a counterparty on it — a family
loan is usually genuinely 0% with no schedule, and inventing 12.5% would put an
interest charge into a relationship that does not have one. And
expectedInMonth produces a repayment only when there is an agreed cadence
and an agreed amount; "when I can" generates nothing, because a hope has no
business holding up a month somebody is budgeting against.
Copy rules, enforced in review
Never write:
- Anything implying a person is waiting on money, on either side of a loan between two people (§7).
- "Keep your streak alive" — especially anywhere near a payment field.
- "You lost…", "Your streak ended", "Don't break your…"
- Any comparison of this payment to a previous payment as a target: "beat last month", "you paid $300 last month", "one more push".
- Any countdown, deadline, or expiry attached to a user action.
- Any comparison to other users, in any form, including aggregate.
- "Just $X more to…" attached to an amount the user pays.
Prefer:
- "Welcome back." over any acknowledgement of absence.
- "You checked in 6 weeks running" over "6 week streak!"
- Descriptions of what happened ("$4,300 down since March") over exhortations about what should happen next.
- The user's own past self as the only reference point, and only factually.
The test to apply to anything new
Could this string, read by someone having their worst month of the year, make them move money they need for rent?
If the answer is anything other than a confident no, it does not ship.