[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"content:site:en":3,"content:products:en":22,"content:post:zero-downtime-deploy:en":250},{"email":4,"salesEmail":4,"supportEmail":5,"phone":6,"telegram":7,"telegramUrl":8,"whatsappUrl":6,"githubUrl":9,"linkedinUrl":10,"locale":11,"footerAbout":12,"contactPromise":13,"whereBody":14,"officeCity":15,"workHours":16,"budgetRanges":17},"sales@jvdsoft.com","support@jvdsoft.com",null,"@jvdsoft_support","https:\u002F\u002Ft.me\u002Fjvdsoft_support","https:\u002F\u002Fgithub.com\u002FEvgeniyKiryanow","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fyevhenii-kirianov-54b8081ba\u002F","en","Full-cycle web development. Kyiv — working with clients in Ukraine, the EU and the US. Our own products, Qrenza and ShiftPlan, run on infrastructure we maintain ourselves.","Write however suits you — we answer within the working day. sales for new projects, support for our products.","Kyiv, Ukraine. We work remotely with clients in Ukraine, the EU and the US. Contract and NDA, invoiced from a Ukrainian sole trader or company.","Kyiv, Ukraine","Mon–Fri, 10:00–19:00 (Kyiv)",[18,19,20,21],"under [amount]","[amount] — [amount]","over [amount]","not sure yet",[23,154],{"slug":24,"status":25,"order":26,"siteUrl":27,"logoUrl":28,"heroImageUrl":29,"accentColor":30,"stack":31,"launchedYear":38,"locale":11,"name":39,"tagline":40,"summary":41,"positioning":42,"metaTitle":43,"metaDescription":44,"audience":45,"features":54,"steps":85,"plans":95,"faq":114,"gallery":136},"qrenza","live",0,"https:\u002F\u002Fqrenza.jvdsoft.com","\u002Fmedia\u002Fproducts\u002Fqrenza\u002Flogo.svg","\u002Fmedia\u002Fproducts\u002Fqrenza\u002Fhero.webp","#6366f1",[32,33,34,35,36,37],"Laravel","React","TypeScript","PostgreSQL","Tailwind CSS","Vite",2026,"Qrenza","A digital catalog platform with QR menus and real-time orders","Catalog, ordering and analytics for any business with products or services. Customers scan a QR code and see the menu — no app, no paper, no waiting.","Qrenza replaces the paper menu and the spreadsheet: you keep categories, items, prices and photos in one place, and the customer opens the catalog from a QR code on the table, the counter or the shop window. Orders land on the dashboard straight from the customer’s phone, move through three status steps, and a table map shows where work is happening right now. It fits restaurants, cafés, bars, bakeries, shops, salons and studios — anyone with a list of what they sell.","Qrenza — QR menus and digital catalogs for business","Qrenza is a digital catalog platform: QR menus, real-time orders, table map, analytics, team roles and six languages. A JVD Soft product, live in production.",[46,47,48,49,50,51,52,53],"Restaurants","Cafés and coffee shops","Bars and night clubs","Bakeries and patisseries","Shops and grocery stores","Beauty and wellness","Salons and studios","Markets and kiosks",[55,58,61,64,67,70,73,76,79,82],{"title":56,"body":57},"Smart catalog","Categories and items with images, prices, descriptions and availability control — for menus, product catalogs or service lists.",{"title":59,"body":60},"Real-time orders","Customers order from the QR menu and the order appears on the dashboard instantly. Three status steps: new → preparing → ready.",{"title":62,"body":63},"Table management","A table map shows where the active orders are. Move an order between tables and follow every seat separately.",{"title":65,"body":66},"Live dashboard","Real-time statistics on active catalogs and daily operations, reachable from any device.",{"title":68,"body":69},"Analytics and reports","Revenue over time, top items, cancellation rate and the full order history in one dashboard.",{"title":71,"body":72},"Team roles","Owners, administrators and staff with the access level each needs. The whole team is managed from one place.",{"title":74,"body":75},"Six languages","The catalog can be read in the customer’s language — built for bilingual and tourist venues.",{"title":77,"body":78},"Your brand, your domain","Logo, favicon, colours, navigation style, custom domain, meta tags and a Google Analytics ID — no plugins needed.",{"title":80,"body":81},"Loyalty programme","Built-in points are awarded automatically for every order, so customers come back.",{"title":83,"body":84},"Embed anywhere","Drop the full catalog into any website as an iframe with a single snippet.",[86,89,92],{"title":87,"body":88},"Create an account","Sign up in seconds, no credit card. The 14-day trial starts immediately with full access to every feature.",{"title":90,"body":91},"Build the catalog","Add categories and items — products, dishes, services. Upload photos, set prices, write descriptions; drag to reorder.",{"title":93,"body":94},"Share the QR code","Print your unique QR code and put it anywhere — table, counter, shop window. Customers scan and browse instantly.",[96,104,109],{"name":97,"price":98,"note":99,"features":100,"popular":103},"[Start]","[amount]","\u002F mo",[101,102,102],"[Plan limit]","[What is included]",false,{"name":105,"price":98,"note":99,"features":106,"popular":108},"[Working]",[107,102,102],"[Everything in Start, plus]",true,{"name":110,"price":98,"note":99,"features":111,"popular":103},"[Team]",[112,102,113],"[Everything in Working, plus]","Priority support",[115,118,121,124,127,130,133],{"q":116,"a":117},"Is there a free trial?","Yes — 14 days with full access to every feature and no credit card. The trial starts the moment you sign up.",{"q":119,"a":120},"Can the catalog be updated in real time?","Yes. A change to a price, description or availability is visible to customers immediately — the QR code never needs reprinting, it always points at the current catalog.",{"q":122,"a":123},"Do customers need to install an app?","No. The catalog opens in the phone’s browser after scanning the QR code. The interface is mobile-first, so it works on any device.",{"q":125,"a":126},"Can I use my own domain?","Yes. Connect your own domain and set your logo, favicon and brand colours — the catalog looks like part of your own site.",{"q":128,"a":129},"Which businesses is Qrenza for?","Any business with a list of products or services: restaurants, cafés, bars, bakeries, shops, beauty salons, studios, markets and kiosks.",{"q":131,"a":132},"Can I track customer orders?","Yes. Every order moves through three status steps on the dashboard and the table map shows where it is. The full history stays in the system.",{"q":134,"a":135},"Where is the data stored?","On our infrastructure: sign-in with email and password or Google OAuth, token sessions with email confirmation, and access separated by role.",[137,142,146,150],{"src":138,"alt":139,"width":140,"height":141},"\u002Fmedia\u002Fproducts\u002Fqrenza\u002Forders.webp","Qrenza dashboard with live orders and the table map",1280,588,{"src":143,"alt":144,"width":140,"height":145},"\u002Fmedia\u002Fproducts\u002Fqrenza\u002Fmenu.webp","The Qrenza QR menu on a customer’s phone",572,{"src":147,"alt":148,"width":140,"height":149},"\u002Fmedia\u002Fproducts\u002Fqrenza\u002Fsettings.webp","Qrenza establishment settings: identity, theme, navigation, SEO",879,{"src":151,"alt":152,"width":140,"height":153},"\u002Fmedia\u002Fproducts\u002Fqrenza\u002Ffeatures.webp","The Qrenza platform feature grid",1020,{"slug":155,"status":25,"order":156,"siteUrl":157,"logoUrl":158,"heroImageUrl":159,"accentColor":160,"stack":161,"launchedYear":38,"locale":11,"name":162,"tagline":163,"summary":164,"positioning":165,"metaTitle":166,"metaDescription":167,"audience":168,"features":169,"steps":200,"plans":210,"faq":217,"gallery":233},"shiftplan",1,"https:\u002F\u002Fshifts.jvdsoft.com","\u002Fmedia\u002Fproducts\u002Fshifts\u002Flogo.svg","\u002Fmedia\u002Fproducts\u002Fshifts\u002Fhero.webp","#f97316",[32,33,34,35,36,37],"ShiftPlan","Smarter shifts, happier teams","Create, assign and publish work schedules in minutes. Your team gets notified automatically and conflicts are caught before they ship.","ShiftPlan replaces the spreadsheet and the \"who is on today?\" chat. Schedules are built on a calendar board with month, week and day views; shifts repeat on a rule, carry a colour, and can hold several people at once. The moment a schedule is published everyone sees their own shifts and gets a push notification about any change, while overlaps and double bookings are blocked as you type. Managers get shift statistics and a read on the team’s workload.","ShiftPlan — shift scheduling and team planning","ShiftPlan is shift scheduling for teams: calendar board, recurring shifts, colour coding, multiple assignees, instant notifications and workload analytics.",[],[170,173,176,179,182,185,188,191,194,197],{"title":171,"body":172},"Visual scheduling","Build and manage shifts on a clean calendar board with month, week and day views.",{"title":174,"body":175},"Recurring shifts","Shifts that repeat daily, weekly, monthly or on a custom schedule, created with one click.",{"title":177,"body":178},"Unlimited colours","Colour-code shifts with unlimited custom colours or pick from the preset palette.",{"title":180,"body":181},"Team management","Assign several employees to one shift, manage roles, and track who works when.",{"title":183,"body":184},"Analytics and insights","Shift statistics, per-employee schedules and a clear read on the team’s workload.",{"title":186,"body":187},"Smart notifications","Instant push alerts on every schedule change, so nobody misses a shift.",{"title":189,"body":190},"Conflict detection","Overlaps and double bookings are detected automatically and blocked before they are saved.",{"title":192,"body":193},"Mobile-first","The responsive interface works the same on phones, tablets and desktops.",{"title":195,"body":196},"End-to-end encrypted","All data is encrypted in transit and at rest — your schedules stay yours alone.",{"title":198,"body":199},"Compliant and backed up","GDPR, CCPA and SOC 2 compliant, with automatic daily backups you can restore from.",[201,204,207],{"title":202,"body":203},"Create shifts","Build the schedule on the calendar: add shifts, set times, assign employees.",{"title":205,"body":206},"Assign employees","Put one or several people on each shift, with colour coding for quick reference.",{"title":208,"body":209},"Notify your team","The team gets instant notifications about their schedule. Everyone stays in sync.",[211,213,215],{"name":97,"price":98,"note":99,"features":212,"popular":103},[101,102,102],{"name":105,"price":98,"note":99,"features":214,"popular":108},[107,102,102],{"name":110,"price":98,"note":99,"features":216,"popular":103},[112,102,113],[218,221,224,227,230],{"q":219,"a":220},"What does it cost to start?","You can start free and upgrade later — signing up does not require payment.",{"q":222,"a":223},"What happens if two shifts overlap?","Conflict detection finds overlaps and double bookings automatically and flags them instantly, before the schedule is published.",{"q":225,"a":226},"How does the team learn about changes?","Every employee gets an instant push notification. Updates arrive in real time, so the \"who is on today?\" thread disappears.",{"q":228,"a":229},"Does it work on a phone?","Yes. The interface is responsive and mobile-first — the same on phones, tablets and desktops.",{"q":231,"a":232},"How is schedule data protected?","Data is encrypted in transit and at rest, the service is GDPR, CCPA and SOC 2 compliant, and backups run daily.",[234,238,242,246],{"src":235,"alt":236,"width":140,"height":237},"\u002Fmedia\u002Fproducts\u002Fshifts\u002Ffeatures.webp","ShiftPlan features: calendar, recurring shifts, colours, team",696,{"src":239,"alt":240,"width":140,"height":241},"\u002Fmedia\u002Fproducts\u002Fshifts\u002Fhow.webp","The three steps of working in ShiftPlan",476,{"src":243,"alt":244,"width":140,"height":245},"\u002Fmedia\u002Fproducts\u002Fshifts\u002Fwhy.webp","Why teams choose ShiftPlan",580,{"src":247,"alt":248,"width":140,"height":249},"\u002Fmedia\u002Fproducts\u002Fshifts\u002Fsecurity.webp","ShiftPlan security: encryption, compliance, daily backups",508,{"slug":251,"category":252,"tags":253,"coverImageUrl":6,"coverImageAlt":258,"readingMinutes":259,"featured":108,"publishedAt":260,"updatedAt":261,"locale":11,"title":262,"excerpt":263,"lead":264,"bodyHtml":265,"metaTitle":266,"metaDescription":267,"takeaways":268,"faq":273,"author":280,"related":286},"zero-downtime-deploy","devops",[254,255,256,257],"deploy","docker","postgres","ci-cd","",9,"2026-07-28T09:00:00.000Z","2026-08-28T15:57:52.378Z","Zero-downtime deploys on a single server: what it actually takes","Zero downtime does not start with Kubernetes. It starts with migrations that are compatible with the old code, and a health check that tells the truth. Here is the order of operations on an ordinary VPS running docker compose.","Most zero-downtime articles open with a five-node cluster. But most products live on one server with docker compose, and that is exactly where downtime hurts most, because nothing else can pick up the traffic. The good news: zero downtime is reachable there too, and the real work is not in the orchestrator — it is in how you write migrations.","\u003Ch2 id=\"why\">Why even a simple deploy drops requests\u003C\u002Fh2>\u003Cp>The classic sequence is \u003Ccode>docker compose up -d --build\u003C\u002Fcode>. The old container stops, the new one takes 8–20 seconds to warm up, and every request in that window gets a 502 from nginx. If a user was submitting a form, that enquiry is gone and you will never hear about it.\u003C\u002Fp>\u003Cp>The second cause is worse: the migration. You rename a column, apply it, and while the new image builds the old code keeps writing to a column that no longer exists. Errors in the log, data on the floor.\u003C\u002Fp>\u003Ch2 id=\"migrations\">Migrations that work in both directions\u003C\u002Fh2>\u003Cp>This is the important part, and it has nothing to do with infrastructure. One rule: \u003Cstrong>a migration must work with both the old code and the new code\u003C\u002Fstrong>. That gives you expand\u002Fcontract across three releases:\u003C\u002Fp>\u003Col>\u003Cli>\u003Cstrong>Expand.\u003C\u002Fstrong> Add the new column, nullable, with a default. Old code cannot see it and does not break. New code writes to both.\u003C\u002Fli>\u003Cli>\u003Cstrong>Migrate.\u003C\u002Fstrong> Backfill in a background job, not in the migration. A million rows inside a migration means a table lock — the same downtime under a different name.\u003C\u002Fli>\u003Cli>\u003Cstrong>Contract.\u003C\u002Fstrong> Drop the old column in a later release, once no instance reads it.\u003C\u002Fli>\u003C\u002Fol>\u003Cp>Three deploys instead of one feels excessive until the first time you roll back at two in the morning. A single-step rename is a deploy you cannot undo: nobody has ever tested the down migration.\u003C\u002Fp>\u003Cblockquote>\u003Cp>A migration you cannot roll back is not a migration, it is a one-way door. Walk through it deliberately, not by accident.\u003C\u002Fp>\u003C\u002Fblockquote>\u003Ch2 id=\"order\">The right order of operations\u003C\u002Fh2>\u003Cp>The order matters more than the tool:\u003C\u002Fp>\u003Cpre tabindex=\"0\" role=\"region\">\u003Ccode>1. build       build the new image (the old one still serves traffic)\n2. migrate     apply backward-compatible migrations\n3. start       bring the new container up beside the old one\n4. wait        block until \u002Fhealth\u002Fready returns 200\n5. switch      point the nginx upstream at the new container\n6. drain       give the old one 10 seconds to finish in-flight requests\n7. stop        stop the old container\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Steps 3–5 are what docker compose will not do for you. The cheapest way to get them without Kubernetes: two services in compose (\u003Ccode>app_blue\u003C\u002Fcode> and \u003Ccode>app_green\u003C\u002Fcode>) and an nginx upstream read from a file you swap, followed by \u003Ccode>nginx -s reload\u003C\u002Fcode>. A reload does not cut live connections — old workers finish their requests, new workers pick up the new config.\u003C\u002Fp>\u003Ch2 id=\"health\">A health check that tells the truth\u003C\u002Fh2>\u003Cp>The most common mistake is a health check that returns 200 the moment the process starts. You then switch traffic to a container with no database connection and get the same outage, except now it looks like a 500 instead of a 502.\u003C\u002Fp>\u003Cp>Split it in two:\u003C\u002Fp>\u003Cul>\u003Cli>\u003Ccode>\u002Fhealth\u002Flive\u003C\u002Fcode> — the process is alive. If this fails, restart the container.\u003C\u002Fli>\u003Cli>\u003Ccode>\u002Fhealth\u002Fready\u003C\u002Fcode> — the database is connected, Redis answers, the queue is reachable. If this fails, take the container out of the load balancer but do \u003Cem>not\u003C\u002Fem> restart it.\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Confusing the two is how you get cascading failures: the database slows down, readiness fails, the orchestrator restarts every container, and on boot they all hammer the database that was already struggling.\u003C\u002Fp>\u003Ch2 id=\"warmup\">Warm-up\u003C\u002Fh2>\u003Cp>An SSR app compiles routes on first request and starts with an empty content cache. The first user after a deploy waits three seconds instead of 300 milliseconds. Technically there was no downtime; practically the site is slow at exactly the moment someone is looking at it.\u003C\u002Fp>\u003Cp>Ten lines fix it: after the container passes readiness but before you switch traffic, request the handful of pages and cache-filling endpoints that matter. Cache warm-up is part of the deploy, not an optimisation for later.\u003C\u002Fp>\u003Ch2 id=\"rollback\">A rollback that actually works\u003C\u002Fh2>\u003Cp>A rollback is not \"put the previous image back\". It is \"put the previous image back and be sure it works against the current database schema\". That is why expand\u002Fcontract matters more than the deploy script: with backward-compatible migrations a rollback is one command. Without them it is a restore from backup.\u003C\u002Fp>\u003Cp>The minimum worth having: image tags from the commit SHA (never \u003Ccode>latest\u003C\u002Fcode>), the previous tag kept around, and a smoke test after the switch. If the smoke test is red, point the upstream back while the old container is still alive. That is why step 7 is last.\u003C\u002Fp>\u003Ch2 id=\"checklist\">What to do this week\u003C\u002Fh2>\u003Cul>\u003Cli>Split liveness and readiness if you have a single \u003Ccode>\u002Fhealth\u003C\u002Fcode>.\u003C\u002Fli>\u003Cli>Review your last five migrations: would the old code have survived them?\u003C\u002Fli>\u003Cli>Add a warm-up after start and a smoke test after the switch.\u003C\u002Fli>\u003Cli>Replace \u003Ccode>latest\u003C\u002Fcode> with a commit-SHA tag.\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Four small changes, and together they buy more than moving to an orchestrator you would then have to operate.\u003C\u002Fp>","Zero-downtime deployment on one server — a practical guide","Zero-downtime deploys without Kubernetes: backward-compatible migrations, separate liveness and readiness checks, cache warm-up, smoke tests and rollback on docker compose.",[269,270,271,272],"Zero downtime is decided by your migrations, not your orchestrator","Expand \u002F migrate \u002F contract: three releases instead of one risky step","Liveness and readiness are different endpoints with different consequences","Cache warm-up belongs to the deploy, or the first user sees a slow site",[274,277],{"q":275,"a":276},"Can you really reach zero downtime on a single server?","Yes. You need two containers running in parallel for a few seconds, nginx reload instead of restart, and a readiness check that waits for the database. An orchestrator gives you this out of the box, but the mechanism does not depend on one.",{"q":278,"a":279},"How long does it take to set up?","A blue\u002Fgreen deploy script with warm-up is roughly a day of work. Moving to expand\u002Fcontract migrations is a change of habit rather than a one-off task: the first few releases feel slower, then it becomes normal.",{"slug":281,"name":282,"role":283,"avatarUrl":284,"photoUrl":285},"yevhenii-kirianov","Yevhenii","Frontend and full-stack, interfaces, product development","\u002Fmedia\u002Fteam\u002Fyevhenii-avatar.webp","\u002Fmedia\u002Fteam\u002Fyevhenii.webp",[287,298,310],{"slug":288,"category":289,"tags":290,"coverImageUrl":6,"coverImageAlt":258,"readingMinutes":293,"featured":103,"publishedAt":294,"updatedAt":295,"locale":11,"title":296,"excerpt":297},"architecture-small-team","architecture",[289,291,292],"monolith","team",11,"2026-06-24T09:00:00.000Z","2026-08-28T15:57:52.490Z","Architecture for a team of three","Microservices cost a small team three times what the diagram suggests. What to choose when you have three developers and a product that must last years: a modular monolith, shared contracts, and boundaries you can see in the code.",{"slug":299,"category":252,"tags":300,"coverImageUrl":6,"coverImageAlt":258,"readingMinutes":305,"featured":103,"publishedAt":306,"updatedAt":307,"locale":11,"title":308,"excerpt":309},"monitoring-for-three",[301,302,303,304],"monitoring","alerts","prometheus","uptime",6,"2026-04-30T09:00:00.000Z","2026-08-28T15:57:52.760Z","Monitoring for a team of three: the minimum that works","You do not need a full observability stack to stop hearing about outages from customers. Four signals, three notification channels, and one rule that prevents alert fatigue.",{"slug":311,"category":312,"tags":313,"coverImageUrl":6,"coverImageAlt":258,"readingMinutes":317,"featured":103,"publishedAt":318,"updatedAt":319,"locale":11,"title":320,"excerpt":321},"website-cost-2026","money",[314,315,316],"budget","estimation","process",7,"2026-07-11T09:00:00.000Z","2026-08-28T15:57:52.399Z","What a website costs in 2026, and why the range is so wide","The same sentence — \"we need a website\" — can mean a week of work or three months. Here is what the price is actually made of, which line items vanish from cheap quotes, and what to ask before signing."]