A mobile journaling app built with Ionic (React & TypeScript) and a Node.js/Express backend using MongoDB.
Stitched supports tracking recurring tasks (Moments), daily notes (Memories), and events/episodes (Mementos), with built-in history look-up and statistics.
Caution
Development on this project is currently paused, and it isn't production-ready. See Current Status & Limitations for details.
Stitched has three types of data one can journal:
Recurring tasks with flexible schedules.
For example, "Lunch" can be tracked as a daily task, or "Laundry" as a task to complete twice per month.
Each moment is displayed differently based on its frequency and previous completions, indicating whether it is due, could be done today, or not due.
The History tab displays when each task was completed, didn't need to be done, or was skipped, along with statistics such as completion percentage.
History - "Lunch" Moment
History - "Laundry" Moment
Daily notes with custom titles.
For example, a "Daily summary" note can list the activities of the day, or an "Ideas" note can store more abstract thoughts.
Note
Notes are rendered with small formatting conversions for readability:
- List->• List[ ] Empty checkbox->☐ Empty checkbox[x] Checked checkbox->☒ Checked checkboxThis is complete V->This is complete ✓This is complete X->This is complete ✗---->⎯⎯⎯⎯⎯⎯⎯⎯⎯(separator)
The History tab includes a search bar to quickly find past notes by keyword.
History - Memories with Keyword "readme"
Episodes or events.
For example, they can represent vacations, projects, being sick or having headaches. Virtually anything with a start and end date.
Mementos can also predict future occurrences, which is useful for tracking recurring events - such as planning vacations at regular intervals or anticipating recurring headaches. Works for tracking periods too.
Predictions are displayed on the main calendar.
Journal - Ongoing Mementos
Journal - Memento Prediction
Note
To add/edit a memento:
- Tap
Add started. - Select type from the list.
- Select a
startdate. - Optionally, tap the
enddate slot to set the end date.
(To remove the end date tap the selected date again)
The History tab lists all past mementos, along with statistics such as average duration and intervals, either individually or grouped by category.
History - "Headache" Memento
History - "Social" Category
Stitched is functional but currently it's in a paused development state. The following limitations apply to this prototype version.
Note
It is not recommended to use this app's current state as is, but rather as inspiration for your own projects.
The frontend lacks several features, such as the ability to adjust moment, memory, or memento settings directly within the UI. These options need to be be modified manually in the database.
Additionally, the layout was designed specifically for my Android device and will not display correctly on most screen sizes or platforms.
The app is using Capacitor's Local Notifications, which are limited in functionality and did not meet the intended design for the app.
Using non-simple notifications (moment, memory, or memento) is unintuitive - when the app asks if a moment was complete, pressing Yes opens the app, loads the data, and then marks it as complete. Pressing No also opens the app. Ideally, neither action would open the app, but this isn't possible using Local Notifications.
Note
This is the reason the simple notifications were implemented, sending generic notifications in set times regardless of what was complete or not complete during the day.
These limitations were a major reason why development on this version was paused and why a future rebuild is planned using Push Notifications, which would allow background actions and more advanced features.
The app is currently in a "testing" state. Some features were never finalized, but they remain functional enough to explore the core concepts.
- Multiple files have a
printLogsboolean at the top, allowing to enable/disable debug logs for that file. - A race condition can occur during new entry creation. Although a queue system exists, entries can still be duplicated if multiple fields are updated too quickly on a new day, and some content may be lost.
- Notifications sometimes fail to schedule on app start, requiring a manual refresh (although it's possibly an emulator only issue and won't happen on proper builds).
The History tab has a Debug subpage, allowing to copy the selected day's data to the clipboard and refreshing notifications manually. Both actions print debug information to the console.
The frontend/src/ folder:
- components/ - The app's components:
- calendar/ - A custom calendar hook & a calendar reset button.
- history/ - The subpages displayed under the
Historytab:- debug/ - Debug subpage, allows copying the selected day's data and manually refreshing the notifications.
- memento/ - Memento subpage components.
- memory/ - Memory subpage components.
- moment/ - Moment subpage components.
- DebugPage.tsx - Debug subpage.
- EmptyCard.tsx - Component used for empty blocks.
- MementoHistory.tsx - Memento history subpage.
- MomentHistory.tsx - Moment history subpage.
- MemoryHistory.tsx - Memory history subpage.
- journal/ - The components displayed under the
Journaltab:- Calendar.tsx - The app's main calendar.
- Mementos.tsx - The mementos area at the bottom of the screen.
- MemModal.tsx - Memento adding/editing modal.
- Memory.tsx - The memory textbox blocks.
- Moments.tsx - Moments checkboxes list.
- context/ - The app's context:
- Context.jsx - Main context provider, fetches data from the backend and initializes other contexts.
- useEntries.jsx - Keeps track of the selected entry (based on date), updates memories and moments in the database.
- useExtendedMemento.jsx - Extends memento data: calculates statistics, predicts end dates, and future occurrences.
- useExtendedMoment.jsx - Extends moment data: calculates
due/could do/not duestatus based on frequency. - useMementosHistory.jsx - Keeps track of the selected memento in the
Historytab and its data. - useMementos.jsx - Keeps track of current mementos (based on date), updates mementos in the database.
- useMemoryHistory.jsx - Keeps track of the memory list in the
Historytab and their data. - useMomentHistory.jsx - Keeps track of the selected moment in the
Historytab and its data. - utils.jsx - Utility functions for the app.
- pages/ - App's main pages:
- History.tsx - The
Historytab page. - Journal.tsx - The
Journaltab page.
- History.tsx - The
- theme/ - Color presets and custom css files.
- App.tsx - App main page and tab selection.
- main.tsx - The app's entry point.
Note
Other folders and files were generated by Ionic.
The backend/ folder:
- stitched/
- api.js - The API endpoints.
- database.js - The database schemas and connection.
- index.js - The app's entry point.
- Dockerfile - For containerizing the backend - useful to host on a server. Can be deleted if not in use.
Note
The backend is intentionally minimal, so it can be integrated into existing Express apps without requiring a separate deployment.
To attach to an existing app, copy the stitched/ folder and add the following lines to the existing app's main file:
//[Stitched backend]
const { stitchedDB } = require("./stitched/database");
//[Routes]
const stitchedRouter = require("./stitched/api");
app.use("/api", stitchedRouter);- Node.js 22.14.0
- npm 10.1.0
The app may work with other versions, but these are the versions that were used during development.
See Database for detailed information.
- Copy the contents of
backend/. - Open a MongoDB project if you don't already have one.
- Create a
.envfile in the root directory of the project and fill it with the following:
STITCHED_DBURL=mongodb+srv://<USERNAME>:<PASSWORD>@<CLUSTER>.mongodb.net/<DATABASE>?retryWrites=true&w=majority
STITCHED_API=<custom API key>- Create a document in your MongoDB database according to the schema in Defaults Schema.
- Run
npm i. - Start
index.js.
Important
For the app to work on mobile, the backend needs to be hosted on a server with a public URL.
- Copy the contents of
frontend/. - Create a
.envfile in the root directory of the project and fill it with the following:
VITE_API=<base url of the backend>
VITE_TOKEN=<backend custom API key>- Run
npm i.
Note
At this point you can run npm start or ionic serve to open the app in browser.
To run the app on mobile:
- Install the package:
npm install @capacitor/android
- Build the web app:
npm run build
- Add the platform:
npx cap add android
- Generate Android app icons and splash screens from the source images in the
resources/directory:
npx capacitor-assets generate --android
- Sync web assets and config:
npx cap sync android
-
Additional Setup: See Android Setup for additional required changes to the Android project files.
-
Open in Android Studio:
npx cap open android
- Build and run the app on your device.
Important
The app was tested only on an Android 13+ device.
- Install the package:
npm install @capacitor/ios
- Build the web app:
npm run build
- Add the platform:
npx cap add ios
- Generate iOS app icons and splash screens from the source images in the
resources/directory:
npx capacitor-assets generate --ios
- Sync web assets and config:
npx cap sync ios
-
Additional setup: While I can provide the steps required to run the app on Android, I can’t provide their equivalents for iOS, as I don’t have the setup to test or verify them.
The manual changes applied on Android are:- Enabling
usesCleartextTrafficin the manifest to allow HTTP connections. - Adding a
POST_NOTIFICATIONSpermission to the manifest. - Adding code to request notification permissions on app start.
- Copying the notification icon (
resources/manual/ic_notif_icon.png) to the resources folder.
- Enabling
-
Open in Xcode:
npx cap open ios
- Build and run the app on your device.
- Configure your
Defaultsdocument in the database to suit your needs, and update it as required. - Use the app to keep track of your moments, memories and mementos.
To summarize, the future plans for this app are:
- Rebuild the app from scratch, moving most of the logic to the backend.
- Migrate to Push Notifications.
- Improve documentation and provide more detailed usage instructions.
