{
  "site": {
    "name": "Passionfruit Design",
    "owner": "Dr Matt Dennis",
    "url": "https://passionfruit.design",
    "email": "hello@passionfruit.design",
    "phone": {
      "display": "07385 509278",
      "tel": "+447385509278",
      "whatsapp": "https://wa.me/447385509278"
    },
    "location": {
      "town": "Portsmouth",
      "country": "UK",
      "countryCode": "GB"
    },
    "repo": null,
    "description": "Websites and web apps your own team can update. Researched, designed, built, kept safe and kept running by one person.",
    "areaServed": "GB",
    "versions": {
      "plain": "Plain English",
      "technical": "For IT people"
    },
    "hero": {
      "headline": "The whole job. One person.",
      "lede": "I make websites and web apps that your own team can update. I find out what your people need. Then I design it, build it, keep it safe and keep it running."
    },
    "what": {
      "heading": "What I do",
      "items": [
        {
          "title": "I start with your people.",
          "text": "I talk to the people who will use it and watch how they work. Then I test what I build with them."
        },
        {
          "title": "You change the words yourself.",
          "text": "Your team updates the text and pictures from a simple editing screen. Nobody has to phone a developer."
        },
        {
          "title": "It works for everyone.",
          "text": "On phones, on slow connections and with screen readers. I build to the recognised accessibility standard from the start."
        },
        {
          "title": "It is quick and cheap to run.",
          "text": "I keep things small, so pages load fast and the hosting bill stays low."
        },
        {
          "title": "It is kept safe.",
          "text": "I keep the software up to date and close everything that does not need to be open. I set up your email so nobody can send fakes from your address."
        },
        {
          "title": "It can take money.",
          "text": "Card payments, ticket sales and bookings, when you need them."
        },
        {
          "title": "It is yours to keep.",
          "text": "I use standard, widely used tools. If you ever move on, you take everything with you."
        },
        {
          "title": "One person to ask.",
          "text": "I do the design, the building, the hosting and the email myself. When something needs fixing, you know who to call."
        }
      ]
    },
    "technical": {
      "title": "For IT people",
      "description": "Modern web apps with a CMS your team can actually use. Researched, designed, built, secured, hosted and run by one person, from the interface to DNS.",
      "hero": {
        "headline": "The whole stack. One person.",
        "lede": "Modern web apps with a CMS your team can actually use. Researched with the people who will use them, then designed, built, secured, hosted and run by me. Interface to DNS."
      }
    },
    "principles": {
      "heading": "How I build",
      "items": [
        {
          "title": "Slim servers.",
          "text": "Small Node services with thin handlers, behind a reverse proxy, with one identity service for every app. Several production apps share one 2GB server. You get speed and a small hosting bill."
        },
        {
          "title": "JSON throughout.",
          "text": "Content is structured data from a headless CMS. The same data feeds your website, an app, a dashboard or another system without rework."
        },
        {
          "title": "People first.",
          "text": "I research with the people who will use it, then test with them. Accessible to WCAG 2.2 AA from the first commit."
        },
        {
          "title": "Server-rendered.",
          "text": "Pages arrive complete. JavaScript makes them better. It is never needed to read them."
        },
        {
          "title": "Built in CI, not on the server.",
          "text": "Few dependencies, so less to patch and less to break. Servers run code. They never build it."
        },
        {
          "title": "Yours to keep.",
          "text": "Standard and portable. It runs on a VPS, on Vercel or in a cloud, and you can take it anywhere."
        }
      ]
    },
    "about": {
      "heading": "About",
      "paragraphs": [
        "I'm Matt. I'm based in Portsmouth, UK. I'm a human-centred designer who writes the code and runs the servers.",
        "My doctorate is in human-computer interaction: how software should adapt to the person using it. User research, usability and accessibility are what I trained in, not something I added later.",
        "I'm an academic. I have taught web technologies for over a decade and published peer-reviewed research. I have run production systems since 2018.",
        "I'm a member of the BCS and a charity trustee, and I have held a senior role covering safeguarding, regulatory compliance and data protection. I write the policy as well as the code."
      ]
    },
    "advice": {
      "heading": "Advice",
      "intro": "I also advise and consult, especially for charities and non-profits. I'm a charity trustee myself, so I know how far the money has to go.",
      "items": [
        "Networking",
        "Websites",
        "Choosing and buying software",
        "Regulatory compliance",
        "Data protection"
      ],
      "outro": "Tell me what you have and what worries you. I'll tell you plainly what to do next."
    },
    "contact": {
      "heading": "Tell me what you need",
      "intro": "A few lines about the project is enough. I read every message myself.",
      "sent": "Thanks. Your message has been sent. I will reply to the address you gave.",
      "failed": "That did not send. Please email me directly instead."
    },
    "legal": "Passionfruit Design is the trading name of Dr Matt Dennis."
  },
  "stack": {
    "heading": "The lot",
    "intro": "Every layer, from the people using it down to the network. No subcontractors. No gaps.",
    "layers": [
      {
        "name": "Research and design",
        "text": "I find out what people need before I build it, then test it with them.",
        "items": [
          "User research",
          "Interviews",
          "Usability testing",
          "Prototyping",
          "Interaction design",
          "UX",
          "Accessibility to WCAG 2.2 AA"
        ]
      },
      {
        "name": "Architecture",
        "text": "Designed for the job and sized to run fast on modest hardware.",
        "items": [
          "Headless CMS",
          "JSON APIs",
          "Small services",
          "Server rendering",
          "Pre-rendering",
          "Progressive enhancement"
        ]
      },
      {
        "name": "Web apps with a CMS",
        "text": "Your staff edit the content. Nobody phones a developer.",
        "items": [
          "Payload",
          "Directus",
          "A custom CMS written for the job"
        ]
      },
      {
        "name": "Interface",
        "text": "Hand-written where that is enough, a framework where the app warrants it.",
        "items": [
          "HTML",
          "CSS",
          "JavaScript",
          "React",
          "Next.js",
          "TypeScript",
          "Tailwind"
        ]
      },
      {
        "name": "Application and data",
        "text": "APIs, databases, and the data you already have, moved in safely.",
        "items": [
          "Node",
          "Express",
          "Fastify",
          "REST and JSON APIs",
          "Postgres",
          "SQLite",
          "Prisma",
          "Full-text search",
          "Data migrations",
          "Legacy imports",
          "Feeds to and from other systems"
        ]
      },
      {
        "name": "Identity",
        "text": "One sign-in for every app, with roles that match how your organisation works.",
        "items": [
          "Passkeys (WebAuthn)",
          "OIDC",
          "Single sign-on",
          "Google sign-in",
          "Magic links",
          "Role hierarchies",
          "Central identity service"
        ]
      },
      {
        "name": "Payments and ticketing",
        "items": [
          "Stripe",
          "Box office",
          "Events",
          "Bookings"
        ]
      },
      {
        "name": "Integrations",
        "items": [
          "Social media hooks",
          "Webhooks",
          "Media pipelines",
          "Third-party feeds"
        ]
      },
      {
        "name": "AI",
        "text": "LLM features behind a provider you can swap, with privacy designed into the schema.",
        "items": [
          "LLM features",
          "Swappable provider interface",
          "Privacy by schema"
        ]
      },
      {
        "name": "DevSecOps",
        "items": [
          "GitHub Actions",
          "Automated deploys",
          "Dependency patching",
          "Content Security Policy",
          "Security headers",
          "Secrets management",
          "pm2",
          "Docker",
          "Monitoring",
          "Health checks"
        ]
      },
      {
        "name": "Hosting",
        "text": "Several production apps on one small box.",
        "items": [
          "Linux VPS",
          "nginx",
          "Vercel",
          "Google Cloud",
          "Managed Postgres",
          "Backblaze B2",
          "Object storage behind a CDN"
        ]
      },
      {
        "name": "Cloudflare",
        "items": [
          "DNS",
          "CDN",
          "Caching",
          "TLS",
          "Edge protection"
        ]
      },
      {
        "name": "DNS and email",
        "text": "Your domain cannot be spoofed, and your mail arrives.",
        "items": [
          "DNS management",
          "Domain migrations",
          "SPF",
          "DKIM",
          "DMARC to p=reject",
          "BIMI",
          "MTA-STS",
          "Mail forwarding",
          "Mailing lists",
          "Transactional email"
        ]
      },
      {
        "name": "Network",
        "items": [
          "Reverse proxies",
          "TLS",
          "Private networking",
          "VPN (Tailscale)",
          "Network design"
        ]
      },
      {
        "name": "Policy and governance",
        "text": "I write the policy as well as the code.",
        "items": [
          "Data protection by design",
          "Accessibility",
          "Security policy",
          "Safeguarding",
          "Regulatory compliance"
        ]
      }
    ]
  },
  "work": {
    "heading": "Work",
    "intro": "A charity platform, small-business sites on custom CMSs, university systems and a public archive.",
    "plainIntro": "A charity, small businesses, a university, a school and a public archive.",
    "projects": [
      {
        "name": "Solent Gay Men's Chorus",
        "url": "https://sgmc.org.uk",
        "kind": "Registered charity. The whole platform, built and run by me.",
        "plain": "A choir and registered charity. I built and run everything they have online: the website, ticket sales and the members' area. The chorus updates the site itself.",
        "flagship": true,
        "facts": [
          "One identity service for every app, with passkey sign-in and a role hierarchy.",
          "Stripe payments, box office and ticket sales, and events.",
          "Media library on object storage behind Cloudflare.",
          "Social media hooks, member email and a CMS the chorus edits itself.",
          "Five Node services: main website, box office, governance, members portal and identity. Content in Payload.",
          "All five share one 2GB server behind nginx, deployed from GitHub Actions.",
          "Email domain at DMARC p=reject, with DKIM aligned."
        ]
      },
      {
        "name": "SUMS",
        "url": null,
        "kind": "Blind double-marking and moderation platform for a university.",
        "plain": "A marking system for a university. Two markers grade each student project without seeing each other's marks, and every step is recorded. In use since 2018, with about 600 projects and 100 markers a year.",
        "facts": [
          "In production since 2018, on Google Cloud with single sign-on and a full audit trail.",
          "About 600 projects a year: 350 undergraduate and 250 master's, plus resits and two international partner programmes. About 100 markers a year.",
          "More than 4,800 projects marked since 2018."
        ]
      },
      {
        "name": "Student feedback platform",
        "url": null,
        "kind": "Commissioned by a university, designed from research with students and staff.",
        "plain": "A university asked me for a way to collect feedback from students. I designed it from research with students and staff. Nobody can trace an answer back to the student who gave it.",
        "facts": [
          "Next.js, TypeScript, Postgres and Prisma.",
          "Anonymity is enforced by the schema: a response cannot be joined to the student who wrote it.",
          "LLM features sit behind a swappable provider interface."
        ]
      },
      {
        "name": "Survey analysis dashboard",
        "url": null,
        "kind": "Adopted across a university faculty.",
        "plain": "A tool that works through a whole institution's survey results in three hours. A university faculty adopted it.",
        "facts": [
          "Whole-institution survey results analysed in three hours."
        ]
      },
      {
        "name": "geraldlarner.com",
        "url": "https://geraldlarner.com",
        "kind": "A public, searchable archive, built from a pile of old files.",
        "plain": "About 6,700 old word-processor files, turned into a public archive that anyone can search. It covers 444 composers.",
        "facts": [
          "About 6,700 legacy word-processor files, covering 444 composers.",
          "A thin Express server over one SQLite file of pre-rendered pages, with full-text search and a JSON API."
        ]
      },
      {
        "name": "alicedennis.net",
        "url": "https://alicedennis.net",
        "kind": "Site for a piano and singing teacher. Replaced a broken legacy site.",
        "plain": "A site for a piano and singing teacher. It replaced one that was broken. She updates it herself.",
        "facts": [
          "A custom lightweight CMS with a built-in admin page and Google sign-in, so the owner edits it herself.",
          "Express on my VPS."
        ]
      },
      {
        "name": "morganharnett.tattoo",
        "url": "https://morganharnett.tattoo",
        "kind": "Site for a tattoo artist, on a custom CMS written for the job.",
        "plain": "A site for a tattoo artist. It fills itself from his Instagram, so he updates one place.",
        "facts": [
          "It fills itself from Instagram, so the artist updates one place."
        ]
      },
      {
        "name": "Photo archive for a school",
        "url": null,
        "kind": "Private. Built on Directus.",
        "plain": "A private archive for a school. Artists' photographs are kept in one place so students can learn from them.",
        "facts": [
          "Artists' photographs managed in one place so students can learn from them."
        ]
      },
      {
        "name": "ASICA",
        "url": null,
        "kind": "Research tablet app for melanoma self-monitoring.",
        "plain": "A research app on a tablet that helps people check their own skin for melanoma. Designed with patients and run in a six-month NHS pilot.",
        "facts": [
          "Designed with patients and run in a six-month NHS pilot."
        ]
      }
    ]
  },
  "pages": {
    "colophon": {
      "title": "Colophon",
      "description": "How passionfruit.design is built, in plain language.",
      "lede": "How this site is built. It follows the same rules as the work I do for clients.",
      "sections": [
        {
          "heading": "Words are data",
          "paragraphs": [
            "Every word on this site lives in a few JSON files. The server checks them when it starts and refuses to run if anything is missing.",
            "The same content is published as JSON, so you can read the whole site as data."
          ],
          "links": [
            {
              "text": "This site as JSON",
              "href": "/api/site.json"
            },
            {
              "text": "The live figures as JSON",
              "href": "/api/receipts.json"
            }
          ]
        },
        {
          "heading": "Made on the server",
          "paragraphs": [
            "One small Node process using Express builds each page and sends it complete. There is no framework, no bundler and no build step.",
            "It has two runtime dependencies: Express, and Nodemailer for the contact form. Everything else is a few lines written for the job.",
            "The page works with JavaScript turned off. A few lines of JavaScript make the contact form reply without reloading the page. That is all it does."
          ]
        },
        {
          "heading": "Locked down",
          "paragraphs": [
            "The server sets a strict content security policy. The browser may load nothing from anywhere but this domain, so third-party requests are impossible, not just absent.",
            "Other headers stop the site being framed, stop the browser guessing file types, send no referrer and turn off every browser feature the site does not use.",
            "The contact form checks where it was sent from, limits how often one address can use it and catches bots without a CAPTCHA."
          ],
          "links": [
            {
              "text": "Check the headers with Mozilla Observatory",
              "href": "https://developer.mozilla.org/en-US/observatory/analyze?host=passionfruit.design"
            },
            {
              "text": "Check TLS with SSL Labs",
              "href": "https://www.ssllabs.com/ssltest/analyze.html?d=passionfruit.design"
            }
          ]
        },
        {
          "heading": "Hosted on a small box",
          "paragraphs": [
            "The app runs under pm2 on a Linux VPS it shares with other production apps. nginx sits in front of it and handles TLS with a Let's Encrypt certificate.",
            "GitHub Actions lints and tests every change, checks accessibility, page weight and Lighthouse scores, then deploys. Nothing is built on the server."
          ]
        },
        {
          "heading": "Type and colour",
          "paragraphs": [
            "The type is your device's own system font, so there is nothing to download. The colours come from the fruit: aubergine skin, yellow pulp, pale pith. Every pairing passes WCAG 2.2 AA contrast."
          ]
        }
      ]
    },
    "privacy": {
      "title": "Privacy",
      "description": "What passionfruit.design collects, which is very little.",
      "lede": "This site collects nothing unless you send me a message.",
      "sections": [
        {
          "heading": "Who I am",
          "paragraphs": [
            "Passionfruit Design is the trading name of Dr Matt Dennis. I am responsible for this site and for anything you send through it."
          ]
        },
        {
          "heading": "No cookies, no tracking",
          "paragraphs": [
            "This site sets no cookies and uses no analytics. It loads nothing from any other company. That is why there is no cookie banner."
          ]
        },
        {
          "heading": "If you use the contact form",
          "paragraphs": [
            "Your name, email address and message are sent to me by email. The site does not store them.",
            "I use them only to reply and to handle any work that follows. I keep them in my mailbox for as long as that takes, and I never pass them on or add you to a mailing list."
          ]
        },
        {
          "heading": "If you message me on WhatsApp",
          "paragraphs": [
            "WhatsApp is run by Meta, not by me. If you message me there, Meta's privacy policy covers what they do with it. I use your messages only to reply and to handle any work that follows.",
            "The WhatsApp link on this site is an ordinary link. Nothing from WhatsApp or Meta loads unless you click it."
          ]
        },
        {
          "heading": "Server logs",
          "paragraphs": [
            "Like every web server, mine records the address each request came from, the page asked for and the time. I use these logs only to keep the site running and secure, and they are deleted automatically within 14 days."
          ]
        },
        {
          "heading": "Your rights",
          "paragraphs": [
            "You can ask me for a copy of anything I hold about you, or ask me to delete it, by email. If you are unhappy with how I handle your data, you can complain to the Information Commissioner's Office."
          ],
          "links": [
            {
              "text": "Information Commissioner's Office",
              "href": "https://ico.org.uk/make-a-complaint/"
            }
          ]
        }
      ]
    }
  }
}