You got a little bit lucky with this project because there's a decently built-out test suite. I would start by digesting the tests because if they're good, you'll be able to see the mechanics about how the exposed interfaces in the code work, and this should also give you a good idea if changes you're making are breaking the expected workflow or not.
From my experience, there are really two ways that learning a new codebase can happen. One is that there's an existing test suite that's fairly comprehensive, and you can learn a lot by examining the tests, making changes to add features / make bug fixes, and then validate that work by rerunning the tests and adding new ones. That's really a great place to be as someone unfamiliar with a new codebase. The other is that there are no tests, and you inevitably need to rely on people familiar with the code, and make peace with the idea that you're going to write bad code that breaks things as you learn the depth of how the project works.
From my experience, there are really two ways that learning a new codebase can happen. One is that there's an existing test suite that's fairly comprehensive, and you can learn a lot by examining the tests, making changes to add features / make bug fixes, and then validate that work by rerunning the tests and adding new ones. That's really a great place to be as someone unfamiliar with a new codebase. The other is that there are no tests, and you inevitably need to rely on people familiar with the code, and make peace with the idea that you're going to write bad code that breaks things as you learn the depth of how the project works.