Case study · Full-stack web application

La Marée Malouine

I designed a Click & Collect application connecting online orders to a fishmonger’s daily operations, from choosing products to collecting them in the shop.

  • Click & Collect
  • React
  • TanStack Start
  • PostgreSQL
  • Stripe
  • Brevo
  • GitLab CI/CD

Visit the website · Explore the code

Bringing the local shop online.

  1. Choose

    Build a basket from the catalogue and current offers.

  2. Book & pay

    Choose a collection slot, then pay through Stripe.

  3. Collect

    Receive confirmation, then collect the order from the shop.

My role
Full-stack development

Customer journey, administration, business logic and payment and email integrations.

Scope
Website and management tools

Catalogue, ordering, shop collection, stock and customer history in one application.

Technical challenge
Reliable ordering

Reserve stock and collection slots, confirm payments and handle retries without duplicates.

For the merchant: everyday management tools

Screenshots of the application running locally with fictional data. Demo orders illustrate payment on collection; the online journey integrates Stripe Checkout.

Administration: counters, search, status filters and fictional orders awaiting preparation or ready for collection.Enlarge screenshot

Track each order through to collection

Statuses and preparation actions share one screen. The merchant can find an order, mark it ready and record its collection.

Administration: product list, stock quantities, availability, visibility and editing controls.Enlarge screenshot

Manage the catalogue and stock

Prices, quantities, availability and visibility are managed from the catalogue. Out-of-stock products are immediately identifiable.

The need: order and pay online, collect in store

The fishmonger needed to present fresh arrivals, promote special offers and receive orders for defined pickup slots. The experience had to be simple on mobile, with a catalogue the merchant could update every day without technical help.

  • Browse products and place an order from a phone.
  • Choose a pickup slot with capacity suited to preparation.
  • Card payment through Stripe Checkout, with a final total shown before confirmation.

Sprints with a review every week

Development was organised into sprints, with a weekly review to demonstrate completed features and discuss progress. These demonstrations made the work tangible: we could walk through the screens, discuss how they worked and consider the next steps. This regular rhythm provided opportunities to check the application against the fishmonger’s needs throughout the project.

A customer journey through to collection

Visitors browse the catalogue and build their selection. Ordering has three steps: basket, pickup slot and contact details. They then pay by card on the Stripe-hosted page. Once the server verifies payment, the order moves to preparation; the merchant marks it ready, then collected.

  • Filterable catalogue and promotions displayed on relevant products.
  • Summary of quantities, prices and pickup location.
  • Payment confirmation, ready-for-collection and cancellation emails through Brevo.

A dashboard for daily operations

A protected administration area brings routine tasks together. The merchant manages deliveries and stock movements, organises pickups, tracks payments and views customer order history.

  • Create and edit products, photos, prices and availability, and track stock movements.
  • Schedule promotions and generate recurring slots with limited capacity.
  • Track orders and payments, cancel with a Stripe refund and retry failed refunds.
  • Customer records with order history and CSV export of email addresses.
  • Search and filter customer messages, reply from the dashboard, and update contact details and opening hours.

Reserved stock and server-verified payments

The server recalculates prices and promotions, then reserves stock and a pickup place within a PostgreSQL transaction for around 30 minutes. Payment is confirmed through signed Stripe events or periodic server checks. Verified expiry releases reservations; retries avoid creating a second order or repeating a payment operation.

  • Webhook signature verification and handling of duplicate events.
  • Refund tracking and automatic retries for pending operations.
  • Notifications saved with the order and sent in the background through Brevo, with retries and delivery tracking.

Security: protecting access to administration

The merchant dashboard provides access to orders and customer data. I integrated two-step authentication: a password, followed by a temporary authenticator app code (TOTP) or a WebAuthn passkey. An administrator session is only created once the complete flow has been validated.

  • TOTP replay protection and login rate limits per account and IP address.
  • Management of sign-in methods and single-use recovery codes, with only their hashes stored in the database.
  • Identity verification before security changes, revocation of other sessions and an audit trail of changes.
  • Server-side input validation and permission checks, scrypt password hashing and HttpOnly session cookies.

Clear responsibilities and indexable pages

React, TypeScript and TanStack Start handle the interface and server rendering. Routes compose pages, services implement business rules, and data access modules use Drizzle ORM and PostgreSQL. This separation supports changes to customer and merchant workflows without mixing presentation and persistence.

  • Tailwind CSS for layouts that adapt to mobile and desktop.
  • Metadata, canonical URLs, sitemap and structured data for public pages.
  • GitLab CI/CD pipeline: automated tests, Docker image build and scanning with Trivy, then VPS deployment for protected tags.
  • Maintenance mode controlled from the dashboard, keeping merchant access available.

Testing: checking scenarios that can fail

The suite combines unit tests, PostgreSQL integration tests and a Playwright browser flow. It targets business rules, access controls and recovery after failures, including cases where two orders compete for the last available collection slot.

  • Business rules: quantities, fees, collection slots and order transitions.
  • PostgreSQL integration: concurrent orders, stock, collection capacity and duplicate prevention. Payment tests use the real database with simulated Stripe calls for confirmation, expiry, retries and refunds.
  • Security and browser: access denied before the second factor, TOTP setup, rejection of reused codes, WebAuthn passkeys and account security management.
  • Delivery: GitLab CI prepares dedicated test databases and runs migrations, tests, builds, TypeScript checks and HTML/SEO checks. The Playwright flow has a separate command.

Delivery and handover

The site is online, with management tools for the merchant to populate the catalogue and organise pickups. A user guide documents everyday operations. The project also includes an action history, backup export and a restoration procedure reserved for the operator.

  • A merchant guide for daily operations.
  • Backup export and a restoration procedure, with a dedicated integration test.

Visit the website · Explore the code

Explore further

Let’s start with your needs.

Your goal, your deadline, the tools you use: a few lines are enough to start the conversation.

Describe my project