https://beta.csidubai.com/ — frontend architecture, backend communication, third-party integrations, assets, APIs, page composition — from page load to fully interactive. Deliver a professional, self-contained HTML report with diagrams, tables, and expandable sections.
beta.csidubai.com is the staging/preview build of the public website for CSI Parish (Malayalam) Dubai — the first Church of South India parish in the UAE (Holy Trinity Church Complex, Dubai). It is not a bespoke site: it is one tenant (tenant00002-ntaw-4465b887) on the Hamanahel Software Solutions multi-tenant church-management platform (base_path: platform.csidubai.com), the same product powering ~12+ other CSI/Mar Thoma parishes across the Gulf and India.
The site is a client-side rendered single-page application built with React 18 + Vite + React Router, styled with Tailwind CSS v4 and shadcn/ui (Radix), with motion via Framer Motion. The server returns a 1 KB HTML shell (<div id="root">) and ~150 lazily-loaded JS chunks compose the page from a widget-type system (HeaderType5, HeroType5, event-calendar-type-3, etc.) driven by a JSON config (/config/index.json) fetched at runtime. Content (events, news, gallery) is loaded from a REST API at /api/v3/content/*. All media is served from a Cloudflare R2 bucket (r2-pub.csidubai.com).
Infrastructure is modern and sound: Cloudflare DNS + CDN + R2 object storage + Email Routing, TLS 1.3, HTTP/2 + HTTP/3 (QUIC), zstd compression, IPv6 dual-stack, no origin-IP leak, no cookies on static documents. Performance is good for a JS-heavy SPA (FCP 1.62 s, CLS 0, TBT ~0).
The notable weaknesses are operational and SEO/security-hygiene, not architectural: a broken SPA fallback (deep links 404 at the origin), missing HTTP security headers (no HSTS/CSP/XFO/etc.), placeholder meta tags and zero OpenGraph/Twitter/canonical/schema, no sitemap or web manifest, and a robots.txt that is a content-signals template with no actual signals or crawl rules. These are the priority remediations.
Each detection below is grounded in a verifiable code/header marker, not inference.
| Layer | Technology | Exact evidence (verbatim) |
|---|---|---|
| Build tool | Vite | __vite__mapDeps=(i,m=…) lazy-chunk map in index-Gtnzb6_b.js; [name]-[hash].js chunk naming; 33 modulepreload links |
| UI framework | React 18 + react-dom | react-dom.production, react.production, createRoot(document.getElementById("root")); root fiber __reactContainer$bj8h8ao86kr; window.__reactRouterVersion |
| Routing | React Router | react-router-dom, RouterProvider; route table path:"/events", element:jsx(pT,{}) |
| Styling | Tailwind CSS v4.1.5 | CSS banner /*! tailwindcss v4.1.5 | MIT License */; OKLCH tokens |
| Components | shadcn/ui (Radix) | Chunks dialog-…, popover-…, sidebar-wrapper-…; Radix-style tokens |
| Animation | Framer Motion | window.MotionIsMounted; chunk use-reduced-motion-… |
| Calendar | FullCalendar | Tokens --fc-button-bg-color:#2c3e50, --fc-event-border-color:#3788d8 |
| Backend | Hamanahel SaaS | config/index.json: "built_by_entity":"Hamanahel Software Solutions Pvt. Ltd." |
| Payments | Razorpay (gated) | Keys razorpay_key_id/razorpay_secret; OnlinePayment:false on public site |
| Analytics | CF Web Analytics | static.cloudflareinsights.com/beacon.min.js; POST /cdn-cgi/rum |
| Video | YouTube IFrame | Embed youtube.com/embed/UGZXzvTb60U |
| Hosting/CDN/DNS | Cloudflare | server: cloudflare; NS *.ns.cloudflare.com; MX route*.mx.cloudflare.net |
| Object storage | Cloudflare R2 | r2-pub.csidubai.com/tenant00002-ntaw-…/common_images/… |
| TLS / transport | TLS 1.3 + HTTP/2 + HTTP/3 | TLSv1.3 / AEAD-CHACHA20-POLY1305; ALPN h2; alt-svc: h3 |
| Compression | zstd | content-encoding: zstd on HTML/JS/CSS |
Explicitly NOT detected Next.js, Nuxt, Gatsby, Astro, Remix, Vue, Angular, SvelteKit, jQuery, WordPress, Drupal, Webflow, Wix, Squarespace, Google Analytics, GTM, Meta Pixel, Hotjar, Sentry, Stripe SDK. The site uses no analytics vendor besides Cloudflare Web Analytics and no third-party UI/fonts beyond YouTube.
The page is composed at runtime by a widget-type engine: a JSON tenant-config is fetched, then React renders a tree of typed widgets (Type5 = the tenant's chosen variant among several), each fetching its own data from the REST API.
| Step | Request | Purpose | Trigger |
|---|---|---|---|
| 1 | GET / | 1 KB HTML shell; cf-cache:HIT | Navigation |
| 2 | GET /assets/index-Gtnzb6_b.js (113 KB) | Vite entry; React + Router | HTML script type=module |
| 3 | GET /assets/index-Dw4T0NrO.css (22 KB) | Tailwind v4 stylesheet | HTML link rel=stylesheet |
| 4 | 33× link rel=modulepreload | Pre-fetch widget chunks | App bootstrap |
| 5 | GET /config/tenant/v3manifest.json | Cluster + tenant roster | App init |
| 6 | GET /config/index.json | Tenant config: flags, sections, wards, stats | App init |
| 7 | Widget chunks (HeaderType5, HeroType5, event-calendar-type-3…) | Lazy widget code | Router + config |
| 8 | GET /api/v3/content/update/list/news?page=1 | News list (empty) | News widget |
| 9 | GET /api/v3/content/event/list/upcoming-events?page=1 | Upcoming events (empty) | Events widget |
| 10 | GET /api/v3/content/event/by_date/month/2026-08 | Calendar month data | Calendar widget |
| 11 | 16× media from r2-pub.csidubai.com (AVIF/JPEG/PNG) | Logos, hero, gallery | Widget render |
| 12 | 10× images.unsplash.com (300×300) | Placeholder imagery | Gallery widget |
| 13 | YouTube embed UGZXzvTb60U | Welcome video + googleapis + doubleclick | Media widget |
| 14 | POST /cdn-cgi/rum (204) | Cloudflare RUM beacon | beacon.min.js |
The homepage is composed of 8 top-level semantic regions. Heading outline, images, and interactivity per region:
Logo, nav: Home · Who we are · Our Ministries · Media · Resources · Get in Touch. Dropdowns are Radix menus. Mobile: MobileHeaderType2.
Headline + tagline. No background image in computed styles — likely solid/gradient. No CTA on this variant.
Image 1024×768 (R2 JPEG) + body copy. Section heading variant SectionHeadingType3.
Service schedule cards. Icons via inline SVG (25 SVGs site-wide).
Audio player widget ("Go to next podcast"). <audio> element with controls.
Month grid (Aug 2026). Fetches /api/v3/content/event/by_date/month/2026-08. Currently empty.
10 Unsplash placeholders labeled "Office Inauguration / Team Building Workshop" — template defaults, not real photos. Content debt.
Form (name, email, submit) — method="get" action="/", non-functional placeholder. YouTube welcome-video iframe.
Address (Al Ghusais, PO Box 6365), motto, social links (fb/ig/tw/yt — all bare facebook.com), © 2026, "Developed by Hamanahel".
No <h1> on the page. First heading is an h2. Outline:
h2 CSI Parish (Malayalam) Dubai · Welcome… · Event Calendar · August 2026 · Get in Touch · Our Journeyh3 Services & Timings · Worship Portions · Podcasts · Our MissionOther a11y notes: html lang="en" ✓; images mostly have alt ✓; social links icon-only — fail name-keyboard-label; contact inputs have no <label>; tel:null/mailto:null invalid. 701 DOM nodes.
All observed XHR/fetch calls. The backend exposes a clean REST API v3 returning a uniform envelope {result, message, data, notifications, meta}. No auth tokens observed on the public homepage; member-only APIs (login, family, payments) live behind platform.csidubai.com / the accounts app and are not invoked here. Tip: tap any endpoint code to copy.
| Endpoint | Method | Status | Purpose | Auth | Cache |
|---|---|---|---|---|---|
/config/tenant/v3manifest.json | GET | 200 | Cluster + tenant roster | None · public | Edge HIT |
/config/index.json | GET | 200 | Tenant config: flags, sections, wards, stats, Razorpay, branding | None · public | Edge HIT |
/api/v3/content/update/list/news?page=1 | GET | 200 | News/updates list | None · public | revalidate |
/api/v3/content/event/list/upcoming-events?page=1 | GET | 200 | Upcoming events list | None · public | revalidate |
/api/v3/content/event/by_date/month/YYYY-MM | GET | 200 | Calendar month events | None · public | revalidate |
/cdn-cgi/rum | POST | 204 | Cloudflare RUM beacon | CF-internal | — |
googleapis.com/…/Waa/GenerateIT | POST | 200 | YouTube anti-abuse token | — | |
youtube.com/youtubei/v1/log_event | POST | 200 | YouTube playback telemetry | — |
/config/index.jsonmember_count: 990, family_count: 309 — disclosed publicly.mobile_app, family, accounts_app, gst, reports_group01/02, organisations, cheque, approval, outstation."razorpay_key_id":"razorpay_key_id" — not real secrets; server-side keyed separately. OnlinePayment:false.enable_whatsapp_code_01, enable_long_code_01, enable_email_otp_01, enforce_mobile_2fa — OTP/2FA flows in member app."built_by_entity":"Hamanahel Software Solutions Pvt. Ltd.".API design: uniform envelope. OPTIONS preflight returns 405 — backend doesn't handle CORS preflight (correct for same-origin SPA). No access-control-* emitted (closed posture). Pagination via meta.pagination.{total,current_page,last_page}.
| Host | Role | Requests | ~Transfer | Notes |
|---|---|---|---|---|
beta.csidubai.com | Origin (HTML, JS, CSS, API, config) | ~44 | ~360 KB | 34 JS chunks · 1 CSS · 3 JSON · 1 HTML · 6 XHR |
r2-pub.csidubai.com | Cloudflare R2 — tenant media | 6 | ~150 KB | Logos (PNG), hero (AVIF/JPEG). max-age=604800, HIT |
images.unsplash.com | Placeholder stock photos | 10 | ~250 KB | Template defaults, 300×300 |
www.youtube.com + ytimg | Welcome video embed | ~8 | ~120 KB | IFrame + player JS + thumbnail |
fonts.gstatic.com | Roboto woff2 | 1 | ~10 KB | Via YouTube player only |
googleads.g.doubleclick.net | YouTube ad-status | 2 | <2 KB | Side-effect of YouTube embed |
static.cloudflareinsights.com | CF Web Analytics beacon | 1 | ~2 KB | Privacy-friendly, cookieless |
| Asset | Type | Transfer | Duration |
|---|---|---|---|
/assets/index-Gtnzb6_b.js | JS (entry) | 113 KB | 50 ms |
/assets/OLDENGL-D1c84Ydg.TTF | Font (Old English) | 65 KB | 78 ms |
/assets/index-D7ZNyrf4.js | JS chunk | 60 KB | 23 ms |
/assets/proxy-gejbcCh0.js | JS chunk | 38 KB | 25 ms |
Unsplash photo-1556761175… | IMG | 37 KB | 88 ms |
Unsplash photo-1531482615713 | IMG | 31 KB | 83 ms |
Unsplash photo-1522071820081 | IMG | 29 KB | 77 ms |
Unsplash photo-1497215728101 | IMG | 27 KB | 64 ms |
Unsplash photo-1497366811353 | IMG | 26 KB | 76 ms |
/assets/index-Dw4T0NrO.css | CSS (Tailwind v4) | 22 KB | 35 ms |
sessionToken only. sessionStorage: empty. Cookies: none (CF RUM cookieless).OLDENGL-D1c84Ydg.TTF (Old English) via JS font-chunk — TTF not woff2, no font-display, no preload.Measured live in-browser (Chromium, broadband). Single run — directional, not a lab median.
*LCP entry absent in this run; treat 1.62 s FCP as practical time-to-content.
| Phase | Time | Note |
|---|---|---|
| DNS | — (cached) | Subsequent visit |
| TCP | 13 ms | QUIC fast-open |
| TLS | 13 ms | TLS 1.3 1-RTT |
| TTFB | 27 ms | Edge cache HIT |
| HTML transfer | 990 B | 690 B encoded / 1045 B decoded (zstd) |
| DOMContentLoaded | 175 ms | Shell + entry script |
| load | 175 ms | No heavy sync work |
Resource mix (61 requests, ~660 KB): JS 34 / 295 KB · Images 16 / 254 KB · CSS 1 / 65 KB · XHR 7 / 24 KB · Stylesheet 1 / 22 KB · iframe 1.
font-display:swap, preload only if above-fold.max-age=0, must-revalidate defeats long-term caching — set max-age=31536000, immutable for /assets/*.Transport and infra are strong; HTTP security headers are entirely absent — highest-priority remediation.
CN=csidubai.com, SAN beta.csidubai.com ✓, issuer Google Trust Services WE1, 90-day ACME (2026-07-17 → 2026-10-15).access-control-*; OPTIONS→405. Correct for same-origin SPA.nel/report-to expose CF telemetry endpoint group — harmless info disclosure.| Header | Status | Severity | Recommendation |
|---|---|---|---|
Strict-Transport-Security | absent | high | max-age=63072000; includeSubDomains; preload |
Content-Security-Policy | absent | high | Strict CSP: script-src 'self'; img-src 'self' https://r2-pub.csidubai.com https://images.unsplash.com; ... |
X-Content-Type-Options | absent | medium | nosniff |
X-Frame-Options | absent | medium | DENY or CSP frame-ancestors |
Referrer-Policy | absent | medium | strict-origin-when-cross-origin |
Permissions-Policy | absent | medium | Disable camera/mic/geo/payment if unused |
Cross-Origin-Opener-Policy | absent | medium | same-origin |
X-XSS-Protection | absent | good | Do NOT add — deprecated; rely on CSP |
Not Found in path list:<url> — normalise.990 members / 309 families. Reconsider for beta.null: tel:null, mailto:null, bare facebook.com.SEO surface essentially absent. CSR-only shell + broken deep links + no metadata + no sitemap → effectively non-indexable.
| Signal | Present? | Detail |
|---|---|---|
<title> | yes | CSI Parish (Malayalam) Dubai |
meta description | placeholder | CSI Parish (Malayalam) Dubai - Description |
OpenGraph (og:*) | none | No og:title/url/image/type |
| Twitter Card | none | — |
link rel=canonical | none | Duplicate-content risk with www |
| JSON-LD schema | none | Should ship Organization/Church/Event |
hreflang | none | Site is bilingual EN/Malayalam |
robots.txt | empty | Content-signals template, no rules, no Sitemap |
| Sitemap | none | /sitemap.xml 404s |
| Web manifest / PWA | none | No manifest, theme-color, apple-touch-icon |
<h1> | none | Page jumps to h2 |
lang | en only | Should declare lang="ml" on Malayalam passages |
| Icon | mismatch | type="image/svg+xml" on .png href |
Verified: curl https://beta.csidubai.com/events → 404, body Not Found in path list:…. Same for /pages/about, /updates, /sermons-grid. ~18 React Router routes — none work when opened directly, shared, or crawled. Only / and /contact-us resolve.
index.html for non-asset paths. Effort ~1 h.Edge returns 404 for all React Router paths except / and /contact-us. Breaks sharing, indexing, refresh-on-route.
_routes.json / Worker rewrite to index.html for non-asset paths. Effort ~1 h.No HSTS, CSP, X-Content-Type-Options, X-Frame-Options/frame-ancestors, Referrer-Policy, Permissions-Policy, COOP. TLS-1.3 + CF — but no application-layer hardening.
_headers. Effort ~2 h (CSP needs careful connect-src/img-src tuning for R2 + Unsplash + YouTube).Placeholder description, no OG/Twitter/canonical/JSON-LD, no sitemap, no <h1>, empty robots.txt.
Organization/Church JSON-LD; generate /sitemap.xml once SPA fallback is in place; real robots.txt. Effort ~1 day.All HTML/JS/CSS use public, max-age=0, must-revalidate. Hashed Vite assets are immutable — should cache for a year.
max-age=31536000, immutable for /assets/* via CF Cache Rules. Keep revalidate for / and /config/*.10 Unsplash photos labeled "Office Inauguration / Team Building Workshop", bare facebook.com social links, tel:null/mailto:null, contact form posting to /?. ~250 KB wasted.
/config/index.json + /config/tenant/v3manifest.json expose member counts, ward distributions, full tenant roster (12+ parishes, UUIDs, locations), internal feature-flag matrix.
Old English font as TTF (65 KB), no font-display; YouTube IFrame loads ~120 KB + doubleclick on first paint.
font-display:swap; YouTube facade, load real iframe on click.No manifest, theme-color, apple-touch-icon, or service worker. Mobile-heavy audience; platform ships native app per flags.
manifest.webmanifest + theme-color + basic offline-first SW. Effort ~0.5 day.access-control-*, OPTIONS→405).