First Init
Deploy to Production / Build & Verify (push) Failing after 5m56s
Ping Search Engines / Notify Search Engines (push) Successful in 2s
Deploy to Production / Pre-Deploy Tests (push) Has been skipped
Deploy to Production / Deploy to Railway (push) Has been skipped
Deploy to Production / Deploy to Render (push) Has been skipped
Deploy to Production / Deploy to VPS (PM2) (push) Has been skipped
Deploy to Production / Deploy to Fly.io (push) Has been skipped
Deploy to Production / Post-Deploy Verification (push) Has been skipped
Deploy to Production / Notify on Failure (push) Successful in 2s
E2E Test Suite / Critical User Journeys (push) Has been skipped
E2E Test Suite / API Integration Tests (push) Has been skipped
E2E Test Suite / Smoke Tests (P0) (push) Failing after 11m26s
E2E Test Suite / Form Interaction Tests (push) Failing after 11m42s
E2E Test Suite / Destructive & Chaos Tests (push) Failing after 12m2s
E2E Test Suite / Cross-Browser Regression (chromium) (push) Failing after 16m14s
E2E Test Suite / Cross-Browser Regression (webkit) (push) Failing after 17m45s
E2E Test Suite / Cross-Browser Regression (firefox) (push) Failing after 25m23s
E2E Test Suite / Security Header Tests (push) Failing after 7m55s
E2E Test Suite / Test Report Summary (push) Failing after 20s
E2E Test Suite / Mobile Device Tests (push) Failing after 2h49m9s
Uptime Monitor / Health & Response Time (push) Failing after 2s
Uptime Monitor / SSL Certificate (push) Successful in 2s
Uptime Monitor / Send Alerts (push) Failing after 3s
Uptime Monitor / Record Uptime Success (push) Has been skipped

This commit is contained in:
2026-03-21 16:46:46 +05:30
commit d402256547
216 changed files with 48375 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
Contact: mailto:security@workroot.in
Expires: 2027-01-01T00:00:00.000Z
Preferred-Languages: en
Canonical: https://workroot.in/.well-known/security.txt
Policy: https://workroot.in/security-policy
Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
<rect width="32" height="32" rx="6" fill="#0891b2"/>
<path d="M8 12L14 20L8 20" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M24 12L18 20L24 20" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="16" cy="16" r="2" fill="#f59e0b"/>
</svg>

After

Width:  |  Height:  |  Size: 410 B

+14
View File
@@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630" viewBox="0 0 1200 630">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#3B82F6;stop-opacity:1" />
<stop offset="100%" style="stop-color:#8B5CF6;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="1200" height="630" fill="url(#grad1)"/>
<circle cx="900" cy="150" r="200" fill="rgba(255,255,255,0.1)"/>
<circle cx="300" cy="500" r="150" fill="rgba(255,255,255,0.1)"/>
<text x="600" y="280" font-family="Arial, sans-serif" font-size="64" font-weight="bold" fill="white" text-anchor="middle">AI Transforming</text>
<text x="600" y="360" font-family="Arial, sans-serif" font-size="64" font-weight="bold" fill="white" text-anchor="middle">Business</text>
<text x="600" y="430" font-family="Arial, sans-serif" font-size="28" fill="rgba(255,255,255,0.9)" text-anchor="middle">Artificial Intelligence &amp; Machine Learning</text>
</svg>

After

Width:  |  Height:  |  Size: 997 B

+14
View File
@@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630" viewBox="0 0 1200 630">
<defs>
<linearGradient id="grad2" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#FF5D01;stop-opacity:1" />
<stop offset="100%" style="stop-color:#FF1639;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="1200" height="630" fill="url(#grad2)"/>
<circle cx="200" cy="150" r="100" fill="rgba(255,255,255,0.1)"/>
<circle cx="1000" cy="480" r="150" fill="rgba(255,255,255,0.1)"/>
<text x="600" y="280" font-family="Arial, sans-serif" font-size="64" font-weight="bold" fill="white" text-anchor="middle">Getting Started</text>
<text x="600" y="360" font-family="Arial, sans-serif" font-size="64" font-weight="bold" fill="white" text-anchor="middle">with Astro</text>
<text x="600" y="430" font-family="Arial, sans-serif" font-size="28" fill="rgba(255,255,255,0.9)" text-anchor="middle">Modern Web Framework for Fast Websites</text>
</svg>

After

Width:  |  Height:  |  Size: 992 B

+14
View File
@@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630" viewBox="0 0 1200 630">
<defs>
<linearGradient id="grad3" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#0EA5E9;stop-opacity:1" />
<stop offset="100%" style="stop-color:#06B6D4;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="1200" height="630" fill="url(#grad3)"/>
<circle cx="800" cy="200" r="180" fill="rgba(255,255,255,0.1)"/>
<circle cx="400" cy="450" r="120" fill="rgba(255,255,255,0.1)"/>
<text x="600" y="280" font-family="Arial, sans-serif" font-size="64" font-weight="bold" fill="white" text-anchor="middle">Cloud Migration</text>
<text x="600" y="360" font-family="Arial, sans-serif" font-size="64" font-weight="bold" fill="white" text-anchor="middle">Guide</text>
<text x="600" y="430" font-family="Arial, sans-serif" font-size="28" fill="rgba(255,255,255,0.9)" text-anchor="middle">Best Practices for Moving to the Cloud</text>
</svg>

After

Width:  |  Height:  |  Size: 986 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

+52
View File
@@ -0,0 +1,52 @@
{
"name": "WorkRoot IT Solutions",
"short_name": "WorkRoot",
"description": "Professional IT services including web development, cloud solutions, and digital transformation for businesses.",
"start_url": "/",
"display": "standalone",
"background_color": "#0f172a",
"theme_color": "#0891b2",
"orientation": "any",
"scope": "/",
"lang": "en-US",
"categories": ["business", "productivity"],
"icons": [
{
"src": "/apple-touch-icon.png",
"sizes": "180x180",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/favicon.svg",
"sizes": "any",
"type": "image/svg+xml",
"purpose": "any"
}
],
"screenshots": [
{
"src": "/og-image.jpg",
"sizes": "1200x630",
"type": "image/jpeg",
"label": "WorkRoot IT Solutions Homepage"
}
],
"shortcuts": [
{
"name": "Contact Us",
"short_name": "Contact",
"description": "Get in touch with our team",
"url": "/contact",
"icons": [{ "src": "/apple-touch-icon.png", "sizes": "180x180" }]
},
{
"name": "Our Services",
"short_name": "Services",
"description": "Explore our IT services",
"url": "/services",
"icons": [{ "src": "/apple-touch-icon.png", "sizes": "180x180" }]
}
],
"prefer_related_applications": false
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

+82
View File
@@ -0,0 +1,82 @@
# Robots.txt for WorkRoot IT Solutions
# https://workroot.in
# Default rules for all bots
User-agent: *
Allow: /
# Disallow admin and build directories
Disallow: /admin/
Disallow: /private/
Disallow: /_astro/
# Allow access to CSS and JS files for proper rendering
Allow: /*.css$
Allow: /*.js$
Allow: /*.webp$
Allow: /*.jpg$
Allow: /*.png$
Allow: /*.svg$
# Crawl-delay for polite crawling
Crawl-delay: 1
# Sitemap location
Sitemap: https://workroot.in/sitemap.xml
# Traditional Search Engines
User-agent: Googlebot
Allow: /
User-agent: Googlebot-Image
Allow: /
User-agent: Bingbot
Allow: /
User-agent: Slurp
Allow: /
User-agent: DuckDuckBot
Allow: /
User-agent: Baiduspider
Allow: /
User-agent: YandexBot
Allow: /
# Google AdSense Bot
User-agent: Mediapartners-Google
Allow: /
# AI Search Engines & LLM Crawlers (GEO Optimization)
# OpenAI/ChatGPT
User-agent: ChatGPT-User
Allow: /
User-agent: GPTBot
Allow: /
# Anthropic/Claude
User-agent: anthropic-ai
Allow: /
User-agent: Claude-Web
Allow: /
# Perplexity AI
User-agent: PerplexityBot
Allow: /
# Google Gemini/Bard
User-agent: Google-Extended
Allow: /
# Common Crawl (used by many AI models)
User-agent: CCBot
Allow: /
# Meta AI
User-agent: FacebookBot
Allow: /
+43
View File
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://workroot.in/</loc>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://workroot.in/about/</loc>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://workroot.in/services/</loc>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://workroot.in/portfolio/</loc>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://workroot.in/blog/</loc>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://workroot.in/contact/</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://workroot.in/privacy/</loc>
<changefreq>yearly</changefreq>
<priority>0.3</priority>
</url>
<url>
<loc>https://workroot.in/terms/</loc>
<changefreq>yearly</changefreq>
<priority>0.3</priority>
</url>
</urlset>
+247
View File
@@ -0,0 +1,247 @@
/**
* WorkRoot IT Solutions - Service Worker
* Implements:
* - Cache-first strategy for static assets
* - Stale-while-revalidate for HTML pages
* - Offline fallback page
* - Background sync for form submissions
*/
const CACHE_VERSION = 'v1';
const STATIC_CACHE = `workroot-static-${CACHE_VERSION}`;
const PAGE_CACHE = `workroot-pages-${CACHE_VERSION}`;
const SYNC_QUEUE = 'workroot-sync-queue';
// Static assets to pre-cache on install
const PRECACHE_ASSETS = [
'/',
'/offline',
'/manifest.json',
'/favicon.svg',
'/apple-touch-icon.png',
];
// Page routes to cache with stale-while-revalidate
const PAGE_ROUTES = [
'/',
'/about',
'/services',
'/portfolio',
'/contact',
'/blog',
'/privacy',
'/terms',
];
// ─── Install Event ────────────────────────────────────────────────────────────
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(STATIC_CACHE).then((cache) => {
return cache.addAll(PRECACHE_ASSETS);
}).then(() => self.skipWaiting())
);
});
// ─── Activate Event ───────────────────────────────────────────────────────────
self.addEventListener('activate', (event) => {
event.waitUntil(
Promise.all([
// Delete old caches
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames
.filter((name) => name.startsWith('workroot-') && name !== STATIC_CACHE && name !== PAGE_CACHE)
.map((name) => caches.delete(name))
);
}),
// Take control immediately
self.clients.claim(),
])
);
});
// ─── Fetch Event ──────────────────────────────────────────────────────────────
self.addEventListener('fetch', (event) => {
const { request } = event;
const url = new URL(request.url);
// Only handle same-origin requests
if (url.origin !== self.location.origin) return;
// Skip non-GET requests (POST etc. handled via background sync)
if (request.method !== 'GET') return;
// Skip API routes — always go to network
if (url.pathname.startsWith('/api/')) return;
// Static assets: cache-first
if (isStaticAsset(url.pathname)) {
event.respondWith(cacheFirst(request, STATIC_CACHE));
return;
}
// HTML pages: stale-while-revalidate with offline fallback
if (request.headers.get('Accept')?.includes('text/html')) {
event.respondWith(staleWhileRevalidate(request));
return;
}
});
// ─── Background Sync Event ───────────────────────────────────────────────────
self.addEventListener('sync', (event) => {
if (event.tag === 'form-sync') {
event.waitUntil(processSyncQueue());
}
});
// ─── Push Event (for future notifications) ──────────────────────────────────
self.addEventListener('push', (event) => {
if (!event.data) return;
const data = event.data.json();
event.waitUntil(
self.registration.showNotification(data.title || 'WorkRoot', {
body: data.body || '',
icon: '/apple-touch-icon.png',
badge: '/favicon.svg',
data: data.url ? { url: data.url } : undefined,
})
);
});
self.addEventListener('notificationclick', (event) => {
event.notification.close();
if (event.notification.data?.url) {
event.waitUntil(clients.openWindow(event.notification.data.url));
}
});
// ─── Strategy Helpers ─────────────────────────────────────────────────────────
function isStaticAsset(pathname) {
return (
pathname.startsWith('/_assets/') ||
/\.(js|css|woff2?|ttf|otf|eot|png|jpg|jpeg|gif|webp|avif|svg|ico)$/i.test(pathname)
);
}
async function cacheFirst(request, cacheName) {
const cache = await caches.open(cacheName);
const cached = await cache.match(request);
if (cached) return cached;
try {
const response = await fetch(request);
if (response.ok) {
cache.put(request, response.clone());
}
return response;
} catch {
return new Response('Asset unavailable offline', { status: 503 });
}
}
async function staleWhileRevalidate(request) {
const cache = await caches.open(PAGE_CACHE);
const cached = await cache.match(request);
const fetchPromise = fetch(request)
.then((response) => {
if (response.ok) {
cache.put(request, response.clone());
}
return response;
})
.catch(() => null);
if (cached) {
// Serve cached immediately, update in background
fetchPromise.catch(() => {});
return cached;
}
// No cache — await network
const response = await fetchPromise;
if (response) return response;
// Network failed and no cache — serve offline fallback
const offlineFallback = await cache.match('/offline') || await caches.match('/offline');
if (offlineFallback) return offlineFallback;
return new Response(
'<html><body><h1>You are offline</h1><p>Please check your connection.</p></body></html>',
{ status: 503, headers: { 'Content-Type': 'text/html' } }
);
}
// ─── Background Sync Queue ────────────────────────────────────────────────────
async function processSyncQueue() {
const db = await openDB();
const queue = await getAllFromDB(db, SYNC_QUEUE);
for (const item of queue) {
try {
const response = await fetch(item.url, {
method: item.method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(item.body),
});
if (response.ok) {
await deleteFromDB(db, SYNC_QUEUE, item.id);
// Notify any open clients of success
const clients = await self.clients.matchAll();
clients.forEach((client) => {
client.postMessage({ type: 'SYNC_SUCCESS', id: item.id, formType: item.formType });
});
}
} catch {
// Leave in queue for next sync attempt
}
}
}
// ─── IndexedDB Helpers ────────────────────────────────────────────────────────
function openDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open('workroot-pwa', 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(SYNC_QUEUE)) {
const store = db.createObjectStore(SYNC_QUEUE, { keyPath: 'id', autoIncrement: true });
store.createIndex('timestamp', 'timestamp', { unique: false });
}
};
request.onsuccess = (event) => resolve(event.target.result);
request.onerror = () => reject(request.error);
});
}
function getAllFromDB(db, storeName) {
return new Promise((resolve, reject) => {
const tx = db.transaction(storeName, 'readonly');
const store = tx.objectStore(storeName);
const request = store.getAll();
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
function deleteFromDB(db, storeName, id) {
return new Promise((resolve, reject) => {
const tx = db.transaction(storeName, 'readwrite');
const store = tx.objectStore(storeName);
const request = store.delete(id);
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
}