Client work · 2024 – present Project 2 of 20
Cukrárna Laušman
Website, orders and ratings for a pastry shop with a tradition going back to 1791.
Visit the site
Verified site status: Up, 735 ms response,
At a glance
- Role
- Design, development and operations
- Period
- 2024 – present
- Status
- Live
- Technologies
- 10 technologies
- Client
- Cukrárna Laušman
Cukrárna Laušman in Miletín bakes gingerbread and cakes from family recipes. I wrote the first version of the website in 2024; in 2026 I rebuilt it on Nette and added an admin for products, texts, orders and reviews. The catalogue did not get locked away in a database, though: it lives in a Google spreadsheet that can be edited even without the admin.
Why it is technically interesting
- The spreadsheet as the single source of truth. Products and prices are read from Google Sheets, and the admin writes back to them through the API. A deleted product is only emptied and switched off so that rows do not shift, and assigning photos in bulk rewrites a single column instead of the whole row.
- Price list and gallery without manual work. The PDF price list is generated from the spreadsheet with one click, and a console command downloads gallery photos from a shared Google Drive folder, thumbnails included.
- Orders through links. Every company or event gets its own address for the order form. A switched-off link says it is closed instead of showing an error, and even a deleted link stays in the order history and in the CSV export.
- Ratings after hand-over. As soon as an order is marked as handed over, the customer gets an email with stars, and a click pre-fills the rating. Each item is rated separately, and the admin works out an average for every product across orders.
Obstacles and how I solved them
- Emails failed only on the web. The production PHP-FPM lacks the iconv extension, which Nette Mail needs for headers with accented characters, while the command-line PHP has it – so tests from the shell passed and the site failed. I added a replacement built on mbstring that steps aside as soon as the extension is installed, and I test with the same binary the site runs on.
- Accents in the PDF. FPDF needs the Windows-1250 encoding, but on some PHP builds mbstring swaps it for ISO-8859-2 and "š" turns into "ą". The price list therefore converts characters with its own table.
- A schema without migrations. The SQLite database brings itself up to date on start and adds missing columns based on PRAGMA table_info. The catch was the Nette Database cache, which did not know about a new table and claimed it did not exist. The initialiser now rebuilds the cache whenever the schema changes.
What you don't see
- Statistics without third-party tools. Visits, product clicks and price list downloads are measured by a small system of my own, with charts in the admin. The IP address is only stored with consent.
- Ratings without accounts. The rating link carries a random token, an order can be rated only once, and a rating becomes a review on the site only with the customer's consent and after approval in the admin.
- History that does not get lost. Orders keep the link they came through, so they stay readable after the link is deleted and can be exported to CSV at any time.
Technology
- Nette 3.2 and Latte – forms with CSRF protection and templates that escape output on their own.
- SQLite – orders, ratings, texts and statistics; the catalogue stays in the spreadsheet.
- Google Sheets API and Google Drive API – products, prices and gallery photos.
- FPDF – a PDF price list with Czech accents.
- Tailwind CSS, GSAP and Lenis – smooth scrolling and scroll-triggered animations.
- Chart.js – visitor charts in the admin.
- Symfony Console – the gallery sync command.
Screenshots
5 screenshots
Built with
- PHP 8.2
- Nette
- SQLite
- Google Sheets API
- Latte
- Google Drive API
- FPDF
- Tailwind CSS
- GSAP
- Chart.js