Documentation

System Architecture

This page is the map. The other docs each zoom into one component; here the concern is how five of them - the Bio-DID-Seq core, BioAgents, the knowledge graph, IPFS storage, and UCAN authorization - fit together, and which one to look at when something crosses a boundary.

USERSResearcher / UserWeb Interface / APIBIO-DID-SEQ COREDID ManagementIdentity ResolutionUCAN IssuanceAPI GatewayBIOAGENTSKnowledge ExtractionEntity RecognitionAI ProcessingNL InterfaceKNOWLEDGE & STORAGEKnowledge GraphSPARQL · entity relationshipsIPFS Storagecontent addressed data layerTRUST & PUBLICATIONUCAN Authorizationcapability based securityDataverseDOI registry · publicationauthenticated requestsAI processingsemantic storageauthorize & publish
System Architecture

Who does what

APPLICATION LAYERUsersubmits researchBio-DID-Seq APIBioAgentsmetadata + entitiesAUTHORIZATION LAYERUCAN Authorizationcapability tokensDelegated Accessshare & controlIDENTITY LAYER · SSIW3C DID ImplementationJWT / VC Creationbio-did-registrySolana programSTORAGE LAYERIPFS Storagecontent-addressedPinning ServicepersistenceINTEGRATIONHarvard Dataverse / ZenodopublicationResearch Institutionsacademic partnersauthorizecreate & link DIDstorepublish
System Integration

A useful rule of thumb: the core owns identity, BioAgents owns meaning, the graph owns relationships, IPFS owns bytes, and UCAN owns permission. When you're debugging, the question "which of those five things is wrong?" usually routes you to the right service.

ComponentPrimary ResponsibilitySecondary Functions
Bio-DID-Seq CoreDID ManagementMetadata Registry, UCAN Issuance
BioAgentsKnowledge ExtractionEntity Recognition, Relationship Detection
Knowledge GraphSemantic RepresentationSPARQL Queries, Data Discovery
IPFS StorageDecentralized Data StorageContent Addressing, Data Integrity
UCAN ServiceAuthorization & Access ControlCapability Delegation, Permission Management

Three cross-component workflows

Each of these touches at least three of the five components, which is exactly why they're diagrammed here rather than on any single component's page.

Processing a research paper

Upload Research PaperAuthenticate & AuthorizeStore PaperReturn CIDProcess Paper (CID)Retrieve PaperExtract KnowledgeGenerate Knowledge GraphStore Extracted KnowledgeReturn Graph IDReturn Processing ResultsUpdate DID DocumentPublish to DataverseReturn DOIReturn Complete ResultsResearcherBio-DID-Seq APIIPFS StorageBioAgentsKnowledge GraphDataverse
Sequence Diagram

Answering a knowledge query

Knowledge Query + TokenValidate UCAN TokenAuthorization ResultAuthorizedForward QueryProcess QueryReturn ResultsUnauthorizedAccess DeniedResearcherBio-DID-Seq APIUCAN ServiceKnowledge Graph
Knowledge Query Workflow

Delegating access

Request UCAN for CollaboratorGenerate UCAN TokenReturn TokenReturn UCAN TokenShare TokenRequest Data AccessValidate TokenValidation ResultGrant AccessProvide DataData OwnerBio-DID-SeqUCAN ServiceCollaboratorData Resource
UCAN Delegation

Integration details

Route map

typescript
// Example API routes showing system integration
const apiRoutes = {
  // Bio-DID-Seq Core Routes
  "/api/did": "DID document management",
  "/api/auth": "Authentication & UCAN issuance",
  
  // BioAgents Integration Routes
  "/api/bioagents/process": "Process research papers",
  "/api/bioagents/query": "Natural language queries",
  
  // Knowledge Graph Routes
  "/api/kg/sparql": "SPARQL query endpoint",
  "/api/kg/search": "Semantic search interface",
  
  // Data Integration Routes
  "/api/dataverse": "Dataverse integration",
  "/api/ipfs": "IPFS storage operations"
};

How services talk

Synchronous calls are REST. Long-running work - paper processing, bulk uploads

  • goes through an event bus so nothing holds a connection open for minutes.

WebSockets push status updates to clients, and internal service-to-service traffic uses gRPC where the serialization overhead of JSON would actually show up in latency.

Security at the seams

Component boundaries are where authorization bugs live, so the same two mechanisms guard every crossing: session tokens establish who you are, UCANs establish what you may do.

Login RequestVerify DIDDID VerificationGenerate Auth TokenReturn Auth TokenAPI Request + Auth TokenValidate TokenValidation ResultProcess RequestResponseUserAuth ServiceDID ServiceBio-DID-Seq API
Authentication Flow

Every service that receives a capability token runs the same check:

typescript
async function validateCapability(ucanToken, requiredCapability, resourceId) {
  const valid = await ucanService.verify(ucanToken);
  if (!valid) return false;
  
  const hasCapability = await ucanService.hasCapability(
    ucanToken, 
    requiredCapability,
    resourceId
  );
  
  return hasCapability;
}

Deployment

Everything ships as Docker containers and scales horizontally. The one deployment-relevant subtlety: because the service's signing identity is derived from a seed rather than stored, adding a replica means setting one environment variable, not running a key distribution ceremony.

Why it's split this way

The honest answer is that a monolith would have been easier to build. The split earns its keep in three places: a researcher can trust the storage layer without trusting the AI layer (they never see each other's credentials); the knowledge graph can be rebuilt from scratch without touching a single byte of stored data; and UCAN delegation means collaboration doesn't route through an admin who grants folder permissions. Modularity here isn't an aesthetic - it's what keeps any single component from becoming the thing everyone has to trust.