chore: add missing source modules to version control
Deploy to Production / deploy (push) Failing after 7s

apix-demo, apix-portal/src, apix-spider/src, apix-registry/src,
apix-common/src were never staged. Without them the CI build has no
source to compile and the Docker images cannot be produced.

Also adds docs/ (infrastructure notes) missed in prior commits.

Co-Authored-By: Mira <noreply@anthropic.com>
This commit is contained in:
Carsten Rehfeld
2026-05-14 15:49:03 +02:00
parent a9b3354bde
commit 46f32c2df2
87 changed files with 6657 additions and 34 deletions
@@ -5,42 +5,98 @@ import jakarta.validation.Valid;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.hibernate.validator.constraints.URL;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@Schema(description = "Bot Service Manifest (BSM) payload — the machine-readable description of a service registered in the APIX registry. An AI agent reads this to understand what the service does, how to call it, and under what terms.")
@JsonInclude(JsonInclude.Include.NON_NULL)
public record BsmPayload(
@Schema(description = "Human-readable service name.", example = "Acme Translation Service")
@NotBlank String name,
@Schema(description = "What this service does, in plain language readable by an AI agent. Should describe inputs, outputs, and intended use cases.", example = "Translates text between 50 languages. Input: source text + target language code. Output: translated text with confidence score.")
@NotBlank String description,
@Schema(description = "Base URL of the service endpoint. Must be publicly reachable. Agents POST requests here.", example = "https://api.acme.example/translate")
@NotBlank @URL String endpoint,
@Schema(description = "Capability identifiers this service fulfils. Use lowercase kebab-case strings (e.g. nlp, translation, speech-to-text, image-classification, summarisation). Agents search the registry by these values — choose terms an agent would naturally use when looking for this type of service.", example = "[\"translation\", \"nlp\"]")
@NotEmpty List<@NotBlank String> capabilities,
@Schema(description = "Contact email of the registrant. Used for verification notifications and O-level progression.", example = "ops@acme.example")
@NotBlank @Email String registrantEmail,
@Schema(description = "Full legal name of the registrant (person or organisation).", example = "Acme GmbH")
@NotBlank String registrantName,
@Schema(description = "ISO 3166-1 alpha-2 country code of the registrant's legal jurisdiction.", example = "DE")
@NotBlank String registrantJurisdiction,
@Schema(description = "Legal form of the registrant organisation. Defaults to INDIVIDUAL if omitted.")
OrgType registrantOrgType,
@Schema(description = "Legal Entity Identifier (LEI, ISO 17442). 20-character alphanumeric code issued by a GLEIF-accredited Local Operating Unit. Required to reach O-level LEGAL_ENTITY_VERIFIED (O2) or above.", example = "5493001KJTIIGC8Y1R12")
String registrantLei,
@Schema(description = "URL of the OpenAPI 3.x specification for this service. Agents follow this link to discover available operations, request/response schemas, and authentication requirements.", example = "https://api.acme.example/openapi.json")
@URL String openApiSpecUrl,
@Schema(description = "URL of the Model Context Protocol (MCP) manifest. Enables AI agents to invoke this service as an MCP tool without writing custom integration code.", example = "https://api.acme.example/mcp/manifest.json")
@URL String mcpSpecUrl,
@Schema(description = "URL of the service's terms of use or acceptable-use policy.", example = "https://acme.example/terms")
@URL String policyUrl,
@Schema(description = "URL of the security disclosure page (e.g. /.well-known/security.txt). Required for O-level HYGIENE_VERIFIED (O3).", example = "https://acme.example/.well-known/security.txt")
@URL String securityContactUrl,
@Schema(description = "Pricing information. Omit for free or internally-billed services.")
@Valid Pricing pricing,
@Schema(description = "BSM payload schema version. Must be '0.1' for the current registry.", example = "0.1")
@NotBlank String bsmVersion,
@Schema(description = "Lifecycle stage of the service. Defaults to DEVELOPMENT if omitted. Only PRODUCTION services are returned by default capability searches (?capability=X without an explicit ?stage= parameter).")
ServiceStage serviceStage,
// IoT transition fields — null for non-IoT services
@Schema(description = "IoT migration lock. When true, agents are blocked from automatically switching to a replacement service. Use during controlled IoT device migration windows.")
Boolean locked,
@Schema(description = "Scheduled decommission timestamp (UTC, ISO 8601). Must be set when transitioning to DEPRECATED stage. Agents use this to plan migration timelines.", example = "2027-01-01T00:00:00Z")
Instant sunsetAt,
@Schema(description = "URL of a human- or machine-readable migration guide for consumers of this service.", example = "https://acme.example/migrate-v1-to-v2")
@URL String migrationGuideUrl,
List<UUID> replacesServiceIds
@Schema(description = "UUIDs of services this entry supersedes. Consumers of those deprecated services are directed here via the /replacements endpoint.")
List<UUID> replacesServiceIds,
@Schema(description = "Domain-specific extension properties that are not covered by the standard BSM fields. " +
"Keys are free-form strings; values may be strings, numbers, or booleans. " +
"Extensions are stored and queryable: use ?property=key:value in capability searches to filter by any extension field. " +
"Example uses: industry vertical ('industry':'healthcare'), geographic scope ('region':'eu'), " +
"data-residency requirement ('dataResidency':'DE'), agent framework ('agentFramework':'langchain').")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
Map<String, Object> extensions
) {
@Schema(description = "Pricing details for metered or subscription services.")
@JsonInclude(JsonInclude.Include.NON_NULL)
public record Pricing(
@Schema(description = "Billing model. Known values: PER_CALL, SUBSCRIPTION, FREE.", example = "PER_CALL")
String billingModel,
@Schema(description = "Price per unit in the stated currency.", example = "0.001")
BigDecimal pricePerCall,
@Schema(description = "ISO 4217 currency code.", example = "EUR")
String currency,
@Schema(description = "Billing unit description.", example = "per-1k-tokens")
String billingUnit
) {}
}
@@ -1,10 +1,25 @@
package org.botstandards.apix.common;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
@Schema(description = "Organisation verification level assigned by the APIX registry. Higher levels indicate greater identity assurance. Agents can filter search results by minimum O-level using the minOLevel parameter on the /replacements endpoint.")
public enum OLevel {
@Schema(description = "No verification performed. Default for all newly registered services.")
UNVERIFIED,
@Schema(description = "O1: DNS ownership of the registrant domain verified. The registry confirmed the registrant controls the domain via a DNS TXT record challenge.")
IDENTITY_VERIFIED,
@Schema(description = "O2: Legal entity confirmed via GLEIF LEI database or OpenCorporates registry. Requires a valid registrantLei in the BSM payload.")
LEGAL_ENTITY_VERIFIED,
@Schema(description = "O3: Service passes technical hygiene checks — security.txt present, OpenAPI or MCP spec accessible, endpoint responding within SLA.")
HYGIENE_VERIFIED,
@Schema(description = "O4: Service has demonstrated operational history and passes continuous liveness monitoring.")
OPERATIONALLY_VERIFIED,
@Schema(description = "Highest level. Full independent audit completed by an APIX-accredited auditor.")
AUDITED
}
@@ -1,9 +1,22 @@
package org.botstandards.apix.common;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
@Schema(description = "Legal form of the registrant.")
public enum OrgType {
@Schema(description = "Natural person acting in a personal capacity.")
INDIVIDUAL,
@Schema(description = "Commercial for-profit company or corporation.")
COMMERCIAL,
@Schema(description = "Non-profit or charitable organisation.")
NON_PROFIT,
@Schema(description = "Government body or public authority.")
GOVERNMENT,
@Schema(description = "University, research institution, or academic organisation.")
ACADEMIC
}
@@ -0,0 +1,31 @@
package org.botstandards.apix.common;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.time.Instant;
import java.util.List;
import java.util.Map;
/** Public dashboard view of a sandbox — served by registry, consumed by portal. */
public record SandboxDashboardResponse(
String sandboxId,
String name,
String tier,
int ratePerMinute,
@JsonInclude(JsonInclude.Include.ALWAYS) Integer maxServices,
@JsonInclude(JsonInclude.Include.ALWAYS) Integer maxOrgs,
Instant createdAt,
Instant expiresAt,
/** Declared location string as provided at registration. Absent if not provided. */
@JsonInclude(JsonInclude.Include.NON_NULL) String registrarLocation,
/** Resolved latitude. Absent if no location was provided or geocoding failed. */
@JsonInclude(JsonInclude.Include.NON_NULL) Double registrarLat,
/** Resolved longitude. Absent if no location was provided or geocoding failed. */
@JsonInclude(JsonInclude.Include.NON_NULL) Double registrarLon,
/** Cumulative event counts since sandbox creation. */
Map<String, Long> usage,
Instant lastActivityAt,
/** Up to 200 most recent agent visits with resolved coordinates only (no raw IPs). */
List<AgentVisit> recentVisits
) {
public record AgentVisit(double lat, double lon, Instant visitedAt) {}
}
@@ -1,9 +1,22 @@
package org.botstandards.apix.common;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
@Schema(description = "Lifecycle stage of a registered service. Controls visibility in default capability searches.")
public enum ServiceStage {
@Schema(description = "Under active development. Not returned by default search queries. Discover with ?stage=DEVELOPMENT.")
DEVELOPMENT,
@Schema(description = "Publicly available for testing but not production-ready. Discover with ?stage=BETA.")
BETA,
@Schema(description = "Live and ready for autonomous agent consumption. Returned by default capability searches (no ?stage= parameter required).")
PRODUCTION,
@Schema(description = "Scheduled for decommission. A sunsetAt date and replacement service IDs should be set. Still operational but agents should plan migration.")
DEPRECATED,
@Schema(description = "Retired and no longer operational. Kept in the registry for historical reference and to support replacement chain lookups.")
DECOMMISSIONED
}