Plan Your Visit landing page for visit.waterschurch.org

Next.js 16 static export + PHP 8 API for cPanel/Apache hosting.

- Location-aware campus finder (IP estimate, optional precise location, ZIP search)
- Three-step Plan Your Visit form with separate email/SMS consent
- PHP API: validation, anti-spam, rate limiting, SQLite lead store,
  Mailchimp and Sinch Engage adapters, idempotent retries via cron
- Attribution capture (utm_*, gclid/gbraid/wbraid, fbclid, ttclid, twclid) and
  consent-aware analytics hooks
- Vitest and PHP test suites, cPanel deployment script and docs

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Waters Church
2026-09-22 13:22:26 -04:00
co-authored by Claude Fable 5.1
commit 78cd0cc550
109 changed files with 16861 additions and 0 deletions
+187
View File
@@ -0,0 +1,187 @@
{
"$schema": "./campuses.schema.json",
"_readme": "Single source of truth for campus data. Read by the Next.js frontend (src/config/campuses.ts) and by the PHP API (public/api/lib/campuses.php). Facts were verified against waterschurch.org on 2026-09-22 unless listed under `verify`. Edit this file, then rebuild (npm run build) and re-upload.",
"campuses": [
{
"id": "north-attleboro",
"name": "North Attleboro",
"label": "North Attleboro, MA",
"status": "open",
"isCentral": true,
"address": {
"line1": "57 John L Dietsch Square",
"city": "North Attleboro",
"state": "MA",
"postalCode": "02763"
},
"coordinates": { "lat": 41.97396, "lng": -71.29631 },
"timezone": "America/New_York",
"serviceTimes": [
{ "day": "Sunday", "times": ["7:30 AM", "9:30 AM", "11:30 AM"] }
],
"phone": "+15086951300",
"smsNumber": "+15086951300",
"sinchAccountId": "WatersChurch_OLA_0007",
"email": "info@waterschurch.org",
"campusUrl": "https://waterschurch.org/locations/north-attleboro/",
"directionsUrl": "https://www.google.com/maps/dir/?api=1&destination=Waters+Church%2C+57+John+L+Dietsch+Square%2C+North+Attleboro%2C+MA+02763",
"leader": { "title": "Lead Pastor", "name": "Tim Hatch" },
"arrivalNotes": null,
"parkingNotes": null,
"kidsNotes": "Waters Kids programs run at every service time.",
"image": "north-attleboro",
"verify": ["parkingNotes", "arrivalNotes", "coordinates"]
},
{
"id": "norwood",
"name": "Norwood",
"label": "Norwood, MA",
"status": "open",
"isCentral": false,
"address": {
"line1": "668 Walpole Street",
"city": "Norwood",
"state": "MA",
"postalCode": "02062"
},
"coordinates": { "lat": 42.17153, "lng": -71.22482 },
"timezone": "America/New_York",
"serviceTimes": [
{ "day": "Sunday", "times": ["9:30 AM", "11:00 AM"] },
{ "day": "First Wednesday of the month", "times": ["7:00 PM"] }
],
"phone": "+17817623357",
"smsNumber": "+17817623357",
"sinchAccountId": "WatersChurch_OLA_0002",
"email": "info@waterschurchnorwood.org",
"campusUrl": "https://waterschurch.org/locations/norwood/",
"directionsUrl": "https://www.google.com/maps/dir/?api=1&destination=Waters+Church+Norwood%2C+668+Walpole+Street%2C+Norwood%2C+MA+02062",
"leader": { "title": "Senior Pastor", "name": "Tommy Geyser" },
"arrivalNotes": null,
"parkingNotes": null,
"kidsNotes": "Waters Kids programs run at every service time.",
"image": "norwood",
"verify": ["parkingNotes", "arrivalNotes", "coordinates"]
},
{
"id": "woonsocket",
"name": "Woonsocket",
"label": "Woonsocket, RI",
"status": "open",
"isCentral": false,
"address": {
"line1": "1500 Diamond Hill Road",
"city": "Woonsocket",
"state": "RI",
"postalCode": "02895"
},
"coordinates": { "lat": 42.01634, "lng": -71.47692 },
"timezone": "America/New_York",
"serviceTimes": [
{ "day": "Sunday", "times": ["9:00 AM", "11:00 AM"] }
],
"phone": "+15086951300",
"smsNumber": "+18332414837",
"sinchAccountId": "WatersChurch_OLA_0005",
"email": "info@waterschurch.org",
"campusUrl": "https://waterschurch.org/locations/woonsocket/",
"directionsUrl": "https://www.google.com/maps/dir/?api=1&destination=Waters+Church+Woonsocket%2C+1500+Diamond+Hill+Rd%2C+Woonsocket%2C+RI+02895",
"leader": { "title": "Location Pastor", "name": "Jim Shekleton" },
"arrivalNotes": null,
"parkingNotes": null,
"kidsNotes": "Waters Kids programs run at every service time.",
"image": "woonsocket",
"verify": ["parkingNotes", "arrivalNotes", "coordinates", "phone"]
},
{
"id": "southcoast",
"name": "Southcoast",
"label": "Southcoast, RI/MA",
"status": "open",
"isCentral": false,
"address": {
"line1": "28 Fish Road",
"city": "Tiverton",
"state": "RI",
"postalCode": "02878"
},
"coordinates": { "lat": 41.66752, "lng": -71.17603 },
"timezone": "America/New_York",
"serviceTimes": [
{ "day": "Sunday", "times": ["10:30 AM"] }
],
"phone": "+15086951300",
"smsNumber": "+15088093490",
"sinchAccountId": "WatersChurch_OLA_0006",
"email": "info@waterschurch.org",
"campusUrl": "https://waterschurch.org/locations/southcoast/",
"directionsUrl": "https://www.google.com/maps/dir/?api=1&destination=Waters+Church+Southcoast%2C+28+Fish+Road%2C+Tiverton%2C+RI+02878",
"leader": { "title": "Location Pastor", "name": "Mehdi Chniouli" },
"arrivalNotes": null,
"parkingNotes": null,
"kidsNotes": "Waters Kids programs run at every service time.",
"image": "southcoast",
"verify": ["parkingNotes", "arrivalNotes", "coordinates", "phone"]
},
{
"id": "apollo-beach",
"name": "Apollo Beach",
"label": "Apollo Beach, FL",
"status": "open",
"isCentral": false,
"address": {
"line1": "5309 North US Hwy 41",
"city": "Apollo Beach",
"state": "FL",
"postalCode": "33572"
},
"coordinates": { "lat": 27.74286, "lng": -82.41918 },
"timezone": "America/New_York",
"serviceTimes": [
{ "day": "Sunday", "times": ["9:00 AM", "11:00 AM"] }
],
"phone": "+18136426979",
"smsNumber": "+18136426979",
"sinchAccountId": "WatersChurch_OLA_0003",
"email": "info@waterschurch.org",
"campusUrl": "https://waterschurch.org/locations/apollo-beach/",
"directionsUrl": "https://www.google.com/maps/dir/?api=1&destination=Waters+Church+Apollo+Beach%2C+5309+N+US+Hwy+41%2C+Apollo+Beach%2C+FL+33572",
"leader": { "title": "Location Pastor", "name": "Tom Duck" },
"arrivalNotes": null,
"parkingNotes": null,
"kidsNotes": "Waters Kids programs run at every service time.",
"image": "apollo-beach",
"verify": ["parkingNotes", "arrivalNotes", "coordinates"]
},
{
"id": "orlando",
"name": "Orlando",
"label": "Orlando, FL",
"status": "launching",
"isCentral": false,
"address": {
"line1": "Castle Door Studios, 1890 Kentucky Ave",
"city": "Winter Park",
"state": "FL",
"postalCode": "32789"
},
"coordinates": { "lat": 28.59213, "lng": -81.37501 },
"timezone": "America/New_York",
"serviceTimes": [
{ "day": "Sunday", "times": ["10:30 AM"], "note": "Doors open 10:00 AM. Currently gathering with the launch team only." }
],
"phone": "+15086951300",
"smsNumber": null,
"sinchAccountId": null,
"email": "info@waterschurch.org",
"campusUrl": "https://waterschurch.org/locations/orlando/",
"directionsUrl": "https://www.google.com/maps/dir/?api=1&destination=1890+Kentucky+Ave%2C+Winter+Park%2C+FL+32789",
"leader": { "title": "Pastor", "name": "Tim Hatch" },
"arrivalNotes": null,
"parkingNotes": null,
"kidsNotes": null,
"image": "orlando",
"verify": ["status", "serviceTimes", "smsNumber", "kidsNotes", "coordinates"]
}
]
}
+48
View File
@@ -0,0 +1,48 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Waters Church campuses",
"type": "object",
"required": ["campuses"],
"properties": {
"campuses": {
"type": "array",
"items": {
"type": "object",
"required": ["id", "name", "label", "status", "address", "coordinates", "serviceTimes", "phone", "campusUrl", "directionsUrl"],
"properties": {
"id": { "type": "string", "pattern": "^[a-z0-9-]+$" },
"name": { "type": "string" },
"label": { "type": "string" },
"status": { "enum": ["open", "launching", "hidden"] },
"isCentral": { "type": "boolean" },
"address": {
"type": "object",
"required": ["line1", "city", "state", "postalCode"],
"properties": {
"line1": { "type": "string" }, "city": { "type": "string" },
"state": { "type": "string" }, "postalCode": { "type": "string" }
}
},
"coordinates": { "type": "object", "required": ["lat", "lng"], "properties": { "lat": { "type": "number" }, "lng": { "type": "number" } } },
"timezone": { "type": "string" },
"serviceTimes": {
"type": "array",
"items": { "type": "object", "required": ["day", "times"], "properties": { "day": { "type": "string" }, "times": { "type": "array", "items": { "type": "string" } }, "note": { "type": ["string", "null"] } } }
},
"phone": { "type": "string", "pattern": "^\\+[1-9][0-9]{6,14}$" },
"smsNumber": { "type": ["string", "null"], "pattern": "^\\+[1-9][0-9]{6,14}$" },
"sinchAccountId": { "type": ["string", "null"] },
"email": { "type": ["string", "null"] },
"campusUrl": { "type": "string", "format": "uri" },
"directionsUrl": { "type": "string", "format": "uri" },
"leader": { "type": ["object", "null"], "properties": { "title": { "type": "string" }, "name": { "type": "string" } } },
"arrivalNotes": { "type": ["string", "null"] },
"parkingNotes": { "type": ["string", "null"] },
"kidsNotes": { "type": ["string", "null"] },
"image": { "type": ["string", "null"] },
"verify": { "type": "array", "items": { "type": "string" } }
}
}
}
}
}