Aller au contenu

Adding a New Practice Website

Step-by-step guide for adding a new dental practice to the Helios platform.

Estimated time: 2-3 hours (infrastructure + configuration) + content creation time.


Phase B (2026-07-10): identity is the code, domain is optional. A practice is created, previewed, and served by its internal_code — the production .fr domain is a cutover-time attribute, blank until go-live. You can stand up a new site and preview it at {code}.{env}.groupe-suffren.com with no domain set at all, then fill the domain in at cutover.

Phase C (2026-07-11): previews are DERIVED — onboarding a preview is ONE step. A preview host is {code}.{env}.groupe-suffren.com (dotted env), derived by nginx (per-env regex server_name) and by Helios (codeFromHost), and already covered by the per-env wildcard cert + wildcard DNS. Creating the Aletheia SiteConfig row is the whole job — no DNS record, no nginx edit, no cert, no monitoring, no Helios code deploy. Sections 5 and 6 below apply only at .fr cutover, not to stand up a preview.

Prerequisites

  • Practice exists in Aletheia (Practice model with address, phone, hours, team)
  • Practice internal code chosen (the identity key; e.g., cda, vsm, pds — URL-safe: letters/digits/dashes)
  • Production domain decided (optional until cutover; e.g., cabinet-dentaire-aubagne.fr)
  • Brand colors chosen (primary hue/chroma, accent hue/chroma)

1. Aletheia — Create SiteConfig

In Aletheia's /websites/config/:

  1. Create SiteConfig for the practice:
  2. Domain: leave blank until cutover (Phase B) — set the production domain (e.g., nouveau-cabinet.fr) only when the .fr goes live. The site is keyed by the practice code meanwhile.
  3. City name: for SEO URL generation
  4. Primary hue/chroma + accent hue/chroma
  5. Enabled locales (default: ["fr"])
  6. Enabled services (e.g., ["implantologie", "esthetique", "parodontologie"])
  7. Meta title template + default description

  8. Add core model data (if not already in Aletheia):

  9. Dentist photos (photo field)
  10. Dentist slugs (auto-generated)
  11. Dentist display_order on DentistContract
  12. Practice logo
  13. WhatsApp number (if applicable)

2. Aletheia — Create Pages & Content

In Aletheia's /websites/pages/:

Required pages (minimum for launch)

Page Template Slug Notes
Homepage homepage accueil Hero + text + stats blocks minimum
Contact contact contact Hero + contact_form block
Mentions légales legal mentions-legales Legal text
Politique de confidentialité legal politique-confidentialite Privacy policy

Service pages (per enabled service)

Page Template Slug pattern
Service hub (L1) service_hub {service}-{ville}/ (e.g., implant-dentaire-aubagne)
Service detail (L2) service_detail {service}-{ville}/{treatment}/
Page Template Slug
Notre philosophie cabinet cabinet/notre-philosophie
Nos technologies cabinet cabinet/nos-technologies
Tarifs cabinet cabinet/tarifs
Accès & informations cabinet cabinet/acces-informations
Résultats results resultats

"Votre Besoin" pages

Create PatientNeed entries and corresponding pages with M2M links to service pages.


3. Aletheia — Create Navigation

The navigation tree is auto-generated from: - ServiceCategory entries (for "Nos Soins" dropdown) - PatientNeed entries (for "Votre Besoin" dropdown) - Published pages with specific templates (for "Le Cabinet" dropdown)

Verify navigation at: GET /api/v1/websites/sites/{code}/nav/


4. Helios — Add Domain Mapping

src/lib/practices.ts — Single source of truth

Add one entry to the PRACTICES array:

// `domain` is optional (Phase B) — omit it until cutover; `{ code: "nvc" }` alone
// is enough to preview at nvc[-staging|-dev].groupe-suffren.com.
export const PRACTICES: PracticeConfig[] = [
  // ...existing...
  { code: "nvc", domain: "nouveau-cabinet.fr" },
];

This automatically registers the practice in src/proxy.ts (Host → /_sites/[practice]/… rewrite keyed on the code + redirects), the [practice] route segment (generateStaticParams prerenders the tenant once its Aletheia API is live), allowedDevOrigins (next.config.ts), and the /api/contact proxy (src/app/api/contact/route.ts), which only forwards submissions for a code present in PRACTICES. All hostname variants (nvc.groupe-suffren.com, nvc-staging, nvc-dev, nvc.local, and www.nouveau-cabinet.fr once a domain is set) are derived from the code (and domain, when present).

Unknown hosts 404. A Host header not in the derived map gets a plain 404 from the proxy (Sentry-alerted in prod). There is no default-tenant fallback — a misconfigured domain fails loud instead of serving Aubagne's content.

Note: the contact form POSTs same-origin to /api/contact, which forwards to Aletheia server-side — there is no CORS config to set on Aletheia and no per-practice browser-facing URL. Adding the entry here is all that's needed for the form to work.

Indexing gate — no per-practice code change

There is no per-practice domain whitelist. Indexing is gated by shouldIndexSite() in src/lib/seo.ts (consumed by both src/app/[practice]/robots.txt/route.ts and the <meta name="robots"> in src/app/[practice]/layout.tsx):

  • Environment: only a deployment with ENVIRONMENT=prod allows indexing — staging/dev/local always emit noindex + a blocking robots.txt.
  • Per practice: go-live is controlled in Aletheia — flip SiteConfig.is_active for the practice. While inactive, its API endpoints 404 and Helios never serves the site at all.

5. Infrastructure — DNS (cutover only — previews need none)

OVH DNS (groupe-suffren.com zone)

No action for a preview (Phase C): the per-env wildcards *.prod. / *.staging. / *.dev.groupe-suffren.com already resolve every {code}.{env} host to the VPS. This section is only the production .fr registrar step at cutover (below).

Production domain DNS (at domain registrar)

When ready to go live:

Type Name Value
A @ 54.36.99.184
CNAME www nouveau-cabinet.fr

6. Infrastructure — Nginx + cert (cutover only — previews need none)

No action for a preview (Phase C): the prod/staging/dev vhosts already accept any {code}.{env}.groupe-suffren.com via their per-env regex server_name, and the per-env wildcard cert already covers it. Nothing below is touched to stand up a preview.

At .fr cutover — add the real domain only

In Aether nginx/conf.d/ (/opt/docker/aether/repo/), edit helios-prod.conf.full: add nouveau-cabinet.fr (+ www.) to the prod server_name and to the $helios_preview_realm map as off (so the public domain isn't password-gated). Do not add any *.groupe-suffren.com preview host — those are derived.

cd /opt/docker/aether/repo && make deploy && make restart-nginx

Then mint the real domain's cert — a separate per-domain HTTP-01 cert, NOT the helios wildcard (do not pass --cert-name helios — it would overwrite the wildcard):

docker exec certbot certbot certonly --webroot -w /var/www/certbot \
  --non-interactive --agree-tos --email admin@groupe-suffren.com \
  -d nouveau-cabinet.fr -d www.nouveau-cabinet.fr

7. Deploy

# Commit Helios changes
cd ~/code/helios
git add -A && git commit -m "Add [practice name] practice" && git push

# Deploy to server
# Dev first:
ssh server "cd /opt/docker/helios/repo && git pull && ./deploy.sh dev"
# Then staging, then prod

8. Verify

Pre-launch checklist

  • [ ] Homepage loads at https://nvc-dev.groupe-suffren.com/
  • [ ] All nav links work (no 404s)
  • [ ] Contact form submits successfully
  • [ ] Team page shows correct practitioners
  • [ ] Service pages have content
  • [ ] Footer shows correct hours, address, phone
  • [ ] SEO: meta titles correct on all pages
  • [ ] SEO: robots.txt allows crawling on production domain
  • [ ] SEO: sitemap.xml lists all published pages
  • [ ] Schema.org: test with Google Rich Results Test
  • [ ] Mobile: nav works, bottom dock shows, responsive layout
  • [ ] Performance: Lighthouse > 90

DNS cutover (go live)

  • [ ] Point production domain DNS to server
  • [ ] SSL cert covers production domain
  • [ ] Add production domain to nginx server_name
  • [ ] Set SiteConfig.is_active = True in Aletheia admin (per-practice go-live; ENVIRONMENT=prod in the env file is the deployment-wide indexing gate — see src/lib/seo.ts)
  • [ ] Verify robots.txt allows crawling
  • [ ] Submit sitemap to Google Search Console
  • [ ] Set up 301 redirects from old site URLs (if migrating)
  • [ ] Monitor for 2 weeks post-launch

Quick Reference — Files to Edit

File What to add
src/lib/practices.ts Practice entry (code, domain) — drives the proxy rewrite, static params, allowedDevOrigins, and the /api/contact allowlist
Aletheia admin SiteConfig.is_active = True when going live (indexing itself is env-gated — ENVIRONMENT=prod, src/lib/seo.ts; no Helios code change)
Aether nginx/conf.d/helios-*.conf.full server_name domains