<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Codee]]></title><description><![CDATA[Codee]]></description><link>https://newsletter.codee.dev</link><image><url>https://substackcdn.com/image/fetch/$s_!to_b!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bd3e947-2f2c-492c-9dbf-9f6f49cfe5ef_338x338.png</url><title>Codee</title><link>https://newsletter.codee.dev</link></image><generator>Substack</generator><lastBuildDate>Sun, 14 Jun 2026 16:10:14 GMT</lastBuildDate><atom:link href="https://newsletter.codee.dev/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Krzysztof Polak]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[codeesh@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[codeesh@substack.com]]></itunes:email><itunes:name><![CDATA[Krzysztof Polak]]></itunes:name></itunes:owner><itunes:author><![CDATA[Krzysztof Polak]]></itunes:author><googleplay:owner><![CDATA[codeesh@substack.com]]></googleplay:owner><googleplay:email><![CDATA[codeesh@substack.com]]></googleplay:email><googleplay:author><![CDATA[Krzysztof Polak]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[EN: How we built a POS system based on the Medusa.js framework]]></title><description><![CDATA[Today, I&#8217;m taking you into the world of Medusa.js by describing how we built a POS extension for handling vending machines for our client.]]></description><link>https://newsletter.codee.dev/p/en-how-we-built-a-pos-system-based</link><guid isPermaLink="false">https://newsletter.codee.dev/p/en-how-we-built-a-pos-system-based</guid><dc:creator><![CDATA[Krzysztof Polak]]></dc:creator><pubDate>Thu, 30 Apr 2026 17:10:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oz6v!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Oz6v!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Oz6v!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Oz6v!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Oz6v!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Oz6v!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Oz6v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg" width="1189" height="595" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:595,&quot;width&quot;:1189,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:21522,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://newsletter.codee.dev/i/190024585?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Oz6v!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Oz6v!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Oz6v!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Oz6v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Hi!</p><p>This is the first article, but definitely not the last one, about headless solutions for online stores and websites.</p><h2><strong>What is Medusa.js?</strong></h2><p>Medusa.js is a framework for building headless online stores, where the back-end is based on Node.js and TypeScript. The front-end, can be built with anything. By default, Medusa.js supports Next.js, but you can easily choose Astro or Nuxt.js instead.</p><h2><strong>Why did we choose Medusa.js?</strong></h2><p>We chose this framework for several reasons.</p><p>The first one is that it is, and will remain, open source, while also offering ready-to-use modules from the start.</p><p>The Medusa.js team is doing a great job!</p><p>The second reason is that it is a headless solution, which means the back-end and front-end work together independently through a REST API.</p><p>The third reason is that the framework is based on Node.js, fully typed, and designed with modularity and flexibility in mind. This was important for our team because we work with technologies based on Node.js, React.js, and Next.js on a daily basis.</p><h2><strong>What was the reason behind the project?</strong></h2><p>The need was to build an online store where users could shop online while also connecting the shopping experience with the offline world.</p><p>To support vending machines, we needed a flexible and efficient solution. Modularity was also important, as it allowed us to:</p><ul><li><p>manage multiple sales channels, where one sales channel corresponds to exactly one location,</p></li><li><p>connect a selected payment method,</p></li><li><p>display products available in the store before purchase,</p></li><li><p>show users their previously purchased products in their account after logging in, whether they bought them online or offline.</p></li></ul><h2><strong>Architecture</strong></h2><p>The vending machine has three modes: purchase, return, and service.</p><ul><li><p>Purchase mode - the customer can buy a product from the fridge by taking it from a specific scale.</p></li><li><p>Return mode - the customer can return an empty product container by placing it back on the scale.</p></li><li><p>Service mode - the administrator can open the device and, for example, restock it, assign the right products to a specific scale or synchronize products.</p></li></ul><h2><strong>Additional technical solutions</strong></h2><p>Additional solutions we implemented:</p><ul><li><p>Firestore - between the user and the back-end for fast data exchange,</p></li><li><p>MQTT - between the machine and the back-end, we used a lightweight communication protocol often used in IoT systems,</p></li><li><p>Stripe - a system for handling payments.</p></li></ul><h2><strong>What features did we implement?</strong></h2><p>Our solution included several interesting features:</p><ol><li><p>Sessions - we needed a single source of truth for sessions.</p><p>When we open the device, we need to communicate with it asynchronously. <br>In the database, we store data such as:</p><ol><li><p>session ID,</p></li><li><p>device ID,</p></li><li><p>hub ID,</p></li><li><p>locker ID,</p></li><li><p>session type,</p></li><li><p>current code,</p></li><li><p>the mode in which the device was opened,</p></li><li><p>user ID.</p></li></ol></li><li><p>Session preview - the administrator can view all currently created sessions. If something happened and the device did not send us information about being closed, we can check it here and analyze the situation.</p></li><li><p>Turning service mode on and off<strong> - </strong>the administrator can open the device and organize it or replace products.</p></li><li><p>Machine configuration<strong> - </strong>we added the option to add new devices and assign them to a given location. Thanks to this, one back end can handle multiple vending machines from a single place.</p></li><li><p>Product assignment<strong> - </strong>products are assigned to a specific scale, and there can be many of them. Apart from basic data, each product also contains information such as the minimum and maximum product weight.</p></li><li><p>Synchronization with the device<strong> - </strong>the source of truth for products is the product management module in Medusa.js. After assigning products to scales, we can synchronize them with the device using a single button.</p></li><li><p>Notifications - using our automation and notification plugin, we implemented custom notifications that inform administrators about the state of the device.<br>For example, when a device goes offline, the administrator receives a notification in Slack that something is happening with it. This allows them to react very quickly.</p></li></ol><h2><strong>What did we learn?</strong></h2><p>The most important lesson is that you need to test. And then test again.</p><p>Machines can be unreliable, and you never know what might happen. Together with the team responsible for the software on the hardware side, we faced countless edge cases. We had to predict different behaviors of the user, the software, and the hardware.</p><p>More than once, the doors were supposed to open, but then&#8230; nothing. The signal was sent, but the software on the hardware side did not detect it. Or it detected it, but the update failed.</p><p>Another example was when the device sent us information that the doors were closed, but a simple bug appeared on the back-end side, and the session did not close correctly. The same happened the other way around: for some reason, the doors did not close, and the session could remain open.</p><p>Another challenge was the question: what happens if someone bumps into the machine? Will the signal be sent or not?</p><p>It is hard to count how many attempts we made when calibrating and assigning weights to the scales.</p><h2><strong>Summary</strong></h2><p>This was a very interesting challenge for us because we had not previously worked on projects where communication with IoT systems was required. It is a completely different approach, because here we could not rely on synchronous responses in the same way as in standard web solutions.</p><p>Medusa.js is a very flexible and modular solution based on modern technology. It offers a lot of possibilities while maintaining quality and performance.</p><div><hr></div><p>I hope you enjoyed the article and learned something new about the possibilities this framework offers, as well as how we approached solving these problems.</p>]]></content:encoded></item><item><title><![CDATA[Jak zbudowaliśmy POS oparty o framework Medusa.js]]></title><description><![CDATA[Zabieram was dzisiaj do &#347;wiata Medusa.js opisuj&#261;c rozwi&#261;zanie o tym jak stworzyli&#347;my rozszerzenie POS do obs&#322;ugi Vending&#243;w dla naszego klienta.]]></description><link>https://newsletter.codee.dev/p/jak-zbudowalismy-pos-oparty-o-framework</link><guid isPermaLink="false">https://newsletter.codee.dev/p/jak-zbudowalismy-pos-oparty-o-framework</guid><dc:creator><![CDATA[Krzysztof Polak]]></dc:creator><pubDate>Fri, 06 Mar 2026 09:44:21 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oz6v!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Oz6v!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Oz6v!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Oz6v!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Oz6v!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Oz6v!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Oz6v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg" width="1189" height="595" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:595,&quot;width&quot;:1189,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:21522,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://newsletter.codee.dev/i/190024585?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Oz6v!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Oz6v!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Oz6v!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Oz6v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f1c402-cf60-41e8-9461-017a0d26d823_1189x595.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Cze&#347;&#263;!</p><p>Jest to pierwszy artyku&#322; i nie ostatni o rozwi&#261;zaniach Headless dla sklep&#243;w i stron internetowych.</p><h2>Czym jest framework Medusa.js?</h2><p>W skr&#243;cie Medusa.js to framework do budowy sklep&#243;w internetowych o strukturze Headless gdzie Back-end jest oparty o Node.js oraz TypeScript. Natomiast Front-end mo&#380;e by&#263; zbudowany z czegokolwiek - bazowo Medusa.js wspiera Next.js ale bez problemu mo&#380;na wybra&#263; Astro albo Nuxt.js.</p><h2>Dlaczego wybrali&#347;my Medusa.js?</h2><p>Wybrali&#347;my ten framework z kilku powod&#243;w. Pierwszym z nich jest to, &#380;e jest i pozostanie Open Source, maj&#261;c ju&#380; na starcie gotowe modu&#322;y. <br>Zesp&#243;&#322; Medusa.js wykonuje &#347;wietn&#261; robot&#281;!</p><p>Drugim powodem jest to, &#380;e jest to rozwi&#261;zanie Headless, czyli back-end i front-end wsp&#243;&#322;pracuj&#261; ze sob&#261;, w niezale&#380;ny spos&#243;b opieraj&#261;c si&#281; o REST-API.</p><p>Trzecim powodem to framework oparty o Node.js, w pe&#322;ni otypowany i stworzony z my&#347;l&#261; o modularno&#347;ci i elastyczno&#347;ci. Dla naszego zespo&#322;u by&#322;o to wa&#380;ne gdy&#380; na co dzie&#324; pracujemy w technologiach opartych o Node.js, React.js, Next.js.</p><h2>Jaki by&#322; pow&#243;d?</h2><p>Potrzeb&#261; by&#322;o zbudowanie sklepu internetowego w kt&#243;rym mo&#380;na zrobi&#263; zakupy online jednocze&#347;nie &#322;&#261;cz&#261;c zakupy w &#347;wiecie offline. </p><p>Do obs&#322;ugi Vending&#243;w potrzebowali&#347;my elastycznego i wydajnego rozwi&#261;zania. Istotna jest tak&#380;e modu&#322;owo&#347;&#263; kt&#243;ra pozwoli&#322;o na:</p><ul><li><p>zarz&#261;dzanie wieloma kana&#322;ami sprzeda&#380;y (jeden kana&#322; sprzeda&#380;y odpowiada dok&#322;adnie jednej lokalizacji), </p></li><li><p>podpi&#281;ciem wybranej formy p&#322;atno&#347;ci,</p></li><li><p>przedstawienia produkt&#243;w kt&#243;re s&#261; dost&#281;pne, w sklepie przed zakupem,</p></li><li><p>mo&#380;liwo&#347;ci&#261; wy&#347;wietlenie u&#380;ytkownikowi wcze&#347;niej zakupionych produkt&#243;w w jego panelu po zalogowaniu (czy to w kanale online czy offline). </p></li></ul><h2>Architektura:</h2><p>Vending posiada trzy tryby: zakupowy, zwrotowy i serwisowy.</p><ol><li><p>Zakupowy - klient mo&#380;e kupi&#263; produkt znajduj&#261;cy si&#281; w lod&#243;wce, bior&#261;c go z konkretnej wagi.</p></li><li><p>Zwrotowy - klient mo&#380;e zwr&#243;ci&#263; pusty pojemnik po produkcie odk&#322;adaj&#261;c z powrotem na wag&#281;.</p></li><li><p>Serwisowy - administrator mo&#380;e otworzy&#263; urz&#261;dzenie i np. uzupe&#322;ni&#263; magazyn, przypisa&#263; odpowiednie produkty do danej wagi czy te&#380; zrobi&#263; synchronizacj&#281; produkt&#243;w. </p></li></ol><h2>Dodatkowe rozwi&#261;zania technologiczne:</h2><p>Dodatkowe rozwi&#261;zania kt&#243;re wdro&#380;yli&#347;my:</p><ul><li><p>Firestore - mi&#281;dzy u&#380;ytkownikiem, a back-endem do szybkiej wymiany danych,</p></li><li><p>MQTT - mi&#281;dzy maszyn&#261;, a back-endem zastosowali&#347;my lekki protok&#243;&#322; komunikacyjny cz&#281;sto u&#380;ywany w systemach IoT,</p></li><li><p>Stripe - system do obs&#322;ugi p&#322;atno&#347;ci</p></li></ul><h2>Jakie wdro&#380;yli&#347;my funkcjonalno&#347;ci?</h2><p>W naszym rozwi&#261;zaniu znalaz&#322;o si&#281; kilka ciekawych funkcjonalno&#347;ci:</p><ol><li><p>Sesje - potrzebowali&#347;my jedno &#378;r&#243;d&#322;o prawdy dla sesji. <br>W momencie gdy otwieramy urz&#261;dzenie to musimy komunikowa&#263; si&#281; z nim w trybie asynchronicznym. W bazie danych zapisujemy dane tj. </p><ol><li><p>ID sesji, </p></li><li><p>ID urz&#261;dzenia, </p></li><li><p>ID hab&#8217;u, </p></li><li><p>ID locker, </p></li><li><p>Typ sesji, </p></li><li><p>Aktualny kod, </p></li><li><p>Tryb w jakim zosta&#322;o otwarte urz&#261;dzenie,</p></li><li><p>ID u&#380;ytkownika,</p></li></ol></li><li><p>Podgl&#261;d sesji - administrator jest wstanie podejrze&#263; wszystkie obecne utworzone sesje. Je&#347;li wydarzy&#322;a si&#281; jaka&#347; sytuacja i urz&#261;dzenie nie wys&#322;a&#322;o do nas informacji o zamkni&#281;ciu to mo&#380;emy w tym miejscu to sprawdzi&#263; i zrobi&#263; analiz&#281;.</p></li><li><p>W&#322;&#261;czanie i wy&#322;&#261;czanie trybu serwisowego - administrator jest wstanie otworzy&#263; urz&#261;dzenie i zrobi&#263; w nim porz&#261;dek czy te&#380; wymieni&#263; produkty.</p></li><li><p>Konfiguracja maszyn - dodali&#347;my mo&#380;liwo&#347;&#263; dodawania nowych urz&#261;dze&#324; i przypisywania ich do danej lokalizacji. Dzi&#281;ki temu, jeden back-end mo&#380;e odpowiada&#263; za obs&#322;ug&#281; wielu Vending&#243;w z jednego miejsca.</p></li><li><p>Przypisywanie produkt&#243;w - produkty s&#261; przypisywane do konkretnej wagi kt&#243;rych mo&#380;e by&#263; wiele. Ka&#380;dy produkt opr&#243;cz danych podstawowych zawiera jeszcze np. minimaln&#261; i maksymaln&#261; wag&#281; produktu.</p></li><li><p>Synchronizacja z urz&#261;dzeniem - &#378;r&#243;d&#322;em prawdy dla produkt&#243;w jest modu&#322; do zarz&#261;dzania produktami w Medusa.js. Po przypisaniu produkt&#243;w do wag, za pomoc&#261; jednego przycisku mo&#380;emy zrobi&#263; synchronizacj&#281; z urz&#261;dzeniem.</p></li><li><p>Powiadomienia - za pomoc&#261; naszego pluginu do Automatyzacji i Notyfikacji wdro&#380;yli&#347;my customowe notyfikacje informuj&#261;ce o stanie urz&#261;dzenia. Na przyk&#322;ad gdy urz&#261;dzenie wejdzie w tryb Offline, to administrator dostaje powiadomienie do komunikatora Slack, &#380;e co&#347; si&#281; z nim dzieje. Dzi&#281;ki temu bardzo szybko mo&#380;na zareagowa&#263;.</p></li></ol><h2>Czego si&#281; nauczyli&#347;my?</h2><p>Najwa&#380;niejsza lekcja jest taka, &#380;e.. trzeba robi&#263; testy, i jeszcze raz testy. Maszyny s&#261; zawodne i nigdy nie wiesz co Ci&#281; mo&#380;e spotka&#263;. Razem z zespo&#322;em odpowiedzialnym za software po stronie hardware&#8217;u, mieli&#347;my niezliczon&#261; seri&#281; r&#243;&#380;nych edge-case&#8217;&#243;w. Musieli&#347;my przewidzie&#263; r&#243;&#380;ne zachowania u&#380;ytkownika, software&#8217;u i hardware&#8217;u.<br><br>Nie raz by&#322;o tak, &#380;e drzwi powinny si&#281; otworzy&#263;, a tu.. klops - sygna&#322; zosta&#322; wys&#322;any, jednak software po stronie hardware&#8217;u go nie wykry&#322;.. albo wykry&#322; ale aktualizacja si&#281; nie powiod&#322;a.</p><p>Innym przyk&#322;adem jest to, &#380;e urz&#261;dzenie wysy&#322;a&#322;o do nas informacje o zamkni&#281;tych drzwiach ale pojawi&#322; si&#281; trywialny b&#322;&#261;d po stronie back-endu, i sesja si&#281; nie zamyka&#322;a poprawnie. Tak samo by&#322;o w drug&#261; stron&#281;, drzwi z jakiego&#347; powodu si&#281; nie zamkn&#281;&#322;y i sesja mog&#322;a nie zosta&#263; zamkni&#281;ta.</p><p>Kolejn&#261; zagwozdk&#261; by&#322;o pytanie - co je&#347;li maszyn&#261; kto&#347; szturchnie, sygna&#322; zostanie wys&#322;any czy nie zostanie? </p><p>To ile pr&#243;b robili&#347;my w przypadku kalibracji i nadawaniu wag, uWagom, a&#380; ci&#281;&#380;ko policzy&#263;.</p><h2>Podsumowuj&#261;c</h2><p>By&#322;o to dla nas bardzo ciekawe wyzwanie gdy&#380; wcze&#347;niej nie mieli&#347;my okazji pracowa&#263; w projektach w kt&#243;rych potrzeb&#261; by&#322;o komunikacja z systemami IoT, a to jest totalnie inne podej&#347;cie gdy&#380; tutaj nie mogliby&#347;my polega&#263; na synchronicznych odpowiedziach tak, jak w przypadku standardowych rozwi&#261;zaniach webowych. </p><p>Medusa.js to bardzo elastyczne i modu&#322;owe rozwi&#261;zanie oparte na nowoczesnej technologii pozwalaj&#261;ce na bardzo wiele zachowuj&#261;c przy tym jako&#347;&#263; i szybko&#347;&#263; dzia&#322;ania.</p><div><hr></div><p>Mam nadziej&#281;, &#380;e artyku&#322; si&#281; spodoba&#322; i dowiedzia&#322;e&#347; si&#281; czego&#347; nowego o mo&#380;liwo&#347;ciach jakie oferuje ten framework, a tak&#380;e jak podeszli&#347;my do rozwi&#261;zania problem&#243;w.</p>]]></content:encoded></item></channel></rss>