Website Technical Audit · Reverse-Engineering Report · 2026-08-05

beta.csidubai.com — Architecture & Technical Analysis

Target & Objective Perform a complete reverse-engineering and technical analysis of 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.

01Executive Summary

Entity
CSI Parish
(Malayalam) Dubai
Church · faith-based
Platform
Hamanahel
Church SaaS
multi-tenant · tenant #2
Frontend
React 18 + Vite
CSR SPA
Tailwind v4 · shadcn/ui
Infra
Cloudflare
full-stack
DNS · CDN · R2 · Email
Page weight
~660 KB
61 requests
34 JS · 16 img · 1 CSS
FCP
1.62 s
on broadband
CLS 0 · TBT 0 · h3

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.

02Technology Stack Detection

Each detection below is grounded in a verifiable code/header marker, not inference.

↔ swipe
LayerTechnologyExact evidence (verbatim)
Build toolVite__vite__mapDeps=(i,m=…) lazy-chunk map in index-Gtnzb6_b.js; [name]-[hash].js chunk naming; 33 modulepreload links
UI frameworkReact 18 + react-domreact-dom.production, react.production, createRoot(document.getElementById("root")); root fiber __reactContainer$bj8h8ao86kr; window.__reactRouterVersion
RoutingReact Routerreact-router-dom, RouterProvider; route table path:"/events", element:jsx(pT,{})
StylingTailwind CSS v4.1.5CSS banner /*! tailwindcss v4.1.5 | MIT License */; OKLCH tokens
Componentsshadcn/ui (Radix)Chunks dialog-…, popover-…, sidebar-wrapper-…; Radix-style tokens
AnimationFramer Motionwindow.MotionIsMounted; chunk use-reduced-motion-…
CalendarFullCalendarTokens --fc-button-bg-color:#2c3e50, --fc-event-border-color:#3788d8
BackendHamanahel SaaSconfig/index.json: "built_by_entity":"Hamanahel Software Solutions Pvt. Ltd."
PaymentsRazorpay (gated)Keys razorpay_key_id/razorpay_secret; OnlinePayment:false on public site
AnalyticsCF Web Analyticsstatic.cloudflareinsights.com/beacon.min.js; POST /cdn-cgi/rum
VideoYouTube IFrameEmbed youtube.com/embed/UGZXzvTb60U
Hosting/CDN/DNSCloudflareserver: cloudflare; NS *.ns.cloudflare.com; MX route*.mx.cloudflare.net
Object storageCloudflare R2r2-pub.csidubai.com/tenant00002-ntaw-…/common_images/…
TLS / transportTLS 1.3 + HTTP/2 + HTTP/3TLSv1.3 / AEAD-CHACHA20-POLY1305; ALPN h2; alt-svc: h3
Compressionzstdcontent-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.

03Architecture & Request Flow

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.

BROWSER HTML shell 1 KB · <div id=root> React 18 app index-Gtnzb6_b.js Widget tree Header/Hero/About… Tailwind v4 CSS index-Dw4T0NrO.css CF Web Analytics beacon.min.js CLOUDFLARE EDGE CDN cache cf-cache-status: HIT R2 public bucket r2-pub.csidubai.com Pages/Workers /assets · / · /config RUM collector /cdn-cgi/rum Email Routing route*.mx.cloudflare.net HAMANAHEL PLATFORM platform.csidubai.com Tenant config /config/index.json Tenant manifest /config/tenant/v3manifest.json Content API (v3) /api/v3/content/* Member DB / Auth 990 members · 309 families Razorpay gateway (gated on public site) THIRD-PARTY YouTube IFrame embed + googleapis Unsplash CDN placeholder imagery ui-avatars.com (manifest only) gstatic fonts Roboto (via YouTube) doubleclick (YouTube ad signal)
Figure 1 — Runtime composition: HTML shell → Vite app → widget tree, fed by tenant config + Content API; static media on R2; YouTube + Unsplash as the only external content dependencies.
Sequence: first paint → interactive (14 steps)
StepRequestPurposeTrigger
1GET /1 KB HTML shell; cf-cache:HITNavigation
2GET /assets/index-Gtnzb6_b.js (113 KB)Vite entry; React + RouterHTML script type=module
3GET /assets/index-Dw4T0NrO.css (22 KB)Tailwind v4 stylesheetHTML link rel=stylesheet
433× link rel=modulepreloadPre-fetch widget chunksApp bootstrap
5GET /config/tenant/v3manifest.jsonCluster + tenant rosterApp init
6GET /config/index.jsonTenant config: flags, sections, wards, statsApp init
7Widget chunks (HeaderType5, HeroType5, event-calendar-type-3…)Lazy widget codeRouter + config
8GET /api/v3/content/update/list/news?page=1News list (empty)News widget
9GET /api/v3/content/event/list/upcoming-events?page=1Upcoming events (empty)Events widget
10GET /api/v3/content/event/by_date/month/2026-08Calendar month dataCalendar widget
1116× media from r2-pub.csidubai.com (AVIF/JPEG/PNG)Logos, hero, galleryWidget render
1210× images.unsplash.com (300×300)Placeholder imageryGallery widget
13YouTube embed UGZXzvTb60UWelcome video + googleapis + doubleclickMedia widget
14POST /cdn-cgi/rum (204)Cloudflare RUM beaconbeacon.min.js

04Page Structure & DOM

The homepage is composed of 8 top-level semantic regions. Heading outline, images, and interactivity per region:

① Sticky Header

header.sticky · bg #F9F2E8

Logo, nav: Home · Who we are · Our Ministries · Media · Resources · Get in Touch. Dropdowns are Radix menus. Mobile: MobileHeaderType2.

② Hero ("Join us for worship")

HeroType5

Headline + tagline. No background image in computed styles — likely solid/gradient. No CTA on this variant.

③ About / Welcome

AboutUsType5

Image 1024×768 (R2 JPEG) + body copy. Section heading variant SectionHeadingType3.

④ Services & Worship

h3 "Services & Timings"

Service schedule cards. Icons via inline SVG (25 SVGs site-wide).

⑤ Podcasts

prayer-audio-type-5

Audio player widget ("Go to next podcast"). <audio> element with controls.

⑥ Event Calendar

event-calendar-type-3 · FullCalendar

Month grid (Aug 2026). Fetches /api/v3/content/event/by_date/month/2026-08. Currently empty.

⑦ Gallery / "Our Journey"

gallery-card-type-2

10 Unsplash placeholders labeled "Office Inauguration / Team Building Workshop" — template defaults, not real photos. Content debt.

⑧ Contact / Newsletter

contact-us-type-5

Form (name, email, submit) — method="get" action="/", non-functional placeholder. YouTube welcome-video iframe.

⑨ Footer

footer.bg-primaryColor

Address (Al Ghusais, PO Box 6365), motto, social links (fb/ig/tw/yt — all bare facebook.com), © 2026, "Developed by Hamanahel".

Heading outline & accessibility notes

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 Journey
  • h3 Services & Timings · Worship Portions · Podcasts · Our Mission

Other 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.

05API Analysis

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.

↔ swipe · tap code to copy
EndpointMethodStatusPurposeAuthCache
/config/tenant/v3manifest.jsonGET200Cluster + tenant rosterNone · publicEdge HIT
/config/index.jsonGET200Tenant config: flags, sections, wards, stats, Razorpay, brandingNone · publicEdge HIT
/api/v3/content/update/list/news?page=1GET200News/updates listNone · publicrevalidate
/api/v3/content/event/list/upcoming-events?page=1GET200Upcoming events listNone · publicrevalidate
/api/v3/content/event/by_date/month/YYYY-MMGET200Calendar month eventsNone · publicrevalidate
/cdn-cgi/rumPOST204Cloudflare RUM beaconCF-internal
googleapis.com/…/Waa/GenerateITPOST200YouTube anti-abuse tokenGoogle
youtube.com/youtubei/v1/log_eventPOST200YouTube playback telemetryGoogle
Notable config exposed by /config/index.json
  • Member stats: member_count: 990, family_count: 309 — disclosed publicly.
  • Geo structure: 12+ wards/areas across Sharjah, Ajman, Al Qusais, Al Nahda, Muhaisnah, Deira, Bur Dubai (per-area counts).
  • Feature flags: mobile_app, family, accounts_app, gst, reports_group01/02, organisations, cheque, approval, outstation.
  • Payment config placeholders: literal "razorpay_key_id":"razorpay_key_id" — not real secrets; server-side keyed separately. OnlinePayment:false.
  • Comms flags: enable_whatsapp_code_01, enable_long_code_01, enable_email_otp_01, enforce_mobile_2fa — OTP/2FA flows in member app.
  • Built-by: "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}.

06External Resources & File Inventory

By host

HostRoleRequests~TransferNotes
beta.csidubai.comOrigin (HTML, JS, CSS, API, config)~44~360 KB34 JS chunks · 1 CSS · 3 JSON · 1 HTML · 6 XHR
r2-pub.csidubai.comCloudflare R2 — tenant media6~150 KBLogos (PNG), hero (AVIF/JPEG). max-age=604800, HIT
images.unsplash.comPlaceholder stock photos10~250 KBTemplate defaults, 300×300
www.youtube.com + ytimgWelcome video embed~8~120 KBIFrame + player JS + thumbnail
fonts.gstatic.comRoboto woff21~10 KBVia YouTube player only
googleads.g.doubleclick.netYouTube ad-status2<2 KBSide-effect of YouTube embed
static.cloudflareinsights.comCF Web Analytics beacon1~2 KBPrivacy-friendly, cookieless

Largest assets (top 10)

AssetTypeTransferDuration
/assets/index-Gtnzb6_b.jsJS (entry)113 KB50 ms
/assets/OLDENGL-D1c84Ydg.TTFFont (Old English)65 KB78 ms
/assets/index-D7ZNyrf4.jsJS chunk60 KB23 ms
/assets/proxy-gejbcCh0.jsJS chunk38 KB25 ms
Unsplash photo-1556761175…IMG37 KB88 ms
Unsplash photo-1531482615713IMG31 KB83 ms
Unsplash photo-1522071820081IMG29 KB77 ms
Unsplash photo-1497215728101IMG27 KB64 ms
Unsplash photo-1497366811353IMG26 KB76 ms
/assets/index-Dw4T0NrO.cssCSS (Tailwind v4)22 KB35 ms
Storage, fonts, third-party SDKs, tracking pixels
  • localStorage: sessionToken only. sessionStorage: empty. Cookies: none (CF RUM cookieless).
  • IndexedDB / Service Worker / Web Worker: none. No offline/PWA.
  • Fonts: system stack only for UI. Single custom OLDENGL-D1c84Ydg.TTF (Old English) via JS font-chunk — TTF not woff2, no font-display, no preload.
  • Analytics: Cloudflare Web Analytics only — no GA, GTM, Meta Pixel, Hotjar, Clarity, Sentry.
  • Chat / payments SDKs: none on public site (Razorpay server-side gated).
  • Maps / CAPTCHA / A-B: none.
  • Source maps: none exposed.

07Performance Analysis

Measured live in-browser (Chromium, broadband). Single run — directional, not a lab median.

FCP
1.62 s
good (<1.8s)
LCP
n/a
not registered*
CLS
0.000
excellent
TBT
0 ms
0 long tasks
TTFB
27 ms
edge HIT · h3

*LCP entry absent in this run; treat 1.62 s FCP as practical time-to-content.

Connection / navigation timing & resource mix
↔ swipe
PhaseTimeNote
DNS— (cached)Subsequent visit
TCP13 msQUIC fast-open
TLS13 msTLS 1.3 1-RTT
TTFB27 msEdge cache HIT
HTML transfer990 B690 B encoded / 1045 B decoded (zstd)
DOMContentLoaded175 msShell + entry script
load175 msNo 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.

Recommendations

~250 KB of placeholder Unsplash imagery ships on first paint — replace, lazy-load below-fold rows.
Old English TTF (65 KB) render-blocking by inclusion — convert to woff2, add font-display:swap, preload only if above-fold.
YouTube IFrame ~120 KB + 8 requests + doubleclick — use facade (lite-youtube-embed), defer until click.
Cache policy on hashed assets: max-age=0, must-revalidate defeats long-term caching — set max-age=31536000, immutable for /assets/*.
CLS 0 and TBT 0 — layout stable, main thread unblocked.
HTTP/3 + zstd + edge HIT → 27 ms TTFB. Infra is not the bottleneck.

08Security Analysis

Transport and infra are strong; HTTP security headers are entirely absent — highest-priority remediation.

Transport & infrastructure sound

TLS 1.3 (AEAD-CHACHA20-POLY1305).
Cert CN=csidubai.com, SAN beta.csidubai.com ✓, issuer Google Trust Services WE1, 90-day ACME (2026-07-17 → 2026-10-15).
HTTP→HTTPS enforced (CF 301). No mixed content.
No origin-IP leak — fully proxied. No cookies on static docs.
CORS closed: no access-control-*; OPTIONS→405. Correct for same-origin SPA.
nel/report-to expose CF telemetry endpoint group — harmless info disclosure.

Security response headers attention

↔ swipe
HeaderStatusSeverityRecommendation
Strict-Transport-Securityabsenthighmax-age=63072000; includeSubDomains; preload
Content-Security-PolicyabsenthighStrict CSP: script-src 'self'; img-src 'self' https://r2-pub.csidubai.com https://images.unsplash.com; ...
X-Content-Type-Optionsabsentmediumnosniff
X-Frame-OptionsabsentmediumDENY or CSP frame-ancestors
Referrer-Policyabsentmediumstrict-origin-when-cross-origin
Permissions-PolicyabsentmediumDisable camera/mic/geo/payment if unused
Cross-Origin-Opener-Policyabsentmediumsame-origin
X-XSS-ProtectionabsentgoodDo NOT add — deprecated; rely on CSP

Other observations

404 body reflects user input: Not Found in path list:<url> — normalise.
Tenant manifest fully public: enumerates all 12+ parishes with UUIDs/locations.
Member stats + ward breakdown public: 990 members / 309 families. Reconsider for beta.
Social/contact hrefs are null: tel:null, mailto:null, bare facebook.com.
No CSRF tokens on contact form — but form is non-functional placeholder.
Razorpay secret field contains literal placeholder, not a real key.

09SEO, Social & PWA

SEO surface essentially absent. CSR-only shell + broken deep links + no metadata + no sitemap → effectively non-indexable.

↔ swipe
SignalPresent?Detail
<title>yesCSI Parish (Malayalam) Dubai
meta descriptionplaceholderCSI Parish (Malayalam) Dubai - Description
OpenGraph (og:*)noneNo og:title/url/image/type
Twitter Cardnone
link rel=canonicalnoneDuplicate-content risk with www
JSON-LD schemanoneShould ship Organization/Church/Event
hreflangnoneSite is bilingual EN/Malayalam
robots.txtemptyContent-signals template, no rules, no Sitemap
Sitemapnone/sitemap.xml 404s
Web manifest / PWAnoneNo manifest, theme-color, apple-touch-icon
<h1>nonePage jumps to h2
langen onlyShould declare lang="ml" on Malayalam passages
Iconmismatchtype="image/svg+xml" on .png href
CRITICAL

No SPA fallback — every deep link returns HTTP 404

Verified: curl https://beta.csidubai.com/events404, 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.

Fix: Cloudflare Pages/Workers rewrite to index.html for non-asset paths. Effort ~1 h.

10Consolidated Findings

CRITICAL

No SPA fallback (deep links 404 at origin)

Edge returns 404 for all React Router paths except / and /contact-us. Breaks sharing, indexing, refresh-on-route.

Remediate: Cloudflare Pages _routes.json / Worker rewrite to index.html for non-asset paths. Effort ~1 h.
HIGH

HTTP security headers completely absent

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.

Remediate: Cloudflare Transform Rule or origin _headers. Effort ~2 h (CSP needs careful connect-src/img-src tuning for R2 + Unsplash + YouTube).
HIGH

SEO surface absent

Placeholder description, no OG/Twitter/canonical/JSON-LD, no sitemap, no <h1>, empty robots.txt.

Remediate: real meta + OG/Twitter from tenant config; Organization/Church JSON-LD; generate /sitemap.xml once SPA fallback is in place; real robots.txt. Effort ~1 day.
MEDIUM

Cache policy defeats long-term caching

All HTML/JS/CSS use public, max-age=0, must-revalidate. Hashed Vite assets are immutable — should cache for a year.

Remediate: set max-age=31536000, immutable for /assets/* via CF Cache Rules. Keep revalidate for / and /config/*.
MEDIUM

Placeholder content shipped to a public beta

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.

Remediate: replace placeholders before promoting beta → production; wire contact form; configure social URLs.
MEDIUM

Public tenant config discloses operational detail

/config/index.json + /config/tenant/v3manifest.json expose member counts, ward distributions, full tenant roster (12+ parishes, UUIDs, locations), internal feature-flag matrix.

Remediate: split config into public branding slice + private admin slice (auth-gated), or redact counts/wards/flags.
LOW

Web font & YouTube loading strategy

Old English font as TTF (65 KB), no font-display; YouTube IFrame loads ~120 KB + doubleclick on first paint.

Remediate: TTF → woff2, preload + font-display:swap; YouTube facade, load real iframe on click.
LOW

No PWA / offline support

No manifest, theme-color, apple-touch-icon, or service worker. Mobile-heavy audience; platform ships native app per flags.

Remediate: add manifest.webmanifest + theme-color + basic offline-first SW. Effort ~0.5 day.

What is genuinely good

Modern, maintainable stack (React 18 + Vite + Tailwind v4 + shadcn/ui) with clean code-splitting (~150 lazy chunks).
Excellent perf baseline: CLS 0, TBT 0, FCP 1.62 s, 27 ms TTFB on HTTP/3 + zstd.
Cloudflare full-stack infra (DNS, CDN, R2, Email Routing, Web Analytics) — no origin-IP leak, TLS 1.3, IPv6.
Closed CORS posture (no access-control-*, OPTIONS→405).
Payment keys correctly server-side (Razorpay placeholder literals, not real secrets).
Privacy-positive telemetry: CF Web Analytics only — no GA, Meta Pixel, behavioural trackers.
Copied