Hi all! We're a system called the Nox Syndicate :)
We suspect we are traumagenic with possible OSDD 1b - we're exploring our plurality and we're still learning so please be patient with us! We're also Autistic and ADHD.
Please do not engage in syscourse with us - we do not care for infighting. Our only stance is: we DO agree that endos must not use disordered language and labels for themselves, however we are fine with the endogenic community as a whole. Feel free to block us if this doesn't align with your view, we understand!
We are bodily an adult and would prefer to not interact with anyone under the age of 20, however it's not a hard limit. We do not engage with adult content on this account
Our app SysNotes
We are a web developer who are in the process of making a system management tool fit for our needs. You can find the first devlog of SysNotes here:
💬 0 🔁 1 ❤️ 6 · SysNotes devlog 1 · Hiya! We're a web developer by trade and we wanted to build ourselves a web-app to manage our system an
Once the app is a bit more fleshed out, we are hoping to release a Beta version to the public so that you all can play around with it!
Welcome back to my SysNotes update! SysNotes is a system management app for people with DID, OSDD, and those who are otherwise plural.
This is part 2 of 3(?) about editing profiles.
Phew, it has been a hot minute! To be honest I had this devlog 80% done in drafts for months and just didn't have the spoons to finish it off... But I gained quite a few followers since the last devlog so I feel bad keeping you all waiting.
Not gonna lie, I'm not the same person who wrote up the previous devlogs so this may read kinda odd, but I'm tired of putting it off. Hopefully this still reads coherent.
First Devlog (1) | Previous Devlog (4)
To recap, these are the fields available to a blank profile. In the previous devlog I covered how the user would add the header information as well as an image. The description and history are text fields, while the remaining fields are presented as a collection of "badges". Traits, likes, dislikes, and triggers are collectively called "categories".
In this devlog I will cover the editing of description, history, characteristics, and categories. I will also brainstorm some ways to add relationships towards the end.
Image edit demonstration
Last devlog I reached the image limit for the a post so I couldn't show you the result of editing an image. Well, here it is now!
Editing description and history
These 2 sections are intended to be used as a sort of a self-discovery journal, where you can explore the alter in-depth. I prefer using generalized free-form fields rather than lots of specific custom fields because I find it to be less rigid and therefore easier to fill out. Plus, not every alter will know the specifics about themself so it is more inclusive.
Formatting text
Editing the description and history fields is pretty much the same as editing the name, but one thing that's different about them is that they support formatted user input.
Originally, I wanted to add support for HTML input as it is more customizable. However, it is more technical than markdown which makes it less accessible to users. I also heard that embedding user-submitted HTML code into the page can have security risks, and I'm not sure how to do it safely.
Instead of rendering HTML, I installed the Spatie package to allow support for markdown rendering. Though I have never used SimplyPlural myself, I read that it uses markdown to format text, so SP users would feel more comfortable using SysNotes. Now my app will display markdown (but not HTML) in the description and history sections.
Would you prefer HTML or markdown? Let me know! I can switch the code from using markdown to using HTML quite easily if the need arose just by editing a couple of lines:
(I can also combine HTML and markdown compatibility to maximize flexibility if needed)
I added a semi-transparent "markdown" badge to the corner of the text area as you will see in the following screenshot to let the user know that they can use markdown syntax in the text area.
Editing description
I have added a placeholder with prompts to guide the user through writing a description. These prompts are a rough draft, and I'm not sure what else to add (that wouldn't be covered by later sections) so if you have any ideas, shout them out!
Here is the full user journey for adding a description:
The green text is a markdown heading (#) and a markdown subheading (##). I wanted user-inputted tags to be visually distinct from the app's own headings and subheadings, so I gave them the color green. If you have any better ideas on how to display them, I would be happy to listen. Another type of styling I will eventually add is some spacing between headings and paragraphs so it doesn't look so squished 😅 However, currently I am just focused on making the technical parts work correctly.
Editing history
The history section works and looks exactly the same as description, except the prompts are different. This section is for summarizing the alter's formation and activity within the system. Note that while some of the prompts ask about fronting, this is not intended as a place for front tracking. This is more about how the alter's presence and activity has impacted the dynamics between alters and the system as a whole. You are, of course, free to use this field however you like.
Editing characteristics and categories
To edit characteristics (such as traits, likes, dislikes, and front triggers) and categories, I wanted to do something similar to Tumblr tags. The idea is that the existing traits show up in self-contained boxes and you can type the name of an existing trait into the search box to add traits. Also there would be a cross icon for removing the trait:
I found the JavaScript library Select2 that does exactly this, which was a relief because I didn't need to code this from scratch!
Challenges
Installation
I couldn't get JQuery and Select2 installations to work properly so I resorted to using a CDN, which basically means that all the files necessary for the searching to work live on someone else's server. This isn't recommended for production builds - at work, we had a few instances of CDN servers going down, and we had to scramble to minimize the impact this had on our own web-app by looking for alternative CDNs. This will need to be sorted out eventually, however I just wanted to get the ball rolling so this will do for now.
Event listener
Another big problem I ran into is getting Select2 to work with Livewire lifecycle hooks. The way my app works is:
The input box does not exist when the page first loads
The user clicks the edit button
This renders the input box on the page for the first time
The app needs to "listen out" for the component rendering in order to know that Select2 needs to be initialized on it. This is done by attaching an event listener to the page. I struggled with figuring out the correct syntax for attaching this event listener for my specific case.
I think the main problem was that I was trying to use Livewire-specific event listeners instead of native JavaScript. They weren't working, so I resorted to a DOM mutation observer, which worked:
Getting a list of all characteristics
Initially, I told Select2 to pull suggestions from a list of the user's likes/dislikes/whatever trait is being edited. However, a clear problem with this was that it could only give you suggestions for the traits that the alter already had selected, and couldn't access the full list of traits for you to add to the alter.
To get around this I had to build a quick internal API that gets a list of ALL existing traits, and have Select2 access it using an internal URL instead of getting the user's existing traits.
This sounds like a bunch of tech mumbo-jumbo, but basically an API is just a script that gathers all relevant data from the database and then formats it in a way that is ready to be used, usually in JSON format. Instead of calling it like a function, you access it using its own URL that you define.
Variable sync
The final issue I encountered was syncing the selected values with the Livewire variable. JavaScript (which is what Select2 uses) operates on the front-end, while the Livewire component operates on the back-end. Livewire has a built-in way of syncing front-end and back-end data, however since I'm using Select2 to manipulate front end data, I can't use this way or it will clash with Livewire's data and cause issues
I managed to solve this using a JavaScript event listener which listens out for the "save button" click and tells Laravel to call its save function:
(This is the function for saving categories, the function for saving characteristics is very similar to this so I won't bore you)
Result
Now when the user clicks the edit button, they get this Tumblr-esque textbox with their existing characteristics, and they can search for additional characteristics as well:
(Here is the user searching for a term containing the letter "b":)
This way, you can add existing traits to the profile. We will cover adding new traits to the list in the next devlog.
Owner ID
In the Alter-Char-Values table, you can see a column called "owner_id". This relates to the user who the trait belongs to. This means that the app only gives you a list of traits that you have created yourself, not the traits that other users have created. This is done for both privacy and list length concerns.
(My test user's ID is 1)
Adding relationships - ideas
This is the last field that I have yet to add to the profile functionality. Currently, the app can display existing relationships, but the user cannot add new relationships.
Since relationships have 2 components (relationship type and alter name), it wouldn't make sense to add them the exact same way as traits and characteristics. However, I'm not quite sure what the best way to add them is. Here is my current idea:
There is a pair of Select2s, one for the relationship type and one for the alter's name. The user will select the value of each input to set a relationship. To add more relationships, they will click on the "+" (add another relationship) button and another pair of selects will appear.
My biggest concern with this implementation is that the number of select pairs may get unreasonably large for systems with many alters and relationships. If you have any other ideas on how to implement the relationship inputs, I'd love to hear them! I will make devlog 5.5 with my implementation of it.
...And here we go!
If you have made it to the end, I'm very grateful for your support! And a big thank you for being patient with me. I look forward to continuing the development of SysNotes :)
chat I'm not going to lie, I am no longer interested in being on the Internet so there will not be any more devlogs.
I'm abandoning the development of SysNotes, mostly because I found an app that can already do most of these things. It's called *Obsidian*, and you can do a lot of cool, connected, and interactive things using its properties, canvas, and bases features. I wish I could elaborate or make a tutorial, but I just don't have the energy.
If you could reblog this to let others know that it's not going ahead, that would be nice. I'm going to delete my account soon so all my posts will be gone, including this one.
I haven't logged into tumblr (or any other social media) in months and it has been super nice. But *change doesn't come without commitment*, and I'm committing to my wellbeing by deleting all social media accounts and selling several of my computing devices. If you're looking for a *sign* to do the same, this is it. I feel much better knowing that my sense of identity doesn't rely on the turbulent nature of the Internet right now.
Touch grass, go to the library, engage with your community center, and start conversations with strangers. You won't find what you're looking for online. If you have anything to say, I don't really care because I won't be there to read it.
Welcome back to my SysNotes update! SysNotes is a system management app for people with DID, OSDD, and those who are otherwise plural.
This is part 2 of 3(?) about editing profiles.
Phew, it has been a hot minute! To be honest I had this devlog 80% done in drafts for months and just didn't have the spoons to finish it off... But I gained quite a few followers since the last devlog so I feel bad keeping you all waiting.
Not gonna lie, I'm not the same person who wrote up the previous devlogs so this may read kinda odd, but I'm tired of putting it off. Hopefully this still reads coherent.
First Devlog (1) | Previous Devlog (4)
To recap, these are the fields available to a blank profile. In the previous devlog I covered how the user would add the header information as well as an image. The description and history are text fields, while the remaining fields are presented as a collection of "badges". Traits, likes, dislikes, and triggers are collectively called "categories".
In this devlog I will cover the editing of description, history, characteristics, and categories. I will also brainstorm some ways to add relationships towards the end.
Image edit demonstration
Last devlog I reached the image limit for the a post so I couldn't show you the result of editing an image. Well, here it is now!
Editing description and history
These 2 sections are intended to be used as a sort of a self-discovery journal, where you can explore the alter in-depth. I prefer using generalized free-form fields rather than lots of specific custom fields because I find it to be less rigid and therefore easier to fill out. Plus, not every alter will know the specifics about themself so it is more inclusive.
Formatting text
Editing the description and history fields is pretty much the same as editing the name, but one thing that's different about them is that they support formatted user input.
Originally, I wanted to add support for HTML input as it is more customizable. However, it is more technical than markdown which makes it less accessible to users. I also heard that embedding user-submitted HTML code into the page can have security risks, and I'm not sure how to do it safely.
Instead of rendering HTML, I installed the Spatie package to allow support for markdown rendering. Though I have never used SimplyPlural myself, I read that it uses markdown to format text, so SP users would feel more comfortable using SysNotes. Now my app will display markdown (but not HTML) in the description and history sections.
Would you prefer HTML or markdown? Let me know! I can switch the code from using markdown to using HTML quite easily if the need arose just by editing a couple of lines:
(I can also combine HTML and markdown compatibility to maximize flexibility if needed)
I added a semi-transparent "markdown" badge to the corner of the text area as you will see in the following screenshot to let the user know that they can use markdown syntax in the text area.
Editing description
I have added a placeholder with prompts to guide the user through writing a description. These prompts are a rough draft, and I'm not sure what else to add (that wouldn't be covered by later sections) so if you have any ideas, shout them out!
Here is the full user journey for adding a description:
The green text is a markdown heading (#) and a markdown subheading (##). I wanted user-inputted tags to be visually distinct from the app's own headings and subheadings, so I gave them the color green. If you have any better ideas on how to display them, I would be happy to listen. Another type of styling I will eventually add is some spacing between headings and paragraphs so it doesn't look so squished 😅 However, currently I am just focused on making the technical parts work correctly.
Editing history
The history section works and looks exactly the same as description, except the prompts are different. This section is for summarizing the alter's formation and activity within the system. Note that while some of the prompts ask about fronting, this is not intended as a place for front tracking. This is more about how the alter's presence and activity has impacted the dynamics between alters and the system as a whole. You are, of course, free to use this field however you like.
Editing characteristics and categories
To edit characteristics (such as traits, likes, dislikes, and front triggers) and categories, I wanted to do something similar to Tumblr tags. The idea is that the existing traits show up in self-contained boxes and you can type the name of an existing trait into the search box to add traits. Also there would be a cross icon for removing the trait:
I found the JavaScript library Select2 that does exactly this, which was a relief because I didn't need to code this from scratch!
Challenges
Installation
I couldn't get JQuery and Select2 installations to work properly so I resorted to using a CDN, which basically means that all the files necessary for the searching to work live on someone else's server. This isn't recommended for production builds - at work, we had a few instances of CDN servers going down, and we had to scramble to minimize the impact this had on our own web-app by looking for alternative CDNs. This will need to be sorted out eventually, however I just wanted to get the ball rolling so this will do for now.
Event listener
Another big problem I ran into is getting Select2 to work with Livewire lifecycle hooks. The way my app works is:
The input box does not exist when the page first loads
The user clicks the edit button
This renders the input box on the page for the first time
The app needs to "listen out" for the component rendering in order to know that Select2 needs to be initialized on it. This is done by attaching an event listener to the page. I struggled with figuring out the correct syntax for attaching this event listener for my specific case.
I think the main problem was that I was trying to use Livewire-specific event listeners instead of native JavaScript. They weren't working, so I resorted to a DOM mutation observer, which worked:
Getting a list of all characteristics
Initially, I told Select2 to pull suggestions from a list of the user's likes/dislikes/whatever trait is being edited. However, a clear problem with this was that it could only give you suggestions for the traits that the alter already had selected, and couldn't access the full list of traits for you to add to the alter.
To get around this I had to build a quick internal API that gets a list of ALL existing traits, and have Select2 access it using an internal URL instead of getting the user's existing traits.
This sounds like a bunch of tech mumbo-jumbo, but basically an API is just a script that gathers all relevant data from the database and then formats it in a way that is ready to be used, usually in JSON format. Instead of calling it like a function, you access it using its own URL that you define.
Variable sync
The final issue I encountered was syncing the selected values with the Livewire variable. JavaScript (which is what Select2 uses) operates on the front-end, while the Livewire component operates on the back-end. Livewire has a built-in way of syncing front-end and back-end data, however since I'm using Select2 to manipulate front end data, I can't use this way or it will clash with Livewire's data and cause issues
I managed to solve this using a JavaScript event listener which listens out for the "save button" click and tells Laravel to call its save function:
(This is the function for saving categories, the function for saving characteristics is very similar to this so I won't bore you)
Result
Now when the user clicks the edit button, they get this Tumblr-esque textbox with their existing characteristics, and they can search for additional characteristics as well:
(Here is the user searching for a term containing the letter "b":)
This way, you can add existing traits to the profile. We will cover adding new traits to the list in the next devlog.
Owner ID
In the Alter-Char-Values table, you can see a column called "owner_id". This relates to the user who the trait belongs to. This means that the app only gives you a list of traits that you have created yourself, not the traits that other users have created. This is done for both privacy and list length concerns.
(My test user's ID is 1)
Adding relationships - ideas
This is the last field that I have yet to add to the profile functionality. Currently, the app can display existing relationships, but the user cannot add new relationships.
Since relationships have 2 components (relationship type and alter name), it wouldn't make sense to add them the exact same way as traits and characteristics. However, I'm not quite sure what the best way to add them is. Here is my current idea:
There is a pair of Select2s, one for the relationship type and one for the alter's name. The user will select the value of each input to set a relationship. To add more relationships, they will click on the "+" (add another relationship) button and another pair of selects will appear.
My biggest concern with this implementation is that the number of select pairs may get unreasonably large for systems with many alters and relationships. If you have any other ideas on how to implement the relationship inputs, I'd love to hear them! I will make devlog 5.5 with my implementation of it.
...And here we go!
If you have made it to the end, I'm very grateful for your support! And a big thank you for being patient with me. I look forward to continuing the development of SysNotes :)
Adding custom statuses, characteristics, relationships, and categories
First Devlog (1) | Previous Devlog (3)
Editing profiles
You see this little icon in the corner of a profile?
Originally, this was the icon for toggling edit mode for the entire profile. This means transforming all the text into textboxes and showing the interface for populating empty sections. However, I don't think that is the most elegant approach. It also would be quite messy computationally, because every time you wanted to edit one field the app would need to validate and process all the other fields in addition to the one you edited before it was able to save it.
So what I propose to do now is to have a separate edit icon for each individual section so that you can edit them selectively. To be able to edit the sections I will need to display them all, each with their own edit icon:
(The reason the first line is a darker orange is because it's a main heading, and the other lines are subheadings)
Editing header & main editing logic
Ok, let's transform the name into a textbox when the button is clicked.
First, I created a variable to track whether the user is editing the header or not. At the start, it is set to false:
Then, I created a function that sets the variable to true when the edit button is clicked:
(& #128393; here is just the pencil emoji symbol code; "clear" in "btn-clear" refers to the background transparency, not the action of clearing)
Finally, in my component I check if edit mode is on. If so, a textbox is rendered. If not, it displays just the text:
("@if ($editMode['header'])" is logically the same as "@if($editMode['header'] == true)")
One issue I ran into is that Livewire doesn't actually work correctly with associative arrays such as "$selectedProfile['name']" (when I clicked save, the whole component would stop displaying). So I had to assign the name to a temporary variable called "tempName" for it to be able to refresh correctly.
(And then I had to update the textbox to reference tempName)
Annoyingly, that means I would need to create a separate variable for each editable field instead of dynamically assigning them from the profile itself. It's messy, but it works so I'll roll with it.
Now that we're back on track, let's say Jenny is trans and wants a more masc name, like Jeremy:
Now we need a way to save the new name. Let's add a "submit" and "cancel" buttons when the edit mode is on:
(Again, the codes in red represent the ✔ and ✗ symbols)
For the new name to actually save, we need to validate it to make sure the database can accept it. I copied the validation code from devlog 3 :
(The save code is boring so I'll skip it, I bet you're so sick of code by now) xD
After the name is saved, we need to add a success message and turn off edit mode:
Rinse and repeat (header)
Now if you remember, the header has 4 pieces of information: name, pronouns, status, and origin.
I can follow the same process to create an edit view for the rest of the header components. Now we can add pronouns, status, and origin to the new profile, as well as edit them later:
Drop-downs
I want to show how I did the status and origin dropdowns because I think it's cool, and not overly complex.
First, I initialized the variables that will store a list of statuses/that are available to the user.
Then, I did a database query for each one, basically getting the statuses/origins that either have an owner ID of null (available to all users) or an owner ID of the user's ID (custom-added by the user). This is so that you don't have access to another user's custom statuses/origins.
Finally, I iterated over the array (list) of statuses (and origins) and added a dropdown option for each status/origin in the array:
Responsive design (narrow screens)
I haven't really started to work on the mobile design yet, however my header isn't quite fitting on my screen even on desktop:
To make it easier to give edit mode and view mode different layouts, I separated them into 2 parts. As you can see, one is displayed if the edit mode is off, and the other displays if the edit mode is on:
(" @if (!$editMode['header'])" is equivalent to "@if ($editMode['header']) == false" (specifically the "!" symbol))
Next, the CSS framework Tailwind that I'm using for styling has screen breakpoints built in. Here, I used "md:" to display the inputs in 2 columns from medium widths onward, and "xl:" to display the inputs in 4 columns from extra large screens onward. Since I didn't specify the column number for small screens, the inputs will display in one column by default.
(Medium screen:)
(Extra large screen:)
Editing profile image
If you compare a filled profile with the new profile, you'll see that the profile image and description don't have their own headings to attach an edit button to. Having headers wouldn't make sense as the name is already a header for the character bio (image + description).
So where would I squeeze in 2 extra edit buttons, and how would the user know which parts of the profile they're for?
My solution was to add placeholders where the image and the description text would go!
...Aaaand I have just reached the image limit for this post, oops. We're almost at the end of the devlog so that should be alright. All I need to do now is save the image to the database the same way I saved the name etc, and that's this part done!
I will cover editing the description and history in the next devlog as I have some things to say about their format, see you then!
SysNotes devlog 3 - Ability to create a new profile
Welcome back to my SysNotes update! SysNotes is a system management app for people with DID, OSDD, and those who are otherwise plural.
(I will keep the intro text the same in all devlogs for context)
This devlog will be shorter than usual because I didn't want to lump it in with the next feature, which I expect will be quite long. In this devlog, I will add a way to create a new profile.
First Devlog (1) | Previous Devlog (2)
Quick Refactor before we jump in
"So I did some refactoring off-camera..." - originally, everything on the page was happening inside one component. I decided to split it up into the main page and the profile section, which is a new separate component. This will keep my code shorter and easier to maintain.
I also added a way to refer to each profile individually by their ID in the URL:
(Colin's profile is ID 4, which is shown in the URL)
I was also storing profile data as separate variables, which would be inconvenient to individually pass into the new main profile component. So I moved them all into one variable:
(old | new)
Design of the New Profile form
To be honest, I've been dreading this part since the beginning. I mean, how do I even lay this out? 💀
It is common for developers to avoid UI design because they are "coders not designers". I, for one, quite enjoy web design. Still, this task feels quite overwhelming to me. So, let's take this little mockup I made and turn it into something usable 💪
Too much stuff?
I think the biggest challenge here is the sheer number of inputs. And as the app grows, the number of inputs in this form will only increase.
The only mandatory input for a new profile is just their name. Therefore, the first step should be separating the Name field from the rest of the inputs.
The new and improved New Profile form is looking much better now:
...Yes, really! That's the whole form!
You are unlikely to know everything about an alter that has just split, so all those fields are completely unnecessary for an alter to be added to the list. Every other detail can be added later through the edit mode, where each field can be edited separately without needing one giant form.
Another big reason why I decided to forego the big form altogether is that the code for saving a new profile and the code for editing a profile would be almost exactly the same (including validation), and it wouldn't make sense to duplicate this code if I can just use it in one instance.
Saving a new profile
Let's add some validation to the input field to make sure that the user enters the name in a correct format.
As the Name is stored in the database as a string, it has the maximum length of 255 characters. Trying to save a longer name than this will cause errors, so we need to validate the input to make sure it's safe to insert into the database:
Here's what happens when I input a whole paragraph of Lorem Ipsum text and try to save it:
On the other hand, a shorter name saves just fine:
By the way, these flash messages are added in 2 ways: the success is a session message, and the error is an error stored separately by the validator. The flash messages originally have no styling, so I defined those myself using Tailwind's "@apply" for efficiency.
Once submitted, the name list automatically updates with our new profile:
(And if I click cancel it just empties the input)
Okay, let's click on Jenny's profile to see what it looks like! ...Oh
This is because the code tries to access Jenny's status, but she doesn't have one yet, she only has a name!
(When I pull the data from the database, I'm trying to access a non-existent value)
(And when I display the values I got from the database, the display may break if the value is NULL)
(This error applies to all profile fields, not just status, however the app crashes after just the first error it comes across so the remaining errors are not shown)
This can easily fixed by using PHP's "isset()" and/or "empty()" function, which checks if a variable has a value:
(I'm using a ternary operator as a more compact alternative to if-else. it basically goes: "if this condition is true ? then do it : if not, do something else")
(And here I just check if these values are not blank before rendering them)
Success, Jenny's profile shows!
Now, we just have to populate this profile with data about Jenny, and to do that we'll need to be able to edit each field. I will work on this in the next devlog, as I expect this to take quite some time.
Thanks so reading! As always, any suggestions are welcome!
SysNotes devlog 2 - retrieving data from the database and NEW profile features!
Welcome back to my SysNotes update! SysNotes is a system management app for people with DID, OSDD, and those who are otherwise plural.
Today I will flesh out the backend of the application (which was completely missing in the first devlog) and add some new profile fields.
First Devlog (1) | Previous Devlog (1.5)
Pulling data from the database and populating the profiles
If you remember, in the first devlog I used hardcoded data to test the interface like so:
Storing data in code is not sustainable or maintainable, so in devlog 1.5 I have identified the most suitable database structure, created some tables, and filled them with test data. To populate the tables I generated dummy data using the Faker library which uses random Latin words to create sentences. This was the result for the Alter Profiles table:
First, let's delete the hardcoded data from the code. Wow, the user interface is looking so empty now!
I already implemented the basic code for processing alter data and displaying it on the page in devlog 1. However, I had to make some tweaks to it due to the nature of database queries.
Firstly, when loading Alter Profiles for the side menu, I'm only selecting their name and ID, without the other fields (description, history, etc). A common mistake beginner developers make in simple cases like this is retrieving the entire DB record. But the side menu does not need the extra information, and loading it in alongside the name would make the page slower!
You may also notice that I'm getting the names in alphabetical order - I thought this would look nicer on the sidebar than if the names were all random, and make it easier to navigate. I'm only getting the profiles that belong to the current user.
When I get the actual profile data, I retrieve it with its status and characteristics, which are stored in separate tables:
And here we go, the profile page now uses the data stored in the database!
New profile features
But this is all just using the the proof of concept profile fields I mocked up in devlog 1. In this devlog, I want to add NEW fields to allow the profile page to do more powerful things, and better integrate with the future features of Inner World and Front Decider (still looking for a better name for it 😩).
(By the way, I assigned the Ulysses profile to a different user for testing, so you won't see that profile in the sidebar from now on)
Alter origins
One new profile field I've been wanting to add is an alter's origins. Some of my alters split from trauma, others from loneliness, and others through being AuDHD. I created a new table called "Alter Origins" with an optional owner ID. This means that some origins are universally available to all users, while others can be created by users themselves to customize their profile. In this example, "stressgenic" is a custom origin my user (Test System) created.
To use this table, I need to connect it to the Alter Profiles table using a foreign key:
Now we can access it on the front end!
(It shows on the top line, highlighted red)
Side note: I had issues with most Tailwind v4 colors not working so I had to manually define the origin badge color classes based on the official Tailwind values 😓 I'm not sure how to fix it, I wanted to leverage Tailwind to allow users to select "custom colors" from the Tailwind palette... I'll look into it at another time.
Relationships
I wanted the ability to set up bidirectional relationships between alters and display them after the character traits area.
I created an Alter Relationships table with some relationships and their badge colors:
And then I created a pivot table where alter 2 is Alice, alter 3 is Amari, and alter 5 is Benji:
Now if we go to Alice's page, we will see:
And Amari's will show:
This feature took a long time to implement because I ran into some issues with the pivot table and model relationships. I'd be lying if I said I have a good grasp of Eloquent 😅
Alter categories
One last thing I want to add in this devlog is to add custom categories that the names in the sidebar could be sorted into, which would be helpful for systems with many alters (or those who want to store their alter data and OC data in one place but want to distinguish between them, like me).
I will add some default categories to the database - however, you will be able to add new custom categories to suit your needs. I also want each profile to have one OR MORE categories for flexible filtering. This means, annoyingly, that I have to tinker with yet another pivot table 😩
Here is my Alter Categories table. Like with origins and relationships, "owner_id" refers to the user who made the category, and NULL categories are available to all users.
The pivot table looks like any standard pivot table so I'll omit it for this feature. I've had enough of pivot tables. Luckily, I got the model relationships correct the first time 😎
And now, Alice's profile shows her categories under her relationships:
(And here are all the category badges so far)
But this isn't all! I want to be able to filter my profiles by category in the sidebar.
Let's create a drop down! I think this looks alright:
Now let's load the categories of our available profiles into the dropdown. For this, I will need to fetch the categories table when getting the profile names.
The dropdown code basically takes the array (list) of all profiles, compares each profile's category to the selected category, and adds them to the array of filtered profiles, then displays them. If the selected value is "-" it just displays the full list of profiles.
And here we go, our fragments are Alice and Colin:
I also wanted to add the ability to group profiles by their categories (e.g. grouping by Age will split the names in the side bar into "syskid" and "adult" boxes). But this devlog has gone on for quite a while, so I'll save that for another time ;)
What next?
I wanted to finish the whole Profile section and move on to the more exciting inner World and Front decider features, however the complexity of the profile section so far requires me to spend a few more devlogs on it, oops 😅 So here is what you can expect in the next few devlogs:
Rethink the User Interface of the Profile page (all these badge colors are getting messy! And is the current layout the best for displaying the data? Find out next on Dragon Ball Z!)
Add a way to create new profiles using the New Profile form
Add ability to edit the profile information and delete profiles
Do you have ideas on other fields and features I could add to SysNotes? Or maybe you have suggestions on how to clean up the UI? I'd love to hear your thoughts! Thanks for reading 🙌
Hi all! In this post I will continue the development of my plurality management web-app SysNotes. Today I will be focusing mostly on setting up the databases for the app, as currently test data is stored in the code itself. This severely limits the interactivity and features of the web-app, so it is time to separate it.
In this devlog, I will explain the basics of databases and how the Laravel framework interacts with them to give you an idea of what goes on on my screen and in my brain while I code.
This will just be an overview of some technical behind the scenes, nothing will have changed on the front end of the app.
If you missed the first devlog, you can find it here.
What is a database?
A database at the most basic level is a type of file format that has tables. You can think of it as a "spreadsheet file" like the ones you can open in Excel or Google Sheets.
The main structural difference between a database and a spreadsheet is that in a database the tables can have relationships. For example, the relationship between a users table and a posts table is that one user can make many posts, and a post can only belong to one user. This is a one-to-many relationship. You can ask the database to give you all the posts related to a specific user. In my app, each user account will have multiple alter profiles, for example. When a user logs in, the app will only fetch the alter profiles that this user created, and show the profiles to them. You can do a whole bunch of other things with databases, that's why I like them!
The main functional difference between a database and a spreadsheet is that a spreadsheet is used for data analysis and manipulation, like a fancy calculator, while a database is used to store data. Each table stores data related to one type of object/person/place.
Like how spreadsheets can be opened in Excel, database tables can be opened in database software such as MySQL Workbench or HeidiSQL, which is what I'm using since it came with Laragon.
(What my Heidi DB looks like at the end of the devlog)
Plan for today
The users table already exists in my app as a result of installing the Laravel Breeze starter kit, so I don't have to worry about designing this table. With that out of the way, I can think about adding feature-related tables.
The first feature I'm adding to my app is the ability to create alter profiles and to fill in the sections on the profile page. The first step is therefore to create an "alter profiles" table and to normalize it (more on that in a bit).
Setting up the database tables (and why it's a pain)
Migration files
When using the Laravel framework, you're not supposed to create a new table or edit an existing table through the database itself - it has to all be done through code. This is done using a file called a database migration. The migration specifies the table name, what columns it should have, what data types the columns should be, and what other tables this table may be related to. This is done so that if you give the code to another person and they download and ran it, their database will be set up the exact same way is yours. Therefore, the migration file makes your database changes portable, which is especially useful when copying code from your personal computer onto the server where the web-app is running. You don't want to set up your local database and then find out that it doesn't work the same way as the one that runs the actual app!
Migrations aren't just for creating a new table. You also need to make a migration file for every structural change you want to make for that table, such as adding a new column or changing a column's name. Updating a table's structure after it's already been set up and filled with data has a chance of corrupting the data. Therefore, I always impose this expectation of myself of always getting the database structure right on the first try (i.e. in just one migration).
(My migration file for the alter profiles table at the end of this devlog)
Normalization
Normalization is the act of splitting up a table into 2 or more tables in order to simplify the data structure, reduce duplication, and make database queries more efficient.
To illustrate, let's consider the alter profiles table. An alter can have several traits, such as "energetic" or "nervous" and so on. Let's say we should store it in a "traits" column like so:
Now let's say we decide that the word "sad" isn't quite the right descriptor, and we want to change it to "melancholic". To do that, we would need to edit every instance of this word in the table. In this example, it would only be in 2 places: on Benji's profile and on Colin's profile. But what if there were many melancholic alters? That sounds like a lot of work! What if you misspell it on accident somewhere? You won't be able to filter alters by trait properly!
Instead what would be better to do is to split (haha) the alter profile table into that and a traits table. Now we will have:
So if you wanted to change the word "sad" to "melancholic", you could do it in just one place, which makes it easier and more maintainable. This is just one small example of what normalization can be. There are actually like 7 levels of it, and even I don't remember them all. In fact, what I will be doing in my app is a step further than the example and use something called a "pivot table" - a whole new type of headache!
The point is, figuring out the architecture of database tables is a whole science in on itself 😩
Actually doing the coding
After brainstorming how to normalize it, the alter profile will need to be separated into several tables: alter profiles, alter characteristic types (traits, likes, dislikes, an triggers), alter characteristic values, and alter statuses (such as active, dormant, and unknown). Each profile can then reference the characteristics and statuses tables. This way, alters can like or dislike the same thing, creating the ultimate modularity!
The (pretty technical) steps are as follows:
Create the (model with) migrations for the individual tables and specify their table structure
Create a pivot table and set foreign IDs to point to the individual tables
Define the relationships in the model files
It took me a few tries to get past migration errors, and I accidentally rolled back my migrations too many times, losing my users table 🤦♂️ As i don't yet have any alter data in the database, I just re-registered my account and nothing was lost. Heart attack simulator lol.
Seeding data
As I'm just working with test data, I don't really care exactly what words and images are used where as long as it works. I also don't want to pain-stakingly input test data into every field for every profile every time I have to delete (drop) and remake (migrate) a table.
That's where seeding comes in. Seeding is an automated process that generates dummy data and inserts it into the database, ready for me to test.
I'll admit I've never done seeding before - at work I've always worked with a copy of an existing database that has been filled by years of use. But it's never too late to learn!
I used seeding to create dummy data for alter profiles and trait values (trait types and statuses has to be manually inputted because they have pre-defined values). I couldn't quite figure out how to seed pivot tables, as they define relationships rather than data. So I had to add those manually too. I still have a ways to go until I'm a real developer lol.
(My Alter Profile factory at the end of the devlog - i left pronouns blank because I wanted them to somewhat match the names, so I added them manually afterwards)
(My Alter Profile seeder at the end of the devlog)
And here are my seeded tables! The faker is limited to using Latin words so I couldn't get the characteristics to look realistic. But it will be fine for test data.
(I have changed the alter names to match the names from the previous devlog)
...All this just for the profile page! But when designing a database's architecture, it is important to anticipate ways in which the database will grow and facilitate new relationships from the start. This was a tiring coding session but it has paved the way for the new and more exciting features!
What next?
This devlog was just for setting up the database tables - in the next devlog we'll get to actually use them in the app! The plan is:
Pull data from the database into the profile pages to display the freshly generated dummy data
Add a way to create new profiles using the New Profile form
Hiya! We're a web developer by trade and we wanted to build ourselves a web-app to manage our system and to get to know each other better. We thought it would be fun to make a sort of a devlog on this blog to show off the development! The working title of this project is SysNotes (but better ideas are welcome!)
What SysNotes is✅:
A place to store profiles of all of our parts
A tool to figure out who is in front
A way to explore our inner world
A private chat similar to PluralKit
A way to combine info about our system with info about our OCs etc as an all-encompassing "brain-world" management system
A personal and tailor-made tool made for our needs
What SysNotes is not❌:
A fronting tracker (we see no need for it in our system)
A social media where users can interact (but we're open to make it so if people are interested)
A public platform that can be used by others (we don't have much experience actually hosting web-apps, but will consider it if there is enough interest!)
An offline app
So if this sounds interesting to you, you can find the first devlog below the cut (it's a long one!):
(I have used word highlighting and emojis as it helps me read large chunks of text, I hope it's alright with y'all!)
Tech stack & setup (feel free to skip if you don't care!)
The project is set up using:
Database: MySQL 8.4.3
Language: PHP 8.3
Framework: Laravel 10 with Breeze (authentication and user accounts) and Livewire 3 (front end integration)
Styling: Tailwind v4
I tried to set up Laragon to easily run the backend, but I ran into issues so I'm just running "php artisan serve" for now and using Laragon to run the DB. Also I'm compiling styles in real time with "npm run dev".
Speaking of the DB, I just migrated the default auth tables for now. I will be making app-related DB tables in the next devlog.
The awesome thing about Laravel is its Breeze starter kit, which gives you fully functioning authentication and basic account management out of the box, as well as optional Livewire to integrate server-side processing into HTML in the sexiest way. This means that I could get all the boring stuff out of the way with one terminal command. Win!
Styling and layout (for the UI nerds - you can skip this too!)
I changed the default accent color from purple to orange (personal preference) and used an emoji as a placeholder for the logo. I actually kinda like the emoji AS a logo so I might keep it.
Laravel Breeze came with a basic dashboard page, which I expanded with a few containers for the different sections of the page. I made use of the components that come with Breeze to reuse code for buttons etc throughout the code, and made new components as the need arose. Man, I love clean code 😌
I liked the dotted default Laravel page background, so I added it to the dashboard to create the look of a bullet journal. I like the journal-type visuals for this project as it goes with the theme of a notebook/file. I found the code for it here.
I also added some placeholder menu items for the pages that I would like to have in the app - Profile, (Inner) World, Front Decider, and Chat.
i ran into an issue dynamically building Tailwind classes such as class="bg-{{$activeStatus['color']}}-400" - turns out dynamically-created classes aren't supported, even if they're constructed in the component rather than the blade file. You learn something new every day huh…
Also, coming from Tailwind v3, "ps-*" and "pe-*" were confusing to get used to since my muscle memory is "pl-*" and "pr-*" 😂
Feature 1: Profiles page - proof of concept
This is a page where each alter's profiles will be displayed. You can switch between the profiles by clicking on each person's name. The current profile is highlighted in the list using a pale orange colour.
The logic for the profiles functionality uses a Livewire component called Profiles, which loads profile data and passes it into the blade view to be displayed. It also handles logic such as switching between the profiles and formatting data. Currently, the data is hardcoded into the component using an associative array, but I will be converting it to use the database in the next devlog.
New profile (TBC)
You will be able to create new profiles on the same page (this is yet to be implemented). My vision is that the New Alter form will unfold under the button, and fold back up again once the form has been submitted.
Alter name, pronouns, status
The most interesting component here is the status, which is currently set to a hardcoded list of "active", "dormant", and "unknown". However, I envision this to be a customisable list where I can add new statuses to the list from a settings menu (yet to be implemented).
Alter image
I wanted the folder that contained alter images and other assets to be outside of my Laravel project, in the Pictures folder of my operating system. I wanted to do this so that I can back up the assets folder whenever I back up my Pictures folder lol (not for adding/deleting the files - this all happens through the app to maintain data integrity!).
However, I learned that Laravel does not support that and it will not be able to see my files because they are external. I found a workaround by using symbolic links (symlinks) 🔗. Basically, they allow to have one folder of identical contents in more than one place.
I ran "mklink /D [external path] [internal path]" to create the symlink between my Pictures folder and Laravel's internal assets folder, so that any files that I add to my Pictures folder automatically copy over to Laravel's folder.
I changed a couple lines in filesystems.php to point to the symlinked folder:
And I was also getting a "404 file not found" error - I think the issue was because the port wasn't originally specified. I changed the base app URL to the localhost IP address in .env:
…And after all this messing around, it works!
(My Pictures folder)
(My Laravel storage)
(And here is Alice's photo displayed - dw I DO know Ibuki's actual name)
Alter description and history
The description and history fields support HTML, so I can format these fields however I like, and add custom features like tables and bullet point lists.
This is done by using blade's HTML preservation tags "{!! !!}" as opposed to the plain text tags "{{ }}".
(Here I define Alice's description contents)
(And here I insert them into the template)
Traits, likes, dislikes, front triggers
These are saved as separate lists and rendered as fun badges. These will be used in the Front Decider (anyone has a better name for it?? 🤔) tool to help me identify which alter "I" am as it's a big struggle for us. Front Decider will work similar to FlowCharty.
What next?
There's lots more things I want to do with SysNotes! But I will take it one step at a time - here is the plan for the next devlog:
Setting up database tables for the profile data
Adding the "New Profile" form so I can create alters from within the app
Adding ability to edit each field on the profile
I tried my best to explain my work process in a way that wold somewhat make sense to non-coders - if you have any feedback for the future format of these devlogs, let me know!
~~~~~~~~~~~~~~~~~~
Disclaimers:
I have not used AI in the making of this app and I do NOT support the Vibe Coding mind virus that is currently on the loose. Programming is a form of art, and I will defend manual coding until the day I die.
Any alter data found in the screenshots is dummy data that does not represent our actual system.
I will not be making the code publicly available until it is a bit more fleshed out, this so far is just a trial for a concept I had bouncing around my head over the weekend.
We are SYSCOURSE NEUTRAL! Please don't start fights under this post