# Amaan Psychotherapy

Case study 03 | Client | Live

An Ontario practice was paying monthly for a DIY website builder. I designed and built a calm, custom site with a private portal, so they can publish their own blog without calling a developer.

- Role: Design, build, hosting and ongoing maintenance.
- Timeline: September 2026 to now
- Stack: Python, Flask, PostgreSQL, Mailgun, Railway
- Live site: [amaan.abbasvirjee.com ↗](https://amaan.abbasvirjee.com)

325 automated tests

7 public pages

6 custom error pages

1 booking link, set in one place

The problem

## A therapy practice needs to feel safe before anyone books.

The old site came from a template builder: generic, hard to change and paid for every month. The practice wanted something that felt **quiet and trustworthy**, a blog they could run themselves, and a contact form they could rely on.

Before

- × Template site on a monthly plan
- × Blog posts needed outside help
- × Contact messages only in email
- × No control over the details

After

- → Custom design built for the practice
- → Private portal to write and publish
- → Messages saved and emailed
- → Every word on the site editable

What I built

## What I built

Visitors see five calm pages. Behind them is a portal built for someone who isn't technical.

### The website

- → Home, About, Services, Blog and Contact
- → Privacy Policy and Terms of Use
- → Crisis numbers in the footer on every page
- → Search engine and social sharing setup

### The portal

- → Blog editor with autosave and preview
- → Edit any page text, with version history
- → Messages inbox with search and archive
- → Photo uploads, resized and cleaned

### Behind it

- → Booking hands off to the practice's system
- → Separate admin address, hidden from search
- → Branded email template
- → Backups and a restore runbook

The hard part

## A contact form that never loses a message.

For a therapy practice, a lost enquiry is someone who reached out and never heard back. So the form **saves first and emails second**, and every failure has a plan.

Server-side validation Honeypot Rate limiting Header-injection guard

1

Check

Fields are validated on the server and bots are filtered out quietly.

2

Save

The message is stored first, so the portal always has a copy.

3

Email

It's sent to the practice with the visitor as the reply-to address.

4

Retry

If sending fails, the message is flagged and retried in the background.

Email is down: the visitor still sees the thank-you, and the message waits in the portal.

Can't save: the visitor sees an error and keeps everything they typed.

How it's built

## Privacy and security

### Locked-down portal

Sign-ins lock after five failed attempts, and sessions time out when idle.

### Safe blog content

Posts are cleaned against an allow-list before they're published.

### Clean photos

Uploads are verified, resized and stripped of location data.

### Strict headers

Content Security Policy, HSTS and no-index on the admin side.

### Quiet analytics

Privacy-friendly analytics, so no cookie banner on a therapy site.

### Designed first

Every page and state was designed and approved before any code.

Screens

![The Amaan admin dashboard](https://abbasvirjee.com/static/img/amaan-wide.webp)

The admin home: new messages, posts and drafts at a glance.

![The Amaan blog editor](https://abbasvirjee.com/static/img/amaan-a.webp)

The editor: write, preview, publish.

![The Amaan services page on a phone](https://abbasvirjee.com/static/img/amaan-b.webp)

Each service explained in plain language, on any screen.

The practice now updates its own website, without waiting on a developer.

The site is live and moving to the practice's own domain. They write and publish their own posts, every enquiry is kept safe, and I stay on for hosting and improvements.
