1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// SPDX-FileCopyrightText: Cadasto B.V.
// SPDX-License-Identifier: BUSL-1.1
//! The European logging software component of an EHR system (Regulation (EU)
//! 2025/327 Art 2(2)(o), Art 25(1), Annex II 3.2 to 3.4).
//!
//! The Regulation asks an EHR system that gives healthcare providers or
//! other individuals access to personal electronic health data to record, on
//! every access event or group of events, who accessed the data, which
//! natural person, the categories of the data, when, and where the data came
//! from (Annex II 3.2). This crate is that record and what classifies it:
//!
//! - [`record`]: the [`AccessRecord`](record::AccessRecord), with the data
//! subject and the purpose of use beside the five points of 3.2;
//! - [`category`]: the Art 14(1) categories and the national categories a
//! deployment declares;
//! - [`map`] and [`classify`]: the deployment's map from template and
//! archetype ids to categories, and the classification of one access by
//! the model ids of what it reached;
//! - [`retention`]: how long a record is kept, by its categories and its
//! origins, never under the three years of Art 9(2);
//! - [`label`]: the security labels a record carries for its categories and
//! its origins, so the store that holds it can limit who reads it
//! (Annex II 3.4);
//! - [`emergency`]: the purposes of use a deployment declares as asserting
//! an access in the vital interests of the data subject (Art 11(5)), and
//! the mark of a record whose accessor declared one;
//! - [`transformation`]: the record of a semantic transformation an access
//! applied, which rides on its access record (eHealth Network General
//! Guidelines Release 3.1 Art 6(3));
//! - [`sink`]: where records go, and why one could not be stored;
//! - `balp` (feature `balp`): the record written as an IHE BALP `AuditEvent`
//! through `ihe-atna`, and the sink over an `ihe-atna` audit recorder.
//!
//! The crate depends on no interoperability component and on nothing of the
//! system that builds the records, so the logging component stays independent
//! of the interoperability component (Art 2(2)(n), (o)).
//!
//! # Examples
//!
//! ```
//! use std::collections::BTreeMap;
//!
//! use ehds_logging::category::Category;
//! use ehds_logging::classify::{Basis, Evidence, RootObject};
//! use ehds_logging::map::{CategoryMap, Declared};
//!
//! let templates = BTreeMap::from([(
//! "Example Lab Report.v1".to_owned(),
//! Declared::Codes(vec!["Laboratory-Reports".to_owned()]),
//! )]);
//! let map = CategoryMap::declare(&[], &templates, &BTreeMap::new())?;
//! let read = RootObject {
//! template_id: Some("Example Lab Report.v1".to_owned()),
//! ..RootObject::default()
//! };
//! let classified = map.classify(&Evidence::reached(Basis::Returned, vec![read]));
//! assert!(classified.categories().contains_key(&Category::MedicalTestResult));
//! assert!(classified.unclassified().is_none());
//! # Ok::<(), ehds_logging::map::MapError>(())
//! ```