All selected work

Malus Garden (opens in a new tab) · Freelance

From social orders to a storefront.

A bilingual shop and admin for an organic produce business that took its orders over Instagram and Facebook: Stripe payments, BoxNow lockers and door-to-door delivery, live since December 2025.

My role
Freelance Full-Stack Engineer
Period
–
Technologies
React, Node.js, PostgreSQL, Stripe, Express, TanStack Query, i18next, Tailwind CSS, BoxNow API, DigitalOcean
Status
Live since December 2025
The Malus Garden admin dashboard: paid orders and revenue for the day, orders ready to send with BoxNow, upcoming door-to-door delivery dates, and recent product changes.

The context

Malus Garden sells organic fruit and vegetables. Orders used to arrive as Instagram and Facebook messages, which took time to handle and led to mistakes. The business also planned to grow the site beyond a shop, which a hosted shop template would have made hard.

My contribution

I built the whole application on my own in about four months: a shop and an admin, both React apps in Greek and English that share packages in a pnpm monorepo; the Node.js/Express API; the PostgreSQL schema and migrations; and the Stripe and BoxNow integrations. A designer supplied three page designs, typography, photos and a landing-page video; I designed the remaining screens and the admin. The hardest parts were the edge cases, and turning a non-technical client’s requests into precise requirements.

Key decisions

Model the catalog as the business sells it

Products are sold per item, per kilo or in packs, with prices shown to match, and carry a category, offers and an organic flag that shows a BIO badge. Names and descriptions come in Greek and English, and products can be archived. The admin warns when stock changed while a product was being edited, and checks for payments still in progress before a product’s unit changes. The business manages its catalog itself.

The admin’s Edit Product form for walnut bars, with Greek and English tabs, a sold-as-a-pack option and pack quantity, organic and on-offer options, original and offer prices, stock in whole packs, category and product photo.
The product form uses the shop’s own terms: packs, offers, an organic badge, stock counted in whole packs, and an availability note for seasonal products.

Let Stripe confirm payment, not the browser

Prices and stock are checked on the server against the database; the browser’s cart is only a display, and it survives a refresh or a cancelled payment. An order becomes paid only when Stripe’s signed webhook arrives, in the same database transaction that deducts stock; an abandoned checkout is cancelled when its Stripe session expires. If stock ran out between checkout and payment, the order is held, and the shop releases it to delivery after restocking. Refunds go through Stripe with an idempotency key, so a retried request can’t refund twice.

The admin’s order list: one pending order above paid ones, each paid order tagged with its delivery, such as door to door on a given day, ready to send with the hours it has waited, or needs review.
An order turns paid only when Stripe confirms the payment; until then it stays pending, like the top order here.

Deliver the way the business ships

At checkout, customers pick a BoxNow locker on BoxNow’s map widget or, in selected postal codes, door-to-door delivery, with areas, dates and fees managed in the admin. For a locker order, the shop picks the box size and weight and sends it to BoxNow; a background worker creates the parcel and retries. Orders waiting over 24 hours are highlighted, and each order is marked shipped, or refunded, from its page. Customers track an order with its number and checkout email for 90 days, and see its progress, sending date and BoxNow voucher, never personal details.

An order’s page in the admin: the order summary and items, the customer’s details, their chosen BoxNow locker, a form to pick a box size and weight and send the parcel to BoxNow, and buttons to mark the order shipped or refund it.
For a locker order, the shop picks the box size and weight and sends the parcel to BoxNow, then marks the order shipped, or refunds it, from the same page.

Keep releases predictable

One script runs every release: it tries the new build on a spare port first, and a release can be rolled back in seconds. The database is backed up before any migration; migrations are additive, each runs in its own transaction and is rehearsed on a copy of production data, and the server never changes the schema on its own at startup. A staging environment with its own database sits beside production, and 2,300+ automated checks cover the backend, the frontend and the database.

The outcome

The shop has been live since December 2025 and processes customer orders daily. Its accessibility checks show 0 axe violations against WCAG 2.2 A/AA rules on 20 pages, in Greek and English, at desktop and phone sizes, and it has a published statement of partial WCAG 2.2 AA conformance. After four years of trying to get an online shop built, the business is delighted with this one. Next time, I’d put scope, milestones and payment terms in writing before starting.