jacobrobertsbaca / zero

Simple zero-based budgeting
https://zerobudget.vercel.app
MIT License
0 stars 0 forks source link

Sync Accounts #26

Open jacobrobertsbaca opened 6 months ago

jacobrobertsbaca commented 6 months ago

Syncing Transactions with External Accounts

Goal: Track tentative outstanding transactions when a transaction is made to an external account. For instance, buying groceries on your credit card creates an outstanding transaction which can be either linked to an existing transaction or turned into a new transaction.

User Interface

Linked Accounts

Users can view and add linked external accounts by heading to a new Linked Accounts page on the left hand navigation. Alternatively, this could appear under the existing Settings page as an additional category. Either way, the Linked Accounts page/section provides the ability to

Outstanding Transactions

Outstanding transactions show up first above all logged/existing transactions on the Transactions page. They may be highlighted in a different color or divided from normal transactions to indicate that they are outstanding. The outstanding transactions have the same information as other transaction rows (name, amount, budget, etc.) except they may be missing information like what category they are associated with, as this must be filled in by the user.

Clicking on an outstanding transaction brings up a sidebar nearly identical to that of ordinary transactions--users can fill in information about the transaction such as its name, amount, budget, category, and sensible defaults for each of these are provided where available (for instance, the bank certainly provides a name and an amount for each transaction). Saving the transaction creates a new existing transaction (same as any ordinary one) except that it is linked internally to the institution's transaction that created it.

[!IMPORTANT] In other words, if information about the transaction changes from the institution (e.g. a pending transaction posts with a modified amount) the created transaction will be modified to reflect this.

The outstanding transaction can also be linked to an existing transaction. For instance, let's say we logged a transaction for yesterday's dinner, and the associated outstanding transaction for our credit card appears later. We may link the transaction with the existing one we already created.

Finally, outstanding transactions may be ignored. For instance, we may want to ignore a pair of bank transfers for equal amounts (although practically speaking, both such transactions should be logged!) or a transfer to a savings/investment account (again, this really should be logged!). Ignoring a transaction hides it from the view of outstanding transactions, and may for all intents and purposes delete all knowledge of that transaction from zero altogether. It is true that doing so would render it impossible to "undo" ignoring a transaction, so a better solution to this might be worthwhile in the long run.

[!NOTE] Outstanding transactions do not count towards budget/category totals, since they may not possess all the necessary information to be properly categorized.

When searching/filtering/paginating the list of transactions, how should outstanding transactions be handled? There are a couple of options for this. I think the most straightforward is to essentially keep the outstanding transactions prepended onto the list of existing transactions (such that paginating to the second page would hide them). Upon filtering/searching for transactions, they could either be included in the results or not, but they should never be interleaved (always a clear separation between outstanding vs. non-outstanding transactions).

[!NOTE] One aggravating detail is how to handle positive/negative amounts. For instance, contributing to your investment account means that there will likely be a negative amount returned from the contributing account's institution, but it should really be logged as a positive amount in the app. This can be handled seamlessly by tracking what the original (institution's) listed amount for the transaction was, and comparing the sign to the amount the user assigns it. If the signs are different, then any institutional updates for this transaction should be multiplied by negative one.

Existing Transactions

Once an outstanding transaction has been converted or linked with an existing transaction, clicking on the created transaction will show details about which account it is linked with and the institutional transaction which created it. If a user no longer wants the transaction to be linked up (such that updates to that item do not forward to the transaction and their budget in zero), then the user can unlink the transaction, which effectively adds it back to the list of outstanding transactions.

Backend

Account linkage will be handled through a third party provider like Plaid. Given that these APIs (beyond a free usage limit for development) cost money to use, this functionality should be restricted to users marked somehow special inside the database. Ultimately, this special status could be converted into a billed version of the app (e.g. pay X monthly to unlock linked external accounts).

Upon logging in/loading the website, a request will fire which queries new transaction data from Plaid and forwards it into A) updates to existing linked transactions and B) new outstanding transactions. Doing this on sign in allows us to avoid the complexities of doing this as a periodic batch job, and would pair well with something like Plaid's transactions/sync API.

An additional table will be needed to track outstanding transactions. Alternatively, both outstanding and non-outstanding transactions could be lumped into the same table. The benefit of keeping them separate is that it allows us to keep track of outsanding-specific metadata which we might not want to clutter into the list of ordinary transactions. An example of this might be data used for category prediction: by keeping track of how often a user maps a certain kind of institutional transaction (based on how e.g. Plaid categorizes it) to a budget category, we could predict what category an outstanding transaction belongs in when it arrives and give it a more sensible default. This is one example, but other transaction metadata provided by the institution itself might be beneficial to track. Keeping the tables separate would probably more future-proofed vis-a-vis future development as a result.

We also need a formal users table (which I've eluded as of yet) to keep track of linkage information (e.g. from user to Plaid account ID, from user to Plaid transaction cursor, etc.) needed for implementing transactions. This table would have a foreign key into the actual Supabase users table as well as table triggers to initialize the new users table/delete rows when a user deletes their account.

Limitations/Drawbacks

So far, there's no way to see a unified view of all past/present outstanding transactions (i.e. all transactions logged from the users institution, even those that are already linked up). This may be annoying, especially if I want to reconcile all my outstanding transactions from account X inside zero with account X itself.

Right now my answer to this frustration would be: if you see no outstanding transactions at the top of the transactions page, then you're good to go! No need to worry, your budget is up to date. I just don't want to run into the hassle of essentially displaying outstanding transaction information twice (e.g. once on the transactions page, once on a separate view of all institutional transactions). Maybe we could just add a filtering option to the transactions page to show all outstanding transactions, even those that are already linked?

jacobrobertsbaca commented 6 months ago

One concern I have is: what happens when a linked transaction is deleted by the institution? For instance, a company does a credit check resulting in a pending transaction on your credit card. When the payment posts, it is deleted from the account. My gut feeling is to delete this transaction from zero as well. If we are going to propagate updates when a transaction posts, then we should probably also delete transactions when they're deleted as well.

That, or we just set the transaction amount to $0.00. Best of both worlds?

jacobrobertsbaca commented 6 months ago

Implement #28 and #27 first