What features does a subscription tracker actually need?
Nine features carry the product; the rest are noise. Which ones, in what order, and the three that look optional and are not.
Answer
Nine: subscription CRUD with unit-plus-multiplier intervals, per-row currency, categories, status including trial, per-subscription reminder lead times, a price history table, spend aggregation, CSV import with undo, and a calendar feed. Three that look optional and are not: price history, import undo, and one-time payments. Everything else can wait.
Leutrim Miftaraj
Founder, SubTracker · Updated September 5, 2026
The short answer
The feature list that survives contact with users is shorter than the one people plan, and differs in three places. Price history, import undo and one-time payments all get cut as version-two items, and all three are cheap to add on day one and expensive to retrofit.
The nine that carry it
In build order, because the order matters more than the list.
1. Subscription records. Name, amount, currency, interval as unit plus multiplier, next billing date, status. The whole product rests on this row.
2. Per-row currency. Not a profile setting. A user with services in two currencies is the normal case, and converting at entry destroys the original figure.
3. Status, including trial. Active, paused, cancelled, trial. Cancelled rows are kept, not deleted — users want to see what they stopped and what it cost.
4. Categories. A table with a foreign key, not a text column. A text column produces "Streaming", "streaming" and "Streaming " within a week.
5. Spend aggregation. Monthly and annual totals, by category. Derived from the rows rather than stored.
6. Reminder rules, per subscription. Not one global setting. Seven days for monthly, thirty or more for annual — annual notice periods are commonly thirty days.
7. Price history. One row per amount change. See below.
8. CSV import with undo. The difference between a product someone tries and one someone uses.
9. A calendar feed. An ICS subscription that updates as rows change. Cheap to build, disproportionately useful, and it puts renewals where people already look.
The three that get cut and should not
Price history. It looks like analytics and it is not — it is the only way a price increase becomes detectable. The previous amount is gone the moment it is overwritten, and it cannot be reconstructed. Without it you cannot build the alert that is arguably the product's best feature, and adding it later means starting the history from zero.
Import undo. An import writes many rows at once. When it goes wrong — wrong column mapping, wrong file, second run of the same file — the user faces deleting forty rows by hand, and that is where they stop trusting the feature. A "import_batch_id" column plus one delete turns a frightening operation into a reversible one. People import willingly when they can undo.
One-time payments. A domain renewal, an insurance excess, an annual professional membership. They need a reminder but they are not recurring spend. Modelling them as "interval = 'once'" normalising to zero monthly cost is a few lines; retrofitting them means every aggregation query has a special case bolted on.
What can genuinely wait
Shared workspaces, unless households are the point of the product. Retrofitting ownership onto a schema keyed on "user_id" means touching every query and every policy — so if it is on the roadmap at all, put "workspace_id" on the row now and default it to a personal workspace. That is the cheap half; the UI can wait.
Attachments and documents. Useful, not load-bearing.
Tags on top of categories. A second taxonomy before the first is being used.
Charts beyond a monthly total by category. People say they want them and use them twice.
Multi-user permissions with roles. Two levels — member and owner — cover households and small teams. Roles are a business-product feature.
The one thing everybody underestimates
Not a feature. Scheduled reminders that actually fire, once, at the right local time, for every user.
The naive version is a cron job and an SMTP call, an afternoon's work. The real version needs idempotency through stored state so a retried run does not double-send, per-user timezone handling so a reminder does not arrive at 22:00, a resumable cursor so a run that exhausts its time budget does not silently starve the tail of the list, and delivery-outcome recording so a failure is visible rather than assumed successful.
Each of those took us a separate incident to learn. The pattern in all four: the dangerous failures return success while doing nothing.
Die ehrliche Bau-oder-Kauf-Linie
Das Schema ist der einfache Teil. Es ist auch der Teil, der sich nach Fortschritt anfühlt — weshalb das Projekt unmittelbar danach aufhört, Spass zu machen.
Was tatsächlich Zeit kostet, in der Reihenfolge, in der es zubeisst: geplante Erinnerungen mit Idempotenz und Zeitzonen, Wiederholungs-Arithmetik über unregelmässige Intervalle, Währungsbehandlung, und ein Import, aus dem heraus überhaupt etwas entsteht.
Nichts davon ist intellektuell schwierig. Es ist schwierig im Sinne von vier Wochenenden, und das vierte ist das, an dem das Projekt stirbt.
Wenn das Ziel Lernen ist: bau es. Der Code hier ist echt und funktioniert. Wenn das Ziel ist, kein Geld mehr an vergessene Abos zu verlieren, ist der Bau ein Umweg.
Was SubTracker damit macht
Zur Einordnung, weil die Entscheidungen oben aus einem laufenden System stammen und nicht aus einer Entwurfsübung.
SubTracker ist eine Next.js- und PostgreSQL-Anwendung (Supabase), die Abos manuell verfolgt — es gibt keine Bankverbindung, jede Zeile stammt aus einem Formular oder einem CSV-Import. Diese Einschränkung prägt das Schema: kein „erkannt"-Zustand, kein Konfidenzwert, keine Händler-Zuordnungstabelle. Jede Zeile ist eine Behauptung, die jemand aufgestellt hat.
Der kostenlose Plan verfolgt unbegrenzt viele Abos inklusive CSV-Import und Live-Kalender-Feed. Erinnerungen und Preis-Alarme sind Plus für $5.90/Monat; Family kostet $9.90/Monat und fügt einen geteilten Workspace für bis zu zehn Personen hinzu — an dem Punkt hören die Besitzverhältnisse im Schema auf, theoretisch zu sein.
Frequently asked questions
What is the minimum feature set for a subscription tracker?+
Subscription records with interval as unit plus multiplier, per-row currency, categories, status including trial, spend aggregation, and per-subscription reminder lead times. Below that it is a list rather than a tracker.
Why is price history worth building early?+
Because the previous amount is gone the moment it is overwritten and cannot be reconstructed. Without a stored history you cannot detect a price increase at all, and adding the table later starts the history from zero.
Should a subscription tracker support one-time payments?+
Yes, as an interval that normalises to zero monthly cost. Domain renewals and insurance excesses need reminders but are not recurring spend, and including them in a monthly average produces a figure nobody can reconcile.
What is the hardest part of building a subscription tracker?+
Reminders that fire exactly once, at a sensible local time, for every user, with failures visible. Idempotency, timezones, resumable runs and delivery outcomes are each a separate problem and none of them is the schema.
