<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Michal Štefaňák</title>
    <description>The latest articles on DEV Community by Michal Štefaňák (@stefanak-michal).</description>
    <link>https://dev.to/stefanak-michal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1271912%2Fe6e52634-25f9-42ca-aee3-e5eddc86f408.jpg</url>
      <title>DEV Community: Michal Štefaňák</title>
      <link>https://dev.to/stefanak-michal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stefanak-michal"/>
    <language>en</language>
    <item>
      <title>Building Nexus Fleet: a roguelike Sea Battle with React Native</title>
      <dc:creator>Michal Štefaňák</dc:creator>
      <pubDate>Tue, 29 Apr 2025 08:55:57 +0000</pubDate>
      <link>https://dev.to/stefanak-michal/building-nexus-fleet-a-roguelike-sea-battle-with-react-native-4a6l</link>
      <guid>https://dev.to/stefanak-michal/building-nexus-fleet-a-roguelike-sea-battle-with-react-native-4a6l</guid>
      <description>&lt;p&gt;I'm excited to share the journey of creating my mobile game &lt;strong&gt;Nexus Fleet&lt;/strong&gt;. It's a roguelike take on the classic Sea Battle, where each victory propels you into a new game with your surviving fleet, and strategic choices of new ships or powerful admirals with unique abilities heavily influence your chances of success. With 15 distinct admirals to discover, each run offers a fresh tactical challenge. Nexus Fleet is available now on both Android and iOS!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apps.apple.com/us/app/nexus-fleet-game/id6744459493" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm5g9cpp3q6sju5xkahl7.png" alt="Apple AppStore"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.MichalStefanak.NexusFleet" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk0aqny7d6i87xotmk8rw.png" alt="Google play store"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, I wanted to dive into the technology stack behind Nexus Fleet and share some of the experiences I had during its development.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Native
&lt;/h2&gt;

&lt;p&gt;One of the primary motivations for choosing React Native was my existing familiarity with React, even while I'm experienced with Unity. The component-based architecture and the declarative approach to UI development felt natural and allowed me to leverage my web development skills in the mobile space. I was able to dive deeper into making custom game elements like &lt;em&gt;Game management context&lt;/em&gt;, &lt;em&gt;Notification context&lt;/em&gt;, unified &lt;em&gt;Grid component&lt;/em&gt; or &lt;em&gt;Actor (player/enemy) custom effect&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In main &lt;code&gt;_layout.tsx&lt;/code&gt; file I wrapped everything in GameContext. This way game status and access to all game related informations are available anywhere. Here is a preview of available functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GameContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt;
        &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
            &lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;enemy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;newGame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;setGameStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;admiralPool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;secondChanceAdmiral&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;addedSecondChanceAdmiral&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;statistics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;rewardAdmiral&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;setRewardAdmiral&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/GameContext.Provider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I wanted custom whole screen notification so I've made NotificationContext. It handles showing dismissable queued notifications even when switching screens with fade in and out animation. I feel proud on this piece of code. Here is a preview of final result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5z2wm0wkqk91axt9yccm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5z2wm0wkqk91axt9yccm.png" alt="Notification preview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Expo framework
&lt;/h2&gt;

&lt;p&gt;To streamline the development process, I opted to use the Expo framework as it was suggested everywhere. After developing a big portion of my game I discovered I have to use EAS for build. My first emotion was disappointment, because I prefer to do task locally. I started thinking how to get rid of Expo. Fortunatelly I discovered I can still build locally for android while I use Expo. For those interested you need to run these commands:&lt;br&gt;
&lt;code&gt;npx expo prebuild&lt;/code&gt;&lt;br&gt;
&lt;code&gt;npx react-native build-android --mode=release&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you need to build signed bundle for Google play store check out this great manual: &lt;a href="https://reactnative.dev/docs/signed-apk-android" rel="noopener noreferrer"&gt;https://reactnative.dev/docs/signed-apk-android&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Story for making &lt;strong&gt;iOS build&lt;/strong&gt; is a bit different. I discovered I need apple device to make it happened. Which I don't have as windows user. I read something about running MacOS in virtual machine, but that does sound like a lot of hustle. However I realized I could use EAS. Limit 15 free builds should be enough. So I gave it a try and frankly, in the end I was thankful for this cloud tool, it became really helpful to build and submit iOS build. Now my package.json contains following scripts:&lt;br&gt;
&lt;code&gt;eas build --platform ios&lt;/code&gt;&lt;br&gt;
&lt;code&gt;eas submit --platform ios&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Expo router and status bar packages were also very helpful to create required layout. And let me say, one of my favorite things with packages in this framework are icons. It includes all popular icon packages and you can use all of them. &lt;a href="https://docs.expo.dev/guides/icons/" rel="noopener noreferrer"&gt;https://docs.expo.dev/guides/icons/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Visual and AI
&lt;/h2&gt;

&lt;p&gt;As a developer with limited graphic design skills, the emergence of AI image generation tools has been a game-changer. For Nexus Fleet, I heavily relied on AI to create admiral portraits and background elements. These tools allowed me to quickly iterate on visual concepts and generate assets that fit the game's aesthetic without requiring extensive manual design work. This significantly sped up the development process and allowed me to focus on the gameplay mechanics and programming.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7wej7e8caavpyeyrgvmy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7wej7e8caavpyeyrgvmy.png" alt="Admirals"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the end I tried out &lt;strong&gt;Microsoft Clipchamp&lt;/strong&gt; for the first time to make some promotional video. It's really practical and easy to use tool. You can check out the result on youtube:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/z0fydgLwyMs"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Future plans
&lt;/h2&gt;

&lt;p&gt;There are some ideas. I would like to add sounds, music, leaderboard, battle history log and some settings to customize UI. Maybe a multiplayer would be a great feature. We will see.&lt;/p&gt;

&lt;p&gt;If you have some suggestions you can add them here: &lt;a href="https://github.com/stefanak-michal/nexus-fleet-game/issues" rel="noopener noreferrer"&gt;https://github.com/stefanak-michal/nexus-fleet-game/issues&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>gamedev</category>
      <category>programming</category>
    </item>
    <item>
      <title>PHP library and analytics controversy</title>
      <dc:creator>Michal Štefaňák</dc:creator>
      <pubDate>Wed, 16 Apr 2025 08:37:39 +0000</pubDate>
      <link>https://dev.to/stefanak-michal/php-library-and-analytics-controversy-ohn</link>
      <guid>https://dev.to/stefanak-michal/php-library-and-analytics-controversy-ohn</guid>
      <description>&lt;p&gt;My initial release of the &lt;a href="https://github.com/stefanak-michal/php-bolt-driver" rel="noopener noreferrer"&gt;PHP Bolt Driver&lt;/a&gt; aimed to empower developers with a seamless way to interact with graph databases directly from their PHP applications. However, despite its functional success in achieving this goal, the library didn't garner the anticipated level of recognition or reward. To gain a clearer picture of its adoption and usage, and to provide data that could be leveraged in future discussions or collaborations, I implemented anonymous analytics collection.&lt;/p&gt;

&lt;p&gt;The implementation of analytics, even with a focus on aggregated, anonymous data, inevitably invites scrutiny. Despite prioritizing user privacy and aiming solely to gather broad usage patterns, I still encountered concerns regarding data collection. While I collect only two counts: number of executed queries and number of sessions, the default opt-in nature of the solution also contributed to friction. Users expressed concerns about automatic data collection, even with the assurance of anonymity, highlighting the sensitivity surrounding data practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;To minimize performance and requirements impact on the library's users, I opted for a local storage approach. The collected data is stored in a file within the system's temporary directory. This strategy avoids immediate network requests during library operations, ensuring minimal latency.&lt;/p&gt;

&lt;p&gt;The core of the data handling resides within the FileCache class, an implementation of the &lt;a href="https://www.php-fig.org/psr/psr-16/" rel="noopener noreferrer"&gt;PSR-16&lt;/a&gt; cache interface. This allows for flexibility, enabling users to substitute the default FileCache with alternative caching solutions if preferred.&lt;/p&gt;

&lt;h3&gt;
  
  
  Addressing concurrency - file locking
&lt;/h3&gt;

&lt;p&gt;A critical consideration was handling concurrent access to the data file. To prevent data corruption, I implemented file locking mechanisms within the FileCache class. This ensures that only one process can write to the file at any given time, maintaining data integrity. To learn more check the &lt;a href="https://github.com/stefanak-michal/php-bolt-driver/blob/master/src/helpers/FileCache.php" rel="noopener noreferrer"&gt;FileCache source code&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Asynchronous reporting - Mixpanel integration
&lt;/h3&gt;

&lt;p&gt;To minimize the impact of data transmission on application performance, the collected data is sent to Mixpanel via an HTTP request during the library's initialization. This transmission occurs only if unsent data older than a day is detected. Once the data is successfully sent, it is deleted from the local file. This approach effectively avoids persistent network latency during regular library operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Popularity
&lt;/h2&gt;

&lt;p&gt;Besides almost half million downloads with &lt;a href="https://packagist.org/packages/stefanak-michal/bolt/stats" rel="noopener noreferrer"&gt;composer&lt;/a&gt; here are the current data, which are publicly available at &lt;a href="https://eu.mixpanel.com/public/7ttVKqvjdqJtGCjLCFgdeC" rel="noopener noreferrer"&gt;mixpanel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsr8gyvk48i2qfytdtir4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsr8gyvk48i2qfytdtir4.png" alt="Mixpanel dashboard screenshot" width="800" height="765"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Screenshot from 25. april 2025&lt;/em&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>programming</category>
      <category>webdev</category>
      <category>analytics</category>
    </item>
    <item>
      <title>Why PHP file functions cannot finally evolve?</title>
      <dc:creator>Michal Štefaňák</dc:creator>
      <pubDate>Wed, 05 Mar 2025 13:51:27 +0000</pubDate>
      <link>https://dev.to/stefanak-michal/why-php-file-functions-cannot-finally-evolve-1an5</link>
      <guid>https://dev.to/stefanak-michal/why-php-file-functions-cannot-finally-evolve-1an5</guid>
      <description>&lt;p&gt;Seriously, why?  Why, in the name of all what is holy in software development, do we still have to dance with the &lt;code&gt;@&lt;/code&gt; symbol and endless &lt;code&gt;if ($result === false)&lt;/code&gt; checks when dealing with files?  It's 2025 (or whatever year it is when you're reading this), and we're still playing whack-a-mole with warnings instead of having the clean, predictable behavior of exceptions.&lt;/p&gt;

&lt;p&gt;Here it is, the silent treatment. We're just going to pretend that nothing bad could possibly happen. Because, you know, suppressing errors is always a good idea. (Spoiler alert: it's not).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"myfile.txt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"r"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="c1"&gt;// Oh crap, something went wrong. But what? Who knows! &lt;/span&gt;
  &lt;span class="c1"&gt;// Maybe the file doesn't exist. Maybe the server is on fire. &lt;/span&gt;
  &lt;span class="c1"&gt;// Time to consult the PHP manual for the 57 possible reasons why fopen() might fail. &lt;/span&gt;
  &lt;span class="c1"&gt;// And then write a dozen different error handling scenarios. Fun times!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not error handling. This is error guessing. Let's be honest, symbol &lt;code&gt;@&lt;/code&gt; smells. It's the equivalent of saying "I know something might go wrong here, but I'm just going to ignore it and hope for the best." &lt;/p&gt;

&lt;p&gt;Contrast this with a sane language, where working with file would throw an exception if something went wrong. &lt;code&gt;FileNotFoundException&lt;/code&gt;, &lt;code&gt;PermissionDeniedException&lt;/code&gt;, &lt;code&gt;DiskFullException&lt;/code&gt; – beautiful, descriptive, and catchable. We could wrap the file operation in a try-catch block, handle specific errors gracefully, and write much cleaner code.&lt;/p&gt;

&lt;p&gt;Let's leave &lt;code&gt;@&lt;/code&gt; symbol and &lt;code&gt;false&lt;/code&gt; check where they belong: in the dusty archives of bad programming practices. The future of file handling shouldn't involve guesswork and suppressed warnings. It should be clean, clear, and exception-based. Please, PHP, for the sake of our sanity, give us exceptions!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>php</category>
      <category>programming</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Let me explain a ThingsDB Todo app demo</title>
      <dc:creator>Michal Štefaňák</dc:creator>
      <pubDate>Mon, 05 Aug 2024 15:30:00 +0000</pubDate>
      <link>https://dev.to/stefanak-michal/let-me-explain-a-thingsdb-todo-app-demo-2n9g</link>
      <guid>https://dev.to/stefanak-michal/let-me-explain-a-thingsdb-todo-app-demo-2n9g</guid>
      <description>&lt;p&gt;Some time ago I've discovered a database called &lt;a href="https://www.thingsdb.io/" rel="noopener noreferrer"&gt;ThingsDB&lt;/a&gt;. I was curious about it and I did some reading. I've discovered they support TCP connectivity but they didn't have driver for some specific platforms therefore I've developed a driver for it for &lt;a href="https://github.com/stefanak-michal/thingsdb.js" rel="noopener noreferrer"&gt;javascript&lt;/a&gt; and for &lt;a href="https://github.com/stefanak-michal/thingsdb-php" rel="noopener noreferrer"&gt;php&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When I worked on javascript driver I've realized, it would be possible to use ThingsDB directly from frontend without any backend or middleware. You can open websocket (TCP) connection from browser, so I reached out to the authors of ThingsDB and they added support for websocket (available from ThingsDB version 1.6). This way my javascript driver can be used from frontend (browser) and also from javascript based backend (ex. node.js). I wrote &lt;a href="https://dev.to/stefanak-michal/thingsdb-and-php-3c0k"&gt;article here&lt;/a&gt; about my php driver where I have received interesting feedback. People wanted to see more of the potential of ThingsDB. Based on that I chose not to write article about my javascript driver right after I've finished it, but I've decided it would be best to make demo. &lt;/p&gt;

&lt;p&gt;To understand basics of ThingsDB and this demo I suggest you to read continuosly as I explain specific features on the way. &lt;em&gt;I expect you are familiar with programming in general, at least basics. And maybe some javascript and jQuery.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ThingsDB structure introduction
&lt;/h2&gt;

&lt;p&gt;First things first. Let me shortly explain the structure. &lt;/p&gt;

&lt;p&gt;ThingsDB contains collections. Collection contains data, procedures, tasks, data types and enums. There is also prior collection (scope) &lt;code&gt;@thingsdb&lt;/code&gt; which contains user access accounts and it can also contains procedures and tasks. Lastly there is &lt;code&gt;@node&lt;/code&gt; scope which is not important right now.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data - persistent stored data&lt;/li&gt;
&lt;li&gt;Procedure - like function, can have arguments and it can return value&lt;/li&gt;
&lt;li&gt;Tasks - planned events, like cron&lt;/li&gt;
&lt;li&gt;Data types - like classes, it can have properties and methods&lt;/li&gt;
&lt;li&gt;Enums - enumerators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All named things like data, procedures, tasks, data types and enums are defined by developers implementing ThingsDB. New instance of this database only contains empty collection called &lt;code&gt;@:stuff&lt;/code&gt; and user account &lt;code&gt;admin&lt;/code&gt;. I use this collection as main one for this demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Talking to yourself
&lt;/h2&gt;

&lt;p&gt;When you execute query or run procedure on ThingsDB, you have to specify on which collection it will run. That can be sometimes limiting and if you have a need to execute query or run procedure on another collection, there is a way how to achieve that. There is a module called thingsdb (&lt;a href="https://book.thingsdb.io/#chapter-13-2-3" rel="noopener noreferrer"&gt;book&lt;/a&gt;, &lt;a href="https://github.com/thingsdb/module-go-thingsdb" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;) which allows you to access another collection from collection as specific user. My demo use this feature heavily when dealing with user accounts which is reason I mention it here. I have installed this module as explained in manual. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;I'll explain permissions little bit later but fyi: User account I've made for this module has permissions Query, Change, Grant on collection &lt;code&gt;@thingsdb&lt;/code&gt; and Change, Grant on collection &lt;code&gt;@:stuff&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  User accounts
&lt;/h2&gt;

&lt;p&gt;I chose to use only ThingsDB and that means I had to use their user accounts. I had to deal with registration and login which was little bit tricky because of the absence of backend. Of course I could use some third party authentification server (auth0, etc.), but I didn't want to rely on anything else. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;In the case somebody wants to implement 3rd party auth system, you can do HTTP requests from ThingsDB with Request module (&lt;a href="https://book.thingsdb.io/#chapter-13-2-2" rel="noopener noreferrer"&gt;book&lt;/a&gt;, &lt;a href="https://github.com/thingsdb/module-go-requests" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To allow users to register I needed some user account to communicate with ThingsDB and execute the registration. But required credentials for this account would be published in javascript code which doesn't sound very secure. I didn't want to deal with all security problems but I wanted to implement at least the simple ones. ThingsDB support granting permissions for each user account against each collection specifically. Available permissions to grant are Query, Change, Grant, Join and Run.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Query - query ThingsDB&lt;/li&gt;
&lt;li&gt;Change - allow execution of code which does change of data&lt;/li&gt;
&lt;li&gt;Grant - allow granting permissions&lt;/li&gt;
&lt;li&gt;Join - allow join rooms&lt;/li&gt;
&lt;li&gt;Run - run stored procedure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm not able to use &lt;strong&gt;Query&lt;/strong&gt; at all. Because with this command you can execute anything on ThingsDB and opening this to the client browser pose huge security problem. The path was clear, I had to use procedures and just allow &lt;strong&gt;Run&lt;/strong&gt; for client.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Important information to know is the user accounts doesn't have only password but also access tokens (with expiration if needed).&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Prepare ThingsDB for registration
&lt;/h3&gt;

&lt;p&gt;I've created collection &lt;code&gt;@:auth&lt;/code&gt; and user account with name &lt;code&gt;aa&lt;/code&gt; (auth account) and I gave him permission &lt;strong&gt;Run&lt;/strong&gt; over this collection. Collection &lt;code&gt;@:auth&lt;/code&gt; contains only one procedure called &lt;code&gt;register&lt;/code&gt;. All this means, the user &lt;code&gt;aa&lt;/code&gt; can do only one thing which is to run procedure called &lt;code&gt;register&lt;/code&gt;. Therefore his access token can be published.&lt;/p&gt;

&lt;p&gt;Procedure &lt;code&gt;register&lt;/code&gt; does create new account and grant required permissions. The code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new_procedure('register', |email, password| {
    if (email.len() == 0 || password.len() == 0 || !is_email(email)) {
        raise('required values not provided');
    };
    thingsdb.query('@t', "
 if (has_user(email)) {
     raise('email already registered');
 };
 new_user(email);
 set_password(email, password);
 grant('@:stuff', email, RUN | CHANGE);
 ", {
        email:,
        password:,
    });
    nil;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I guess this is your first time seeing code from ThingsDB. It is familiar to another programming languages just with slight changes. What the procedure does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accepts two arguments&lt;/li&gt;
&lt;li&gt;Verify arguments email and password&lt;/li&gt;
&lt;li&gt;Use module &lt;code&gt;thingsdb&lt;/code&gt; explained in section Talking to yourself to run query

&lt;ul&gt;
&lt;li&gt;Check if email is already registered&lt;/li&gt;
&lt;li&gt;Create new user account and set password&lt;/li&gt;
&lt;li&gt;Grant required permissions&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;email:,&lt;/code&gt; can be a little bit confusing but it's a shorthand when you want to pass variable to argument and argument and variable has the same name.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;@t&lt;/code&gt; is shortcut for &lt;code&gt;@thingsdb&lt;/code&gt; scope.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend implemention of registration
&lt;/h3&gt;

&lt;p&gt;With everything ready at ThingsDB side I've created simple website with registration form and few lines of javascript. The code snippet which manages to run procedure inside of ThingsDB looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thingsdb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ThingsDB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@:auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 
    &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#password1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;It performs authentification with token (for &lt;code&gt;aa&lt;/code&gt; user account)&lt;/li&gt;
&lt;li&gt;Runs procedure &lt;code&gt;register&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;I keep access token of user &lt;code&gt;aa&lt;/code&gt; in browser localStorage.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To see whole implementation look here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/register.html" rel="noopener noreferrer"&gt;register.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/js/register.js" rel="noopener noreferrer"&gt;register.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Login
&lt;/h2&gt;

&lt;p&gt;After user is able to register, next step was to implement login action. For login password is required but it would be not very safe to store user password in browser. The solution is to generate access token (with expiration) after login and return it to client, where it can be stored in browser (ex. sessionStorage). So I've created procedure in &lt;code&gt;@:stuff&lt;/code&gt; collection where registered user account has required permissions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new_procedure('login', || {
    email = user_info().load().name;
    if (is_email(email)) {
        thingsdb.query('@t', "new_token(email, datetime().move('days', 1));", {email: })
            .then(|token| token);
    };
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creation of token has to be called on &lt;code&gt;@thingsdb&lt;/code&gt; scope, in that case I use thingsdb module again. The javascript code snippet to call this procedure looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thingsdb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ThingsDB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@:stuff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./overview.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Obtained access token is stored in sessionStorage.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here you can check whole login page which contains login form and required javascript code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/index.html" rel="noopener noreferrer"&gt;index.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/js/index.js" rel="noopener noreferrer"&gt;index.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;After login user is redictered here where he has some account actions and list of his Todos. That required to specify structure, how Todo data will be stored and for this purpose we can use data types. I created &lt;strong&gt;Todo&lt;/strong&gt; type which has name, user_id and items. &lt;strong&gt;Item&lt;/strong&gt; type has description, checked status and &lt;strong&gt;Todo&lt;/strong&gt; reference. Connection between &lt;strong&gt;Todo&lt;/strong&gt; and &lt;strong&gt;Item&lt;/strong&gt; is made with both ways relation (&lt;a href="https://book.thingsdb.io/#chapter-9" rel="noopener noreferrer"&gt;book&lt;/a&gt;, &lt;a href="https://docs.thingsdb.io/v1/collection-api/mod_type/rel/" rel="noopener noreferrer"&gt;docs&lt;/a&gt;). Both types are defined in &lt;code&gt;@:stuff&lt;/code&gt; collection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new_type('Item');
new_type('Todo');

set_type('Item', {
    description: "'str',"
    checked: 'bool',
    todo: 'Todo?',
});
set_type('Todo', {
    name: 'str',
    items: '{Item}',
    user_id: 'int',
});

mod_type('Item', 'rel', 'todo', 'items');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this piece of code you can see how the types are made, what properties with data types does they have and set up of relation between them.&lt;/p&gt;

&lt;p&gt;But this is just definition. We need to store Todos somewhere. For that we create property directly on collection &lt;code&gt;@:stuff&lt;/code&gt; like this. Without the dot it would be just variable and it won't be persistent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.todos = set();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now after the data structure is ready, let's go through each action.&lt;/p&gt;

&lt;h3&gt;
  
  
  Todos
&lt;/h3&gt;

&lt;p&gt;Upon loading of overview page, request to load Todos of users to ThingsDB is made. First we need a procedure on &lt;code&gt;@:stuff&lt;/code&gt; collection which returns list of Todos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new_procedure('list_todos', || {
    user_id = user_info().load().user_id;
    .todos.filter(|t| t.user_id == user_id);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://docs.thingsdb.io/v1/data-types/set/filter/" rel="noopener noreferrer"&gt;Filter&lt;/a&gt; is function available to call on set.&lt;/p&gt;

&lt;p&gt;Now we can call this procedure with javascript code snippet like this (processing received data is omitted):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thingsdb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ThingsDB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@:stuff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list_todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check the whole implementation here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/overview.html#L36" rel="noopener noreferrer"&gt;overview.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/js/overview.js#L7" rel="noopener noreferrer"&gt;overview.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Password change
&lt;/h3&gt;

&lt;p&gt;For this action I've created procedure &lt;code&gt;update_password&lt;/code&gt; which requires to use thingsdb module again. User accounts are stored in &lt;code&gt;@thingsdb&lt;/code&gt; scope.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new_procedure('update_password', |password| {
    email = user_info().load().name;
    if (is_email(email)) {
        thingsdb.query('@t', 'set_password(email, password);', {
            email:,
            password:,
        });
    };
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I use html dialog tag to enter a new password and the javascript code snippet to handle it is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@:stuff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;update_password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#password1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;I don't have to call &lt;code&gt;authToken&lt;/code&gt; again because websocket connection is still open from the request to load Todos.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can check the whole implementation here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/overview.html#L40" rel="noopener noreferrer"&gt;overview.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/js/overview.js#L37" rel="noopener noreferrer"&gt;overview.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Delete account
&lt;/h3&gt;

&lt;p&gt;Procedure for this action removes not only user account but also his Todos. It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new_procedure('delete_user', || {
    email = user_info().load().name;
    if (is_email(email)) {
        .todos.remove(|todo| todo.user_id == user_id);
        thingsdb.query('@t', 'del_user(email);', {email: });
    };
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://docs.thingsdb.io/v1/data-types/set/remove/" rel="noopener noreferrer"&gt;Remove&lt;/a&gt; is another function which can be called on set.&lt;/p&gt;

&lt;p&gt;I had to use thingsdb module again. User accounts are stored in &lt;code&gt;@thingsdb&lt;/code&gt; scope.&lt;/p&gt;

&lt;p&gt;Call of this procedure can be done easily with javascript code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@:stuff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete_user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;I don't have to call &lt;code&gt;authToken&lt;/code&gt; again because websocket connection is still open from the request to load Todos.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Look at the whole implementation here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/overview.html#L29" rel="noopener noreferrer"&gt;overview.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/js/overview.js#L48" rel="noopener noreferrer"&gt;overview.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create Todo
&lt;/h2&gt;

&lt;p&gt;User need a way to create new Todo. For that reason I made page new_todo and overview contains link to it. Form to create todo consist of todo name and items (descriptions). I decided to store new Todo with items in two steps, because originally I wanted to allow editing of Todo (which in the end didn't happen). Therefore I've created two new procedures.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new_procedure('create_todo', |name| {
    t = Todo{
        name:,
        user_id: user_info().load().user_id,
    };
    .todos.add(t);
    t.id();
});

new_procedure('add_todo_items', |todo_id, items| {
    todo = thing(todo_id);
    if (todo.user_id != user_info().load().user_id) {
        raise('Not yours');
    };
    todo.items.clear();
    items.each(|i| {
        item = Item{
            checked: false,
            description: "i,"
        };
        todo.items.add(item);
    });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First procedure to create todo returns it's id and second procedure deletes all items and adds new ones. I think if you read until here you are already getting hang of it and I don't have to explain &lt;code&gt;.todos.add()&lt;/code&gt; or &lt;code&gt;items.each()&lt;/code&gt; (&lt;a href="https://docs.thingsdb.io/v1/data-types/set/add/" rel="noopener noreferrer"&gt;set add&lt;/a&gt;, &lt;a href="https://docs.thingsdb.io/v1/data-types/thing/each/" rel="noopener noreferrer"&gt;thing each&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;What is new here is &lt;code&gt;thing(todo_id)&lt;/code&gt;. You can get reference to any thing (thing is like instance of class/data type) from collection by id. You don't have to know where is stored, you can just get it. Thing has assigned id when is stored persistently.&lt;/p&gt;

&lt;p&gt;To perform defined action you just have to call it with javascript code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@:stuff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create_todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@:stuff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;add_todo_items&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at the whole implementation here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/new_todo.html" rel="noopener noreferrer"&gt;new_todo.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/js/new_todo.js#L32" rel="noopener noreferrer"&gt;new_todo.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Todo detail
&lt;/h2&gt;

&lt;p&gt;Overview page shows list of user Todos. By clicking on it user is redirected to page where he can see Todo items, change their status and delete whole Todo list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Load Todo data
&lt;/h3&gt;

&lt;p&gt;To load one specific Todo I've created new procedure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new_procedure('list_todo', |todo_id| {
    todo = thing(todo_id);
    if (todo.user_id != user_info().load().user_id) {
        raise('Not yours');
    };
    return todo, 2;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you are propably asking why there is &lt;code&gt;return todo, 2;&lt;/code&gt;? With &lt;a href="https://book.thingsdb.io/#chapter-4-3" rel="noopener noreferrer"&gt;return&lt;/a&gt; you can set depth of data you want to return. With number 2 here returned data contains not only Todo itself, but also Items the Todo has relation with.&lt;/p&gt;

&lt;p&gt;Because Todo id is passed as uri get parameter, the javascript code snippet to call this procedure looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@:stuff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list_todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/id=&lt;/span&gt;&lt;span class="se"&gt;(\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at the whole implementation here:&lt;br&gt;
&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/todo.html" rel="noopener noreferrer"&gt;todo.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/js/todo.js#L9" rel="noopener noreferrer"&gt;todo.js&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Change Todo item status
&lt;/h3&gt;

&lt;p&gt;I render todo items as checklist, so to change status of item I've created new procedure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new_procedure('mark_item', |item_id, checked| {
    item = thing(item_id);
    if (item.todo.user_id != user_info().load().user_id) {
        raise('Not yours');
    };
    item.checked = checked;
    nil;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because you can also uncheck, not only check item, javascript code snippet has to be like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@:stuff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mark_item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at the whole implementation here:&lt;br&gt;
&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/todo.html" rel="noopener noreferrer"&gt;todo.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/js/todo.js#L22" rel="noopener noreferrer"&gt;todo.js&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Delete Todo
&lt;/h3&gt;

&lt;p&gt;If we want to delete Todo, we don't have to delete items because they are not stored separately. If Todo is removed, no other reference exists for its items and they are automatically removed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new_procedure('delete_todo', |todo_id| {
    todo = thing(todo_id);
    if (todo.user_id != user_info().load().user_id) {
        raise('Not yours');
    };
    .todos.remove(todo);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the javascript code snippet is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;thingsdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@:stuff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete_todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/id=&lt;/span&gt;&lt;span class="se"&gt;(\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at the whole implementation here:&lt;br&gt;
&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/todo.html" rel="noopener noreferrer"&gt;todo.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/js/todo.js#L27" rel="noopener noreferrer"&gt;todo.js&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation guide
&lt;/h2&gt;

&lt;p&gt;To simplify usage of this demo you can run ThingsDB in docker described in &lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/README.md#how-to-run-this-demo" rel="noopener noreferrer"&gt;README&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Next simply open &lt;a href="https://github.com/stefanak-michal/thingsdb-todo-demo/blob/main/install.html" rel="noopener noreferrer"&gt;install.html&lt;/a&gt; which creates everything required in this ThingsDB instance and store access token of &lt;code&gt;aa&lt;/code&gt; user to localStorage.&lt;/p&gt;




&lt;p&gt;That's it. I hope I gave you basic insight into this technology. If you like my work you can buy me a tea.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/Z8Z5ABMLW" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fko-fi.com%2Fimg%2Fgithubbutton_sm.svg" alt="ko-fi" width="223" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;No AI was used to generate this content, only the cover picture.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>database</category>
      <category>showdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Lively Search Input with Animated Border Progress</title>
      <dc:creator>Michal Štefaňák</dc:creator>
      <pubDate>Sat, 01 Jun 2024 08:52:03 +0000</pubDate>
      <link>https://dev.to/stefanak-michal/lively-search-input-with-animated-border-progress-37op</link>
      <guid>https://dev.to/stefanak-michal/lively-search-input-with-animated-border-progress-37op</guid>
      <description>&lt;p&gt;Ever stared at a blank search bar, willing it to return results faster?  We've all been there. I've decided to explore a unique search input design that adds a touch of interactivity and user feedback to the search process in my graph database administration tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Power of Visual Feedback
&lt;/h3&gt;

&lt;p&gt;A static search bar provides little indication of progress. My design incorporates a dynamic border that animates while the search is ongoing.  This visual cue informs the user that the system is actively processing their request, reducing the perception of wait time and improving the overall user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Behind the Scenes
&lt;/h3&gt;

&lt;p&gt;This animation is achieved using CSS preprocessor code, specifically Sass. The &lt;code&gt;clippath&lt;/code&gt; is used to define the animation, creating a clipping effect that progresses around the border of the search input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="nt"&gt;clippath&lt;/span&gt;
  &lt;span class="nt"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;100&lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;
    &lt;span class="nl"&gt;clip-path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;inset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;95%&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nt"&gt;15&lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;
    &lt;span class="nl"&gt;clip-path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;inset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;95%&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nt"&gt;50&lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;
    &lt;span class="nl"&gt;clip-path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;inset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;95%&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nt"&gt;65&lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;
    &lt;span class="nl"&gt;clip-path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;inset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;95%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nc"&gt;.border-progress&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;::after&lt;/span&gt;
    &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="nl"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="nl"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;bulma-link&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="mi"&gt;.5s&lt;/span&gt;
    &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clippath&lt;/span&gt; &lt;span class="m"&gt;3s&lt;/span&gt; &lt;span class="n"&gt;infinite&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;bulma-input-radius&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Solution is implemented in project using Bulma css framework&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  See it in Action
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqdkbcgrjmc0fecb07jh7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqdkbcgrjmc0fecb07jh7.gif" alt="Feature preview" width="1086" height="638"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Explore More &amp;amp; Support Open Source
&lt;/h3&gt;

&lt;p&gt;If you're looking for a user-friendly web interface to explore and manage your graph database, or you want to try this search input by yourself, consider checking out &lt;a href="https://github.com/stefanak-michal/cyphergui" rel="noopener noreferrer"&gt;cypherGUI&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you like it you can buy me a tea at &lt;a href="https://ko-fi.com/Z8Z5ABMLW" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fko-fi.com%2Fimg%2Fgithubbutton_sm.svg" alt="ko-fi" width="223" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
    </item>
    <item>
      <title>ThingsDB and PHP</title>
      <dc:creator>Michal Štefaňák</dc:creator>
      <pubDate>Fri, 29 Mar 2024 14:25:18 +0000</pubDate>
      <link>https://dev.to/stefanak-michal/thingsdb-and-php-3c0k</link>
      <guid>https://dev.to/stefanak-michal/thingsdb-and-php-3c0k</guid>
      <description>&lt;p&gt;Maybe you never heard about ThingsDB. Me neither until last month. First thing should be some introduction of &lt;a href="https://www.thingsdb.io/" rel="noopener noreferrer"&gt;ThingsDB&lt;/a&gt;. At their website you can read:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyl4n67wcadelwx8hzpo5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyl4n67wcadelwx8hzpo5.png" alt="ThingsDB logo" width="500" height="123"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ThingsDB is an open-source Stored-State-Distributed-Interpreter (SSDI) solution written in the C programming language. It is designed to provide a powerful and scalable platform for storing, managing, and processing data. ThingsDB is particularly well-suited for applications that require real-time data processing, high availability, and fault tolerance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I'm not going to lie, it seemed intruiging to me and I started thinking about what project I can build with it. But I saw immediately there are only few available drivers for communication besides standard HTTP API. I always prefer using socket connection because it's faster than making HTTP requests. It was the same case like when I decided to build client for communication with Neo4j (&lt;a href="https://github.com/neo4j-php/Bolt" rel="noopener noreferrer"&gt;Bolt&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Fortunately they provide well made documentation and that made my job easier. It took few days and driver was working very well. I've learned a bit about ThingsDB while doing that, which gives me more knowledge for building my project around it. My driver is available at github as opensource: &lt;a href="https://github.com/stefanak-michal/thingsdb-php" rel="noopener noreferrer"&gt;thingsdb-php&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Easiest way is to install it into your project is with &lt;a href="https://packagist.org/packages/stefanak-michal/thingsdb-php" rel="noopener noreferrer"&gt;composer&lt;/a&gt;. Driver is made with simple approach. You just create new instance of class ThingsDB. It will immediately connect to provided uri and afterwards you can start communicating with ThingsDB. In the beginning there is just few methods needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;auth - most important one, you need to authorize&lt;/li&gt;
&lt;li&gt;authToken - same as auth but this one is for token authorization&lt;/li&gt;
&lt;li&gt;query - sending query to database&lt;/li&gt;
&lt;li&gt;run - run a procedure available in database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The simplest example of using my driver looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;ThingsDB\ThingsDB&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$thingsDB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ThingsDB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$thingsDB&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// on successful login $result will be true&lt;/span&gt;
&lt;span class="nv"&gt;$message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$thingsDB&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'@:stuff'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'"Hello World!";'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="c1"&gt;// $message will contain "Hello World!" &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;auth&lt;/code&gt; accepts arguments for username and password but ThingsDB default "admin" and "pass" is set as default value. Sending simple "Hello World!" is send back to us. But you can do way more.&lt;/p&gt;

&lt;p&gt;There is a lot of stuff you can do directly in ThingsDB. Go ahead and check their &lt;a href="https://docs.thingsdb.io/v1/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let me show you another example using &lt;code&gt;run&lt;/code&gt; method for executing procedures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;ThingsDB\ThingsDB&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$thingsDB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ThingsDB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$thingsDB&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// check existing procedure, destroy it if it exists&lt;/span&gt;
&lt;span class="nv"&gt;$exists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$thingsDB&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'@:stuff'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'has_procedure(procName);'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'procName'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'multiply'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$exists&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$thingsDB&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'@:stuff'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'del_procedure(procName);'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'procName'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'multiply'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// create procedure&lt;/span&gt;
&lt;span class="nv"&gt;$thingsDB&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'@:stuff'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'new_procedure(procName, |x, y| x * y);'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'procName'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'multiply'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// call procedure&lt;/span&gt;
&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$thingsDB&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'@:stuff'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'multiply'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="c1"&gt;// $result will be int(20)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;For simplicity of example I'm not checking every query response and also I didn't surround the logic with try catch.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you want to see more examples, you can head to &lt;code&gt;tests&lt;/code&gt; directory of repository.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Are you asking what more the driver can do?&lt;/strong&gt; ThingsDB supports rooms which you can join, leave and most importantly, you can listen for emit. This way different actions can be invoked across all connected clients. Here is a set of available methods for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;join - join room(s)&lt;/li&gt;
&lt;li&gt;leave - leave room(s)&lt;/li&gt;
&lt;li&gt;emit - emit an event in room&lt;/li&gt;
&lt;li&gt;listening - Listen for incoming events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;listening&lt;/code&gt; should be used with caution. It will pause php execution and just waits for communication coming from database. You can decide how long you want to wait for incoming message. If you run php script with max_execution_time=0, you can even wait indefinitely. &lt;/p&gt;




&lt;p&gt;I hope you like it and will give it a try. If you do and you would like to support me, you can give a GitHub star to my repository at &lt;a href="https://github.com/stefanak-michal/thingsdb-php" rel="noopener noreferrer"&gt;thingsdb-php&lt;/a&gt; or you can click on donate button. Even so you if you wish to support ThingsDB you can do the same at their repository at &lt;a href="https://github.com/thingsdb/ThingsDB" rel="noopener noreferrer"&gt;ThingsDB&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/Z8Z5ABMLW" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fko-fi.com%2Fimg%2Fgithubbutton_sm.svg" alt="ko-fi" width="223" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I'm also working on javascript driver (&lt;a href="https://github.com/stefanak-michal/thingsdb.js" rel="noopener noreferrer"&gt;link&lt;/a&gt;) but there is still few bumps on the road. Hopefuly it will be resolved soon.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>thingsdb</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>My passion for the world of graph databases</title>
      <dc:creator>Michal Štefaňák</dc:creator>
      <pubDate>Sat, 16 Mar 2024 12:12:03 +0000</pubDate>
      <link>https://dev.to/stefanak-michal/my-passion-for-the-world-of-graph-databases-1585</link>
      <guid>https://dev.to/stefanak-michal/my-passion-for-the-world-of-graph-databases-1585</guid>
      <description>&lt;p&gt;The world of programming has always fascinated me and with hand in hand goes data and databases. I used mostly relational databases in my life but when I discovered graph database my perspective changed. There's something truly special about graph databases. They offer a unique way to store data, represent and explore connections, which makes them perfect for dynamically evolving systems. That's why &lt;strong&gt;I'm incredibly excited to share my journey&lt;/strong&gt; into this dynamic field!&lt;/p&gt;




&lt;p&gt;This technology area is still developing and that opened up opportunities for me to contribute. My first major contribution is a &lt;a href="https://github.com/neo4j-php/Bolt" rel="noopener noreferrer"&gt;PHP Bolt driver&lt;/a&gt;. This might sound technical, but it essentially allows your php backend to communicate seamlessly with any graph database &lt;strong&gt;that uses the Bolt protocol&lt;/strong&gt;. Think of it as a bridge between your code and the database, enabling smooth communication. My goal? To create a low-level library that supports all Bolt protocol versions and stays up-to-date with the latest specifications. This ensures your code can seamlessly interact with evolving graph database technologies. This opened a door for others and php community can now appreciate multiple tools.&lt;/p&gt;

&lt;p&gt;Driver is available at &lt;a href="https://github.com/neo4j-php/Bolt" rel="noopener noreferrer"&gt;Bolt&lt;/a&gt;. Don't be confused by &lt;a href="https://github.com/neo4j-php" rel="noopener noreferrer"&gt;neo4j-php&lt;/a&gt; organization. &lt;a href="https://neo4j.com/" rel="noopener noreferrer"&gt;Neo4j&lt;/a&gt; created GitHub organization for php community, but &lt;strong&gt;they do not provide official support&lt;/strong&gt;. It serves as hub and you can find more libraries there.&lt;/p&gt;

&lt;p&gt;This dedication for staying relevant earned the project significant recognition within the community. I was thrilled to receive the &lt;strong&gt;Graphie Award as MVP in the ecosystems&lt;/strong&gt;, highlighting the driver's impact on developers working with graph databases.&lt;/p&gt;




&lt;p&gt;I didn't stop there. Graph databases hold immense potential, but the Cypher query language can be a barrier for those new to the field. I wanted to make &lt;strong&gt;graph databases more approachable&lt;/strong&gt;, even for those without these knowledges. Tool which will ease transition for everybody who wants to manage and administer data in graph database. I was thinking about it for few years. But then it finally happened and &lt;a href="https://github.com/stefanak-michal/cyphergui" rel="noopener noreferrer"&gt;cypherGUI&lt;/a&gt; was born! This user-friendly administration tool provides a graphical interface for managing your data in graph database, specifically designed to demystify graph databases for everyone. You can view nodes, relationships, and properties – all neatly organized in tables. Plus, you can create, edit, and delete data with ease, even search across all properties. But cypherGUI goes beyond the basics. It is showing you executed cypher queries what gives a opportunity to learn it. Of course it allows you to write own cypher queries and see the results in various formats, including tables, JSON, and even in the natural way of graph databases which is a visual graph!&lt;/p&gt;

&lt;p&gt;Project is available at &lt;a href="https://github.com/stefanak-michal/cyphergui" rel="noopener noreferrer"&gt;cypherGUI&lt;/a&gt;. Recently I spent many hours on adding new features and now it gaves even more mature impression.&lt;/p&gt;




&lt;p&gt;My passion for graph databases extends beyond creating tools. I'm &lt;strong&gt;actively involved in the community&lt;/strong&gt;, collaborating with inspiring folks at &lt;a href="https://neo4j.com/" rel="noopener noreferrer"&gt;Neo4j&lt;/a&gt; and &lt;a href="https://memgraph.com/" rel="noopener noreferrer"&gt;Memgraph&lt;/a&gt;. We exchange ideas, provide feedback, and offer support – it's a fantastic way to stay on the cutting edge of this technology. Unfortunately I haven't yet connected with the Amazon Neptune team which means I haven't been able to provide test coverage for Neptune graph database just yet, but I'm hopeful for future collaborations!&lt;/p&gt;

&lt;p&gt;Speaking of sharing my knowledge, I've had the incredible &lt;strong&gt;opportunity to present my work at conferences&lt;/strong&gt; in Berlin, &lt;a href="https://memgraph.com/blog/graph-data-zagreb-summary-december-2022" rel="noopener noreferrer"&gt;Zagreb&lt;/a&gt;, and even online (ex. &lt;a href="https://www.youtube.com/watch?v=b_OCa3oNGzM" rel="noopener noreferrer"&gt;Nodes 22&lt;/a&gt;, &lt;a href="https://www.youtube.com/watch?v=4Vm_5k_OmRY" rel="noopener noreferrer"&gt;Neo4j Live&lt;/a&gt;)! These experiences have been incredibly rewarding, allowing me to connect with other like-minded individuals and share my enthusiasm for graph databases.&lt;/p&gt;




&lt;p&gt;As you can see my journey in this fascinating world is going on for some time and I believe is far from over. I'm constantly learning, building and improving my tools. If you share my excitement for graph databases, I'd be thrilled for your support! My projects are available as opensource and I will appreciate if you &lt;strong&gt;consider giving my projects&lt;/strong&gt; a star on &lt;a href="https://github.com/stefanak-michal" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, or if you're feeling generous, a donation would mean a lot to me. Every bit of support helps me to keep working on these projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/Z8Z5ABMLW" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fko-fi.com%2Fimg%2Fgithubbutton_sm.svg" alt="ko-fi" width="223" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>graphdatabase</category>
      <category>webdev</category>
      <category>programming</category>
      <category>php</category>
    </item>
    <item>
      <title>Why Elegance in Code Takes a Backseat to Functionality</title>
      <dc:creator>Michal Štefaňák</dc:creator>
      <pubDate>Tue, 12 Mar 2024 11:57:04 +0000</pubDate>
      <link>https://dev.to/stefanak-michal/why-elegance-in-code-takes-a-backseat-to-functionality-cp7</link>
      <guid>https://dev.to/stefanak-michal/why-elegance-in-code-takes-a-backseat-to-functionality-cp7</guid>
      <description>&lt;p&gt;For programmers like myself, there's a certain allure to craft beautiful code. Lines that sing with logic, functions that unfold like origami, and a structure so clear it practically comments itself. We spend hours wrestling with efficiency, readability, and best practices, convinced that this dedication will be rewarded. But then reality hits. You encounter the behemoths of the software world - wildly successful applications with codebases that would make a purist weep.&lt;/p&gt;

&lt;p&gt;This is certainly my experience. I meticulously wrote code, prioritizing quality and readability, sometimes even above all else. Yet, here I am, surrounded by popular programs whose functionality reigns supreme despite their, shall we say, less than stellar internal design. It begs the question: in this world of hidden code, does the pursuit of programming perfection actually matter?&lt;/p&gt;

&lt;p&gt;The truth is, functionality is king.  A program, like a car, can be a masterpiece of engineering under the hood, but if it doesn't get you where you need to go, it's all for naught. Users don't experience the elegance of your code, they experience the results.  If those results are fast, reliable, and solve their problems, the inner workings become irrelevant.&lt;/p&gt;

&lt;p&gt;This doesn't negate the value of well-written code entirely. Clean, well-documented code is easier to maintain, debug, and expand upon. But there's a balance to be struck.  Spending hours crafting the perfect solution when a simpler, albeit less beautiful approach would suffice, might be a waste of resources.&lt;/p&gt;

&lt;p&gt;So, what's the answer for a programmer caught between the desire for perfection and the pressure for results? Perhaps it's about finding the sweet spot. Writing code that prioritizes functionality while still keeping readability and maintainability in mind. Recognizing that there can be beauty in efficiency, even if it's not the striking kind.&lt;/p&gt;

&lt;p&gt;At the end of the day, the code we write exists to serve a purpose. If it fulfills that purpose effectively, then it's a success, regardless of whether it wins any code beauty contests. The true art of programming might lie not in creating a masterpiece for others to see, but in crafting a powerful tool that silently works its magic behind the scenes.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>PHP &amp; graph database?</title>
      <dc:creator>Michal Štefaňák</dc:creator>
      <pubDate>Fri, 02 Feb 2024 13:49:28 +0000</pubDate>
      <link>https://dev.to/stefanak-michal/php-graph-database-25i</link>
      <guid>https://dev.to/stefanak-michal/php-graph-database-25i</guid>
      <description>&lt;p&gt;Are you a PHP developer looking to break free from the limitations of relational databases and explore the exciting world of graph databases? Look no further than the Bolt Driver, an open-source gem that seamlessly connects your PHP projects to Neo4j, Memgraph and Amazon Neptune.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Graph Databases Rock for PHP Developers?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model Complex Relationships:&lt;/strong&gt; Say goodbye to rigid schemas and embrace a flexible data structure that mirrors real-world connections. Graph databases are perfect for social networks, recommendation systems, fraud detection, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boost Performance:&lt;/strong&gt; Experience lightning-fast query execution, especially for complex graph traversals. Handle massive datasets with ease and ensure smooth performance for your demanding applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unlock Powerful Insights:&lt;/strong&gt; Leverage the inherent strengths of graph databases to uncover hidden patterns and connections within your data. Gain deeper insights and make informed decisions that drive your business forward.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Neo4j Bolt Driver: Your PHP Gateway to Graph Power
&lt;/h2&gt;

&lt;p&gt;This open-source driver is meticulously crafted to provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Effortless Communication:&lt;/strong&gt; Establish fluent connections between your PHP applications and Neo4j databases with intuitive and well-documented APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility and Extensibility:&lt;/strong&gt; Choose from various connection methods and driver configurations to match your project's specific needs. Easily extend the driver's capabilities with custom extensions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vibrant Community:&lt;/strong&gt; Tap into the collective knowledge and support of a thriving community of developers and Neo4j enthusiasts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ready to Dive In?
&lt;/h2&gt;

&lt;p&gt;Head over to the Bolt Driver repository on GitHub (&lt;a href="https://github.com/neo4j-php/Bolt" rel="noopener noreferrer"&gt;https://github.com/neo4j-php/Bolt&lt;/a&gt;) to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explore the driver's features and documentation.&lt;/li&gt;
&lt;li&gt;Get started with installation and usage guides.&lt;/li&gt;
&lt;li&gt;Support project through donations or GitHub star.&lt;/li&gt;
&lt;li&gt;Contribute to the project's growth and development.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Join the graph database revolution and empower your PHP projects with the Bolt Driver!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>php</category>
      <category>database</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
