Reflect, Recharge, Repeat: Pocket Therapist – Your Digital Journal
What is Pocket Therapist?
Welcome to Pocket Therapist, a mobile app born out of the collective vision of a team of five fellow students and myself at UNLV during my final semester. Originally conceived as a digital replacement for physical journals, our goal was to address the lack of secure solutions for journaling apps.
Focusing on security, our development team set a standard: the app should not be able to compromise user data while delivering robust functionality, ensuring it surpasses the convenience of a traditional journal or notepad app. The quality of our work was recognized when Pocket Therapist secured the 1st place award in our senior design competition for the computer science department category.
Although the initial collaborative effort concluded at graduation, my commitment to seeing projects through, coupled with a genuine enthusiasm for continuous learning, motivated me to independently carry on with the app’s development, seizing the opportunity to enhance my skills and grow as a programmer.
The result is a digital journal that goes beyond the capabilities of pen and paper. Due to shared ownership of the original code base the app will not be published to the app store, but it still stands as a testament to my growth as a programmer. Moving forward, my focus is on addressing any bugs or issues that may arise to ensure a stable and reliable experience for users along with a future port to IOS(the android port can be found on my GitHub). Looking back, I envision the potential for additional features, such as the ability to save images within entries, but for now, my priority is to maintain the existing functionality while pursuing other creative endeavors.
Key Features
Customize Your App’s Appearance
- Personalize the app’s appearance to match your preference or to adapt to different times of the day.
Effortless Journaling and Future Planning
- Capture past events or plan for the future with ease.
- Journal about past or present events and the creation date is automatically set to the time you save to help organize your past entries.
- You can also create a Plan by picking a time for the scheduled date, allowing you to log emotions or tags leading up to them.
- You also have the ability to convert entries between journal and plan types, providing maximum flexibility during your journaling experience.
Inspiration On-Demand with Guided Questions
- Struggling with a serious case of writer’s block? On the entry creation page you can double tap on the entry body to generate a random question or you can swipe to bring up a list of possible categories. The categories vary from relationships, career, reflection, emotions, and goals and each category has around 10 questions related to the category to help you generate and reflect upon meaningful entries. You can also regenerate questions to add to your current entry or choose to clear previous questions upon each generation.
Expressive Journaling with Tags and Emotions
- Enhance your entries by attaching both tags and emotions. Filter your entries effortlessly with either option or by title, providing a versatile way to organize and navigate your content.
- Tags and Emotions play a crucial role in generating insightful statistics displayed around the app, such as on the linear chart or radar map. Each contains a unique ID, facilitating easy updates to the name or color without the need to redeclare the tag or emotion after each change. This ensures that changes are consistent across all entries and contributes to a seamless and enhanced journaling experience.
- Add depth to your entries by attaching emotions. Adjust the strength of each emotion (0-60) to track emotional trends over time, providing a nuanced reflection of your emotional state in the long term.
Track Trends Over Time
- On the dashboard, you have the option of displaying statistics over the current or selected month. The statistics include the most frequent tag and emotions, along with their usage frequency, and the average and maximum emotion strength. There is also a list of the strongest emotions registered during that month, one of all emotions used up until that point.
- On the Journal or Plans page you can choose to display the same statistics over the last day, week, month or year.
- Utilizing the calendar page, you can take this a step further by selecting a starting point for the statistics over the selected day, week, month, or year.
Visual Data Representation for Reflection
- The use of tags and emotions can also be conceptualized on the radar map with the display options varying from tags journaled, emotions journaled, tags planned, and emotions planned.
- For emotions you are given the following 6 togglable Radar maps that are separated into categories labeled extremes, average, and frequency.
- The two extreme radar maps represent the maximum and minimum emotion strength logged over the selected time period.
- The average radar maps represent the relative and true average that is found from taking the total emotion strength and dividing it by either the number of entries found with emotions or by the total number of entries.
- Lastly the frequency radar maps displays the total or daily frequency to allow for versatility when seeing total usage over time.
- For Tags you are given the two frequency radar maps to help visualize usage over time.
- For emotions you are given the following 6 togglable Radar maps that are separated into categories labeled extremes, average, and frequency.
- For emotions you are also given a line chart that plots the emotion strength over the selected time period.
- The time period for both charts can vary from month, week, to day view to allow for versatility when reflecting over past entries.
Effortless Journal Backup and Restoration
- Create a backup which creates a zip file that contains the journals.db and the settings.yml file used to store everything needed for the current state of the app. Upon the creation of a backup you will be prompted for a name for the backup file and if you would like to overwrite any backups that are named the same as the desired backup name. This allows for custom digital journals that vary in journals, plans, emotions, tags, theme preference, and protection.
- There is the option to share backups that can occur through Bluetooth, Gmail, SMS, etc. If the backup has a password lock, the password would also need to be shared for anyone else to unlock the digital journal.
- Upon selecting a zip file, either internally through the app’s stored backup collection or externally, you are first prompted if you wish to create a backup of your current digital journal. Upon completion of your choice, you will be greeted with either the dashboard or the welcome page depending on if the backup had a lock on it. While you can still access the settings page to load another backup, and as a result view and edit emotions and tags, you will be unable to access the rest of the app or read any entries until the correct password is used to unlock the digital journal.
Argon 2 Security for Your Journal Password
- The password protection is designed using Argon 2 encryption to help provide an added level of security when locking your digital journal. While the security of the app could be improved, it remains that upon handing another individual your phone, without the password they would not be able to read journals or plans through the app.
- Disclaimer: while I do know of an exploit where the user could create a backup of the password protected app and read the .db file or modify the .yml file manually, at this time they could not use the app to read the backup inherently. A possible solution for this could be seen in a future patch that prevents the user from sharing the backup file until they input the password for the digital journal but we must draw the line somewhere for this version of Pocket Therapist so as a result this exploit will remain for version 2.0 of the app.
- When loading a password protected backup, the backup will take you to the welcome page and you will need to input the password or recovery phrase used for that specific backup. Because of this it is recommended to create a backup of your passwords to prevent being locked out.
- While the password field recommends a strong password, the development team opted to make it possible for the user to input any password they prefer whether it be a single character or a phrase to create a more personalized user experience.
Technology Stack
Introduction
- The technology stack adopted for this project was focused on achieving 3 main goals. The development team wanted independence while working (no passing one code base off with a USB), creative freedom with implementation of our selected functions, and to guarantee reliability with a coverage report.
List Of Technologies
Framework: Flutter
- Our main application is crafted with Flutter, a robust framework recognized for its versatility and efficiency in development. Leveraging Dart, Flutter enables our app to seamlessly deploy across Android, IOS, web, and desktop platforms, utilizing a unified code base. Although presently optimized for Android, extending it to IOS requires minimal adjustments. Please note that IOS is temporarily delayed, pending access to a MacBook.
Backend
- We opted for a server-less architecture, leveraging the capabilities of the Flutter framework to handle both frontend and backend development seamlessly. By opting for a server-less architecture, we also had to handle the account set up and password verification along with keeping all storage needs locally as there was not going to be a remote server that the app can communicate with. This was done by saving the encrypted password as plain text in the settings file and only unlocking the vault if the password imputed generates the encrypted text. This approach eliminates the need for a traditional backend and is another reason the development team chose Flutter at the cost of causing a delay during the login process in exchange for security.
Database: SQLite
- As a team decision (later deployed by me), we chose SQLite as our local database for its lightweight and embedded nature, ensuring efficient data management. Storing all plans and journal entries in the same database file, our approach facilitates efficient deployment and minimizes the risk of data breaches while still allowing for backups.
Security: Argon 2 Encrypted Password
- Argon 2 is a key derivation function and password hashing algorithm that provides a secure and efficient password hashing. To achieve this the password is mixed with a salt provided to fill a memory block that is processed for the determined number of iterations.
- As of May 2023 the Open Worldwide Application Security Project (OWASP) Password Cheat Sheet recommends the following minimum configuration of “19 Mebibytes (MiB) of memory, an iteration count of 2, and 1 degree of parallelism”.
- Because the hashing would be performed on the user’s device when implementing Argon 2 the development team agreed to go beyond the minimum standard. Specifically we choose to use 16 bytes that are randomly generated for the salt, 32 bytes for the return hash, 4 degrees of parallelism, 500,000 kilobytes (KiB) or 475 MiB for the memory size, along with 9 iterations to form a robust hash for each password. The salt, computed with the password, fills the provided memory size setting the stage for a robust hashing process. After initializing the memory size, the block undergoes the Fill and Finalization phases nine times (once for each iteration) with computations performed during each cycle. To balance between speed and security on multi-core systems, we increased the degrees of parallelism to 4. By fully utilizing the available resources, this reduction in calculation time on mobile devices contributes to an enhanced overall user experience.
- During the account verification process the salt is obtained from the stored hashed password and is used to calculate each password attempt and verify the input generates the same hash value before letting the user into the account. While the result of our implementation leads to a minor delay during the login process, the trade off results in enhanced security by exceeding OWASP minimum standards and adds a layer of protection by never storing the plain text of the password.
Scalability and Performance: Caching mechanism
- For now the main caching mechanism can be found when displaying the statistical data for the month. When viewing the radar map or linear chart all entries for the month are cached to ensure smooth switching between display options and efficient calculations. This is done by running through all entries possible one time and storing the entries for the month in an array where each index represents its position on the calendar. From here if the radar map is selected the first time each week is selected the calculations are made and saved ensuring a smooth user experience without over generating data that is not used. I developed this approach as an improvement to the original design of the radar map and line chart that allowed for a more versatile selection without sacrificing the cost of calculating each variation.
Version Control
- GitHub served as the central repository for the project during the development cycle with the team. GitHub acts as a version control platform that allows for teams to develop on a shared code base remotely while documenting changes to the code base over time. You can either create changes on branches which represent clones of the original code base(as we did while developing together) or push commits directly to the main code base(my latest update) but either way all changes are managed for easy revertability and for displaying changes over time. It was required to use GitHub by the professor at the time of being given the assignment but moving forward I personally have found GitHub to remain an easy and versatile version control platform.
- The development team utilized the issues functionality of GitHub when adding on functionality to the app. Each feature was given its own branch that was subject to review by 2 other developers before the branch could be merged with the main application.
- The team also used pull requests for the branches and were graded on achieving at least 6 meaningful pull requests for the semester long project.
- Each reviewer was responsible for verifying that the Continuous Integration pipeline did not break on the pull request when verifying coverage, no integration tests were failing, and that the functionality was delivered as described in the pull request. This provided a collaborative environment where we could also leave recommendations on improvements in the pull request before approving changes.
- The original code base in GitHub has since been switched to private so the only remains are located on my GitHub page which began with the final version of the shared code base and right now displays my latest updates.
Continuous Integration(CI) pipeline
- The Continuous Integration pipeline ensures code quality and functionality across a remote code base. This is done by using GitHub Actions for custom CI that allows you to automate your build, test, and deployment. In particular, this allows a development team to ensure code quality by running integration, widget, or unit tests within the pipeline to guarantee the code quality.
- Our team used the CI pipeline to first install flutter and set up an appropriate environment and then run widget tests, but the primary purpose was to verify that the .lcov file covered the targeted coverage percentage we were aiming for at the time(90%). If this failed the pipeline would fail the developer would have to re-run the integration test to ensure that all integration tests passed and that tests were added as necessary.
Testing and Quality Assurance
- Testing, whether it be integration or unit test, ensures that the code base maintains code quality and app stability when running. Each industry agreed that each software project should aim for a code coverage percentage between 60% and 90% and for the project grade we were required to maintain a coverage of 90% for maximum marks in that category.
- Our team primarily utilized integration tests to verify the functionality of the app. While these are similar to unit tests, it is important to distinguish the two as integration tests run on a real(or emulated) device. As a result each test can access functionality similar to what the end user could achieve while using the app such as functions basic like touch, drag, double tap, but continuing to more advance like counting the number of widgets displayed on the screen and verifying the content on them. With this as a team we were able to achieve a 95% for code coverage.
- After the most recent development cycle the App is sitting at 99% code coverage which ensures that the app should remain at a stable point until more features are possibly added.
Development Environment: Visual Studio Code
- We did not enforce a standardization of the Integrated Development Environment (IDE) onto everyone but rather let individuals pick so long as the following criteria was met. Regardless of the end point each individual must be able to run integration tests and verify their code was functional.
- Personally, I chose to develop on Visual Studio Code due to its versatility with Flutter, with a key emphasis on the invaluable “Hot Reload” and built in integration testing functionality. Ultimately these two features alone resulted in me exclusively picking Visual Studio Code as my IDE of choice.
- The “Hot Reload” feature significantly streamlined the development process by allowing instant visualization of code changes on the emulator or device without the need for a full application restart. This allows for changes in widget placement or scaling in seconds versus minutes which add up in the long term. I leveraged Hot Reload extensively, particularly when addressing widget and text overflow issues and ensuring optimal performance in landscape mode.
- The built in Flutter testing section of the IDE which held all the integration tests and allowed me to run them by either file, group, or individually, speeding up the time it took me to write and fix integration tests.
Conclusion
- The technology stack adopted for this project combines the use of flutter with visual studio code seamless end to end development, the efficiency of SQLite for local data storage, and the security of Argon 2 encryption. GitHub played a pivotal role in collaborative coding, allowing for a seamless workflow for the development team. Together, these technologies contribute to a flexible, secure, efficient, and collaborative development environment. In future development, adding a true backend would allow for more features such as cloud backups and will be strived for, but for the current application state the technology stack is enough to cover all the key features and as a result does not need to be added to for any upcoming development.
Challenges and Solutions
During the development process, one significant challenge we faced was related to communication. The non graded requirements consisted of 1 team meeting a week, participation in a discord chat, and the use of GitHub for version control. The graded requirements consisted of 3 design documents (each a revision of the last) and the use of 6 meaningful pull requests on the GitHub repo per team member. Though this is a strong baseline, our team needed 36 total pull requests and meeting for 1 hour a week was not nearly enough time to produce an application of substance.
- Our team personally chose to strengthen communication channels by first extending the weekly meeting time as needed(removing the 1 hour cap). With the first few weeks of the 3 month development cycle dedicated to mapping out the application design, our team quickly noticed how much the weekly meetings limited our discussion time. This time extension produced effective communication on key decisions by giving everyone a chance to speak about approaching deadlines and ideas. This gave us a head start when preparing the Design Document which resulted in the development team consistently submitting assignments early.
- Once the development environment was determined and our draft of the Design Document was finished we quickly went to work utilizing the GitHub issues feature to map out the development cycle. Each feature (36 in total) was mapped out with GitHub issues and would be used when drafting and submitting pull requests. This organized our workload over a 2 month period and ensured a smooth and consistent development process without any developer being overloaded with expectations. Along with being able to divide work easier, the development cycle could now be monitored from the time a pull request is drafted until it is closed and was essential for ensuring development stayed on track.
- By the beginning of the second month our team additionally implemented Sunday voice call meetings. This acted as an extra channel to personally help anyone implement features, raise coverage or fix integration tests, along to notify the team of any upcoming deadlines. There was no fixed call length so long as progress was being made and as a result the average phone call was around 2 hours. At times the phone call was extended past 4 hours but this flexibility resulted in collaborative problem-solving as multiple pull requests could be approved and merged before the end of the call which improved our workflow efficiency immensely.
This adaptability in communication ultimately proved fruitful in utilizing the team’s full potential to produce a minimum viable product. From extending weekly meetings to implementing effective use of GitHub issues and fostering open communication through Sunday calls, our team secured an A for our final project grade and 1st place for our department in our Senior Design Competition. Both these achievements display the importance of dynamic communication channels, clear communication, and collaborative problem solving during the development process and how critical communication is as a whole when developing as a team.
Independent Development
After the Senior Design Competition the team stopped communications but personally I felt unsatisfied with the final state of the app. There were buttons that were not fully programmed, statistics that were inaccurate and not versatile, and entries did not save after the app was closed. Though this did not stop us from winning an award, my personal standards were higher as I wanted the ability to share the app with friends and family. My primary goal was to get the app to a stable state as I could recall multiple times where I would try to show off the app and undoubtedly an error would appear after hitting an edge case in the programming. While I could use the app as is, I felt it was a great opportunity to test my coding skills to not only fix all the issues in the app but also implement some that I originally wanted to include but were scrapped due to time constraints. As a result I spent roughly 3 months developing a pseudo – mark 2 version of the app that contains all the features mentioned above along with the ability to go in landscape mode. I spent most of the time implementing new and fixing existing features that were not fully developed. I also implemented some features such as editing emotions that were scrapped to generate the minimum viable product for the competition. After this stage I went to work to maintain existing integration tests and added in more in to ensure that the code added was thoroughly tested both automatically and manually. Currently the code coverage on the app stands at 99% which serves as a testament to the code’s stability. I plan on continuing to maintain the reliability of the application as it stands but I now believe it is at a point where I can begin other creative endeavors without regrets.
Links To GitHub
The original GitHub repository has unfortunately been set to private due our team lead owning the original repository but I have a copy of the original on my GitHub account. My repository was started from what the development team finished as a collective, to the app’s current state. While there are no pull requests to view, the repository can be utilized in conjunction with flutter to download the app onto a mobile android phone. The repository can be found at https://github.com/JikoJeans/Pocket-Therapist and I plan on maintaining and patching any bugs reported.
Conclusions
Although there are opportunities to do better as a development team, the mistakes made and time spent with the development team has helped provide me with confidence and knowledge that a bachelor’s degree could not alone. While learning how a password is hashed or how a database handles a query on paper can be done, implementing the process in the environment and ensuring stability is a humbling experience as every time the application breaks you must determine if either the algorithm is implemented right or if it needs to be redesigned to work. After working together I can confidently say I can develop in either a team or solo development environment productively. While I believe the time I utilized to independently finish the app could have been more efficient, the time spent to implement the database for saving entries, backup system, and the redesign of the statistics and charts was well spent in honing my development skills. Although the future is unclear, I plan on pursuing another creative endeavor with the aim of either publishing to the app store or for personal use. In either case the repository will be hosted on my GitHub profile and I will post either an update about my next project or when it is complete.