- What to do — Main Task, Bonus Task, Submission
- Project Overview — Architecture, Getting Started, Using the App
- Discussion Questions — Interview only, not part of submission
Goal: Find and fix the bug that causes duplicate bookings on the backend.
Context: Customers are reporting that after submitting a booking they sometimes receive two confirmations for the same time slot. In the administration panel we can see two identical bookings — same customer, same stylist, same time. It doesn't happen every time.
Scope:
- Investigate the root cause
- Propose and implement a fix on the backend
- We recommend using AI tools while working on this task
Create a Claude Code skill that solves a problem you actually hit while working on the main task. The skill must be functional and usable in the Claude Code CLI.
Push your solution to a repository on any code hosting platform (GitHub, GitLab, Bitbucket, etc.) and share the link with us.
A simple online booking application for two barbershops. Customers can choose a service, a stylist, a time slot, and submit a reservation.
- Backend – PHP application (Nette Framework, Doctrine ORM, GraphQL API), SQLite database
- Frontend – Next.js (React, Apollo Client, Tailwind CSS)
- Communication goes through a GraphQL endpoint on the backend
- Docker + Docker Compose
# 1. Start the containers (env files are created automatically)
make up
# 2. Run database migrations and load test data
make db-resetThe default configuration uses docker-compose.local.yml, which maps ports to localhost. Once running:
- Frontend at http://localhost:3000
- GraphQL API at http://localhost:8080/graphql
At http://localhost:3000 you'll find a list of available barbershops. Click on one to open its detail page, where you can:
- Select a service (haircut, shave, …)
- Choose a stylist and a date
- Click an available time slot
- Fill in your name and contact (email or phone) and submit with the Book button
The business panel is available at http://localhost:3000/business-panel.
Credentials:
| Field | Value |
|---|---|
| Username | admin |
| Password | barber |
After logging in you'll see all bookings grouped by date. You can switch between barbershops using the tabs at the top. For each booking in Pending status you can:
- Confirm – confirm the booking
- Reject – reject the booking
Confirmed and rejected bookings display their status and no further actions are available.
make up # build and start containers
make down # stop and remove containers
make db-reset # run migrations and load fixtures
make fixtures # load fixtures only (clears existing data)
make bash # open a shell in the backend container
make logs # tail backend container logsThe following questions are not part of the submission — we'll go through them together during the interview. You are welcome and encouraged to bring your notes — on paper, phone, tablet, laptop, whatever works for you.
General
- Did you notice anything unusual or non-standard in the project? Name at least three things and how you would approach them differently.
Security & Architecture
- The GraphQL API has no authorization — how would you approach this and where would you implement it?
- Walk me through a code review of the entire booking rejection flow — from the GraphQL mutation to
Booking::reject(). What would you flag? - Businesses want to receive a webhook on every booking status change. How would you design this? Where would domain events fit in?
Scalability & Reliability
- How would you design a system serving tens of thousands of businesses that together handle hundreds of thousands of requests per day?
- This project runs as a single service. How would you approach logging if it were split into multiple microservices — how do you trace a single booking request across service boundaries?
AI in Development
- How has AI changed your approach to software development over the last year? What do you find most useful about it, and what risks do you see?