Version: 3.0 Date: 2025-12-29 Status: Implementation Ready (Schema.org Aligned)
This specification defines a software catalog system for tracking software products, vendors, categories, risk assessments, and alternatives. The catalog uses Schema.org vocabulary for field naming and JSON-LD structure.
Design goals:
- Aggregate data from multiple sources (euro-stack, switching.software, CNCF Landscape, Cloud Service Map)
- Support digital sovereignty assessments (NDSI framework)
- Map non-European software to European alternatives
- Enable multi-dimensional categorization (technical, business, developer, platform taxonomies)
- Support multiple user personas with persona-specific filtering
- Schema.org alignment for interoperability and semantic web compatibility
All data files use Schema.org vocabulary:
| Entity | Schema.org Type | Wrapper |
|---|---|---|
| Products | SoftwareApplication |
ItemList |
| Vendors | Organization |
ItemList |
| Assessments | Review + Rating |
ItemList |
| Alternatives | - | ItemList |
| Taxonomies | DefinedTerm |
DefinedTermSet |
Products, Vendors, Alternatives, Assessments:
{
"@context": "https://schema.org",
"@type": "ItemList",
"itemListElement": [...]
}Taxonomies:
{
"@context": "https://schema.org",
"@type": "DefinedTermSet",
"hasDefinedTerm": [...]
}┌─────────────────────┐
│ software-vendors │
│─────────────────────│
│ identifier (PK) │
│ name │
│ addressCountry │
│ url │
│ dateModified │
└─────────┬───────────┘
│ 1
│
│ manufacturer (FK)
│
│ *
┌─────────▼───────────┐ ┌─────────────────────┐
│ software-products │ │ software-alternatives│
│─────────────────────│ │─────────────────────│
│ identifier (PK) │◄──────│ identifier (FK) │
│ name │ │ isSimilarTo[] │──┐
│ description │ │ sources[] │ │
│ url │ │ dateModified │ │
│ manufacturer (FK) │ └─────────────────────┘ │
│ applicationCategory│ │
│ isOpenSource │◄───────────────────────────────┘
│ selfHostable │ (isSimilarTo references products)
│ dataPortability │
│ tags[] │
│ repository{} │
│ sources[] │
│ dateModified │
└─────────┬───────────┘
│ 1
│
│ itemReviewed (FK)
│
│ *
┌─────────▼───────────┐ ┌─────────────────────┐
│ software-assessments│ │ software-taxonomy │
│─────────────────────│ │─────────────────────│
│ itemReviewed (FK) │ │ termCode (PK) │
│ framework │ │ name │
│ version │ │ description │
│ datePublished │ │ icon │
│ reviewRating{} │ │ dateModified │
│ riskLevel │ └─────────────────────┘
│ scores{} │ (4 files: technical, business, developer, platforms)
│ negativeNotes[] │
│ suggestedActions[] │
│ citation[] │
│ dateModified │
└─────────────────────┘
catalog/
├── software-products.json # All products (EU and non-EU)
├── software-vendors.json # All vendors
├── software-alternatives.json # Product → alternatives mapping
├── software-assessments.json # Risk/sovereignty assessments
├── software-taxonomy-technical.json # Technical categories (59)
├── software-taxonomy-business.json # Business function categories (9)
├── software-taxonomy-developer.json # Developer/cloud categories (52)
├── software-taxonomy-platforms.json # Platform categories (10)
├── software-personas.json # User personas with filters (9)
├── software-tags.json # Cross-cutting tags (34)
│
└── schema/
├── software-products.schema.json
├── software-vendors.schema.json
├── software-alternatives.schema.json
├── software-assessments.schema.json
├── software-taxonomy.schema.json
└── framework.schema.json
data/software/ # Deliverable output for Hugo/PWA
├── products.json # Enriched with vendor details, alternatives
├── products-lite.json # Minimal data for PWA filtering
├── taxonomies.json # Merged taxonomies with product counts
└── schemas/ # Output validation schemas
scraped/
├── raw/ # Cached HTML from scrapers
└── normalized/ # Normalized scraper output
├── euro-stack.json
├── euro-stack-alternatives.json
├── switching-software.json
└── switching-software-alternatives.json
Uses Schema.org SoftwareApplication type.
{
"@context": "https://schema.org",
"@type": "ItemList",
"itemListElement": [
{
"@type": "SoftwareApplication",
"identifier": "nextcloud",
"name": "Nextcloud",
"description": "Open source file sync and collaboration platform",
"descriptionSource": {
"sourceName": "switching.software",
"sourceUrl": "https://switching.software/replace/google-drive/",
"license": "CC-BY-SA-4.0",
"fetchedAt": "2025-12-29T12:54:05.607Z"
},
"url": "https://nextcloud.com",
"manufacturer": "nextcloud",
"applicationCategory": {
"technical": ["collaboration", "cloud-storage"],
"business": ["collaboration"],
"developer": ["object-storage", "file-storage"]
},
"tags": ["open-source", "self-hosted", "docker", "gdpr-compliant", "eu-hosted"],
"isOpenSource": true,
"selfHostable": true,
"dataPortability": "full",
"repository": {
"url": "https://github.com/nextcloud/server"
},
"sources": [
{
"sourceName": "euro-stack",
"sourceUrl": "https://euro-stack.com/solutions/nextcloud",
"fetchedAt": "2025-12-23T09:48:42.289Z"
},
{
"sourceName": "switching.software",
"sourceUrl": "https://switching.software/replace/google-drive/",
"fetchedAt": "2025-12-29T12:54:05.607Z"
}
],
"dateModified": "2025-12-29"
}
]
}Field Reference:
| Field | Required | Schema.org | Description |
|---|---|---|---|
@type |
Yes | SoftwareApplication | Type annotation |
identifier |
Yes | identifier | Unique ID (kebab-case) |
name |
Yes | name | Product name |
description |
Yes | description | Short description |
descriptionSource |
No | - | Attribution for description (sourceName, sourceUrl, license, fetchedAt) |
manufacturer |
Yes | manufacturer | Reference to vendor identifier |
isOpenSource |
Yes | - | Boolean |
dateModified |
Yes | dateModified | Date (YYYY-MM-DD) |
url |
No | url | Official website |
repository |
No | codeRepository | Repository info |
applicationCategory |
No | applicationCategory | Taxonomy assignments (technical, business, developer) |
maturity |
No | - | Maturity level (1=experimental, 2=incubating, 3=stable) with source info |
targetAudience |
No | - | Target job roles (developer, platform-engineer, sre, etc.) |
tags |
No | - | Cross-cutting tags for filtering |
links |
No | - | Related links (blog, chat, documentation, video, statistics) |
selfHostable |
No | - | Can be self-hosted |
dataPortability |
No | - | none/partial/full |
sources |
No | - | Array of catalog sources where product was found |
Uses Schema.org Organization type.
{
"@context": "https://schema.org",
"@type": "ItemList",
"itemListElement": [
{
"@type": "Organization",
"identifier": "nextcloud",
"name": "Nextcloud GmbH",
"addressCountry": "DE",
"url": "https://nextcloud.com",
"dateModified": "2025-12-29"
}
]
}Field Reference:
| Field | Required | Schema.org | Description |
|---|---|---|---|
@type |
Yes | Organization | Type annotation |
identifier |
Yes | identifier | Unique vendor ID |
name |
Yes | name | Company name |
addressCountry |
Yes | addressCountry | ISO 3166-1 alpha-2 code |
url |
Yes | url | Company website |
dateModified |
Yes | dateModified | Date (YYYY-MM-DD) |
{
"@context": "https://schema.org",
"@type": "ItemList",
"itemListElement": [
{
"identifier": "ms-teams",
"isSimilarTo": ["whereby", "element", "mattermost", "pexip"],
"sources": [
{
"sourceName": "euro-stack",
"sourceUrl": "https://euro-stack.com/alternatives/microsoft-teams",
"fetchedAt": "2025-12-23T09:48:43.750Z"
}
],
"dateModified": "2025-12-29"
}
]
}Field Reference:
| Field | Required | Schema.org | Description |
|---|---|---|---|
identifier |
Yes | identifier | Product identifier |
isSimilarTo |
Yes | isSimilarTo | Alternative product IDs |
dateModified |
Yes | dateModified | Date (YYYY-MM-DD) |
sources |
No | - | Data sources |
Uses Schema.org Review and Rating types.
{
"@context": "https://schema.org",
"@type": "ItemList",
"itemListElement": [
{
"@type": "Review",
"itemReviewed": "azure",
"framework": "ndsi",
"version": "1.0",
"datePublished": "2025-12-19",
"reviewRating": {
"@type": "Rating",
"ratingValue": 2.08,
"bestRating": 3,
"worstRating": 0
},
"riskLevel": 2,
"scores": {
"strategic": { "score": 3, "rationale": "US company" },
"legal": { "score": 3, "rationale": "Subject to CLOUD Act" },
"data": { "score": 1, "rationale": "Norway regions available" }
},
"negativeNotes": [
"Subject to US CLOUD Act",
"Strategic dependency on US provider"
],
"suggestedActions": [
{
"title": "Use Norway regions",
"description": "Configure for Norway East/West regions",
"effort": "low",
"impact": "medium"
}
],
"citation": [
"https://azure.microsoft.com/en-us/explore/trusted-cloud/"
],
"dateModified": "2025-12-29"
}
]
}Field Reference:
| Field | Required | Schema.org | Description |
|---|---|---|---|
@type |
Yes | Review | Type annotation |
itemReviewed |
Yes | itemReviewed | Product identifier |
framework |
Yes | - | Framework ID (ndsi, eu-csf) |
version |
Yes | - | Framework version |
datePublished |
Yes | datePublished | Assessment date |
reviewRating |
Yes | reviewRating | Rating object |
riskLevel |
Yes | - | Integer risk level |
dateModified |
Yes | dateModified | Last updated |
scores |
No | - | Dimension scores |
negativeNotes |
No | negativeNotes | Key concerns |
suggestedActions |
No | potentialAction | Mitigations |
citation |
No | citation | Source URLs |
Uses Schema.org DefinedTermSet and DefinedTerm types.
{
"@context": "https://schema.org",
"@type": "DefinedTermSet",
"hasDefinedTerm": [
{
"@type": "DefinedTerm",
"termCode": "collaboration",
"name": "Collaboration",
"description": "Software for team communication and information sharing",
"icon": "files",
"dateModified": "2025-12-29"
}
]
}Field Reference:
| Field | Required | Schema.org | Description |
|---|---|---|---|
@type |
Yes | DefinedTerm | Type annotation |
termCode |
Yes | termCode | Unique ID (kebab-case) |
name |
Yes | name | Display name |
description |
Yes | description | Category description |
dateModified |
Yes | dateModified | Date (YYYY-MM-DD) |
icon |
No | - | Icon identifier |
Products can be categorized across multiple dimensions:
| Dimension | File | Count | Purpose | Example Values |
|---|---|---|---|---|
technical |
software-taxonomy-technical.json | 59 | What the software does | devops, crm, monitoring |
business |
software-taxonomy-business.json | 9 | Business function | sales, hr, finance |
developer |
software-taxonomy-developer.json | 52 | Cloud/dev alternatives | relational-database, serverless-functions |
platforms |
software-taxonomy-platforms.json | 10 | Deployment platform | online, windows, linux |
The developer taxonomy provides granular categories for finding alternatives to cloud services:
| Parent | Categories |
|---|---|
| database | relational-database, document-database, graph-database, key-value-store, time-series-database, vector-database, search-engine |
| messaging | message-queue, event-streaming, pubsub |
| compute | serverless-functions, container-orchestration, container-registry, container-runtime, cron-scheduler |
| storage | object-storage, block-storage, file-storage |
| networking | api-gateway, service-mesh, load-balancer, dns, vpn |
| security | secrets-management, identity-provider, certificate-management, waf |
| observability | metrics-monitoring, log-management, distributed-tracing, alerting |
| devops | ci-cd, gitops, infrastructure-as-code, artifact-repository, source-control |
| ai-ml | ml-platform, llm-inference, feature-store |
| data | workflow-orchestration, etl, data-warehouse, data-lake |
Categories are assigned in the applicationCategory field:
{
"identifier": "postgresql",
"applicationCategory": {
"technical": ["database"],
"developer": ["relational-database"],
"platforms": ["linux", "windows", "macos"]
}
}The catalog supports 9 user personas, each with specific filtering criteria:
| Persona | Description | Primary Taxonomy |
|---|---|---|
developer |
Cloud service alternatives, frameworks | developer |
business |
CRM, HR, finance tools | business |
technical |
Infrastructure, monitoring, security | technical |
privacy-conscious |
Ethical alternatives, no tracking | (cross-cutting) |
self-hoster |
Own infrastructure, Docker/K8s | (cross-cutting) |
sovereignty |
EU-based, GDPR compliant | (cross-cutting) |
enterprise |
Compliance, SLAs, vendor assessment | (cross-cutting) |
cost-conscious |
Free/OSS alternatives | (cross-cutting) |
end-user |
Everyday apps | business |
{
"@type": "DefinedTerm",
"termCode": "developer",
"name": "Developer",
"description": "Software developers looking for alternatives to cloud services",
"taxonomy": "software-taxonomy-developer.json",
"filterCriteria": {
"preferTags": ["open-source", "self-hosted", "api", "sdk"],
"preferCategories": ["database", "messaging", "compute", "devops"],
"showFields": ["repository", "applicationCategory.platforms", "isOpenSource"]
},
"exampleQueries": [
"Alternative to AWS Lambda",
"Open source Kafka replacement"
]
}Tags enable filtering across all taxonomies:
| Category | Tags |
|---|---|
| Licensing | open-source, free-tier, source-available |
| Deployment | self-hosted, saas, docker, kubernetes, helm |
| Privacy | privacy-focused, no-tracking, end-to-end-encrypted, zero-knowledge |
| Compliance | gdpr-compliant, hipaa-compliant, soc2, iso27001 |
| Sovereignty | eu-based, eu-hosted, data-residency |
| Enterprise | enterprise, sla, support, sso, audit-log |
| Integration | api, sdk, webhooks, s3-compatible |
| Maturity | cncf-graduated, cncf-incubating, cncf-sandbox |
{
"identifier": "minio",
"tags": ["open-source", "self-hosted", "s3-compatible", "docker", "kubernetes"]
}Alternatives are stored in a separate file (software-alternatives.json), enabling:
- Bidirectional queries
- Multiple data sources per relationship
- Clean separation of concerns
The enriched output (data/software/products.json) includes:
isSimilarTo: Products this can replaceisAlternativeFor: Products that list this as alternative
{
"identifier": "pexip",
"isSimilarTo": ["ms-teams", "zoom"],
"isAlternativeFor": ["ms-teams", "zoom", "google-meet"]
}// "What are alternatives to MS Teams?"
const alts = alternatives.find(a => a.identifier === 'ms-teams');
// → { isSimilarTo: ["whereby", "element", ...] }
// "What is Whereby an alternative to?"
const altTo = alternatives.filter(a => a.isSimilarTo.includes('whereby'));
// → [{ identifier: "ms-teams" }, { identifier: "zoom" }, ...]The build process (npm run catalog:output) generates data/software/products.json with:
- Vendor details merged inline as full
Organizationobjects - Bidirectional alternatives calculated from alternatives file
sourceCount- number of catalogs the product appears in (popularity signal)descriptionSource- attribution for description text- Full Schema.org JSON-LD structure
Example:
{
"@context": "https://schema.org",
"@type": "ItemList",
"itemListElement": [
{
"@type": "SoftwareApplication",
"identifier": "pexip",
"name": "Pexip",
"description": "Norwegian video conferencing solution",
"descriptionSource": {
"sourceName": "euro-stack",
"sourceUrl": "https://euro-stack.com/solutions/pexip",
"license": "verify"
},
"isOpenSource": false,
"sourceCount": 2,
"dateModified": "2025-12-29",
"manufacturer": {
"@type": "Organization",
"identifier": "pexip",
"name": "Pexip Holding ASA",
"url": "https://pexip.com",
"address": {
"@type": "PostalAddress",
"addressCountry": "NO"
}
},
"isSimilarTo": ["ms-teams", "zoom"],
"isAlternativeFor": ["ms-teams", "zoom", "google-meet"],
"sources": [
{ "sourceName": "euro-stack" },
{ "sourceName": "switching.software" }
]
}
]
}The sourceCount field indicates how many different catalogs list this product. Higher counts suggest more well-known/popular software.
Different data sources provide different fields. This table shows which optional fields each scraper populates:
| Field | CNCF | cloud-service-map | euro-stack | switching.software |
|---|---|---|---|---|
maturity |
✓ | ✓ | - | - |
targetAudience |
✓ | - | - | - |
tags |
✓ | - | - | - |
links |
✓ | - | - | - |
selfHostable |
- | - | - | ✓ |
repository |
✓ | - | ✓* | ✓* |
*euro-stack uses placeholder URLs for open source products; switching.software only sets repository if homepage is on github/gitlab/codeberg.
The maturity field uses a 3-level scale for filtering:
| Level | Label | Description |
|---|---|---|
| 1 | Experimental | Early stage, unstable API |
| 2 | Incubating | Growing adoption, stabilizing |
| 3 | Stable | Production-ready |
Source-specific mappings:
| Source | Level 1 | Level 2 | Level 3 |
|---|---|---|---|
| CNCF | Sandbox | Incubating | Graduated |
| cloud-service-map | - | - | GA (all products) |
Cloud services from major providers (AWS, Azure, GCP) are set to level 3 (stable) since they are production-ready GA services.
The targetAudience field uses normalized job roles. CNCF personas are mapped to these values:
platform-engineer,developer,sre,devops,devsecopsarchitect,security-engineer,network-engineerdata-engineer,ml-engineer,cluster-admindatabase-admin,system-admin,it-operations,compliance-officer
The links array contains typed links:
| Type | Description |
|---|---|
blog |
Project blog |
chat |
Community chat (Slack, Discord) |
documentation |
Official docs |
video |
Intro/demo video |
statistics |
DevStats or similar |
repository |
Source code repository |
social |
Social media |
other |
Other links |
- Format: kebab-case (lowercase, hyphens)
- Pattern:
[a-z0-9]+(-[a-z0-9]+)* - Examples:
ms-teams,nextcloud,aws-s3
Different sources may use different IDs. The canonical registry maps aliases to canonical IDs:
catalog/canonical-products.json
{
"microsoft-teams": {
"name": "Microsoft Teams",
"aliases": ["ms-teams"]
},
"aws": {
"name": "Amazon Web Services",
"aliases": ["amazon-web-services-aws"]
}
}Validate all data files against schemas:
npm run catalog:validateExpected output:
✓ software-products.json
✓ software-vendors.json
✓ software-assessments.json
✓ software-taxonomy-business.json
✓ software-taxonomy-technical.json
✓ software-taxonomy-platforms.json
✓ software-taxonomy-developer.json
✓ software-personas.json
✓ software-tags.json
✓ software-alternatives.json
Results: 10 passed, 0 failed
| Metric | Count |
|---|---|
| Total products | 3,245 |
| Total vendors | 1,940 |
| Alternative mappings | 789 |
| Technical categories | 59 |
| Business categories | 9 |
| Developer categories | 52 |
| Platform categories | 10 |
| User personas | 9 |
| Cross-cutting tags | 34 |
| Products with maturity | 790 |
Schema.org alignment changed these field names:
| Old Field | New Field (Schema.org) |
|---|---|
id |
identifier |
vendor_id |
manufacturer |
open_source |
isOpenSource |
updated_at |
dateModified |
taxonomies |
applicationCategory |
| Old Field | New Field (Schema.org) |
|---|---|
id |
identifier |
country |
addressCountry |
website |
url |
updated_at |
dateModified |
country_name |
(removed) |
| Old Field | New Field (Schema.org) |
|---|---|
product_id |
identifier |
alternative_ids |
isSimilarTo |
updated_at |
dateModified |
| Old Field | New Field (Schema.org) |
|---|---|
product_id |
itemReviewed |
date |
datePublished |
score |
reviewRating.ratingValue |
key_concerns |
negativeNotes |
mitigations |
suggestedActions |
sources |
citation |
updated_at |
dateModified |
| Old Field | New Field (Schema.org) |
|---|---|
id |
termCode |
updated_at |
dateModified |
Wrapper: categories |
Wrapper: hasDefinedTerm |
| Term | Definition |
|---|---|
| Schema.org | Vocabulary for structured data on the web |
| JSON-LD | JSON for Linking Data - structured data format |
| identifier | Unique ID for an entity (Schema.org property) |
| manufacturer | Producer/creator of software (Schema.org property) |
| isSimilarTo | Relationship indicating alternatives (Schema.org property) |
| DefinedTermSet | Collection of defined terms (Schema.org type) |
| NDSI | Nasjonal Digital Suverenitet Index - sovereignty risk framework |