SaluData — Arquitectura de Ficha Médica Permisionada
Diagrama SVG (nodos/reglas) + skeletons de interfaces Solidity para la capa on-chain (consentimiento, índice clínico, auditoría, emergencia, directorios, gobernanza).
Diagrama de Arquitectura (SVG)
Interfaces Solidity – Skeletons
Cada interfaz define estructuras y eventos mínimos para la capa de permisos, identidad, índice clínico, auditoría y gobernanza.
Pragma sugerida: ^0.8.24
. Los identificadores tipo DID se representan como bytes32
o string
según preferencia. Aquí se usa bytes32
para eficiencia.
1) IIdentityRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IIdentityRegistry {
enum Role { NONE, REGULATOR, MACRO_NETWORK, PROVIDER, PROFESSIONAL, PATIENT }
struct Entity {
bytes32 did; // Identificador descentralizado
Role role; // Rol verificado
bool active; // Estado
bytes32 meta; // Hash a metadatos off-chain (especialidad, servicio, etc.)
}
event Registered(bytes32 indexed did, address indexed account, Role role);
event Revoked(bytes32 indexed did, address indexed account);
event MetaUpdated(bytes32 indexed did, bytes32 meta);
function register(bytes32 did, address account, Role role, bytes32 meta) external;
function revoke(bytes32 did, address account) external;
function setMeta(bytes32 did, bytes32 meta) external;
function resolve(address account) external view returns (Entity memory);
function resolveByDID(bytes32 did) external view returns (Entity memory);
}
2) IRoleBasedAccessControl.sol (RBAC/ABAC)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IRoleBasedAccessControl {
event PolicySet(bytes32 indexed policyId, bytes32 exprHash); // Expr ABAC off-chain (CEL/Rego/ZK), hash on-chain
event RoleGranted(address indexed account, bytes32 indexed role);
event RoleRevoked(address indexed account, bytes32 indexed role);
function setPolicy(bytes32 policyId, bytes32 exprHash) external;
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function hasRole(bytes32 role, address account) external view returns (bool);
}
3) IConsentManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IConsentManager {
struct Scope {
bool readPermitted; // lectura
bool writePermitted; // anotaciones / adjuntos
uint64 notBefore; // ventana temporal (epoch)
uint64 notAfter; // expiración
bytes32 resourceType; // p.ej. Observation, DiagnosticReport, ImagingStudy
bytes32 resourceTag; // etiquetas: especialidad, establecimiento, etc.
}
event ConsentGranted(bytes32 indexed resourceId, address indexed grantee, Scope scope);
event ConsentRevoked(bytes32 indexed resourceId, address indexed grantee);
event ConsentDelegated(address indexed from, address indexed to, Scope scope);
function grantConsent(bytes32 resourceId, address grantee, Scope calldata scope) external;
function revokeConsent(bytes32 resourceId, address grantee) external;
// Patrón por rol / tipo (p.ej. todos los exámenes Endocrino últimos 6 meses)
event PatternGranted(bytes32 indexed patternId, address indexed granter, bytes32 roleOrType, Scope scope);
function grantByPattern(bytes32 patternId, bytes32 roleOrType, Scope calldata scope) external;
// Delegación de consentimiento (paciente -> profesional/establecimiento)
function delegateConsent(address to, Scope calldata scope) external;
// Chequeo de acceso: off-chain helper debería usar este veredicto
function checkAccess(bytes32 resourceId, address requester) external view returns (bool allowed, Scope memory scope);
}
4) IClinicalDataIndex.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IClinicalDataIndex {
struct Entry {
bytes32 ownerDid; // paciente
bytes32 fhirType; // Observation / DiagnosticReport / ImagingStudy / etc.
bytes32 contentHash; // hash del blob cifrado
bytes uriEnc; // puntero cifrado (p.ej. URL + envelope)
uint64 createdAt; // timestamp
bytes32 tags; // etiquetas resumidas
}
event ResourceIndexed(bytes32 indexed resourceId, bytes32 ownerDid, bytes32 fhirType, bytes32 contentHash);
event PointerRotated(bytes32 indexed resourceId);
function registerResource(bytes32 resourceId, Entry calldata e) external;
function updatePointer(bytes32 resourceId, bytes calldata newUriEnc) external;
function get(bytes32 resourceId) external view returns (Entry memory);
}
5) IEmergencyAccess.sol (Break-glass)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IEmergencyAccess {
enum ReviewStatus { PENDING, APPROVED, REJECTED }
event BreakGlassUsed(address indexed requester, bytes32 indexed patientDid, bytes32 reasonCode, uint64 notAfter);
event BreakGlassReviewed(uint256 indexed ticketId, ReviewStatus status, address reviewer);
function requestEmergency(bytes32 patientDid, bytes32 resourceScope, bytes32 reasonCode, uint64 ttl) external returns (uint256 ticketId);
function reviewEmergency(uint256 ticketId, ReviewStatus status) external;
}
6) IDisclosureLog.sol (Auditoría)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IDisclosureLog {
struct Record { address who; bytes32 what; uint64 whenTs; bytes32 basis; }
event Disclosed(address indexed who, bytes32 indexed what, bytes32 basis, uint64 whenTs);
function seal(address who, bytes32 what, bytes32 basis) external;
function last(address who, bytes32 what) external view returns (Record memory);
}
7) IProviderDirectory.sol / IFacilityDirectory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IProviderDirectory {
event EndpointUpdated(bytes32 indexed did, bytes32 fhirEndpoint);
event KeyRotated(bytes32 indexed did, bytes newPubKey);
function setEndpoint(bytes32 did, bytes32 fhirEndpoint) external;
function rotateKey(bytes32 did, bytes calldata newPubKey) external;
function get(bytes32 did) external view returns (bytes32 fhirEndpoint, bytes memory pubKey);
}
8) IReferralCarePlan.sol (Opcional Fase 2)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IReferralCarePlan {
struct Referral { bytes32 fromDid; bytes32 toDid; bytes32 scope; uint64 expiry; }
event Referred(bytes32 indexed patientDid, bytes32 indexed toDid, bytes32 scope, uint64 expiry);
function createReferral(bytes32 patientDid, bytes32 toDid, bytes32 scope, uint64 expiry) external;
}
9) IPrescriptionRegistry.sol (Opcional)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IPrescriptionRegistry {
struct RxMeta { bytes32 drugCode; uint64 issuedAt; uint64 validUntil; bytes32 prescriberDid; bytes32 tags; }
event RxIndexed(bytes32 indexed rxId, bytes32 patientDid, bytes32 hash);
function indexRx(bytes32 rxId, bytes32 patientDid, bytes32 hash, RxMeta calldata meta) external;
function getRx(bytes32 rxId) external view returns (RxMeta memory meta, bytes32 hash, bytes32 patientDid);
}
10) IResearchAccess.sol (Datasets desidentificados)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IResearchAccess {
enum License { NONE, INTERNAL, ACADEMIC, COMMERCIAL }
struct Dataset { bytes32 id; bytes32 hash; License licenseType; bytes32 meta; }
event DatasetAdded(bytes32 indexed id, License licenseType);
event AccessGranted(bytes32 indexed id, address indexed to);
function addDataset(bytes32 id, bytes32 hash, License licenseType, bytes32 meta) external;
function grant(bytes32 id, address to) external;
function info(bytes32 id) external view returns (Dataset memory);
}
11) IGovernanceDAO.sol (Consorcio)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IGovernanceDAO {
enum ProposalType { ADD_VALIDATOR, REMOVE_VALIDATOR, UPDATE_POLICY, PARAM_CHANGE }
struct Proposal { uint256 id; ProposalType pType; bytes data; uint64 start; uint64 end; bool executed; }
event Proposed(uint256 indexed id, ProposalType pType);
event Voted(uint256 indexed id, address indexed voter, bool support, uint256 weight);
event Executed(uint256 indexed id);
function propose(ProposalType pType, bytes calldata data) external returns (uint256 id);
function vote(uint256 id, bool support) external;
function execute(uint256 id) external;
function get(uint256 id) external view returns (Proposal memory);
}
Siguientes pasos sugeridos: Generar contratos concretos Esquemar tests Definir mapeo DID↔Cuenta Integrar PRE/KMS Definir eventos FHIR
Enfoque
Sostiene una mirada específica que tiene cada actor sobre un mismo concepto dentro de SaluData.
Enfoque Médico: cómo impacta en la práctica clínica y la atención de pacientes.
Enfoque Usuario/Paciente: qué valor aporta en términos de control, confianza y experiencia personal.
Enfoque Inversionista/Analista: qué ventajas ofrece en escalabilidad, sostenibilidad y oportunidad de negocio.
Término | Enfoque Médico | Enfoque Usuario/Paciente | Enfoque Inversionista/Analista |
---|---|---|---|
Ficha Médica Digital Permisionada | Acceso seguro y controlado a la historia clínica. | Solo yo decido quién ve mis datos. | Diferenciada frente a registros centralizados. |
Paciente (Usuario Final) | Actor activo en el manejo de su información. | Soy el dueño de mis datos médicos. | Dueño del activo de datos; nuevo mercado. |
Consentimiento Granular | Acceso a exámenes/periodos específicos. | Botón para dar y quitar acceso en cualquier momento. | Clave de privacidad y confianza. |
MINSAL / Nodo Regulatorio | Respaldo y auditoría sanitaria. | Confianza institucional. | Mitiga riesgo regulatorio. |
Macrorred de Salud | Continuidad de atención en red pública. | Mis datos viajan conmigo entre hospitales. | Escalabilidad nacional. |
Prestadores Privados | Acceso unificado a información del paciente. | Evita repetir exámenes y gastos. | Modelo B2B (clínicas/labs). |
Contratos Inteligentes | Registro automático de accesos. | Nadie entra sin mi permiso. | Eficiencia y reducción de costos. |
Clinical Data Index | Localiza la versión validada del examen. | Sin duplicaciones; todo ordenado. | Base de interoperabilidad eficiente. |
Emergency Access (Break-Glass) | Acceso vital en urgencias con justificación. | Me notifican y queda registro. | Resuelve casos críticos sin perder confianza. |
Wallet del Paciente | Autorizaciones directas del paciente. | Mi app para consentimientos y alertas. | Canal a servicios premium. |
Interoperabilidad FHIR / HL7 | Sistemas hablan el mismo idioma. | Menos trámites y fricción. | Facilita expansión internacional. |
Gobernanza Permisionada | Instituciones validadas y confiables. | Red cerrada y más segura. | Menor riesgo, crecimiento ordenado. |
Auditoría Inmutable | Respaldo legal de accesos. | Historial de quién accedió y cuándo. | Cumplimiento normativo y trazabilidad. |
Criptografía Avanzada (PRE/ABE) | Acceso fluido sin copias extra. | Máxima privacidad y control. | Ventaja tecnológica competitiva. |