Compare commits
21
Commits
22251ea82e
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fccc0115c4 | ||
|
|
189260bbb3 | ||
|
|
8e7070cbaf | ||
|
|
a8d7db562d | ||
|
|
e220f46d35 | ||
|
|
93460ece19 | ||
|
|
7b67897612 | ||
|
|
c5f79f1fd2 | ||
|
|
41abcaa7a4 | ||
|
|
966f3b23fa | ||
|
|
45b30918a0 | ||
|
|
7eeec7e781 | ||
|
|
527131a462 | ||
|
|
6b07b83583 | ||
|
|
c7e130ce4d | ||
|
|
5a2b68763f | ||
|
|
84624976a8 | ||
|
|
a3dd4b9ffa | ||
|
|
0121641163 | ||
|
|
8d35785a4c | ||
|
|
c1585570c6 |
@@ -1,11 +1,11 @@
|
|||||||
# Graph Report - 2e709500-79ab-403f-9ca0-3f027ac9f36e (2026-06-19)
|
# Graph Report - 2e709500-79ab-403f-9ca0-3f027ac9f36e (2026-06-24)
|
||||||
|
|
||||||
## Corpus Check
|
## Corpus Check
|
||||||
- 61 files · ~611,807 words
|
- 64 files · ~615,668 words
|
||||||
- Verdict: corpus is large enough that graph structure adds value.
|
- Verdict: corpus is large enough that graph structure adds value.
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
- 596 nodes · 620 edges · 114 communities (87 shown, 27 thin omitted)
|
- 619 nodes · 640 edges · 117 communities (90 shown, 27 thin omitted)
|
||||||
- Extraction: 99% EXTRACTED · 1% INFERRED · 0% AMBIGUOUS · INFERRED: 4 edges (avg confidence: 0.8)
|
- Extraction: 99% EXTRACTED · 1% INFERRED · 0% AMBIGUOUS · INFERRED: 4 edges (avg confidence: 0.8)
|
||||||
- Token cost: 0 input · 0 output
|
- Token cost: 0 input · 0 output
|
||||||
|
|
||||||
@@ -50,9 +50,8 @@
|
|||||||
- [[_COMMUNITY_Community 34|Community 34]]
|
- [[_COMMUNITY_Community 34|Community 34]]
|
||||||
- [[_COMMUNITY_Community 35|Community 35]]
|
- [[_COMMUNITY_Community 35|Community 35]]
|
||||||
- [[_COMMUNITY_Community 36|Community 36]]
|
- [[_COMMUNITY_Community 36|Community 36]]
|
||||||
- [[_COMMUNITY_Community 41|Community 41]]
|
- [[_COMMUNITY_Community 37|Community 37]]
|
||||||
- [[_COMMUNITY_Community 42|Community 42]]
|
- [[_COMMUNITY_Community 38|Community 38]]
|
||||||
- [[_COMMUNITY_Community 43|Community 43]]
|
|
||||||
- [[_COMMUNITY_Community 44|Community 44]]
|
- [[_COMMUNITY_Community 44|Community 44]]
|
||||||
- [[_COMMUNITY_Community 45|Community 45]]
|
- [[_COMMUNITY_Community 45|Community 45]]
|
||||||
- [[_COMMUNITY_Community 46|Community 46]]
|
- [[_COMMUNITY_Community 46|Community 46]]
|
||||||
@@ -71,6 +70,9 @@
|
|||||||
- [[_COMMUNITY_Community 59|Community 59]]
|
- [[_COMMUNITY_Community 59|Community 59]]
|
||||||
- [[_COMMUNITY_Community 60|Community 60]]
|
- [[_COMMUNITY_Community 60|Community 60]]
|
||||||
- [[_COMMUNITY_Community 61|Community 61]]
|
- [[_COMMUNITY_Community 61|Community 61]]
|
||||||
|
- [[_COMMUNITY_Community 62|Community 62]]
|
||||||
|
- [[_COMMUNITY_Community 63|Community 63]]
|
||||||
|
- [[_COMMUNITY_Community 64|Community 64]]
|
||||||
|
|
||||||
## God Nodes (most connected - your core abstractions)
|
## God Nodes (most connected - your core abstractions)
|
||||||
1. `Performance Testing Scripts` - 12 edges
|
1. `Performance Testing Scripts` - 12 edges
|
||||||
@@ -94,7 +96,7 @@
|
|||||||
- `POST()` --calls--> `logApiRequest()` [INFERRED]
|
- `POST()` --calls--> `logApiRequest()` [INFERRED]
|
||||||
src/pages/api/newsletter.ts → src/utils/logger.ts
|
src/pages/api/newsletter.ts → src/utils/logger.ts
|
||||||
|
|
||||||
## Communities (114 total, 27 thin omitted)
|
## Communities (117 total, 27 thin omitted)
|
||||||
|
|
||||||
### Community 0 - "Community 0"
|
### Community 0 - "Community 0"
|
||||||
Cohesion: 0.05
|
Cohesion: 0.05
|
||||||
@@ -144,49 +146,49 @@ Nodes (11): Code Example, code:astro (---), code:javascript (// Traditional SPA:
|
|||||||
Cohesion: 0.18
|
Cohesion: 0.18
|
||||||
Nodes (10): code:hcl (# Define AWS EC2 instance), code:dockerfile (# Multi-stage build for a Go application), code:yaml (# AWS Cost allocation tags), Common Pitfalls, Conclusion, Containerization as a Migration Strategy, Cost Optimization Strategies, Infrastructure as Code (+2 more)
|
Nodes (10): code:hcl (# Define AWS EC2 instance), code:dockerfile (# Multi-stage build for a Go application), code:yaml (# AWS Cost allocation tags), Common Pitfalls, Conclusion, Containerization as a Migration Strategy, Cost Optimization Strategies, Infrastructure as Code (+2 more)
|
||||||
|
|
||||||
### Community 18 - "Community 18"
|
### Community 16 - "Community 16"
|
||||||
Cohesion: 0.43
|
Cohesion: 0.2
|
||||||
Nodes (6): trackCaseStudyView(), trackEvent(), trackExternalLink(), trackFormSubmit(), trackNewsletterSignup(), trackPortfolioFilter()
|
Nodes (9): Catalogue Listing vs Bidding: How You Actually Win, Common Reasons Software Vendors Get Rejected or Delayed, Document Checklist, Fees, Caution Money, and Timelines, Frequently Asked Questions, MSME and Startup Benefits Worth Claiming, Step-by-Step Registration Process, Turning GeM Access Into Government Contracts (+1 more)
|
||||||
|
|
||||||
### Community 19 - "Community 19"
|
### Community 18 - "Community 18"
|
||||||
Cohesion: 0.36
|
Cohesion: 0.22
|
||||||
Nodes (7): extract_scores(), get_issues(), main(), Run Lighthouse audit on a URL, Extract key scores from Lighthouse data, Extract issues from Lighthouse audit, run_lighthouse()
|
Nodes (8): 2026 Cost Ranges by Project Tier, A Simple Way to Estimate Your Own Cost, Build vs Buy: When Custom Actually Pays Off, Frequently Asked Questions, Getting an Accurate Number for Your Project, Hidden Costs Buyers Forget to Budget, The Biggest Cost Driver: The Team, What "Custom ERP" Actually Means for Pricing
|
||||||
|
|
||||||
### Community 20 - "Community 20"
|
### Community 20 - "Community 20"
|
||||||
Cohesion: 0.46
|
Cohesion: 0.43
|
||||||
Nodes (7): captureScreenshot(), ensureDir(), generateIndex(), main(), screenshotPath(), setTheme(), waitForPageReady()
|
Nodes (6): trackCaseStudyView(), trackEvent(), trackExternalLink(), trackFormSubmit(), trackNewsletterSignup(), trackPortfolioFilter()
|
||||||
|
|
||||||
### Community 21 - "Community 21"
|
### Community 21 - "Community 21"
|
||||||
Cohesion: 0.36
|
Cohesion: 0.36
|
||||||
Nodes (4): deleteFromDB(), getAllFromDB(), openDB(), processSyncQueue()
|
|
||||||
|
|
||||||
### Community 22 - "Community 22"
|
|
||||||
Cohesion: 0.43
|
|
||||||
Nodes (6): trackCaseStudyView(), trackEvent(), trackExternalLink(), trackFormSubmit(), trackNewsletterSignup(), trackPortfolioFilter()
|
|
||||||
|
|
||||||
### Community 23 - "Community 23"
|
|
||||||
Cohesion: 0.46
|
|
||||||
Nodes (7): checkRateLimit(), corsHeaders(), escapeHtml(), OPTIONS(), POST(), sendContactEmail(), validateContactForm()
|
|
||||||
|
|
||||||
### Community 24 - "Community 24"
|
|
||||||
Cohesion: 0.36
|
|
||||||
Nodes (7): extract_scores(), get_issues(), main(), Run Lighthouse audit on a URL, Extract key scores from Lighthouse data, Extract issues from Lighthouse audit, run_lighthouse()
|
Nodes (7): extract_scores(), get_issues(), main(), Run Lighthouse audit on a URL, Extract key scores from Lighthouse data, Extract issues from Lighthouse audit, run_lighthouse()
|
||||||
|
|
||||||
### Community 25 - "Community 25"
|
### Community 22 - "Community 22"
|
||||||
Cohesion: 0.46
|
Cohesion: 0.46
|
||||||
Nodes (7): captureScreenshot(), ensureDir(), generateIndex(), main(), screenshotPath(), setTheme(), waitForPageReady()
|
Nodes (7): captureScreenshot(), ensureDir(), generateIndex(), main(), screenshotPath(), setTheme(), waitForPageReady()
|
||||||
|
|
||||||
### Community 26 - "Community 26"
|
### Community 23 - "Community 23"
|
||||||
Cohesion: 0.36
|
Cohesion: 0.36
|
||||||
Nodes (4): deleteFromDB(), getAllFromDB(), openDB(), processSyncQueue()
|
Nodes (4): deleteFromDB(), getAllFromDB(), openDB(), processSyncQueue()
|
||||||
|
|
||||||
|
### Community 24 - "Community 24"
|
||||||
|
Cohesion: 0.46
|
||||||
|
Nodes (7): checkRateLimit(), corsHeaders(), escapeHtml(), OPTIONS(), POST(), sendContactEmail(), validateContactForm()
|
||||||
|
|
||||||
|
### Community 25 - "Community 25"
|
||||||
|
Cohesion: 0.43
|
||||||
|
Nodes (6): trackCaseStudyView(), trackEvent(), trackExternalLink(), trackFormSubmit(), trackNewsletterSignup(), trackPortfolioFilter()
|
||||||
|
|
||||||
|
### Community 26 - "Community 26"
|
||||||
|
Cohesion: 0.36
|
||||||
|
Nodes (7): extract_scores(), get_issues(), main(), Run Lighthouse audit on a URL, Extract key scores from Lighthouse data, Extract issues from Lighthouse audit, run_lighthouse()
|
||||||
|
|
||||||
### Community 27 - "Community 27"
|
### Community 27 - "Community 27"
|
||||||
Cohesion: 0.48
|
Cohesion: 0.46
|
||||||
Nodes (5): initAllAnimations(), initButtonRipple(), initCounters(), initProgressBars(), initScrollReveal()
|
Nodes (7): captureScreenshot(), ensureDir(), generateIndex(), main(), screenshotPath(), setTheme(), waitForPageReady()
|
||||||
|
|
||||||
### Community 28 - "Community 28"
|
### Community 28 - "Community 28"
|
||||||
Cohesion: 0.48
|
Cohesion: 0.36
|
||||||
Nodes (5): extractJsonLd(), main(), validateOpenGraph(), validatePage(), validateTwitterCard()
|
Nodes (4): deleteFromDB(), getAllFromDB(), openDB(), processSyncQueue()
|
||||||
|
|
||||||
### Community 29 - "Community 29"
|
### Community 29 - "Community 29"
|
||||||
Cohesion: 0.48
|
Cohesion: 0.48
|
||||||
@@ -197,23 +199,31 @@ Cohesion: 0.48
|
|||||||
Nodes (5): extractJsonLd(), main(), validateOpenGraph(), validatePage(), validateTwitterCard()
|
Nodes (5): extractJsonLd(), main(), validateOpenGraph(), validatePage(), validateTwitterCard()
|
||||||
|
|
||||||
### Community 31 - "Community 31"
|
### Community 31 - "Community 31"
|
||||||
Cohesion: 0.47
|
Cohesion: 0.48
|
||||||
Nodes (5): main(), measure_response_time(), print_stats(), Measure response time for a URL over multiple iterations, Print statistics for response times
|
Nodes (5): initAllAnimations(), initButtonRipple(), initCounters(), initProgressBars(), initScrollReveal()
|
||||||
|
|
||||||
|
### Community 32 - "Community 32"
|
||||||
|
Cohesion: 0.48
|
||||||
|
Nodes (5): extractJsonLd(), main(), validateOpenGraph(), validatePage(), validateTwitterCard()
|
||||||
|
|
||||||
### Community 33 - "Community 33"
|
### Community 33 - "Community 33"
|
||||||
Cohesion: 0.47
|
Cohesion: 0.47
|
||||||
Nodes (5): main(), measure_response_time(), print_stats(), Measure response time for a URL over multiple iterations, Print statistics for response times
|
Nodes (5): main(), measure_response_time(), print_stats(), Measure response time for a URL over multiple iterations, Print statistics for response times
|
||||||
|
|
||||||
### Community 35 - "Community 35"
|
### Community 35 - "Community 35"
|
||||||
|
Cohesion: 0.47
|
||||||
|
Nodes (5): main(), measure_response_time(), print_stats(), Measure response time for a URL over multiple iterations, Print statistics for response times
|
||||||
|
|
||||||
|
### Community 37 - "Community 37"
|
||||||
Cohesion: 0.6
|
Cohesion: 0.6
|
||||||
Nodes (3): formatUptime(), GET(), percentile()
|
Nodes (3): formatUptime(), GET(), percentile()
|
||||||
|
|
||||||
### Community 36 - "Community 36"
|
### Community 38 - "Community 38"
|
||||||
Cohesion: 0.6
|
Cohesion: 0.6
|
||||||
Nodes (3): formatUptime(), GET(), percentile()
|
Nodes (3): formatUptime(), GET(), percentile()
|
||||||
|
|
||||||
## Knowledge Gaps
|
## Knowledge Gaps
|
||||||
- **140 isolated node(s):** `Run Lighthouse audit on a URL`, `Extract key scores from Lighthouse data`, `Extract issues from Lighthouse audit`, `Measure response time for a URL over multiple iterations`, `Print statistics for response times` (+135 more)
|
- **156 isolated node(s):** `Run Lighthouse audit on a URL`, `Extract key scores from Lighthouse data`, `Extract issues from Lighthouse audit`, `Measure response time for a URL over multiple iterations`, `Print statistics for response times` (+151 more)
|
||||||
These have ≤1 connection - possible missing edges or undocumented components.
|
These have ≤1 connection - possible missing edges or undocumented components.
|
||||||
- **27 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
- **27 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||||
|
|
||||||
@@ -223,7 +233,7 @@ _Questions this graph is uniquely positioned to answer:_
|
|||||||
- **Are the 2 inferred relationships involving `captureException()` (e.g. with `sendContactEmail()` and `subscribeToNewsletter()`) actually correct?**
|
- **Are the 2 inferred relationships involving `captureException()` (e.g. with `sendContactEmail()` and `subscribeToNewsletter()`) actually correct?**
|
||||||
_`captureException()` has 2 INFERRED edges - model-reasoned connections that need verification._
|
_`captureException()` has 2 INFERRED edges - model-reasoned connections that need verification._
|
||||||
- **What connects `Run Lighthouse audit on a URL`, `Extract key scores from Lighthouse data`, `Extract issues from Lighthouse audit` to the rest of the system?**
|
- **What connects `Run Lighthouse audit on a URL`, `Extract key scores from Lighthouse data`, `Extract issues from Lighthouse audit` to the rest of the system?**
|
||||||
_140 weakly-connected nodes found - possible documentation gaps or missing edges._
|
_156 weakly-connected nodes found - possible documentation gaps or missing edges._
|
||||||
- **Should `Community 0` be split into smaller, more focused modules?**
|
- **Should `Community 0` be split into smaller, more focused modules?**
|
||||||
_Cohesion score 0.05 - nodes in this community are weakly interconnected._
|
_Cohesion score 0.05 - nodes in this community are weakly interconnected._
|
||||||
- **Should `Community 1` be split into smaller, more focused modules?**
|
- **Should `Community 1` be split into smaller, more focused modules?**
|
||||||
|
|||||||
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"nodes": [{"id": "home_agent_ai_agent_backend_workspace_2e709500_79ab_403f_9ca0_3f027ac9f36e_src_middleware_ts", "label": "middleware.ts", "file_type": "code", "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/middleware.ts", "source_location": "L1"}, {"id": "src_middleware_validatecsrforigin", "label": "validateCsrfOrigin()", "file_type": "code", "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/middleware.ts", "source_location": "L19"}], "edges": [{"source": "home_agent_ai_agent_backend_workspace_2e709500_79ab_403f_9ca0_3f027ac9f36e_src_middleware_ts", "target": "astro_middleware", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/middleware.ts", "source_location": "L1", "weight": 1.0}, {"source": "home_agent_ai_agent_backend_workspace_2e709500_79ab_403f_9ca0_3f027ac9f36e_src_middleware_ts", "target": "home_agent_ai_agent_backend_workspace_2e709500_79ab_403f_9ca0_3f027ac9f36e_src_utils_logger_ts", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/middleware.ts", "source_location": "L2", "weight": 1.0}, {"source": "home_agent_ai_agent_backend_workspace_2e709500_79ab_403f_9ca0_3f027ac9f36e_src_middleware_ts", "target": "utils_logger_logger", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/middleware.ts", "source_location": "L2", "weight": 1.0}, {"source": "home_agent_ai_agent_backend_workspace_2e709500_79ab_403f_9ca0_3f027ac9f36e_src_middleware_ts", "target": "home_agent_ai_agent_backend_workspace_2e709500_79ab_403f_9ca0_3f027ac9f36e_src_utils_sentry_ts", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/middleware.ts", "source_location": "L3", "weight": 1.0}, {"source": "home_agent_ai_agent_backend_workspace_2e709500_79ab_403f_9ca0_3f027ac9f36e_src_middleware_ts", "target": "utils_sentry_captureexception", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/middleware.ts", "source_location": "L3", "weight": 1.0}, {"source": "home_agent_ai_agent_backend_workspace_2e709500_79ab_403f_9ca0_3f027ac9f36e_src_middleware_ts", "target": "src_middleware_validatecsrforigin", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/middleware.ts", "source_location": "L19", "weight": 1.0}], "raw_calls": [{"caller_nid": "src_middleware_validatecsrforigin", "callee": "includes", "is_member_call": true, "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/middleware.ts", "source_location": "L24"}, {"caller_nid": "src_middleware_validatecsrforigin", "callee": "startsWith", "is_member_call": true, "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/middleware.ts", "source_location": "L25"}, {"caller_nid": "src_middleware_validatecsrforigin", "callee": "get", "is_member_call": true, "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/middleware.ts", "source_location": "L36"}, {"caller_nid": "src_middleware_validatecsrforigin", "callee": "get", "is_member_call": true, "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/middleware.ts", "source_location": "L37"}, {"caller_nid": "src_middleware_validatecsrforigin", "callee": "startsWith", "is_member_call": true, "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/middleware.ts", "source_location": "L52"}, {"caller_nid": "src_middleware_validatecsrforigin", "callee": "startsWith", "is_member_call": true, "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/middleware.ts", "source_location": "L52"}]}
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"nodes": [{"id": "home_agent_ai_agent_backend_workspace_2e709500_79ab_403f_9ca0_3f027ac9f36e_src_pages_sitemap_xml_ts", "label": "sitemap.xml.ts", "file_type": "code", "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/pages/sitemap.xml.ts", "source_location": "L1"}, {"id": "pages_sitemap_xml_get", "label": "GET()", "file_type": "code", "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/pages/sitemap.xml.ts", "source_location": "L13"}], "edges": [{"source": "home_agent_ai_agent_backend_workspace_2e709500_79ab_403f_9ca0_3f027ac9f36e_src_pages_sitemap_xml_ts", "target": "astro", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/pages/sitemap.xml.ts", "source_location": "L1", "weight": 1.0}, {"source": "home_agent_ai_agent_backend_workspace_2e709500_79ab_403f_9ca0_3f027ac9f36e_src_pages_sitemap_xml_ts", "target": "astro_content", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/pages/sitemap.xml.ts", "source_location": "L2", "weight": 1.0}, {"source": "home_agent_ai_agent_backend_workspace_2e709500_79ab_403f_9ca0_3f027ac9f36e_src_pages_sitemap_xml_ts", "target": "pages_sitemap_xml_get", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/pages/sitemap.xml.ts", "source_location": "L13", "weight": 1.0}], "raw_calls": [{"caller_nid": "pages_sitemap_xml_get", "callee": "getCollection", "is_member_call": false, "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/pages/sitemap.xml.ts", "source_location": "L15"}, {"caller_nid": "pages_sitemap_xml_get", "callee": "getCollection", "is_member_call": false, "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/pages/sitemap.xml.ts", "source_location": "L20"}, {"caller_nid": "pages_sitemap_xml_get", "callee": "map", "is_member_call": true, "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/pages/sitemap.xml.ts", "source_location": "L43"}, {"caller_nid": "pages_sitemap_xml_get", "callee": "map", "is_member_call": true, "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/pages/sitemap.xml.ts", "source_location": "L52"}, {"caller_nid": "pages_sitemap_xml_get", "callee": "join", "is_member_call": true, "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/pages/sitemap.xml.ts", "source_location": "L69"}, {"caller_nid": "pages_sitemap_xml_get", "callee": "map", "is_member_call": true, "source_file": "/home/agent/ai-agent/backend/workspace/2e709500-79ab-403f-9ca0-3f027ac9f36e/src/pages/sitemap.xml.ts", "source_location": "L69"}]}
|
||||||
File diff suppressed because one or more lines are too long
+697
-290
File diff suppressed because it is too large
Load Diff
@@ -58,6 +58,9 @@ Allow: /
|
|||||||
User-agent: GPTBot
|
User-agent: GPTBot
|
||||||
Allow: /
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: OAI-SearchBot
|
||||||
|
Allow: /
|
||||||
|
|
||||||
# Anthropic/Claude
|
# Anthropic/Claude
|
||||||
User-agent: anthropic-ai
|
User-agent: anthropic-ai
|
||||||
Allow: /
|
Allow: /
|
||||||
@@ -65,10 +68,22 @@ Allow: /
|
|||||||
User-agent: Claude-Web
|
User-agent: Claude-Web
|
||||||
Allow: /
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: ClaudeBot
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: Claude-SearchBot
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: Claude-User
|
||||||
|
Allow: /
|
||||||
|
|
||||||
# Perplexity AI
|
# Perplexity AI
|
||||||
User-agent: PerplexityBot
|
User-agent: PerplexityBot
|
||||||
Allow: /
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: Perplexity-User
|
||||||
|
Allow: /
|
||||||
|
|
||||||
# Google Gemini/Bard
|
# Google Gemini/Bard
|
||||||
User-agent: Google-Extended
|
User-agent: Google-Extended
|
||||||
Allow: /
|
Allow: /
|
||||||
@@ -80,3 +95,40 @@ Allow: /
|
|||||||
# Meta AI
|
# Meta AI
|
||||||
User-agent: FacebookBot
|
User-agent: FacebookBot
|
||||||
Allow: /
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: Meta-ExternalAgent
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: meta-externalagent
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
# Apple Intelligence
|
||||||
|
User-agent: Applebot
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: Applebot-Extended
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
# Amazon AI
|
||||||
|
User-agent: Amazonbot
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
# ByteDance / TikTok AI
|
||||||
|
User-agent: Bytespider
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
# Cohere AI
|
||||||
|
User-agent: cohere-ai
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
# DuckDuckGo AI (DuckAssist)
|
||||||
|
User-agent: DuckAssistBot
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
# You.com AI
|
||||||
|
User-agent: YouBot
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
# Diffbot (knowledge graph / AI training)
|
||||||
|
User-agent: Diffbot
|
||||||
|
Allow: /
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
/*!
|
||||||
|
* WRNexus Web Push — service worker.
|
||||||
|
*
|
||||||
|
* ┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
* │ HOST THIS FILE ON YOUR OWN ORIGIN. │
|
||||||
|
* │ │
|
||||||
|
* │ A service worker can only control the origin it is served from, so the │
|
||||||
|
* │ browser will NOT let wrnexus.com register a worker for your site. Copy │
|
||||||
|
* │ this file to the ROOT of your site and serve it at: │
|
||||||
|
* │ │
|
||||||
|
* │ https://your-domain.example/wrnexus-push-sw.js │
|
||||||
|
* │ │
|
||||||
|
* │ It must be served same-origin, over HTTPS, with │
|
||||||
|
* │ `Content-Type: text/javascript`. To control the whole site from a │
|
||||||
|
* │ non-root path, also send `Service-Worker-Allowed: /`. │
|
||||||
|
* └─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
*
|
||||||
|
* Core behaviour needs NO configuration — the click/delivery tracking URLs are
|
||||||
|
* carried inside each push payload built by the WRNexus API. The optional
|
||||||
|
* CONFIG block below is only used to silently re-subscribe after the browser
|
||||||
|
* rotates a subscription (`pushsubscriptionchange`); leave it blank to skip
|
||||||
|
* that.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable no-restricted-globals */
|
||||||
|
|
||||||
|
// ── OPTIONAL: only needed for automatic re-subscription on key rotation ──────
|
||||||
|
var WRNEXUS_PUSH_CONFIG = {
|
||||||
|
// Your site's publicKey (the same value as data-site-id in the snippet).
|
||||||
|
siteKey: '',
|
||||||
|
// The WRNexus API origin (e.g. 'https://api.wrnexus.com').
|
||||||
|
apiBase: '',
|
||||||
|
// Your site's VAPID public key (shown in Push → Settings).
|
||||||
|
vapidPublicKey: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
self.addEventListener('install', function () {
|
||||||
|
self.skipWaiting();
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('activate', function (event) {
|
||||||
|
event.waitUntil(self.clients.claim());
|
||||||
|
});
|
||||||
|
|
||||||
|
// CORS-simple POST (text/plain, no custom headers, no credentials) so the
|
||||||
|
// receipt reaches the WRNexus API cross-origin without a preflight.
|
||||||
|
function postReceipt(url) {
|
||||||
|
if (!url) return Promise.resolve();
|
||||||
|
return fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'text/plain;charset=UTF-8' },
|
||||||
|
credentials: 'omit',
|
||||||
|
keepalive: true,
|
||||||
|
mode: 'cors',
|
||||||
|
}).catch(function () {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function urlBase64ToUint8Array(base64String) {
|
||||||
|
var padding = '='.repeat((4 - (base64String.length % 4)) % 4);
|
||||||
|
var base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
|
||||||
|
var raw = self.atob(base64);
|
||||||
|
var out = new Uint8Array(raw.length);
|
||||||
|
for (var i = 0; i < raw.length; ++i) out[i] = raw.charCodeAt(i);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyToB64(buf) {
|
||||||
|
if (!buf) return '';
|
||||||
|
var bytes = new Uint8Array(buf);
|
||||||
|
var binary = '';
|
||||||
|
for (var i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
||||||
|
return self
|
||||||
|
.btoa(binary)
|
||||||
|
.replace(/\+/g, '-')
|
||||||
|
.replace(/\//g, '_')
|
||||||
|
.replace(/=+$/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Incoming notification ─────────────────────────────────────────────────
|
||||||
|
self.addEventListener('push', function (event) {
|
||||||
|
var data = {};
|
||||||
|
try {
|
||||||
|
data = event.data ? event.data.json() : {};
|
||||||
|
} catch (_e) {
|
||||||
|
try {
|
||||||
|
data = { title: event.data && event.data.text() };
|
||||||
|
} catch (_e2) {
|
||||||
|
data = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var title = data.title || 'Notification';
|
||||||
|
var options = {
|
||||||
|
body: data.body || '',
|
||||||
|
icon: data.icon || undefined,
|
||||||
|
image: data.image || undefined,
|
||||||
|
badge: data.badge || undefined,
|
||||||
|
tag: data.tag || data.campaignId || undefined,
|
||||||
|
requireInteraction: !!data.requireInteraction,
|
||||||
|
data: {
|
||||||
|
clickUrl: data.clickUrl || data.url || '/',
|
||||||
|
url: data.url || '/',
|
||||||
|
openUrl: data.openUrl || '',
|
||||||
|
campaignId: data.campaignId || '',
|
||||||
|
subscriptionId: data.subscriptionId || '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
event.waitUntil(
|
||||||
|
Promise.all([
|
||||||
|
self.registration.showNotification(title, options),
|
||||||
|
// Delivery receipt — records a `delivered` event for analytics.
|
||||||
|
postReceipt(data.deliveredUrl),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ── Click → record + open the destination ─────────────────────────────────
|
||||||
|
self.addEventListener('notificationclick', function (event) {
|
||||||
|
var d = (event.notification && event.notification.data) || {};
|
||||||
|
event.notification.close();
|
||||||
|
|
||||||
|
// `clickUrl` is a signed WRNexus redirect: hitting it records the `clicked`
|
||||||
|
// event and 302s to the real destination, so tracking fires from the open.
|
||||||
|
var target = d.clickUrl || d.url || '/';
|
||||||
|
|
||||||
|
event.waitUntil(
|
||||||
|
self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then(function (list) {
|
||||||
|
// Reuse an existing tab on the destination when possible.
|
||||||
|
for (var i = 0; i < list.length; i++) {
|
||||||
|
var client = list[i];
|
||||||
|
if (d.url && client.url === d.url && 'focus' in client) return client.focus();
|
||||||
|
}
|
||||||
|
if (self.clients.openWindow) return self.clients.openWindow(target);
|
||||||
|
return undefined;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ── Optional: re-subscribe after the browser rotates the subscription ──────
|
||||||
|
self.addEventListener('pushsubscriptionchange', function (event) {
|
||||||
|
var cfg = WRNEXUS_PUSH_CONFIG || {};
|
||||||
|
if (!cfg.siteKey || !cfg.apiBase || !cfg.vapidPublicKey) return;
|
||||||
|
event.waitUntil(
|
||||||
|
self.registration.pushManager
|
||||||
|
.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(cfg.vapidPublicKey) })
|
||||||
|
.then(function (sub) {
|
||||||
|
return fetch(cfg.apiBase.replace(/\/+$/, '') + '/api/push/subscriptions', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'text/plain;charset=UTF-8' },
|
||||||
|
credentials: 'omit',
|
||||||
|
mode: 'cors',
|
||||||
|
body: JSON.stringify({
|
||||||
|
key: cfg.siteKey,
|
||||||
|
endpoint: sub.endpoint,
|
||||||
|
keys: {
|
||||||
|
p256dh: keyToB64(sub.getKey('p256dh')),
|
||||||
|
auth: keyToB64(sub.getKey('auth')),
|
||||||
|
},
|
||||||
|
metadata: { source: 'pushsubscriptionchange' },
|
||||||
|
}),
|
||||||
|
}).catch(function () {});
|
||||||
|
})
|
||||||
|
.catch(function () {})
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -166,6 +166,23 @@ const currentYear = new Date().getFullYear();
|
|||||||
By subscribing, you agree to our
|
By subscribing, you agree to our
|
||||||
<a href="/privacy" class="text-primary hover:underline">Privacy Policy</a>.
|
<a href="/privacy" class="text-primary hover:underline">Privacy Policy</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<!-- Web push opt-in (WRNexus). User-gesture subscribe control.
|
||||||
|
Hidden by default; the client script below reveals it only when the
|
||||||
|
WRNexus SDK + browser push support are available, and sets the
|
||||||
|
correct label based on the visitor's current subscription state. -->
|
||||||
|
<button
|
||||||
|
id="wrnexus-subscribe"
|
||||||
|
type="button"
|
||||||
|
hidden
|
||||||
|
aria-label="Enable notifications"
|
||||||
|
class="mt-6 w-full px-4 py-3 bg-secondary-800 border border-secondary-700 text-white font-medium rounded-lg hover:bg-secondary-700 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 focus:ring-offset-secondary-900 transition-all duration-200 text-sm flex items-center justify-center gap-2 disabled:opacity-60 disabled:cursor-not-allowed"
|
||||||
|
>
|
||||||
|
<svg class="w-4 h-4 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
|
||||||
|
</svg>
|
||||||
|
<span id="wrnexus-subscribe-label">Enable notifications</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -193,6 +210,106 @@ const currentYear = new Date().getFullYear();
|
|||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- WRNexus push subscribe: state-aware control wired via addEventListener
|
||||||
|
(Astro strips inline on* handlers). The button reflects whether the
|
||||||
|
visitor is already subscribed and lets them toggle the subscription. -->
|
||||||
|
<script is:inline>
|
||||||
|
(function () {
|
||||||
|
function init() {
|
||||||
|
var btn = document.getElementById('wrnexus-subscribe');
|
||||||
|
var label = document.getElementById('wrnexus-subscribe-label');
|
||||||
|
if (!btn || !label) return;
|
||||||
|
|
||||||
|
var push = window.WRNexusPush;
|
||||||
|
var supported =
|
||||||
|
push &&
|
||||||
|
'Notification' in window &&
|
||||||
|
'serviceWorker' in navigator &&
|
||||||
|
'PushManager' in window;
|
||||||
|
|
||||||
|
// No SDK or no browser push support: keep the button hidden entirely.
|
||||||
|
if (!supported) {
|
||||||
|
btn.hidden = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permission permanently blocked by the user: the SDK can't re-prompt,
|
||||||
|
// so surface a clear, non-actionable disabled state instead of a button
|
||||||
|
// that silently does nothing.
|
||||||
|
if (window.Notification && Notification.permission === 'denied') {
|
||||||
|
label.textContent = 'Notifications blocked';
|
||||||
|
btn.setAttribute('aria-label', 'Notifications are blocked in your browser settings');
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.hidden = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the button for a given subscription state.
|
||||||
|
// Default UX: subscribed users get an actionable "Unsubscribe" toggle
|
||||||
|
// rather than a dead "Already subscribed" label.
|
||||||
|
// (Alternative: render a disabled "Already subscribed" indicator instead
|
||||||
|
// of the Unsubscribe toggle if product prefers a non-actionable state.)
|
||||||
|
function render(subscribed) {
|
||||||
|
if (subscribed) {
|
||||||
|
label.textContent = 'Unsubscribe';
|
||||||
|
btn.setAttribute('aria-label', 'Unsubscribe from notifications');
|
||||||
|
} else {
|
||||||
|
label.textContent = 'Enable notifications';
|
||||||
|
btn.setAttribute('aria-label', 'Enable notifications');
|
||||||
|
}
|
||||||
|
btn.dataset.subscribed = subscribed ? 'true' : 'false';
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.hidden = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function refresh() {
|
||||||
|
try {
|
||||||
|
var subscribed = await push.isSubscribed();
|
||||||
|
render(!!subscribed);
|
||||||
|
} catch (err) {
|
||||||
|
// On error, fall back to the unsubscribed label so the control stays usable.
|
||||||
|
console.error('[wrnexus-push] isSubscribed() failed:', err);
|
||||||
|
render(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.addEventListener('click', async function () {
|
||||||
|
if (btn.disabled) return;
|
||||||
|
|
||||||
|
var wasSubscribed = btn.dataset.subscribed === 'true';
|
||||||
|
var busyLabel = wasSubscribed ? 'Unsubscribing…' : 'Enabling…';
|
||||||
|
|
||||||
|
// In-progress state to prevent double-clicks while the promise is pending.
|
||||||
|
btn.disabled = true;
|
||||||
|
label.textContent = busyLabel;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (wasSubscribed) {
|
||||||
|
await push.unsubscribe();
|
||||||
|
} else {
|
||||||
|
// prompt() must run from this real user gesture.
|
||||||
|
await push.prompt();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[wrnexus-push] toggle failed:', err);
|
||||||
|
} finally {
|
||||||
|
// Re-read the authoritative state and re-render the label.
|
||||||
|
await refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Determine and render the initial state.
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', init);
|
||||||
|
} else {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { trackNewsletterSignup } from '../utils/analytics';
|
import { trackNewsletterSignup } from '../utils/analytics';
|
||||||
|
|
||||||
|
|||||||
@@ -18,61 +18,68 @@
|
|||||||
// - Keyboard: native <button> handles Enter & Space; Tab moves between
|
// - Keyboard: native <button> handles Enter & Space; Tab moves between
|
||||||
// items. No custom key handling needed.
|
// items. No custom key handling needed.
|
||||||
|
|
||||||
|
// Each answer is written as a definitive, self-contained paragraph: it can be
|
||||||
|
// read (or quoted) in isolation without the question for context, and the
|
||||||
|
// buyer-stage answers bundle the WorkRoot name with the canonical numbers
|
||||||
|
// (founded 2022 · 20+ projects · 11+ districts · 50,000+ records · 99.9%
|
||||||
|
// uptime · GeM · IIT Patna). Keep every figure identical to <ProofNumbers />
|
||||||
|
// and the homepage `companyFacts` set — the visible text below is also the
|
||||||
|
// source for the FAQPage JSON-LD emitted at the bottom of this component.
|
||||||
const moneyFaqs = [
|
const moneyFaqs = [
|
||||||
{
|
{
|
||||||
question: 'How much does a project cost? Do you work with fixed budgets?',
|
question: 'How much does a project cost? Do you work with fixed budgets?',
|
||||||
answer:
|
answer:
|
||||||
'Projects start from ₹1,00,000, and most web, mobile, and ERP builds land between ₹2L and ₹15L depending on scope. And yes — we work with fixed budgets: tell us the number you have in mind and we will scope what we can deliver within it. Every quote is free, itemised, and no-obligation.',
|
'WorkRoot IT Solutions projects start from ₹1,00,000, and most web, mobile, and ERP builds land between ₹2,00,000 and ₹15,00,000 depending on scope. Yes — we work with fixed budgets: tell us the number you have in mind and we will scope exactly what we can deliver within it. Every quote is free, itemised, and carries no obligation.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'How much does a custom ERP cost?',
|
question: 'How much does a custom ERP cost?',
|
||||||
answer:
|
answer:
|
||||||
'Typical engagements run ₹2L–₹15L depending on scope. We offer fixed-price options for well-defined projects and time-and-materials for evolving ones.',
|
'A custom ERP from WorkRoot IT Solutions typically runs ₹2,00,000–₹15,00,000, with a genuinely production-grade single-department system starting around ₹6,00,000. We offer fixed-price quotes for well-defined scopes and time-and-materials pricing for evolving ones, and every estimate is free and itemised.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'What is your typical timeline?',
|
question: 'What is your typical timeline?',
|
||||||
answer:
|
answer:
|
||||||
'4–16 weeks from kickoff to launch. MVPs ship in ~6 weeks on average.',
|
'Most WorkRoot IT Solutions engagements run 4–16 weeks from kickoff to launch, and a typical MVP ships in about 6 weeks. We work in 2-week sprints with a live staging environment from day one, so you see and steer working software early rather than waiting for a single big-bang release.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'Do you sign NDAs?',
|
question: 'Do you sign NDAs?',
|
||||||
answer:
|
answer:
|
||||||
'Yes — happily. We sign mutual NDAs before any detailed discussion.',
|
'Yes. WorkRoot IT Solutions signs a mutual NDA before any detailed discussion of your idea, data, or codebase — at no cost and with no conditions attached. Your concept and commercial details stay confidential from the very first call.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'Who owns the source code?',
|
question: 'Who owns the source code?',
|
||||||
answer:
|
answer:
|
||||||
'You do. Full IP transfer is included; we hand over repositories, deployment access, and documentation.',
|
'You do. Every WorkRoot IT Solutions engagement includes full intellectual-property transfer on delivery: you receive the complete source repositories, deployment access, and documentation, with no per-seat licence fees and no vendor lock-in. You are free to host, extend, or hand the system to another team at any time.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'Do you work with government tenders / GeM?',
|
question: 'Do you work with government tenders / GeM?',
|
||||||
answer:
|
answer:
|
||||||
"Yes. We're empanelled for relevant categories and have delivered platforms used across 11 districts in Bihar.",
|
'Yes. WorkRoot IT Solutions is empanelled on the Government e-Marketplace (GeM) for relevant IT service categories and can respond to government tenders. We have delivered public-service platforms live across 11+ districts of Bihar at 99.9% uptime, including a Police Management System and a Smart Crematorium Management System for the Bihar Government.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'What technologies do you work with?',
|
question: 'What technologies do you work with?',
|
||||||
answer:
|
answer:
|
||||||
'Astro, Next.js, Angular, React Native, Spring Boot, Go, Node.js, PostgreSQL, and the full AWS/GCP stack.',
|
'WorkRoot IT Solutions builds on Astro, Next.js, Angular, and React Native on the front end; Spring Boot, Go, and Node.js on the back end; and PostgreSQL or MySQL for data — the same stack behind the IIT Patna University Management System and our multi-district government deployments, all deployed and operated on the AWS and GCP cloud.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'Do you offer ongoing support after launch?',
|
question: 'Do you offer ongoing support after launch?',
|
||||||
answer:
|
answer:
|
||||||
'Yes. We offer maintenance packages covering bug fixes, security patches, performance monitoring, and feature enhancements — with response SLAs to match your uptime needs.',
|
'Yes. WorkRoot IT Solutions offers maintenance packages covering bug fixes, security patches, performance monitoring, and feature enhancements, each with a response SLA matched to your uptime needs — the same operational discipline that keeps our government systems running at 99.9% uptime.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'What is your development process?',
|
question: 'What is your development process?',
|
||||||
answer:
|
answer:
|
||||||
'Agile with 2-week sprints, weekly check-ins, and a live staging environment from day one. You see working software early and steer the roadmap as it ships.',
|
'WorkRoot IT Solutions works in Agile 2-week sprints with weekly check-ins and a live staging environment from day one. You see working software early and steer the roadmap as it ships, rather than waiting for a single final handover at the end of the project.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'Can you work with our existing team?',
|
question: 'Can you work with our existing team?',
|
||||||
answer:
|
answer:
|
||||||
'Absolutely. We augment in-house teams as readily as we deliver fully managed builds — adapting to your repo, branch strategy, ticket system, and review process.',
|
'Absolutely. WorkRoot IT Solutions augments in-house teams as readily as it delivers fully managed builds, adapting to your repository, branch strategy, ticketing system, and code-review process so we slot into the way your team already works.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
question: 'How do you ensure project security?',
|
question: 'How do you ensure project security?',
|
||||||
answer:
|
answer:
|
||||||
'Security is built into every phase: OWASP-aligned reviews, encrypted data at rest and in transit, role-based access control, regular dependency audits, and compliance with GDPR / SOC 2-style controls where the project demands them.',
|
'Security is built into every phase at WorkRoot IT Solutions: OWASP-aligned code reviews, encrypted data at rest and in transit, role-based access control, regular dependency audits, and GDPR- and SOC 2-style controls where a project demands them. The same architecture secures a Bihar government police platform deployed across 11 districts.',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -40,12 +40,12 @@ interface Props {
|
|||||||
// credibility bug this set was created to fix.
|
// credibility bug this set was created to fix.
|
||||||
//
|
//
|
||||||
// - "20+ Projects" — total delivered engagements
|
// - "20+ Projects" — total delivered engagements
|
||||||
// - "11 Districts Deployed" — matches hero trust badge copy
|
// - "11+ Districts Deployed" — cumulative Bihar government district reach
|
||||||
// - "50,000+ Records Managed" — records under management across deployments
|
// - "50,000+ Records Managed" — records under management across deployments
|
||||||
// - "8+ Years Avg Experience" — average team experience
|
// - "8+ Years Avg Experience" — average team experience
|
||||||
const defaultItems: ProofItem[] = [
|
const defaultItems: ProofItem[] = [
|
||||||
{ value: '20+', label: 'Projects' },
|
{ value: '20+', label: 'Projects' },
|
||||||
{ value: '11', label: 'Districts Deployed' },
|
{ value: '11+', label: 'Districts Deployed' },
|
||||||
{ value: '50,000+', label: 'Records Managed' },
|
{ value: '50,000+', label: 'Records Managed' },
|
||||||
{ value: '8+', label: 'Years Avg Experience' },
|
{ value: '8+', label: 'Years Avg Experience' },
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ const orgId = `${baseUrl}/#organization`;
|
|||||||
// src/pages/index.astro). All three are 5★, so the aggregate rating is 5.0
|
// src/pages/index.astro). All three are 5★, so the aggregate rating is 5.0
|
||||||
// over reviewCount = 3.
|
// over reviewCount = 3.
|
||||||
//
|
//
|
||||||
// Headline proof numbers in the description (20+ projects · 11 districts ·
|
// Headline proof numbers in the description (20+ projects · 11+ districts ·
|
||||||
// 50,000+ records · 99.9% uptime) mirror the canonical set in
|
// 50,000+ records · 99.9% uptime) mirror the canonical set in
|
||||||
// ProofNumbers.astro and the /services stats — keep them identical site-wide.
|
// ProofNumbers.astro and the /services stats — keep them identical site-wide.
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -102,7 +102,7 @@ const organizationSchema = {
|
|||||||
"height": "512"
|
"height": "512"
|
||||||
},
|
},
|
||||||
"image": `${baseUrl}/og-image.jpg`,
|
"image": `${baseUrl}/og-image.jpg`,
|
||||||
"description": "WorkRoot IT Solutions LLP builds production-grade web, mobile, ERP, and government IT systems — 20+ projects delivered across 11 districts, 50,000+ records managed, and 99.9% uptime on mission-critical government deployments.",
|
"description": "WorkRoot IT Solutions LLP builds production-grade web, mobile, ERP, and government IT systems — 20+ projects delivered across 11+ districts, 50,000+ records managed, and 99.9% uptime on mission-critical government deployments.",
|
||||||
"foundingDate": "2022",
|
"foundingDate": "2022",
|
||||||
"founder": {
|
"founder": {
|
||||||
"@type": "Person",
|
"@type": "Person",
|
||||||
@@ -238,7 +238,7 @@ const blogPostingSchema = article && type === 'BlogPosting' ? {
|
|||||||
"dateModified": article.dateModified || article.datePublished,
|
"dateModified": article.dateModified || article.datePublished,
|
||||||
"publisher": {
|
"publisher": {
|
||||||
"@type": "Organization",
|
"@type": "Organization",
|
||||||
"name": "WorkRoot IT Solutions",
|
"name": "WorkRoot IT Solutions LLP",
|
||||||
"url": baseUrl,
|
"url": baseUrl,
|
||||||
"logo": {
|
"logo": {
|
||||||
"@type": "ImageObject",
|
"@type": "ImageObject",
|
||||||
@@ -298,7 +298,7 @@ const webPageSchema = type === 'WebPage' && Astro.url.pathname !== '/' ? {
|
|||||||
},
|
},
|
||||||
"about": {
|
"about": {
|
||||||
"@type": "Organization",
|
"@type": "Organization",
|
||||||
"name": "WorkRoot IT Solutions"
|
"name": "WorkRoot IT Solutions LLP"
|
||||||
},
|
},
|
||||||
"primaryImageOfPage": {
|
"primaryImageOfPage": {
|
||||||
"@type": "ImageObject",
|
"@type": "ImageObject",
|
||||||
@@ -330,7 +330,7 @@ const aboutPageSchema = type === 'AboutPage' ? {
|
|||||||
"inLanguage": "en-US",
|
"inLanguage": "en-US",
|
||||||
"mainEntity": {
|
"mainEntity": {
|
||||||
"@type": "Organization",
|
"@type": "Organization",
|
||||||
"name": "WorkRoot IT Solutions",
|
"name": "WorkRoot IT Solutions LLP",
|
||||||
"url": baseUrl
|
"url": baseUrl
|
||||||
}
|
}
|
||||||
} : null;
|
} : null;
|
||||||
@@ -345,8 +345,8 @@ const contactPageSchema = type === 'ContactPage' ? {
|
|||||||
"inLanguage": "en-US",
|
"inLanguage": "en-US",
|
||||||
"mainEntity": {
|
"mainEntity": {
|
||||||
"@type": "LocalBusiness",
|
"@type": "LocalBusiness",
|
||||||
"name": "WorkRoot IT Solutions",
|
"name": "WorkRoot IT Solutions LLP",
|
||||||
"alternateName": "WorkRoot IT Solutions LLP",
|
"alternateName": "WorkRoot IT Solutions",
|
||||||
"url": baseUrl,
|
"url": baseUrl,
|
||||||
"telephone": "+91-9561417403",
|
"telephone": "+91-9561417403",
|
||||||
"email": "admin@workroot.in",
|
"email": "admin@workroot.in",
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
---
|
||||||
|
title: "GeM Empanelment Process for Software Vendors: A Step-by-Step 2026 Guide"
|
||||||
|
description: "A complete, India-specific walkthrough of how software and IT-services vendors get listed and sell on the Government e-Marketplace (GeM) — registration steps, document checklist, fees, timelines, and how the bidding process actually works."
|
||||||
|
seoTitle: "GeM Empanelment for Software Vendors (2026)"
|
||||||
|
seoDescription: "Step-by-step guide to GeM registration and empanelment for software vendors in India — documents, fees, timelines, OEM panel, bids vs catalogue, and common rejection reasons."
|
||||||
|
pubDate: 2026-06-19
|
||||||
|
heroImage: "/images/blog/govt-systems.jpg"
|
||||||
|
category: "Web Development"
|
||||||
|
tags: ["GeM", "Government IT", "Vendor Registration", "Public Procurement", "India", "Software Services"]
|
||||||
|
author:
|
||||||
|
name: "Ajay"
|
||||||
|
avatar: "/images/team/ajay.jpg"
|
||||||
|
draft: false
|
||||||
|
---
|
||||||
|
|
||||||
|
The Government e-Marketplace (GeM) is the single largest channel for selling software and IT services to Indian government bodies — central ministries, state departments, PSUs, and autonomous institutions all procure through it. If you build custom software, mobile apps, or IT services and you are not on GeM, you are invisible to a buyer base that spends tens of thousands of crores a year. This guide explains exactly how a software vendor gets onto GeM, what it costs, how long it takes, and how to actually win business once you are listed.
|
||||||
|
|
||||||
|
One clarification up front: GeM does not use the word "empanelment" the way traditional government tenders do. On GeM you **register as a Seller** and then **publish offerings** (products or, for software companies, *services*). When people say "GeM empanelment for software vendors," they mean getting your company registered, verified, and listed so government buyers can find and buy from you. We use both terms interchangeably below.
|
||||||
|
|
||||||
|
## Who Should Register: Product Vendor vs Service Provider
|
||||||
|
|
||||||
|
Software companies usually fit one or both of these seller types, and the distinction matters because the catalogue, documents, and bidding flow differ.
|
||||||
|
|
||||||
|
| Seller Type | What You Sell on GeM | Typical Software Company Fit |
|
||||||
|
|-------------|----------------------|------------------------------|
|
||||||
|
| **Product Seller** | Listed goods with a catalogue (e.g., software licences, devices) | Off-the-shelf software, SaaS licences, hardware bundles |
|
||||||
|
| **Service Provider** | Service categories with rate-card / bid-based pricing | Custom development, IT manpower, AMC, cloud, web design |
|
||||||
|
| **OEM** | Original manufacturer with an OEM panel | Companies whose own software product is resold by others |
|
||||||
|
|
||||||
|
Most custom-software firms register primarily as **Service Providers** under categories like "Software Development Services," "Web Site Design & Development," "IT Professional Outsourcing," and "Custom Bid for Services."
|
||||||
|
|
||||||
|
## Step-by-Step Registration Process
|
||||||
|
|
||||||
|
The end-to-end flow from sign-up to your first live listing typically looks like this:
|
||||||
|
|
||||||
|
1. **Create a Primary User account** on gem.gov.in using your business email and the Aadhaar or PAN of the authorised signatory. The primary user is legally the organisation's representative.
|
||||||
|
2. **Select your organisation type** — Proprietorship, Partnership, LLP, Private Limited, etc. This determines which constitution documents you upload.
|
||||||
|
3. **Complete organisation verification** by linking your **Udyam (MSME) registration** or **CIN**, and validating your **PAN** and **GSTIN**.
|
||||||
|
4. **Add your business profile** — office address, bank account (for payments), and authorised signatory details.
|
||||||
|
5. **Complete the GeM seller assessment** where applicable (especially for OEMs and certain service categories).
|
||||||
|
6. **List your offerings** — choose the right service category, fill the technical parameters, upload your rate card / documents, and publish.
|
||||||
|
7. **Set up the Caution Money / e-PBG** mechanism if you intend to bid on higher-value tenders (more below).
|
||||||
|
|
||||||
|
### Document Checklist
|
||||||
|
|
||||||
|
Have these ready before you start — missing or mismatched documents are the number-one cause of delay:
|
||||||
|
|
||||||
|
- PAN of the organisation and the authorised signatory
|
||||||
|
- GSTIN certificate
|
||||||
|
- Udyam (MSME) registration certificate (strongly recommended — unlocks exemptions)
|
||||||
|
- Constitution proof (Certificate of Incorporation / Partnership Deed / GST for proprietorship)
|
||||||
|
- Cancelled cheque or bank account proof matching the registered name
|
||||||
|
- Authorised signatory's Aadhaar (for e-sign / OTP verification)
|
||||||
|
- Income Tax Return acknowledgements (often needed to clear turnover-based bid criteria)
|
||||||
|
- Relevant certifications (ISO, CMMI, CERT-In) if your target tenders demand them
|
||||||
|
|
||||||
|
## Fees, Caution Money, and Timelines
|
||||||
|
|
||||||
|
A frequent question: *is GeM registration free?* Basic seller registration on GeM is **free**. The costs come later, when you transact.
|
||||||
|
|
||||||
|
| Item | 2026 Cost (Indicative) | Notes |
|
||||||
|
|------|------------------------|-------|
|
||||||
|
| Seller registration | ₹0 | No registration fee |
|
||||||
|
| Caution Money Deposit (CMD) | ₹5,000 – ₹25,000 | Slab-based on annual GeM turnover; refundable |
|
||||||
|
| Transaction charge | ~0.30% – 0.45% of order value | Levied on the seller above a threshold per order |
|
||||||
|
| e-PBG / EMD for bids | 2%–3% of bid value (often exempt for MSME) | Tender-specific; bid security |
|
||||||
|
|
||||||
|
**Timeline:** with documents in order, organisation verification typically completes in **3–7 working days**, and you can publish your first listing the same week. In practice, factoring in document corrections and category approvals, most software vendors are live and bid-ready in **2–4 weeks**.
|
||||||
|
|
||||||
|
## Catalogue Listing vs Bidding: How You Actually Win
|
||||||
|
|
||||||
|
Getting listed is necessary but not sufficient. There are three ways government buyers actually buy from you on GeM, and your strategy should target the right one.
|
||||||
|
|
||||||
|
| Mode | How It Works | Best For |
|
||||||
|
|------|-------------|----------|
|
||||||
|
| **Direct Purchase** | Buyer purchases directly up to ₹25,000 (or category limit) | Small, fast, low-value services |
|
||||||
|
| **L1 / Comparison** | Buyer compares listed sellers and picks lowest qualifying price | Standard, well-defined service offerings |
|
||||||
|
| **Bid / Reverse Auction** | Formal tender with eligibility criteria; sellers bid | High-value custom projects and AMCs |
|
||||||
|
|
||||||
|
For custom software and ERP work, the **Bid / Reverse Auction** route is where the meaningful contracts live. A buyer publishes a bid with eligibility criteria (turnover, past performance, certifications), and registered sellers submit technical and financial bids. Reverse auctions then drive the price down to the lowest qualifying bidder, so your win depends on meeting eligibility *and* pricing intelligently — not just being cheapest.
|
||||||
|
|
||||||
|
## MSME and Startup Benefits Worth Claiming
|
||||||
|
|
||||||
|
If you are an MSME or a DPIIT-recognised startup, GeM gives you real, money-saving advantages that you should activate during registration:
|
||||||
|
|
||||||
|
- **Exemption from prior turnover and prior experience** criteria in many bids (under the Public Procurement Policy for MSEs).
|
||||||
|
- **EMD / bid-security exemption** in a large share of tenders.
|
||||||
|
- **Reserved procurement** — a mandated share of government purchases is earmarked for MSEs.
|
||||||
|
- **No registration fee** and reduced caution-money slabs.
|
||||||
|
|
||||||
|
Linking your Udyam registration during onboarding is what unlocks these — skipping it leaves money and eligibility on the table.
|
||||||
|
|
||||||
|
## Common Reasons Software Vendors Get Rejected or Delayed
|
||||||
|
|
||||||
|
Avoid these and you will clear verification on the first attempt:
|
||||||
|
|
||||||
|
- **Name mismatches** across PAN, GST, bank account, and Udyam — every record must match exactly.
|
||||||
|
- **Wrong service category** — listing under a category that does not match your offering causes buyer-side rejection.
|
||||||
|
- **Incomplete technical parameters** in the service listing, so buyers cannot find or compare you.
|
||||||
|
- **Not meeting turnover/experience eligibility** in a bid (and not claiming MSME exemption when eligible).
|
||||||
|
- **Outdated documents** — an expired GST or unrenewed Udyam certificate stalls everything.
|
||||||
|
|
||||||
|
## Frequently Asked Questions
|
||||||
|
|
||||||
|
**Is GeM registration mandatory to sell to the government?**
|
||||||
|
For most central and state government procurement of available goods and services, yes — buyers are directed to procure through GeM. If your offering exists on GeM, being registered is effectively required to compete.
|
||||||
|
|
||||||
|
**How long does GeM registration take for a software company?**
|
||||||
|
Organisation verification typically completes in 3–7 working days. Allowing for document corrections and category approvals, most software vendors are live and bid-ready within 2–4 weeks.
|
||||||
|
|
||||||
|
**Does it cost money to register on GeM?**
|
||||||
|
Basic seller registration is free. Costs arise later: a refundable caution-money deposit (₹5,000–₹25,000 by turnover slab), a small per-order transaction charge, and bid-specific securities (often waived for MSMEs).
|
||||||
|
|
||||||
|
**Can a startup or MSME sell on GeM without prior government experience?**
|
||||||
|
Yes. Under the MSE procurement policy and startup provisions, many bids exempt MSMEs and DPIIT-recognised startups from prior turnover and experience requirements — but you must link your Udyam/DPIIT registration to claim it.
|
||||||
|
|
||||||
|
**What's the difference between being listed and winning a contract?**
|
||||||
|
Listing makes you visible. Winning happens through Direct Purchase (small value), L1 comparison, or Bid/Reverse Auction (high value). For custom software and ERP contracts, you win by qualifying on eligibility criteria and competing in the bid — listing alone generates very few orders.
|
||||||
|
|
||||||
|
**Which categories should a custom software firm register under?**
|
||||||
|
Common fits include Software Development Services, Web Site Design & Development, IT Professional Outsourcing / Manpower, Cloud Services, and "Custom Bid for Services" for non-standard scopes. Register under every category that genuinely matches your delivery capability.
|
||||||
|
|
||||||
|
## Turning GeM Access Into Government Contracts
|
||||||
|
|
||||||
|
Registration is the entry ticket; winning is a discipline. The vendors who succeed on GeM keep their documents current, list under precise categories, claim every MSME benefit they qualify for, and price their bids with the reverse-auction dynamic in mind. WorkRoot has delivered software for Indian government bodies — including police and university systems across multiple states — and we understand both the procurement process and the engineering bar it demands. If you want help positioning for government IT work, [get in touch](/contact).
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
---
|
||||||
|
title: "How Much Does Custom ERP Cost in India? (2026 Pricing Guide)"
|
||||||
|
description: "A transparent, India-specific breakdown of what a custom ERP actually costs in 2026 — by scope, team, and deployment model — with real rupee ranges, a cost calculator framework, and hidden costs to budget for."
|
||||||
|
seoTitle: "Custom ERP Cost in India (2026 Guide)"
|
||||||
|
seoDescription: "What does a custom ERP cost in India in 2026? Real rupee ranges by scope and team, a cost-driver breakdown, build-vs-buy maths, and hidden costs to plan for."
|
||||||
|
pubDate: 2026-06-19
|
||||||
|
heroImage: "/images/blog/erp-systems.jpg"
|
||||||
|
category: "Web Development"
|
||||||
|
tags: ["ERP", "Custom Software", "Pricing", "India", "Enterprise", "Cost Estimation"]
|
||||||
|
author:
|
||||||
|
name: "Ajay"
|
||||||
|
avatar: "/images/team/ajay.jpg"
|
||||||
|
draft: false
|
||||||
|
---
|
||||||
|
|
||||||
|
"How much will it cost?" is the first question every buyer asks about custom ERP — and the honest answer is "it depends." But "it depends" is not a number you can put in a budget. So in this guide we turn the question into something usable: what a custom ERP actually costs in India in 2026, what drives those numbers up or down, and how to estimate your own project before you talk to a single vendor.
|
||||||
|
|
||||||
|
The short version: a focused single-department custom ERP in India typically lands between **₹6,00,000 and ₹18,00,000**, a multi-module mid-market system between **₹18,00,000 and ₹60,00,000**, and a large multi-tenant or government-grade platform between **₹60,00,000 and ₹2,50,00,000+**. The rest of this article explains how to find *your* number inside those ranges.
|
||||||
|
|
||||||
|
## What "Custom ERP" Actually Means for Pricing
|
||||||
|
|
||||||
|
Before any number makes sense, you have to define scope. "ERP" is an umbrella — your price depends entirely on which modules you actually build. A finance-and-inventory system for a trading firm is a completely different project from a 14-module university ERP with admissions, examinations, hostel, and payroll.
|
||||||
|
|
||||||
|
Custom ERP cost in India is driven by five things, in roughly this order of impact:
|
||||||
|
|
||||||
|
1. **Number and complexity of modules** — each module is a mini-application with its own data model, screens, and rules.
|
||||||
|
2. **Number of distinct user roles and permission rules** — RBAC complexity scales non-linearly.
|
||||||
|
3. **Integrations** — payment gateways, GST/e-invoicing, SMS/WhatsApp, biometric, Tally, government APIs.
|
||||||
|
4. **Deployment model** — single-tenant vs multi-tenant, cloud vs on-premise, offline resilience.
|
||||||
|
5. **Non-functional requirements** — audit logging, data residency, uptime SLA, concurrent-user load.
|
||||||
|
|
||||||
|
## 2026 Cost Ranges by Project Tier
|
||||||
|
|
||||||
|
These are realistic, all-in development ranges for an India-based engagement (Indian team rates, INR), covering design, development, testing, and first deployment. They exclude ongoing maintenance, which we cover separately below.
|
||||||
|
|
||||||
|
| Tier | Typical Use Case | Modules | Timeline | Cost Range (INR) |
|
||||||
|
|------|------------------|---------|----------|------------------|
|
||||||
|
| **Starter** | Single-department tool (inventory, billing, or HR) | 1–2 | 6–10 weeks | ₹6L – ₹18L |
|
||||||
|
| **Growth** | Mid-market multi-department ERP | 4–7 | 4–7 months | ₹18L – ₹60L |
|
||||||
|
| **Enterprise** | Multi-entity / multi-location ERP, complex RBAC | 8–14 | 8–14 months | ₹60L – ₹1.5Cr |
|
||||||
|
| **Government / Platform** | Multi-tenant, offline-resilient, audit-heavy | 10+ | 12–24 months | ₹1.5Cr – ₹2.5Cr+ |
|
||||||
|
|
||||||
|
A useful rule of thumb in 2026: a well-defined, production-grade ERP module costs roughly **₹4,00,000 to ₹9,00,000** to build, depending on how many screens, workflows, and integrations it carries.
|
||||||
|
|
||||||
|
## The Biggest Cost Driver: The Team
|
||||||
|
|
||||||
|
Custom software is labour. The single largest line item in any ERP quote is engineering time, so blended day-rates dominate the total. Here is what Indian ERP development talent typically costs in 2026.
|
||||||
|
|
||||||
|
| Role | Junior (₹/month) | Mid (₹/month) | Senior (₹/month) |
|
||||||
|
|------|------------------|---------------|------------------|
|
||||||
|
| Backend Engineer | ₹45,000 – ₹70,000 | ₹80,000 – ₹1,40,000 | ₹1,60,000 – ₹2,80,000 |
|
||||||
|
| Frontend Engineer | ₹40,000 – ₹65,000 | ₹75,000 – ₹1,30,000 | ₹1,50,000 – ₹2,50,000 |
|
||||||
|
| QA / Test Engineer | ₹35,000 – ₹55,000 | ₹60,000 – ₹1,00,000 | ₹1,10,000 – ₹1,80,000 |
|
||||||
|
| Project Manager | — | ₹90,000 – ₹1,50,000 | ₹1,60,000 – ₹3,00,000 |
|
||||||
|
| UI/UX Designer | ₹40,000 – ₹60,000 | ₹70,000 – ₹1,20,000 | ₹1,30,000 – ₹2,20,000 |
|
||||||
|
|
||||||
|
A typical Growth-tier project runs a squad of 4–6 people for 5 months. At blended mid-level rates, that alone accounts for ₹25L–₹40L of the budget — which is why the Growth range sits where it does.
|
||||||
|
|
||||||
|
## Build vs Buy: When Custom Actually Pays Off
|
||||||
|
|
||||||
|
Custom is not always the right call. Off-the-shelf and SaaS ERPs (Zoho, TallyPrime, SAP Business One, Odoo) have real advantages for standard workflows. Here is the honest comparison for an Indian mid-market buyer.
|
||||||
|
|
||||||
|
| Factor | Custom ERP | SaaS / Off-the-Shelf |
|
||||||
|
|--------|-----------|----------------------|
|
||||||
|
| Upfront cost | ₹18L – ₹60L+ | ₹0 – ₹5L setup |
|
||||||
|
| Recurring cost | ~15–20% of build/year (AMC) | ₹500 – ₹3,000 per user / month |
|
||||||
|
| Fit to your process | Exact | Adapt your process to the tool |
|
||||||
|
| Time to first value | 3–7 months | Days to weeks |
|
||||||
|
| Data ownership | Full | Vendor-hosted |
|
||||||
|
| Scaling cost | Predictable (you own it) | Grows with every seat |
|
||||||
|
|
||||||
|
The crossover maths matters. A 100-user SaaS ERP at ₹1,500/user/month costs **₹18,00,000 per year** — recurring, forever. A custom build at ₹40,00,000 with ₹7,00,000/year AMC breaks even against that SaaS bill in roughly **2.5 years**, and is cheaper every year after. Custom wins when your headcount is large, your processes are genuinely non-standard, or data sovereignty is non-negotiable (common in government and BFSI).
|
||||||
|
|
||||||
|
## Hidden Costs Buyers Forget to Budget
|
||||||
|
|
||||||
|
The build quote is not the total cost of ownership. Plan for these:
|
||||||
|
|
||||||
|
- **Annual Maintenance Contract (AMC):** budget **15–20% of build cost per year** for bug fixes, security patches, and minor enhancements.
|
||||||
|
- **Cloud hosting:** a mid-size ERP on AWS/Azure in the Mumbai region typically costs **₹15,000 – ₹60,000/month** depending on load and redundancy.
|
||||||
|
- **Third-party APIs:** SMS (₹0.12–₹0.25/message), WhatsApp Business, payment gateway (~2% per transaction), GST e-invoicing add-ons.
|
||||||
|
- **Data migration:** cleaning and importing legacy data is often underestimated — budget **₹1,50,000 – ₹6,00,000**.
|
||||||
|
- **Training and change management:** for 50+ users, this is a real line item, not an afterthought.
|
||||||
|
- **Post-launch enhancements:** the first three months after go-live always surface new requirements.
|
||||||
|
|
||||||
|
## A Simple Way to Estimate Your Own Cost
|
||||||
|
|
||||||
|
You can get within ±25% of a real quote with this back-of-envelope method:
|
||||||
|
|
||||||
|
1. **List your modules.** Count them honestly.
|
||||||
|
2. **Multiply by ₹4L–₹9L per module** depending on complexity (simple CRUD = lower; workflow + integrations = higher).
|
||||||
|
3. **Add 20% for integrations** if you need GST, payments, or government APIs.
|
||||||
|
4. **Add 15% for multi-tenant or offline-resilient** architecture.
|
||||||
|
5. **Add the first year of AMC** (15–20%) for a true year-one budget.
|
||||||
|
|
||||||
|
Example: a 6-module mid-market ERP with payment + GST integration → (6 × ₹6L) = ₹36L, +20% integrations = ₹43.2L, +18% AMC = roughly **₹51L for year one**. That lands squarely in the Growth tier, which is the reality check you want before any vendor conversation.
|
||||||
|
|
||||||
|
## Frequently Asked Questions
|
||||||
|
|
||||||
|
**What is the minimum realistic budget for a custom ERP in India in 2026?**
|
||||||
|
For a genuinely custom, production-grade single-department system, expect a floor of around **₹6,00,000**. Below that you are buying a configured off-the-shelf tool or a prototype, not a custom ERP.
|
||||||
|
|
||||||
|
**How long does a custom ERP take to build?**
|
||||||
|
A Starter system ships in 6–10 weeks. A Growth-tier multi-module ERP takes 4–7 months. Enterprise and government platforms run 8–24 months. Timeline scales with module count and integration depth, not just budget.
|
||||||
|
|
||||||
|
**Is custom ERP cheaper than SaaS over time?**
|
||||||
|
Often, yes — above roughly 75–100 users or 2.5 years of use. A custom build has a high upfront cost but a flat recurring cost (AMC), while SaaS charges per seat forever. The more you grow, the better custom looks.
|
||||||
|
|
||||||
|
**Why do ERP quotes vary so much between vendors?**
|
||||||
|
Because "ERP" is undefined until you fix scope. A ₹15L and a ₹60L quote are usually answering two different questions about modules, roles, and integrations. Always compare on a fixed, written scope — never on the headline number alone.
|
||||||
|
|
||||||
|
**What ongoing costs should I plan for after launch?**
|
||||||
|
Budget 15–20% of build cost per year for AMC, plus cloud hosting (₹15K–₹60K/month for mid-size systems), third-party API usage, and periodic enhancements. Total cost of ownership over five years is typically 1.7–2x the initial build.
|
||||||
|
|
||||||
|
**Should I pay fixed-price or time-and-materials?**
|
||||||
|
Fixed-price works when scope is locked and well-documented. Time-and-materials fits evolving requirements and longer builds. For most mid-market ERPs, a hybrid — fixed-price per milestone with a change-request process — gives the best balance of predictability and flexibility.
|
||||||
|
|
||||||
|
## Getting an Accurate Number for Your Project
|
||||||
|
|
||||||
|
The ranges above will get your budget into the right order of magnitude, but every project has specifics — a single complex integration or a strict uptime SLA can move the number significantly. At WorkRoot we have delivered ERP and management systems across Indian government and enterprise clients, and we are happy to turn your requirements into a fixed, written estimate. [Tell us about your project](/contact) and we will give you a real number, not a vague "it depends."
|
||||||
@@ -181,6 +181,17 @@ const fullTitle = title === 'Home' ? homeTitle : `${title} | ${brand}`;
|
|||||||
<!-- Analytics (GA4 or Plausible) -->
|
<!-- Analytics (GA4 or Plausible) -->
|
||||||
<Analytics />
|
<Analytics />
|
||||||
|
|
||||||
|
<!-- WRNexus Web Push SDK — loaded once globally so it runs on every page
|
||||||
|
that should collect push subscribers. is:inline keeps Astro's bundler
|
||||||
|
from rewriting the external src and preserves data-site-id / defer. -->
|
||||||
|
<script is:inline src="https://api.wrnexus.com/push/sdk.js" data-site-id="pk_rP51XN8tZnud5HdX9UqidjHk" defer></script>
|
||||||
|
|
||||||
|
<!-- WRNexus Bot Widget — loaded once globally here so the chat widget
|
||||||
|
renders on every route (pages + blog posts) via this shared layout.
|
||||||
|
is:inline keeps Astro's bundler from rewriting the external src and
|
||||||
|
preserves data-bot-id / async. -->
|
||||||
|
<script is:inline src="https://api.wrnexus.com/bots/widget.js" data-bot-id="d3998f1b-51d7-4f7c-a57e-3fa1af4394a0" async></script>
|
||||||
|
|
||||||
<!-- Additional head content slot -->
|
<!-- Additional head content slot -->
|
||||||
<slot name="head" />
|
<slot name="head" />
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
+6
-4
@@ -155,11 +155,13 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|||||||
// - inline scripts/styles: Required for Astro framework
|
// - inline scripts/styles: Required for Astro framework
|
||||||
// - https://www.googletagmanager.com & https://www.google-analytics.com: GA4
|
// - https://www.googletagmanager.com & https://www.google-analytics.com: GA4
|
||||||
// - https://plausible.io: Plausible Analytics
|
// - https://plausible.io: Plausible Analytics
|
||||||
|
// - https://api.wrnexus.com: WRNexus web-push SDK (sdk.js), bot widget
|
||||||
|
// (bots/widget.js) + runtime config/iframe served from the same origin
|
||||||
// Note: unsafe-eval is removed in production (only needed during Astro HMR dev mode)
|
// Note: unsafe-eval is removed in production (only needed during Astro HMR dev mode)
|
||||||
const isProduction = import.meta.env.PROD;
|
const isProduction = import.meta.env.PROD;
|
||||||
const scriptSrc = isProduction
|
const scriptSrc = isProduction
|
||||||
? "script-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://www.google-analytics.com https://plausible.io"
|
? "script-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://www.google-analytics.com https://plausible.io https://api.wrnexus.com"
|
||||||
: "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.googletagmanager.com https://www.google-analytics.com https://plausible.io";
|
: "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.googletagmanager.com https://www.google-analytics.com https://plausible.io https://api.wrnexus.com";
|
||||||
|
|
||||||
const csp = [
|
const csp = [
|
||||||
"default-src 'self'",
|
"default-src 'self'",
|
||||||
@@ -167,11 +169,11 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|||||||
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
|
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
|
||||||
"img-src 'self' data: https://images.unsplash.com https://www.google-analytics.com https://www.googletagmanager.com https://maps.googleapis.com https://maps.gstatic.com",
|
"img-src 'self' data: https://images.unsplash.com https://www.google-analytics.com https://www.googletagmanager.com https://maps.googleapis.com https://maps.gstatic.com",
|
||||||
"font-src 'self' data: https://fonts.gstatic.com",
|
"font-src 'self' data: https://fonts.gstatic.com",
|
||||||
"connect-src 'self' https://www.google-analytics.com https://analytics.google.com https://stats.g.doubleclick.net https://plausible.io",
|
"connect-src 'self' https://www.google-analytics.com https://analytics.google.com https://stats.g.doubleclick.net https://plausible.io https://api.wrnexus.com",
|
||||||
"worker-src 'self'",
|
"worker-src 'self'",
|
||||||
"manifest-src 'self'",
|
"manifest-src 'self'",
|
||||||
"object-src 'none'", // Block Flash/plugins (defense-in-depth)
|
"object-src 'none'", // Block Flash/plugins (defense-in-depth)
|
||||||
"frame-src https://www.google.com", // Allow Google Maps iframe embed
|
"frame-src https://www.google.com https://api.wrnexus.com", // Google Maps iframe + WRNexus bot widget iframe
|
||||||
"frame-ancestors 'none'",
|
"frame-ancestors 'none'",
|
||||||
"base-uri 'self'",
|
"base-uri 'self'",
|
||||||
"form-action 'self'",
|
"form-action 'self'",
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const teamMembers = [
|
|||||||
// stats counters) so the numbers never contradict across pages.
|
// stats counters) so the numbers never contradict across pages.
|
||||||
const stats = [
|
const stats = [
|
||||||
{ value: '20+', label: 'Projects' },
|
{ value: '20+', label: 'Projects' },
|
||||||
{ value: '11', label: 'Districts Deployed' },
|
{ value: '11+', label: 'Districts Deployed' },
|
||||||
{ value: '50,000+', label: 'Records Managed' },
|
{ value: '50,000+', label: 'Records Managed' },
|
||||||
{ value: '8+', label: 'Years Avg Experience' },
|
{ value: '8+', label: 'Years Avg Experience' },
|
||||||
];
|
];
|
||||||
|
|||||||
+108
-3
@@ -124,7 +124,7 @@ const testimonials = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
// NOTE: The homepage stat band is rendered once by <ProofNumbers />, which
|
// NOTE: The homepage stat band is rendered once by <ProofNumbers />, which
|
||||||
// holds the canonical site-wide proof set (20+ Projects · 11 Districts ·
|
// holds the canonical site-wide proof set (20+ Projects · 11+ Districts ·
|
||||||
// 50,000+ Records · 8+ Years). The previously-duplicated "Numbers That
|
// 50,000+ Records · 8+ Years). The previously-duplicated "Numbers That
|
||||||
// Matter" stats section (and its local `stats` array + count-up script) was
|
// Matter" stats section (and its local `stats` array + count-up script) was
|
||||||
// removed so a visitor never sees the same four numbers twice on one page.
|
// removed so a visitor never sees the same four numbers twice on one page.
|
||||||
@@ -171,11 +171,42 @@ const techStack = [
|
|||||||
// "Common Questions" block that used to live above the tech-stack section
|
// "Common Questions" block that used to live above the tech-stack section
|
||||||
// was removed; its unique questions were merged into HomepageFaq's
|
// was removed; its unique questions were merged into HomepageFaq's
|
||||||
// `moneyFaqs` array so no buyer-facing content was dropped.
|
// `moneyFaqs` array so no buyer-facing content was dropped.
|
||||||
|
|
||||||
|
// Quotable, self-contained company facts. Each sentence deliberately bundles
|
||||||
|
// the full company name + a concrete claim + a number so the line stays
|
||||||
|
// accurate and citable when lifted out of context (search snippets, press
|
||||||
|
// quotes, AI assistants). Every figure here is the canonical site-wide value
|
||||||
|
// and MUST stay identical to <ProofNumbers />, the hero trust badge, /about,
|
||||||
|
// and the /services pages. Do not change a number here without updating it
|
||||||
|
// everywhere it appears — mismatched stats reintroduce the credibility bug
|
||||||
|
// this canonical set was created to fix.
|
||||||
|
const companyFacts = [
|
||||||
|
'WorkRoot IT Solutions was founded in 2022 and has delivered 20+ production software systems for startups, enterprises, and government bodies.',
|
||||||
|
'WorkRoot IT Solutions runs government platforms across 11+ districts of Bihar, India, sustaining 99.9% uptime on mission-critical public services.',
|
||||||
|
'WorkRoot IT Solutions manages 50,000+ live records across its government and enterprise deployments.',
|
||||||
|
'WorkRoot IT Solutions built the University Management System for IIT Patna on a Next.js and Spring Boot stack.',
|
||||||
|
'WorkRoot IT Solutions is empanelled on the Government e-Marketplace (GeM), making it eligible to bid on Indian government IT tenders.',
|
||||||
|
'WorkRoot IT Solutions delivered a Police Management System that digitised FIRs and case tracking for 15,000+ officers across 11 districts of Bihar.',
|
||||||
|
'WorkRoot IT Solutions is a senior in-house engineering team averaging 8+ years of experience per engineer.',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Comparison table — custom software (WorkRoot) vs off-the-shelf ERP / SaaS.
|
||||||
|
// Mirrors the deeper table on /services/custom-erp-development, surfaced on the
|
||||||
|
// homepage so the core buying trade-off is framed before a late-stage visitor
|
||||||
|
// reaches the inline lead form. The final row carries the canonical
|
||||||
|
// "11+ districts · 99.9% uptime" proof point.
|
||||||
|
const comparison = [
|
||||||
|
{ dimension: 'Fit to your workflow', offShelf: 'You reshape your process to fit the software', custom: 'The software is built around your exact process' },
|
||||||
|
{ dimension: 'Source-code ownership', offShelf: 'Vendor-locked, closed source', custom: 'Full IP transfer on delivery — you own the code' },
|
||||||
|
{ dimension: 'Licensing cost', offShelf: 'Recurring per-seat fees that grow with headcount', custom: 'One-time build — no per-seat licence tax' },
|
||||||
|
{ dimension: 'Data residency', offShelf: 'The vendor’s cloud and region', custom: 'Your servers, your region, your control' },
|
||||||
|
{ dimension: 'Proven at scale', offShelf: 'Generic, one-size-fits-all', custom: 'Live across 11+ districts at 99.9% uptime' },
|
||||||
|
];
|
||||||
---
|
---
|
||||||
|
|
||||||
<BaseLayout
|
<BaseLayout
|
||||||
title="Home"
|
title="Home"
|
||||||
description="WorkRoot IT Solutions builds production-grade web, mobile, ERP, and government IT systems. 20+ projects delivered across 11 districts with 99.9% uptime."
|
description="WorkRoot IT Solutions builds production-grade web, mobile, ERP, and government IT systems. 20+ projects delivered across 11+ districts with 99.9% uptime."
|
||||||
>
|
>
|
||||||
<SEO
|
<SEO
|
||||||
slot="head"
|
slot="head"
|
||||||
@@ -208,7 +239,7 @@ const techStack = [
|
|||||||
<svg class="w-5 h-5 text-accent-400" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
|
<svg class="w-5 h-5 text-accent-400" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
|
||||||
<path fill-rule="evenodd" d="M6.267 3.455a3.066 3.066 0 001.745-.723 3.066 3.066 0 013.976 0 3.066 3.066 0 001.745.723 3.066 3.066 0 012.812 2.812c.051.643.304 1.254.723 1.745a3.066 3.066 0 010 3.976 3.066 3.066 0 00-.723 1.745 3.066 3.066 0 01-2.812 2.812 3.066 3.066 0 00-1.745.723 3.066 3.066 0 01-3.976 0 3.066 3.066 0 00-1.745-.723 3.066 3.066 0 01-2.812-2.812 3.066 3.066 0 00-.723-1.745 3.066 3.066 0 010-3.976 3.066 3.066 0 00.723-1.745 3.066 3.066 0 012.812-2.812zm7.44 5.252a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
|
<path fill-rule="evenodd" d="M6.267 3.455a3.066 3.066 0 001.745-.723 3.066 3.066 0 013.976 0 3.066 3.066 0 001.745.723 3.066 3.066 0 012.812 2.812c.051.643.304 1.254.723 1.745a3.066 3.066 0 010 3.976 3.066 3.066 0 00-.723 1.745 3.066 3.066 0 01-2.812 2.812 3.066 3.066 0 00-1.745.723 3.066 3.066 0 01-3.976 0 3.066 3.066 0 00-1.745-.723 3.066 3.066 0 01-2.812-2.812 3.066 3.066 0 00-.723-1.745 3.066 3.066 0 010-3.976 3.066 3.066 0 00.723-1.745 3.066 3.066 0 012.812-2.812zm7.44 5.252a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="text-sm font-medium text-white">Trusted by 20+ teams · Deployed across 11 districts</span>
|
<span class="text-sm font-medium text-white">Trusted by 20+ teams · Deployed across 11+ districts</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Main heading — benefit-led: outcome + audience -->
|
<!-- Main heading — benefit-led: outcome + audience -->
|
||||||
@@ -681,6 +712,80 @@ const techStack = [
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Company Facts + Comparison — extractable, self-contained statements
|
||||||
|
that bundle the WorkRoot name with a concrete claim and a number so each
|
||||||
|
line stays accurate when quoted out of context (search snippets, press,
|
||||||
|
AI assistants). Followed by a custom-vs-off-the-shelf comparison table so
|
||||||
|
the buying trade-off is framed in one glance. Every figure matches the
|
||||||
|
canonical set in <ProofNumbers />. -->
|
||||||
|
<section
|
||||||
|
id="company-facts"
|
||||||
|
class="py-24 bg-white dark:bg-secondary-900 border-t border-secondary-100 dark:border-secondary-800"
|
||||||
|
aria-labelledby="company-facts-heading"
|
||||||
|
>
|
||||||
|
<div class="container-wrapper">
|
||||||
|
<div class="text-center max-w-3xl mx-auto mb-16" data-animate="fade-up">
|
||||||
|
<span class="inline-block px-4 py-2 rounded-full bg-primary-50 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300 text-sm font-bold uppercase tracking-wider mb-4">The facts</span>
|
||||||
|
<h2 id="company-facts-heading" class="text-4xl sm:text-5xl font-bold text-secondary-900 dark:text-secondary-100 mb-6">WorkRoot at a glance</h2>
|
||||||
|
<p class="text-xl text-secondary-600 dark:text-secondary-400">
|
||||||
|
The record behind the work, stated plainly — so you know exactly who you're hiring.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="grid grid-cols-1 md:grid-cols-2 gap-4 sm:gap-5 max-w-5xl mx-auto mb-20" role="list">
|
||||||
|
{companyFacts.map((fact, index) => (
|
||||||
|
<li
|
||||||
|
class="flex items-start gap-4 bg-secondary-50 dark:bg-secondary-800/60 rounded-2xl border border-secondary-100 dark:border-secondary-700 p-5 sm:p-6"
|
||||||
|
data-animate="fade-up"
|
||||||
|
data-delay={String((index % 2) * 100)}
|
||||||
|
>
|
||||||
|
<span class="flex-shrink-0 w-10 h-10 rounded-xl bg-primary-100 dark:bg-primary-900/40 flex items-center justify-center" aria-hidden="true">
|
||||||
|
<svg class="w-6 h-6 text-primary-600 dark:text-primary-300" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.2">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<p class="text-base sm:text-lg text-secondary-800 dark:text-secondary-200 leading-relaxed">{fact}</p>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Comparison table: custom build vs off-the-shelf. Reuses the markup
|
||||||
|
pattern from /services/custom-erp-development for visual consistency. -->
|
||||||
|
<div class="max-w-4xl mx-auto" data-animate="fade-up">
|
||||||
|
<div class="text-center mb-8">
|
||||||
|
<h3 class="text-2xl sm:text-3xl font-bold text-secondary-900 dark:text-secondary-100 mb-3">Custom software vs off-the-shelf ERP</h3>
|
||||||
|
<p class="text-secondary-600 dark:text-secondary-400 text-base sm:text-lg">Where a bespoke WorkRoot build pays you back over a packaged SaaS tool.</p>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto rounded-2xl border border-secondary-200 dark:border-secondary-700 shadow-sm">
|
||||||
|
<table class="w-full text-left border-collapse min-w-[640px]">
|
||||||
|
<caption class="sr-only">Comparison of off-the-shelf ERP software versus custom software built by WorkRoot IT Solutions</caption>
|
||||||
|
<thead>
|
||||||
|
<tr class="bg-secondary-50 dark:bg-secondary-800">
|
||||||
|
<th scope="col" class="px-5 py-4 text-sm font-bold text-secondary-700 dark:text-secondary-200">Dimension</th>
|
||||||
|
<th scope="col" class="px-5 py-4 text-sm font-bold text-secondary-500 dark:text-secondary-400">Off-the-shelf ERP</th>
|
||||||
|
<th scope="col" class="px-5 py-4 text-sm font-bold text-primary-700 dark:text-primary-300">Custom software (WorkRoot)</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{comparison.map((row, i) => (
|
||||||
|
<tr class={i % 2 === 0 ? 'bg-white dark:bg-secondary-900' : 'bg-secondary-50/50 dark:bg-secondary-800/40'}>
|
||||||
|
<th scope="row" class="px-5 py-4 text-sm font-semibold text-secondary-900 dark:text-secondary-100 align-top">{row.dimension}</th>
|
||||||
|
<td class="px-5 py-4 text-sm text-secondary-600 dark:text-secondary-400 align-top">{row.offShelf}</td>
|
||||||
|
<td class="px-5 py-4 text-sm text-secondary-700 dark:text-secondary-200 align-top font-medium">
|
||||||
|
<span class="inline-flex items-start gap-2">
|
||||||
|
<svg class="w-4 h-4 mt-0.5 flex-shrink-0 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" /></svg>
|
||||||
|
{row.custom}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Technologies We Work With — relocated from the hero so social proof
|
<!-- Technologies We Work With — relocated from the hero so social proof
|
||||||
leads above the fold. Kept intentionally subdued (border-only cards,
|
leads above the fold. Kept intentionally subdued (border-only cards,
|
||||||
neutral grayscale icons) so it reads as supporting context rather than
|
neutral grayscale icons) so it reads as supporting context rather than
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ const featuredProjects = projects.filter(p => p.featured);
|
|||||||
<div class="mt-14 grid grid-cols-2 sm:grid-cols-4 gap-4 lg:gap-6 reveal-on-scroll reveal-delay-2">
|
<div class="mt-14 grid grid-cols-2 sm:grid-cols-4 gap-4 lg:gap-6 reveal-on-scroll reveal-delay-2">
|
||||||
{[
|
{[
|
||||||
{ value: '20+', label: 'Projects' },
|
{ value: '20+', label: 'Projects' },
|
||||||
{ value: '11', label: 'Districts Deployed' },
|
{ value: '11+', label: 'Districts Deployed' },
|
||||||
{ value: '50,000+', label: 'Records Managed' },
|
{ value: '50,000+', label: 'Records Managed' },
|
||||||
{ value: '8+', label: 'Years Avg Experience' },
|
{ value: '8+', label: 'Years Avg Experience' },
|
||||||
].map((stat) => (
|
].map((stat) => (
|
||||||
|
|||||||
@@ -294,7 +294,7 @@ const processSteps = [
|
|||||||
|
|
||||||
<BaseLayout
|
<BaseLayout
|
||||||
title="ERP, Web & Mobile App Development Services"
|
title="ERP, Web & Mobile App Development Services"
|
||||||
description="Custom web development, mobile apps, ERP platforms, and government IT solutions from WorkRoot. 20+ projects delivered across 11 districts — get a free quote."
|
description="Custom web development, mobile apps, ERP platforms, and government IT solutions from WorkRoot. 20+ projects delivered across 11+ districts — get a free quote."
|
||||||
>
|
>
|
||||||
<SEO
|
<SEO
|
||||||
slot="head"
|
slot="head"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
// ServiceFaq) and feeds Service + FAQ schema into SEO.astro.
|
// ServiceFaq) and feeds Service + FAQ schema into SEO.astro.
|
||||||
//
|
//
|
||||||
// All company stats mirror the canonical site-wide set used in
|
// All company stats mirror the canonical site-wide set used in
|
||||||
// ProofNumbers.astro, /portfolio, and SEO.astro — 20+ projects · 11 districts ·
|
// ProofNumbers.astro, /portfolio, and SEO.astro — 20+ projects · 11+ districts ·
|
||||||
// 50,000+ records · 99.9% uptime · 8+ years. Case-study numbers are taken
|
// 50,000+ records · 99.9% uptime · 8+ years. Case-study numbers are taken
|
||||||
// verbatim from the IIT Patna and Bihar government case studies on /portfolio.
|
// verbatim from the IIT Patna and Bihar government case studies on /portfolio.
|
||||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||||
@@ -44,7 +44,7 @@ const comparison = [
|
|||||||
const stats = [
|
const stats = [
|
||||||
{ value: '5+', label: 'ERP & enterprise deployments' },
|
{ value: '5+', label: 'ERP & enterprise deployments' },
|
||||||
{ value: '20,000+', label: 'Users across systems' },
|
{ value: '20,000+', label: 'Users across systems' },
|
||||||
{ value: '11', label: 'Districts running our platforms' },
|
{ value: '11+', label: 'Districts running our platforms' },
|
||||||
{ value: '99.9%', label: 'Uptime on critical systems' },
|
{ value: '99.9%', label: 'Uptime on critical systems' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
// schema into SEO.astro.
|
// schema into SEO.astro.
|
||||||
//
|
//
|
||||||
// Canonical stats mirror ProofNumbers.astro / /portfolio / SEO.astro:
|
// Canonical stats mirror ProofNumbers.astro / /portfolio / SEO.astro:
|
||||||
// 20+ projects · 11 districts · 50,000+ records · 99.9% uptime · 8+ years.
|
// 20+ projects · 11+ districts · 50,000+ records · 99.9% uptime · 8+ years.
|
||||||
|
// (This page's own hero stat shows "11" — the specific Bihar deployment
|
||||||
|
// underpinning the company-wide "11+" figure; do not inflate it.)
|
||||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||||
import SEO from '../../components/SEO.astro';
|
import SEO from '../../components/SEO.astro';
|
||||||
import GuaranteeBand from '../../components/GuaranteeBand.astro';
|
import GuaranteeBand from '../../components/GuaranteeBand.astro';
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const sitemapSections = [
|
|||||||
links: [
|
links: [
|
||||||
{ name: 'Custom ERP Development', url: '/services/custom-erp-development', description: 'Bespoke enterprise systems on Spring Boot & Angular' },
|
{ name: 'Custom ERP Development', url: '/services/custom-erp-development', description: 'Bespoke enterprise systems on Spring Boot & Angular' },
|
||||||
{ name: 'University ERP', url: '/services/university-erp', description: 'Admissions, exams, grading — built for IIT Patna' },
|
{ name: 'University ERP', url: '/services/university-erp', description: 'Admissions, exams, grading — built for IIT Patna' },
|
||||||
{ name: 'Government IT & GeM Vendor', url: '/services/government-it-solutions-gem-vendor', description: 'GeM-empanelled, live across 11 districts' },
|
{ name: 'Government IT & GeM Vendor', url: '/services/government-it-solutions-gem-vendor', description: 'GeM-empanelled, live across 11+ districts' },
|
||||||
{ name: 'Police Management System', url: '/services/police-management-system', description: 'FIR, case tracking & personnel for 15,000+ officers' },
|
{ name: 'Police Management System', url: '/services/police-management-system', description: 'FIR, case tracking & personnel for 15,000+ officers' },
|
||||||
{ name: 'React Native App Development', url: '/services/react-native-app-development', description: 'One codebase for iOS and Android' },
|
{ name: 'React Native App Development', url: '/services/react-native-app-development', description: 'One codebase for iOS and Android' },
|
||||||
],
|
],
|
||||||
|
|||||||
+2
-2
@@ -84,7 +84,7 @@ export function generateArticleSchema(
|
|||||||
},
|
},
|
||||||
publisher: {
|
publisher: {
|
||||||
'@type': 'Organization',
|
'@type': 'Organization',
|
||||||
name: 'WorkRoot IT Solutions',
|
name: 'WorkRoot IT Solutions LLP',
|
||||||
logo: {
|
logo: {
|
||||||
'@type': 'ImageObject',
|
'@type': 'ImageObject',
|
||||||
url: 'https://workroot.in/logo.png',
|
url: 'https://workroot.in/logo.png',
|
||||||
@@ -132,7 +132,7 @@ export function generateServiceSchema(
|
|||||||
description: description,
|
description: description,
|
||||||
provider: {
|
provider: {
|
||||||
'@type': 'Organization',
|
'@type': 'Organization',
|
||||||
name: 'WorkRoot IT Solutions',
|
name: 'WorkRoot IT Solutions LLP',
|
||||||
url: siteUrl,
|
url: siteUrl,
|
||||||
},
|
},
|
||||||
areaServed: {
|
areaServed: {
|
||||||
|
|||||||
Reference in New Issue
Block a user