← All projects
Tennis Club AmbrosianoSports club · Milan

One customer record instead of disconnected systems.

Sign-ups, tennis school, summer camp and events: an office receiving requests from website, email and phone, rebuilding by hand who was who.

353Past events imported
220Customer records unified
192Forms de-duplicated
1Source of truth for website and office

The challenge

The website was separate from the office: forms arrived by email, the same person appeared several times with slightly different data, and the history in the previous system had never made it into the new one. Nobody could say how many people really used the club.

The approach

First the map: where a person’s data comes from, and which fields reliably say two rows are the same person. Then a fast static website and a CRM sharing the same database. Staff don’t link anything: the system does.

Live

Real screens.

The website, the app and the tools as customers and staff use them today. Tap a screen to enlarge it.

Three requests, three different names.

One person.

Behind the login

Tennis Club Ambrosiano

What you only see from inside — the CRM, the member app — rebuilt and animated with anonymised sample data.

01

Members, tennis school and revenue

How many members, how many in the tennis school and summer camp, how much comes in month by month: after de-duplication these are people, not forms.

crm.club.it/analyticsSample data
Active members0▲ +4%
Revenue this month€ 0▲ +9%
Tennis school sign-ups0
Events this month0

Monthly revenue (€)

DecJanFebMarAprMayJunJulAugSepOctNov

Active memberships by type

0active
  • Members49%
  • Tennis school25%
  • Summer camp11%
  • Events15%
NewRenewedLapsed
Dec
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov

Latest payments

  • L
    Luca V.Tennis school · adult course
    €420.00
02

The same person, only once

A website form, a tennis-school sign-up, a contact from the archive: three rows, one person. The system recognises and merges them; staff see it already done.

Website formLuca Verdiluca.verdi@…—
Tennis schoolVERDI LUCA—+39 347 …12
ArchiveL. Verdiluca.verdi@…347 …12
Single record ✓ MergedLuca Verdiluca.verdi@…+39 347 …12
03

The person’s record

Everything that happened with a person, in order: requests, sign-ups, events, who followed up. The office answers without searching three places.

crm.circolo.it/persone/…Sample data
L
Luca VerdiMember · Verdi family (3) · Tennis school
  1. Oct
    Event sign-upClub doubles tournament
  2. Jul
    Summer campSon · 2 weeks
  3. May
    Invite a friendInvited 2 people
  4. Sep
    Tennis schoolAdult course · Tuesday
  5. 2023
    First contactFrom the imported archive
04

Where people come from

Junior and adult requests, month by month, after de-duplication: finally people, not forms.

crm.circolo.it/analyticsSample data
Unique people0
Duplicates avoided0
Events in the archive0
JuniorAdults
Nov
Dec
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct

What we built

  • 01Fast public website with a CMS for the office
  • 02Request normalisation and de-duplication: one row per person
  • 03Import of past events from the previous system
  • 04Office CRM: people, opportunities, shared calendar, tasks
  • 05Tennis school, summer camp and event sign-ups
  • 06“Invite a friend” pipeline, newsletter, notifications
  • 07Sync with the club’s back office

Technology

AstroTinaCMSNext.jsSupabasePerfectGym APIVercel Cron

How it’s built

Under the hood.

The website stays static and very fast; the office works in a separate CRM with logins and live data. Two projects, one database: it’s the database that holds the people together.

The architecture, layer by layer

01
Interfaces
Website · Astro + TinaCMSOffice CRM · Next.js + ReactPush notifications
02
Logic
n8n · form flowsNormalisation and de-duplicationEdge Functions · back-office syncVercel Cron
03
Data
Postgres on SupabasePeople · opportunities · eventsRow Level Security
04
External systems
PerfectGym APIEmailPrevious CRM archive

The pieces, one by one

01

Astro

The website

Generated ahead of time: no server to maintain, ready HTML pages, minimal CSS. Content is updated from a visual editor.

02

Why two applications

Website and CRM apart

The website is static; the CRM needs logins and data that’s current to the second. Keeping them apart, on the same database, keeps the website simple and leaves the CRM free to grow.

03

De-duplication

One row per person

Rules on normalised name, email and phone decide when two rows are the same person. Requests stay many, the person is one; opportunities belong to the person.

04

n8n

Automation

Website forms go through n8n flows that normalise them and write them to the right tables, with nobody in between.

05

Supabase + RLS

Who sees what

Access rules live in the database, row by row: every operator sees what their role allows, whatever page they use.

In numbers

1Database for website and CRM
353Past events imported
192Duplicates recognised
18Database migrations