Plans for Jinya CMS 26

It has been about 10 months since the last major version of Jinya CMS. Since version 25 there were two minor releases containing mainly maintenance updates. Version 25.1.0 made PHP 8.2 an officially supported PHP version for Jinya CMS and version 25.2.0 added an option for theme developers to expose the data of a site via an open API. These were small steps and there were no plans for big new features in the mid term. Jinya CMS does what it should do very well, it is fast and easy to use. Our focus was set on mobile and desktop apps, while the Android app made a huge leap forward, there will be a post about it, the desktop app stalled and nothing really happend on that front. Since the Android app is based on Flutter there might be a version of that app for desktop, but that isn't certain yet. Anyway, this post is about Jinya CMS 26 and not the mobile and desktop apps.

The life of Jinya CMS

Well, the technical side of it

Jinya CMS started back in October 2017 as Jinya Gallery CMS, back then was clear, Jinya has to be a CMS focusing on art and images not on text. So the development began, and well, the first version of the backend and designer was a train wreck. First of all there were two backends, the backend for user, file and gallery management and the designer. The designer was, essentially, the place to arrange your galleries and thats it. I have no idea why it was a separate page, with a completely different design, but that was how it was. Based on Symfony, Bootstrap and JavaScript the code was working rather well.

All new with version 2

With version 2.0 this whole design catastrophy was thrown away and rewritten. Now there was a single UI which got the name designer. The designer contained everything, from user management over theme management down to the file management. Back then files could only be images. Version 2.0 was released just a few months after version 1.0. This version of the designer "lived" about two years, it was gradually improved over time and got new features, for example a drag and drop designer for galleries, in future versions. As base for the new designer I decided on Vue.js, which was a good decision and made it easy to extend the designer in the future. The backend was written in Symfony and was API first from that point onwards, back with version 1.0 the backend was classic MVC which meant no interaction for, lets say, mobile apps or similar. Not that I was able to write such apps back then.

Lets try new technology

After two years Jinya CMS was at version 16.0. The development of version 16.0 was one hell of a ride. It started with the replacement of the Symfony backend with a backend based on the Slim Framework. By version 15 it was clear, Jinya will not use any other database than MySQL or its forks in the future so the decision was made to replace the Doctrine ORM with a direct usage of the PHP integrated PDO. This allowed for the direct usage of SQL queries which made the whole system a good point faster, the downside was that there will, probably, be no other supported database than MySQL in the future. In its core the backend in Jinya 25 is still the same, a few parts were refactored or extracted, but at the end it has the same base.

The designer is a different story. Back then rust and webassembly were on the horizon and I decided to try it out. While the design of the designer in version 15.0 was good, it had its flaws and I wasn't sure how to fix these flaws, while keeping the spirit of the design system. The logical decision, create a new design system from scratch. That is the story how Jinya UI was born, and well, Jinya UI survived like 2 months. While the design behind it was really well made, according to friends of mine, the tech implementing the design wasn't there yet. The designer was based on a rust single page framework and web assembly basically. Rust was and is a great language, but back in 2020 web assembly was still not there yet and most frameworks were at the beginning and not that nice to use IMO. I still really like the design of Jinya UI, and I probably will revive it in a different Jinya project. Since 2020 the framework used for the designer has come a very long way and I realized a few, private, projects with it in the past months.

Sadly the designer in version 16.0 was really hard to use and had several issues. Apart from the technical issues even Jinya UI had a few issues too. The design was fine and well for small management apps but the designer, a editing heavy site, suffered from the design of Jinya UI. So with version 18.0 the whole designer got a rewrite once again. I kind of detect a pattern here.

Cosmo rises

Jinya CMS 18.0 was the first Jinya CMS version featuring the new Cosmo CSS design system. While the CSS implementation was new, Cosmo itself is a really old design system. Built back in 2012 by Microsoft it was designed for Silverlight apps. When I discovered it I wanted to use it for my apps, back in 2012 I mainly developed desktop apps based on WPF so I looked around and found the project Modern UI for WPF by firstfloorsoftware, lets hope the link isn't dead when you read this. I used it for nearly every app I developed but at some point, around 2015/2016, I eventually shifted my development focus to web apps. The design system of choice for me back then was Semantic UI, but I always wanted to create Modern UI for WPFCSS. But I didn't have either the design skills nor the CSS skills. Luckily, that changed over time and that was the point Cosmo CSS was born.

The first project built with the new design system I built was, of course, Jinya CMS. The implementation began, again, of course, with a new framework. It was the year 2021 and it was, again, one of the years of JavaScript frontend frameworks. I do web development since 2011 and every year seems like the year of JavaScript frontend frameworks. Since Jinya CMS is kind of the biggest project I maintain in my free time I always try to use it to learn new stuff and decided to use a framework I haven't used before. Looking around I found a few viable options. React and Vue.js were out of the playing field, I used React at work a lot and the designer from version 2.0 up to version 15.0 was based on Vue.js. Other frameworks available were either Angular, Polymer or Svelte. Well, that were not all, but I narrowed it down to these three. While Angular was definitely the most mature one of those three, I wanted to test one of the other two. Polymer is based on web components, which is cool, but has its own issues. What really appealed to me was the idea of Svelte having a compile step and not using a VirtualDOM. I decided to give Svelte a go and well, it was the right decision.

Rewriting the designer in Svelte was a breeze, I still have a few projects based on Svelte. The website of Jinya, jinya.de, is based on SvelteKit. I really liked the way Svelte handled updating of the UI and all the technical stuff, while still giving you lots of control. It took about two months to develop Cosmo CSS, the new designer and extend the backend API. Some features of the old Jinya UI designer were kept out, just to get the replacement up and running as fast as possible. End of January 2021 the Cosmo CSS based version of the Jinya CMS Designer was released. And the design is still the same til this day, and will probably stay the same for a long time. But don't take me by the word, you should have noticed I like to throw stuff away and rewrite it.

And well, of course I threw it all away and rewrote it. That was in 2022, starting in July I threw the Svelte designer away. It was a tough decision but I wanted to get a version of the designer which is stable and will be given new features without getting rewritten every second year, and yes I see the irony. The main reason I rewrote the designer in the past was, that it was either shit or that I wanted to try new tech. That is a nice thing if it is used with like one page, but by now it is used by three different people (that I know of) and powers five sites. So there needed to be a final rewrite to stop the rewrites. After doing research I decided on rewriting it in plain JavaScript. I wanted to keep it simple and use everything JavaScript gives me, sadly I decided against web components, but there might be a future version using them. After gathering all the feature the designer had at that point and checking what I can built myself without the need for libraries, it turned out to be a lot. I still needed libs, but not many.

First of all, writing a WYSIWYG editor all by yourself is hell, so tiny was the editor of choice. The second component that was set was the Monaco editor for the direct database access. While charting is not as crucial, I wanted to include access stats in the dashboard so I kept ApexCharts in the libraries. The last feature I didn't want to write myself was the drag and drop features of the gallery designer, segment page designer, form designer, menu designer and what not. There is a lot of drag and drop. When I wrote the designer based on Jinya UI I failed horribly writing that myself. So I wanted to take a lib that does that really well and I decided on SortableJS. That is it, this is the basis for the current version of the Jinya CMS Designer.

Half a year no real progress

After the release of Jinya CMS 25.0 it got silent, a small release was made in February 2023 with version 25.1 making sure Jinya CMS is compatible with PHP 8.2 and then a month ago version 25.2 which added the option to expose a theme as JSON API. Looking at the calendar it is start of September 2023 and there have been no big new features. But that will change, let me announce Version 26.

Jinya CMS 26.0 and what will change

Again the technical side

Another rewrite? Are you serious?

You won't believe it, ok who am I lying to, you won't be shocked, I will rewrite Jinya CMS. But this time is different so bear with me. There are a few things that get rewritten, this time the designer won't be rewritten. It is the backend which gets a major overhaul. The current version of the backend is about 3 years old, got a few changes but one major issue was never tackled, code generation and performance.

Caching the API

A lot of the code in Jinya CMS is based on reflection. While reflection got a lot more performant over the past versions of PHP it is still slow and the result of the reflection is (most of the time) the same. So there needs to be some kind of cache for it. The routes for the frontend are already static, but the API is a completely different story. Most of the routes for the API are generated on the fly which makes the whole thing slow. The thing is though, I want to keep the comfort of using attributes to generate routes. That makes the whole database interaction really easy and simple to maintain.

Back in June 2023 I made a small experiment. What if I replace Slim by a custom implementation that scans a given directory for attributes and generates a routing configuration for FastRoute? The result was interesting, the first request, generating the routing cache, was slow. It involved a ton of reflection, code generation and then execution of the generated code. But the second request was fast, it only executed the generated code and had no reflection, code generation or other magic. That way I keep the advantages of attribute based routing for models and actions, while still getting the performance boost of a static route configuration. Since Jinya CMS has an integrated updater it is also possible to generate the routing cache after every update, and that will prevent it from ever needing to be generated when a real request is made.

This whole routing library will be created in two new projects and composer packages. The first will be called Jinya Router. Jinya Router will contain a simple attribute based router revolving around a classic controller action pattern. The second package, Jinya Model Router, will extend Jinya Router with a base to route models, how to do that needs to be figured out, but it will be loads of fun.

A new way for analytics

Currently Jinya CMS has analytics based on Matomo. The decision to use Matomo was made back in 2020. Jenny and I wanted to include a way to track page views without needing a cookie banner. So we choose Matomo. We boiled the tracking down to the absolute minimum and it doesn't use cookies, fingerprinting or any other way to identify users after they left the site. While Matomo guarantees a high level of control over your data and makes it possible to completely anonymize tracking it still is a huge software suite. Don't get me wrong, I really like Matomo, but for the current use in Jinya CMS it is completely overkill and it requires another application to be running. Currently the dashboard in the designer only shows like 6 statistics. That is all, Matomo has many more statistics we don't use and don't need.

Before reinventing the wheel, again, I decided to look around for other solutions. I was surprised, most analytics software is not PHP based. That makes it hard to run on webspaces and so most of them are ruled out. The ones that were not ruled out, did way to much. So the decision was set, there will be integrated analytics. These analytics will only track the really needed information. If a site based on Jinya CMS needs more info, there are lots of great analytics suites out there. I personally really like Plausible, Umami and, of course, Matomo.

What to track?

Now the heart of analytics is, well, tracking. The tracking in Jinya CMS needs to be the absolute bare minimum, so no cookies can be used, no local storage and no IndexedDB. I now wonder what you could track with IndexedDB. Since we want to count unique page views there needs to be a way to identify whether a view is unique. The simplest way would be to just check the referrer, if it is a different domain, then you have a unique view. The really interesting statistics are of course about your users, so what is interesting about them? First of all, the country where they are from. It is fairly uninteresting which state or even which city they come from, so just don't track it. The language selected in the browser is always important, since based on that you can tell if a version of the site in a different language would be worth it. What else? Well for your theme it is interesting to know which browser your visitors use and what devices, that way you can keep track of the most important platforms. And for overall tracking that is about it. For more details it would be cool to see how successful a menu item or maybe even a gallery or segment page is, but for now that is all that is needed. So it boils down to 5 metrics, the country, the language, the browser, the device type and the OS.

How to track?

Now that we know what we want to track, we need to tackle the how. Most importantly, the tracking has to be as privacy conformant as possible that means the following things are not allowed:

  • Storing IP addresses in the database
  • Storing narrow location data in the database, like a city
  • Cookies
  • LocalStorage
  • Browser fingerprinting
  • JavaScript
  • External services for IP to country lookup

But it also means that we should respect the users wish to not be tracked at all, while the good old do not track header is deprecated these days, it is still widely supported and if the user cares to enable it, we should respect it. More interesting is the working draft Global Privacy Control, this will make a huge difference since we are legally bound to respect it.

Since the tracking is theme independent there needs to be a setting to disable tracking all together which brings us to another new feature, but more on that later. If the visitor tracking is disabled the whole dashboard about tracking data should be removed from the designer aswell.

Looking up countries

Getting a country for an IP address is a thing that is not as easy as it should be. First of all you need the IP, well that part is easy if you have a web server. The second thing you need is an IP to country lookup database. And that part is a bit harder. There are several options but most of them are paid, so they are not an option anymore. The free options need to be freely available meaning it should be possible to generate a download link dynamically, that leaves not many. For Jinya IP Locator I used the database provided by db-ip.com, which works really well. So I think I will use that aswell. They have a free version which is more than accurate enough. Here you can see the output for the server this blog is hosted on:

{
  "city": "Karlsruhe (Nordweststadt)",
  "country": "Germany",
  "region": "Baden-Wurttemberg",
  "providedBy": "https://db-ip.com"
}

Which is basically a request to https://ip.jinya.de/?ip=185.216.179.123 you can try it yourself, just replace the IP with any IP you like.

When using this database it will be possible also use it to lookup the IP address when a user logs in, which will make the usage of Jinya IP Locator in Jinya CMS redundant, which is a good thing. Again relying on external services is not that great. The database can either be downloaded as mmdb or as csv. I think I will stick to the csv, that will be easier to dump into prepared database tables.

Changing Jinya settings, and the hell it is to do so

Changing a setting in Jinya CMS means to edit the .env file in the root of your project. I have no idea why I thought that is a good idea but hey, that is where we are now. This "feature" has two major drawbacks:

  1. Changing settings is hell and not user friendly at all
  2. Adding settings in an update doesn't really work

The easiest way to solve this is a new database table which can override every setting made in the .env file. This should have happend back with Jinya CMS 2.0, but hasn't so it is now happening in Jinya CMS 26.0. In this table should the setting to disable tracking reside.

Riding the whale

I love docker, seriously, I use docker for nearly every project. But Jinya CMS lacks one thing, different editions of the docker image. Currently there is only one image, an Apache and Debian based image. If you look at other PHP based apps on Dockerhub, I'll wait, you will see they have more than just one image. Most have an Apache based image, an image based on PHP-FPM on Debian and on with PHP-FPM on Alpine. If they ship with a console, what Jinya CMS does, they also provide a CLI image. Jinya CMS ships exactly one image, the Apache one and that is it. Now that is not that big of an issue since it "only" has around 4.000 pulls, it still is a drawback. So there will be more images with Jinya CMS 26.0. I am also thinking about adding an image based on nginx unit. Unit looks really promising and I want to test it out.

Two factor and other security adventures

One thing Jinya CMS does since version, I think 2.0, is two factor auth. Currently the method to deliver the two factor codes is via email. While this works, it is highly impractical. When you are on a foreign computer you probably don't have access to your emails, if you have, good for you, if not, well fuck. So what I want to implement with version 26.0 is a app based two factor auth. This can easily be achieved with TOTP and then can be used with Authy, Google Authenticator and all the other apps around.

Another cool feature, though I don't know if I actually build it, would be integration of OAuth2. That would allow Jinya CMS to include a single sign-on, which would be just plain cool. Like I said, I am not sure if I will integrate it, but if it will be cool.

Document all the things

Jinya CMS is completely documented, currently this documentation is transformed into a webpage using phpDocumentor. But I like Docusaurus more, so the docs will be migrated to Docusaurus with version 26.0. I will also create a complete API documentation something that is missing since version 17.

What next?

What comes next you ask? Well, there will be a metric ton of development on my desk and I will enjoy it very much. To bring this, way too long post, to an end, with Jinya CMS 26.0 there will be huge improvements, it will be more performant, more secure, easier to maintain, more private and better documented. I am really looking forward to this version.

I will keep you updated, and we will see how the new release turns out.