Abaks: events

I tend to start with the events whenever I start an event source-based system.

But first, let's recall the requirements:

  • I should start a Period with a name (i.e. "June 2023"), start and stop dates, an initial balance
  • I can add/change/comment/delete an Entry, which is defined by an amount, a date, and a category
  • An Entry can be expected or not
  • At the end, I should be able to validate or flag in conflict an entry

Which gives us:

data AbaksEvent
  = Started {periodId :: PeriodId, name :: Text, from :: Day, to :: Day, initialBalance :: Amount}
  | EntryAdded {entry :: Entry}
  | EntryAmountChanged {entryId :: EntryId, amount :: Amount}
  | EntryValidated {entryId :: EntryId}
  | EntryCommented {entryId :: EntryId, comment :: Text}
  | EntryMarkedInConflict {entryId :: EntryId, reason :: Text}
  | EntryDeleted {entryId :: EntryId, comment :: Text}
  deriving stock (Eq, Show, Generic)

Also with the following supporting types:

newtype PeriodId = PeriodId {getPeriodId :: Int}
  deriving stock (Eq, Ord, Show, Generic)

data Entry = Entry
  { entryId :: EntryId,
    amount :: Amount,
    category :: Text,
    comment :: Text,
    state :: EntryState,
    date :: Day
  }
  deriving stock (Eq, Show, Generic)

newtype EntryId = EntryId {getEntryId :: Int}
  deriving stock (Eq, Ord, Show, Generic)

newtype Amount = Amount {getAmountInCents :: Int}
  deriving stock (Eq, Ord, Show, Generic)

data EntryState
  = Expected
  | Unexpected
  | Validated
  | InConflict Text
  deriving stock (Eq, Show, Generic)

Actually, there's four shortcomings in this design:

  • EntryAmountChanged is not explicitly required and might probably be a parameter of EntryMarkedInConflict
  • EntryDeleted is not required
  • EntryAdded takes a full Entry, which mean it could be in a 'final' EntryState
  • Amount does not distinguish deposits and withdrawals

I would argue that these are 'improvements' made for UX purposes, users can make mistakes, enter the wrong amount, or on the wrong period, etc.

Next time we will see the commands, we'll have a lot to cover since I have a quite opinionated design.