veda-logic.com · 2 September 2026 · vl-web-audit v2.1 · Internal use only
| # | Category | Check Item | Status | Finding / Evidence | Screenshot | Recommendation | Owner | Priority | Effort |
|---|---|---|---|---|---|---|---|---|---|
| SEO / On-Page | |||||||||
| 1 | SEO | robots.txt valid and readable by crawlers | Fail | /robots.txt returns HTML page loading third-party JS from directfwd.com (2022 domain-parking script). content-type: text/html. Not a valid robots.txt. | Add Screenshot |
Delete current file. Create text/plain robots.txt: User-agent: * / Allow: / / Sitemap: https://veda-logic.com/sitemap.xml | DevOps | P0 | Quick Win |
| 2 | SEO | Meta title in server-rendered HTML | Fail | <title inertia>VL_HRM</title> — internal identifier. Correct title applied client-side only by React. Social crawlers see "VL_HRM". | Add Screenshot |
Inject correct <title> server-side from page.seo.title in Blade layout before Inertia renders | Developer | P1 | Medium |
| 3 | SEO | Meta description in server-rendered HTML | Fail | No <meta name="description"> in HTML source. Description exists in Inertia page.seo.description props but rendered only by JS. | Add Screenshot |
Render <meta name="description"> server-side from page.seo.description in Blade layout | Developer | P1 | Medium |
| 4 | SEO | Canonical tag present in HTML | Fail | canonical: null in all page.seo props. No <link rel="canonical"> in HTML. Duplicate URL variants may be indexed. | Add Screenshot |
Add <link rel="canonical"> server-side, defaulting to url()->current() if page.seo.canonical is null | Developer | P1 | Small |
| 5 | SEO | OG (Open Graph) meta tags in HTML | Fail | og_image: null. No og:title, og:description, og:image in server-rendered HTML. LinkedIn and WhatsApp shares show "VL_HRM" with no image. | Add Screenshot |
Add og:title, og:description, og:image, og:url server-side. Create 1200×630px og:image for each page template. | Developer / SEO | P1 | Medium |
| 6 | SEO | Twitter Card meta tags in HTML | Fail | No twitter:card, twitter:title, twitter:description, or twitter:image in HTML source | Add Screenshot |
Add twitter:card (summary_large_image), twitter:title, twitter:description server-side alongside OG tags | Developer | P1 | Small |
| 7 | SEO | XML sitemap present and accessible | OK | /sitemap.xml returns 200 with 27 URLs covering product, solutions, resources, pricing, demo, about, contact, security, why-vl-hrm | Add Screenshot |
No change needed. Reference sitemap from robots.txt once fixed. | — | P2 | Quick Win |
| 8 | SEO | Sitemap lastmod reflects actual content dates | Warn | All 27 URLs show lastmod of either 2026-07-14 or 2026-07-16 regardless of actual content updates | Add Screenshot |
Generate lastmod from CMS page updated_at timestamp dynamically | Developer | P2 | Small |
| 9 | SEO | Structured data (JSON-LD schema.org) | Fail | No JSON-LD detected on any page. No Organization, SoftwareApplication, FAQPage, or BreadcrumbList schema. | Add Screenshot |
Add Organization + SoftwareApplication JSON-LD to homepage. FAQPage to product pages. BreadcrumbList to all pages. | Developer / SEO | P2 | Small |
| 10 | SEO | hreflang (not applicable — single language) | N/A | Single-language (English) site. hreflang not required. | Add Screenshot |
No action required unless adding regional/language variants | — | P3 | Quick Win |
| Security | |||||||||
| 11 | Security | HTTP redirects to HTTPS | Fail | http://veda-logic.com/ returns HTTP/1.1 200 OK — no redirect. Plain-text access allowed. | Add Screenshot |
Add nginx port 80 server block: return 301 https://$host$request_uri; | DevOps | P0 | Quick Win |
| 12 | Security | HSTS (Strict-Transport-Security) header present | Fail | Strict-Transport-Security header absent from all responses | Add Screenshot |
Add after HTTPS redirect confirmed: Strict-Transport-Security: max-age=31536000; includeSubDomains | DevOps | P1 | Quick Win |
| 13 | Security | Content-Security-Policy header present | Fail | CSP header absent from all responses. No header-level XSS protection. | Add Screenshot |
Deploy Content-Security-Policy-Report-Only for 4–6 weeks. Promote to enforcing after clean reports. | DevOps | P1 | Small |
| 14 | Security | X-Frame-Options header | OK | x-frame-options: SAMEORIGIN — clickjacking protection present on all pages | Add Screenshot |
No change needed. CSP frame-ancestors can replace this when CSP is deployed. | — | P1 | Quick Win |
| 15 | Security | X-Content-Type-Options header | OK | x-content-type-options: nosniff — MIME sniffing protection present | Add Screenshot |
No change needed | — | P1 | Quick Win |
| 16 | Security | Referrer-Policy header | OK | referrer-policy: strict-origin-when-cross-origin — correct, modern value | Add Screenshot |
No change needed | — | P1 | Quick Win |
| 17 | Security | Permissions-Policy header | OK | permissions-policy: camera=(), microphone=(), geolocation=() — browser APIs correctly restricted | Add Screenshot |
No change needed. Good practice. | — | P1 | Quick Win |
| 18 | Security | X-XSS-Protection header not deprecated | Warn | x-xss-protection: 1; mode=block — deprecated since 2019; ignored by Chrome, Firefox, Edge | Add Screenshot |
Remove header (or set to 0). Deploy CSP (check #13) which provides real protection. | DevOps | P2 | Quick Win |
| 19 | Security | Server version not disclosed in response header | Fail | GET requests: server: nginx/1.29.8. HEAD requests: server: Apache. Version disclosed aids targeted CVE attacks. | Add Screenshot |
nginx: server_tokens off; Apache: ServerTokens Prod. Ensure both HEAD and GET are handled consistently. | DevOps | P1 | Quick Win |
| 20 | Security | Internal route map not exposed in public HTML | Fail | Ziggy serialises 200+ named routes to data-page attribute. Includes /install, /hr/employees, /api/media, /permissions, /email-templates, /_debugbar routes. Visible in any browser DevTools. | Add Screenshot |
Scope Ziggy config to marketing-only routes. Use config/ziggy.php 'only' array. Exclude admin, HR, API, installer, updater, debugbar. | Developer | P0 | Medium |
| 21 | Security | Laravel installer routes disabled in production | Fail | Routes /install, /install/environment, /install/database, /install/final, /update, /update/database registered in production route map. Routes redirect to /dashboard (installer guard active) but remain discoverable. | Add Screenshot |
Remove laravel-installer and laravel-updater packages from production composer.json. Add 403 middleware to /install/* as backstop. | Developer | P1 | Small |
| 22 | Security | Session cookie flags correct (secure, httponly, samesite) | OK | vl_hrm_session: secure; httponly; samesite=lax — all correct flags set. Session not readable by JS. | Add Screenshot |
No change needed. Good configuration. | — | P1 | Quick Win |
| Privacy / Legal | |||||||||
| 23 | Privacy | Privacy Policy page exists and is accessible | Fail | /privacy-policy returns HTTP 404. No privacy policy page exists on the site. | Add Screenshot |
Draft and publish Privacy Policy covering: data collected, purposes, DPDPA 2023 rights, third-party processors, contact. Legal review required. | Management / Legal | P1 | Medium |
| 24 | Privacy | Terms of Service page exists and is accessible | Fail | /terms returns HTTP 404. No terms of service page exists. | Add Screenshot |
Draft and publish Terms of Service. Enterprise prospects in regulated sectors require ToS before vendor onboarding. | Management / Legal | P1 | Medium |
| 25 | Privacy | Cookie consent mechanism | Missing | No cookie consent banner or mechanism detected. No analytics currently — lower immediate risk. Google Fonts request does transfer IP to Google. | Add Screenshot |
Implement before adding analytics. Disclose Google Fonts in Privacy Policy at minimum. | Developer | P1 | Small |
| 26 | Privacy | Google Fonts third-party request disclosed | Warn | fonts.googleapis.com loaded on every page — sends user IP to Google. Not disclosed anywhere (no Privacy Policy page). | Add Screenshot |
Self-host fonts after reducing to ≤ 2 families. Or disclose Google Fonts in Privacy Policy. | Developer | P2 | Small |
| Accessibility | |||||||||
| 27 | Accessibility | HTML lang attribute present | OK | <html lang="en"> present on all pages | Add Screenshot |
No change needed | — | P1 | Quick Win |
| 28 | Accessibility | Page title meaningful in HTML (not JS-only) | Fail | <title inertia>VL_HRM</title> — internal identifier. Screen readers and browser tabs show "VL_HRM" until JS executes. | Add Screenshot |
Render correct title server-side from page.seo.title in Blade layout | Developer | P1 | Small |
| 29 | Accessibility | WCAG 2.2 AA full audit completed | Warn | SPA rendering prevents external source-based assessment. Skip navigation, ARIA, contrast, focus management, and keyboard navigation not verifiable. | Add Screenshot |
Commission browser-based WCAG 2.2 AA audit: axe-core automated + manual keyboard + screen reader (NVDA + VoiceOver) | Developer / Designer | P2 | Medium |
| Performance | |||||||||
| 30 | Performance | Cache-Control headers set appropriately | Fail | cache-control: no-cache, private on all responses. x-proxy-cache: MISS confirms nginx caching layer bypassed. Every visit hits origin. | Add Screenshot |
HTML: max-age=300. Vite-hashed assets: max-age=31536000, immutable. Enable nginx proxy_cache for marketing GET requests. | DevOps | P1 | Small |
| 31 | Performance | Google Fonts load optimised (≤ 2 families) | Fail | Single stylesheet loads 12 font families: DM Sans, Inter, Poppins, Nunito, Roboto, Open Sans, Lato, Montserrat, Plus Jakarta Sans, Manrope, Syne, Material Symbols. Massive render-blocking payload. | Add Screenshot |
Audit CSS to find which families are actually applied. Reduce to ≤ 2. Self-host with font-display: swap. Use Material Symbols only if no lighter icon option exists. | Developer | P2 | Small |
| 32 | Performance | jQuery removed (redundant alongside React) | Warn | <script src="/js/jquery.min.js"> loaded alongside Inertia + React bundle. ~90 KB redundant dependency. | Add Screenshot |
Grep for $ and jQuery usage. Replace with native JS or React equivalents. Remove script tag from Blade layout. | Developer | P2 | Small |
| 33 | Performance | Vite content-hashed assets (cache invalidation ready) | OK | All build assets use content hashes (app-Cu5gOz5Z.css, app-D4YWebEo.js etc). Correct architecture for long-TTL caching once cache headers are set. | Add Screenshot |
No change to fingerprinting. Set max-age=31536000 immutable on build/assets/* (PERF-001) | — | P2 | Quick Win |
| 34 | Performance | Dark-mode CSS not loaded for light-mode users | Warn | dark-mode CSS preloaded unconditionally via <link rel="preload"> for all visitors regardless of system preference | Add Screenshot |
Add media="(prefers-color-scheme: dark)" to preload link. Light-mode users skip the download. | Developer | P3 | Small |
| Technology / CI / CD | |||||||||
| 35 | CI/CD | Server config (AWS/SMTP) not in public HTML | Fail | globalSettings in data-page includes: aws_access_key_id, aws_secret_access_key, aws_bucket, email_host, email_username. Currently empty/placeholder but pattern exposes any real values immediately. | Add Screenshot |
Implement PublicSettings::toArray() returning only UI keys. Never include AWS/SMTP/storage keys in Inertia shared props for public pages. | Developer | P0 | Medium |
| 36 | CI/CD | Server header consistent (HEAD vs GET) | Warn | HEAD → server: Apache. GET → server: nginx/1.29.8. Inconsistent response from same URL. | Add Screenshot |
Investigate nginx proxy_pass for HEAD vs GET handling. Ensure server_tokens off on both layers. Standardise all methods through nginx. | DevOps | P2 | Small |
| 37 | CI/CD | Footer copyright year current | Warn | footerText: "© 2025 VL HRM. All rights reserved." — one year behind (current: 2026) | Add Screenshot |
Update footerText in admin settings to 2026. Automate with current year in future. | Content | P3 | Quick Win |
| 38 | CI/CD | Web analytics tracking implemented | Missing | No GA4, GTM, Plausible, Mixpanel, or equivalent analytics detected in HTML source on any page | Add Screenshot |
Implement Plausible Analytics (DPDPA-friendly, no personal data) or GA4 with Consent Mode v2 before any marketing campaign. | Developer / Marketing | P2 | Small |