✍️

DOC

P4 · Long-term Planned · P4 long-term Owner: CLO seat + CTO

Legally-binding electronic signatures — eIDAS QTSP for EU, AATL for non-EU, VNeID + Vietnamese CA chain for Vietnam. Multi-party workflows, immutable archival, signature audit chain for 10 years.

DOC is the document signing surface. It is P4 long-term because legally-binding electronic signatures require integration with regulated trust-service providers and CyberOS will not pretend to be one. The architecture is partner-routed: the DOC service owns the workflow (upload, template, multi-party order, identity verification, archival), and delegates the cryptographic act of signing to an eIDAS-conformant QTSP (e.g. GlobalSign or Cryptomathic in EU, an Adobe-AATL-listed CA for US/non-EU enterprises, and Vietnamese CAs — VnPay, MK Group, Viettel-CA — for VN tenants). For Vietnamese-citizen signers, identity verification goes through VNeID (the national digital identity service per Decision 06/2022/QĐ-TTg). The signing chain is preserved as a per-document hash-chained audit log (certificate hash + timestamp authority + WebAuthn binding + identity-proof event). Signed PDFs are archived to an S3 Object-Lock-Compliance bucket with 10-year retention (eIDAS, US ESIGN), residency-pinned per tenant. DocuSign / Adobe Sign / HelloSign migration support lets customers bring legacy signed-document libraries into CyberOS without re-signing. Risk: notary fraud — high-value signing requires multi-factor identity verification before the request leaves DOC. PRD §9.20 and SRS §7.20 lock the FRs.

DOC is CyberOS's e-signature workflow + immutable archival service. The cryptographic signing act is delegated to an eIDAS-conformant QTSP (qualified trust-service provider) per jurisdiction; DOC owns everything else: document upload + SHA-256 integrity hashing, template definition + auto-fill from CRM data, multi-party workflow (signer order, parallel vs sequential), identity verification (WebAuthn for CyberOS-resident users; VNeID for Vietnamese citizens; SMS-OTP fallback), per-document hash-chained audit log, and S3 Object-Lock archival with residency-pinning. Three certificate chains are supported: eIDAS QTSP (qualified electronic signature, QES) for the EU; Adobe AATL for US/non-EU enterprise; Vietnamese CA chain (VnPay, MK Group, Viettel-CA) for VN per Decree 130/2018. Migration paths from DocuSign, Adobe Sign, and HelloSign preserve original audit trails without re-signing. The default retention is 10 years; longer per applicable law (e.g. employment contracts under VN labour law).

Status
Planned
P4 long-term
Cert chains
3
eIDAS · AATL · VN CA
Identity proof
4 methods
WebAuthn · VNeID · SMS-OTP · email-link
Retention
10 years
eIDAS · ESIGN minimum
Archive
S3 Object-Lock
Compliance mode + residency pin
Migration
3 sources
DocuSign · Adobe Sign · HelloSign
i18n
vi + en
+ regional certs
Depends on
AUTH · BRAIN · QTSP partner
+ CRM · HR · INV consumers
1

Why DOC exists

Consultancies sign documents all day: MSAs, SOWs, employment contracts, NDAs, change orders, supplier agreements, COIs, retention letters. They send them through DocuSign or Adobe Sign at $30–$50 per seat per month, and the resulting signed PDFs land in someone's email or shared drive — never in the same audit chain as the workflow that produced them, never re-discoverable by the AI surface, never bound to the CRM record. DOC fixes this by making "sign this document" a first-class CyberOS workflow: the template is defined in DOC, the signer field auto-pulls from CRM, the QTSP partner does the actual crypto, and the resulting PDF + cert chain + audit log lands back in DOC, citable from BRAIN, and visible to the AM in CHAT. The cost saving (no per-seat DocuSign) is incidental; the integration is the value.

🤝
Partner-routed signing

DOC owns the workflow; eIDAS QTSP / Adobe AATL / VN CA owns the crypto. CyberOS does not invent trust — it integrates regulated trust.

🆔
Identity proof matters

VNeID for VN citizens, WebAuthn for repeat signers, SMS-OTP for one-time external signers. High-value docs require multi-factor.

📦
Archive is immutable

Signed PDFs land in S3 Object-Lock Compliance mode with 10-year retention. The "did they actually sign?" question is one cosign verification away.

The bet is that the dollars saved on DocuSign are nice but the real value is the binding: a signed MSA appears as a CRM activity, an employment contract appears in HR, a SOW appears under PROJ.engagement, an INV-issued purchase order links to the signed-doc record. Future-AI surfaces — "show me every signed agreement with Acme Corp" — become a single GraphQL query, not a Sharepoint hunt.

2

What it does — 5W1H2C5M

Structured decomposition. Cells trace to PRD §9.20 + SRS §7.20.

AxisQuestionAnswer
5W · WhatWhat is DOC?A document-management + e-signature workflow service. Owns: documents, templates, signing sessions, signature records, identity-verification events, audit log, archive. Delegates cryptographic signing to QTSP partners.
5W · WhoWho uses it?AMs: initiate MSA / SOW signing. HR: contract signing. Finance: PO + invoice signing. Counterparties: external signers via email link. CLO: reviews high-value docs pre-send.
5W · WhenWhen does it run?On-demand for signing-session create. Continuous for archival jobs and certificate-chain validation. Nightly for retention-policy enforcement (purge after retention expiry per legal).
5W · WhereWhere does it run?P4: SG-1 primary + VN-hanoi-1 partition. S3 Object-Lock bucket per residency. QTSP API calls outbound to partner regions.
5W · WhyWhy a separate module?Because every other module needs to attach signed documents to its primitives (CRM.deal → MSA, HR.employee → contract, INV.invoice → signed PO). Owning the surface once means every consumer reads the same signature audit chain.
1H · HowHow does it work?Document upload → SHA-256 integrity hash → template overlay (auto-fill from CRM/HR data) → signing session created with ordered signer list → identity verification per signer (WebAuthn/VNeID/SMS) → QTSP signing call → certificate + timestamp returned → PDF stamped + AATL/CAdES-format embedded → archive to S3 Object-Lock.
2C · CostCost budget?P4: QTSP partner cost ~$0.50–$2.00 per signature (passes through). Infra ~$80 / month (Fargate + S3 storage + Object-Lock + KMS).
2C · ConstraintsConstraints?(a) eIDAS conformity required for QES — partner-only. (b) VN Decree 130/2018 — signature must use VN-licenced CA for legal effect in VN. (c) 10-year minimum retention. (d) PDPL Art. 14 DSAR — export support for signers' own data. (e) GDPR Art. 17 — purge with archival exemption for legal docs.
5M · MaterialsStack?Rust 1.81 · axum · sqlx · PostgreSQL 16 · S3 (Object-Lock Compliance) · KMS · pdfium for PDF manipulation · CAdES + PAdES formats · OpenTelemetry. QTSP partners: GlobalSign (EU), DigiCert (US-AATL), VnPay (VN), MK Group (VN), Viettel-CA (VN).
5M · MethodsMethod choices?PAdES-B-LT (long-term) format for archived PDFs — includes cert chain + revocation info + LTV. Per-document hash-chained audit log mirrors BRAIN chain semantics. Multi-signer workflows are state machines.
5M · MachinesDeployment?Fargate tasks (workflow), separate task for archival jobs. S3 Object-Lock buckets per residency. KMS-wrapped encryption for at-rest documents.
5M · ManpowerWho maintains?0.3 FTE at P4; legal counsel reviews QTSP partner contracts annually; security review of cert-chain handling annually.
5M · MeasurementHow measured?N(FR pending) (signature non-repudiation — cosign verifies any archive byte-for-byte), N(FR pending) (zero archive loss over 10 years), KPI signature-time p95 (≤ 5 min including human-confirm).
3

Architecture

DOC is a Rust service split into three planes: workflow (document, template, session, signer state machine), partner-broker (QTSP routing per jurisdiction), and archive (S3 Object-Lock + LTV PAdES validation). The architecture is partner-routed: signature crypto never happens inside CyberOS; identity verification is normalised across WebAuthn / VNeID / SMS-OTP / email-link.

graph TB subgraph UI ["UI surfaces"] SPA["Signer SPA
(React + pdf.js)"] TPL["Template designer"] INBOX["Counterparty link"] end subgraph DOC ["DOC service (Rust · axum)"] DCRUD["doc.rs
document CRUD"] TPL_S["template.rs
field overlay"] SESSION["session.rs
signing-session state machine"] SIGNER["signer.rs
per-signer flow"] IDV["idv.rs
identity verification dispatcher"] BROKER["broker.rs
QTSP routing"] ARCHIVE["archive.rs
PAdES-LT + S3 Object-Lock"] MIGRATE["migrate.rs
DocuSign / AdobeSign import"] PDF["pdf.rs
pdfium wrapper"] end subgraph IDV_BACKENDS ["Identity-verification backends"] WA["AUTH WebAuthn"] VNEID["🇻🇳 VNeID API"] SMS["SMS-OTP provider"] EMAIL["Email-link"] end subgraph QTSP ["QTSP partners (delegated crypto)"] GS["GlobalSign QTSP (EU)"] DG["DigiCert AATL (US/non-EU)"] VNPAY["VnPay CA (VN)"] MKG["MK Group CA (VN)"] VTL["Viettel-CA (VN)"] end subgraph STORES ["Stores"] PG[("PostgreSQL 16
doc.document · template
session · signer · signature
audit_event")] S3[("S3 Object-Lock Compliance
10y retention
residency-pinned")] KMS[("AWS KMS
document encryption keys")] end subgraph SINKS ["Audit"] BRAIN["🧠 BRAIN
doc.* rows"] OBS["👁 OBS"] end SPA --> DCRUD TPL --> TPL_S INBOX --> SIGNER DCRUD --> PDF DCRUD --> S3 DCRUD --> KMS TPL_S --> PG SESSION --> PG SESSION --> SIGNER SIGNER --> IDV IDV --> WA IDV --> VNEID IDV --> SMS IDV --> EMAIL SIGNER --> BROKER BROKER --> GS BROKER --> DG BROKER --> VNPAY BROKER --> MKG BROKER --> VTL BROKER --> ARCHIVE ARCHIVE --> S3 ARCHIVE --> BRAIN SESSION --> BRAIN DOC --> OBS MIGRATE --> S3 MIGRATE --> PG classDef planned fill:#fde68a,stroke:#78350f classDef store fill:#f5f3ff,stroke:#7c3aed classDef sink fill:#f5ede6,stroke:#45210e classDef partner fill:#fef2f2,stroke:#7f1d1d class SPA,TPL,INBOX,DCRUD,TPL_S,SESSION,SIGNER,IDV,BROKER,ARCHIVE,MIGRATE,PDF planned class PG,S3,KMS store class BRAIN,OBS sink class GS,DG,VNPAY,MKG,VTL,WA,VNEID,SMS,EMAIL partner

Internal components

ComponentPath (planned)Responsibility
doc.rsservices/doc/src/doc.rsDocument CRUD — upload, version, SHA-256 hash, encrypt-at-rest via KMS, store on S3.
template.rsservices/doc/src/template.rsTemplate definition: signer fields, text fields, date fields, conditional fields. Auto-fill rules pulling from CRM/HR/INV.
session.rsservices/doc/src/session.rsSigning session: ordered signer list, parallel/sequential mode, deadline, reminder schedule.
signer.rsservices/doc/src/signer.rsPer-signer state machine: invited → identity_verified → signed | rejected | expired.
idv.rsservices/doc/src/idv.rsIdentity-verification dispatcher. Routes based on signer profile + document risk-tier. WebAuthn / VNeID / SMS-OTP / email-link.
vneid.rsservices/doc/src/vneid.rsVNeID API client. CCCD (Citizen ID) validation; biometric assertion for high-value docs (Decision 06/2022/QĐ-TTg).
broker.rsservices/doc/src/broker.rsQTSP routing. Picks partner per (jurisdiction × document_type × signer_country). Failover between partners on outage.
pades.rsservices/doc/src/pades.rsPAdES-B-LT formatter. Embeds cert chain + OCSP revocation info + DSS dictionary for long-term validation.
archive.rsservices/doc/src/archive.rsS3 Object-Lock Compliance archival. Residency-pinned bucket. 10-year retention by default; per-tenant override.
audit_chain.rsservices/doc/src/audit_chain.rsPer-document hash-chained audit log. Each signature event chains to previous; export bundle for legal discovery.
retention.rsservices/doc/src/retention.rsRetention policy enforcement. Nightly job: identifies docs past retention + legal hold lifted; purges with audit row.
migrate.rsservices/doc/src/migrate.rsDocuSign / Adobe Sign / HelloSign import. Preserves original audit trail; flags imported docs as "external-trust".
fraud.rsservices/doc/src/fraud.rsNotary-fraud detection: velocity check, impossible-travel for signers, device fingerprint, anomaly score.
migrations/services/doc/migrations/sqlx migrations. RLS by tenant_id. Indices on (doc_id), (session_id, signer_id), (status).
DOC-INV-001 · Signed-document integrity is byte-for-byte verifiable

Every archived PDF MUST cosign-verify against (a) its SHA-256 stored at archive time, (b) its cert chain stored with the document, and (c) its BRAIN audit-chain leaf. The verification path is implemented in cyberos-doc verify --archive-id … and is exercised quarterly by an automated chaos job that randomly picks 1% of archived docs and verifies them. Failure halts retention purges until investigation completes.

4

Data model

Documents, templates, signing sessions, signers, signatures, audit events, archive records. PostgreSQL holds metadata; PDF content (encrypted) lives on S3 Object-Lock.

erDiagram TENANT ||--o{ DOCUMENT : "owns" TENANT ||--o{ TEMPLATE : "defines" DOCUMENT ||--o| TEMPLATE : "instantiated from" DOCUMENT ||--o{ SIGNING_SESSION : "has" SIGNING_SESSION ||--o{ SIGNER : "lists" SIGNER ||--o| SIGNATURE : "produces" SIGNATURE ||--o{ AUDIT_EVENT : "logs" SIGNING_SESSION ||--o{ AUDIT_EVENT : "logs" DOCUMENT ||--o{ AUDIT_EVENT : "logs" DOCUMENT ||--o| ARCHIVE : "archived as" TEMPLATE ||--o{ TEMPLATE_FIELD : "defines" TENANT { uuid id PK string slug string default_residency int default_retention_years } DOCUMENT { uuid id PK uuid tenant_id FK string name string s3_key "encrypted at rest" string sha256_original string status "draft | in_signing | executed | expired | revoked" uuid template_id FK timestamp created_at uuid created_by FK } TEMPLATE { uuid id PK uuid tenant_id FK string name string jurisdiction "EU | US | VN | OTHER" string s3_key "template PDF" timestamp created_at } TEMPLATE_FIELD { uuid id PK uuid template_id FK string field_type "signature | text | date | checkbox | initial" string name int page int x int y int width int height string auto_fill_source "crm.contact.name | hr.member.email | …" } SIGNING_SESSION { uuid id PK uuid document_id FK string mode "sequential | parallel" timestamp deadline string status "open | completed | expired | cancelled" string brain_chain } SIGNER { uuid id PK uuid session_id FK int order_index string email string display_name string country "VN | EU | US | …" string idv_method "webauthn | vneid | sms_otp | email_link" string idv_proof_id "external reference" string status "invited | viewed | identity_verified | signed | rejected | expired" timestamp invited_at timestamp signed_at } SIGNATURE { uuid id PK uuid signer_id FK string qtsp_partner "globalsign | digicert | vnpay | mkgroup | viettelca" bytea cert_chain "X.509 chain DER" string timestamp_authority "RFC 3161 TSA" bytea signature_blob "CAdES detached or PAdES embedded" string sha256_signed_pdf timestamp signed_at string brain_chain } AUDIT_EVENT { uuid id PK uuid document_id FK string actor_type "human | agent | system | qtsp" uuid actor_id string event_type "uploaded | template_applied | session_created | invited | viewed | idv_attempted | idv_passed | signed | rejected | archived | purge_blocked | purged" string event_chain_hash string prev_chain_hash bytea details_json timestamp ts } ARCHIVE { uuid id PK uuid document_id FK string s3_bucket "cyberos-doc-archive-vn-hanoi" string s3_key string sha256_archived string pades_b_lt_format date retention_until bool legal_hold timestamp archived_at }

Per-document audit chain (mirrors BRAIN semantics)

// each audit_event row carries:
//   prev_chain_hash  = previous event's chain hash for this doc
//   event_chain_hash = SHA-256(canonical(this_event_minus_chain) || prev_chain_hash)
//
// `cyberos-doc verify --doc-id …` walks the chain end-to-end:
//   - validates SHA-256 of original at upload event
//   - validates each event's chain hash
//   - validates QTSP cert chain at signed event
//   - validates timestamp authority RFC 3161 token
//   - validates final archive SHA-256 against archive event
//
// Tampering at any point fails verification with a precise diagnosis row.
5

API surface

GraphQL subgraph for cross-module reads (CRM.deal → contract list, HR.member → contract history), REST for the signer SPA, MCP tools for natural-language workflow ("send the standard MSA to acme@…").

GraphQL subgraph (federated)

extend schema
  @link(url: "https://specs.apollo.dev/federation/v2.5", import: ["@key", "@external", "@shareable", "@requiresScopes"])

type Document @key(fields: "id") {
  id: ID!
  name: String!
  status: DocStatus!
  template: Template
  sessions: [SigningSession!]!
  auditEvents: [AuditEvent!]!
  archive: Archive
  createdAt: DateTime!
}

type Template @key(fields: "id") {
  id: ID!
  name: String!
  jurisdiction: Jurisdiction!
  fields: [TemplateField!]!
}

type TemplateField {
  fieldType: FieldType!
  name: String!
  autoFillSource: String
}

type SigningSession @key(fields: "id") {
  id: ID!
  document: Document!
  mode: SessionMode!
  status: SessionStatus!
  deadline: DateTime!
  signers: [Signer!]!
}

type Signer @key(fields: "id") {
  id: ID!
  orderIndex: Int!
  email: String!
  displayName: String!
  country: String!
  idvMethod: IdvMethod!
  status: SignerStatus!
  signature: Signature
}

type Signature {
  qtspPartner: QtspPartner!
  timestampAuthority: String!
  signedAt: DateTime!
}

type AuditEvent {
  eventType: AuditEventType!
  actorType: ActorType!
  ts: DateTime!
  eventChainHash: String!
}

type Archive {
  s3Bucket: String!
  retentionUntil: Date!
  legalHold: Boolean!
  padesFormat: String!
}

enum DocStatus { DRAFT IN_SIGNING EXECUTED EXPIRED REVOKED }
enum SessionMode { SEQUENTIAL PARALLEL }
enum SessionStatus { OPEN COMPLETED EXPIRED CANCELLED }
enum SignerStatus { INVITED VIEWED IDENTITY_VERIFIED SIGNED REJECTED EXPIRED }
enum IdvMethod { WEBAUTHN VNEID SMS_OTP EMAIL_LINK }
enum QtspPartner { GLOBALSIGN DIGICERT VNPAY MKGROUP VIETTELCA }
enum Jurisdiction { EU US VN OTHER }
enum FieldType { SIGNATURE TEXT DATE CHECKBOX INITIAL }
enum ActorType { HUMAN AGENT SYSTEM QTSP }
enum AuditEventType { UPLOADED TEMPLATE_APPLIED SESSION_CREATED INVITED VIEWED IDV_ATTEMPTED IDV_PASSED SIGNED REJECTED ARCHIVED PURGE_BLOCKED PURGED }

extend type Deal @key(fields: "id") {
  id: ID! @external
  documents: [Document!]! @requiresScopes(scopes: [["doc.read"]])
}

extend type Member @key(fields: "id") {
  id: ID! @external
  contracts: [Document!]! @requiresScopes(scopes: [["doc.read"]])
}

type Query {
  document(id: ID!): Document @requiresScopes(scopes: [["doc.read"]])
  myPendingSignatures: [Signer!]! @requiresScopes(scopes: [["doc.read"]])
  templates(jurisdiction: Jurisdiction): [Template!]! @requiresScopes(scopes: [["doc.read"]])
}

type Mutation {
  uploadDocument(name: String!, sha256: String!): UploadUrl! @requiresScopes(scopes: [["doc.write"]])
  createSession(input: SessionInput!): SigningSession! @requiresScopes(scopes: [["doc.write"]])
  cancelSession(id: ID!, reason: String!): SigningSession! @requiresScopes(scopes: [["doc.write"]])
  setLegalHold(documentId: ID!, hold: Boolean!): Document!
    @requiresScopes(scopes: [["doc.legal_hold"]])
}

REST endpoints

MethodPathPurpose
POST/doc/uploadMultipart upload — returns doc_id + s3_key.
POST/doc/{id}/template/{tpl}Apply template overlay; resolve auto-fill from CRM/HR.
POST/doc/{id}/sessionCreate signing session.
GET/doc/sign/{signer_token}External signer landing page (counterparty).
POST/doc/sign/{signer_token}/idvIdentity-verification challenge response.
POST/doc/sign/{signer_token}/finalizeCapture signature; trigger QTSP call.
GET/doc/{id}/audit-bundle.zipLegal-discovery bundle: PDF + cert chain + audit log.
POST/doc/migrate/docusignImport legacy DocuSign envelope (preserve original trail).
POST/doc/migrate/adobesignImport legacy Adobe Sign.
POST/doc/migrate/hellosignImport legacy HelloSign.
GET/doc/{id}/verifyCosign verify of archived PDF.
POST/doc/{id}/legal-holdApply / lift legal hold.
POST/doc/admin/retention-sweepRun nightly retention sweep manually.

MCP tool catalogue

Tool nameInputsOutputsAnnotations
cyberos.doc.listfilter, status?Document[]readonly · scope=doc.read
cyberos.doc.start_signingtemplate_id, deal_id, signers[]{session_id, signer_links[]}destructive · scope=doc.write · human-confirm
cyberos.doc.statussession_id{session, signers}readonly
cyberos.doc.cancel_sessionsession_id, reason{ok}destructive · scope=doc.write · human-confirm
cyberos.doc.find_templatename_match, jurisdictionTemplate[]readonly
cyberos.doc.legal_discovery_bundledoc_id{zip_url}destructive · scope=doc.legal_export
cyberos.doc.verify_archivedoc_id{ok, diagnostics}readonly
cyberos.doc.set_legal_holddoc_id, hold{ok}destructive · scope=doc.legal_hold · human-confirm
6

Key flows

Flow 1 — Document upload + template fill

sequenceDiagram autonumber participant AM as Account Manager participant SPA as DOC SPA participant D as doc.rs participant T as template.rs participant CRM as 🏢 CRM participant KMS as AWS KMS participant S3 as S3 (residency-pinned) participant B as 🧠 BRAIN AM->>SPA: upload "Acme MSA.pdf" + select template "MSA-EU-v3" SPA->>D: POST /doc/upload (multipart, sha256) D->>KMS: encrypt at rest (envelope) D->>S3: PutObject (encrypted body) D->>B: append doc.uploaded row {sha256, by:AM} SPA->>T: POST /doc/{id}/template/MSA-EU-v3 T->>CRM: query Deal.contact for auto-fill (name, email, address) CRM-->>T: contact rows T->>T: overlay fields onto template canvas; SHA-256 final body T->>B: append template.applied row T-->>SPA: ready-to-send preview

Flow 2 — Multi-party signing (sequential)

sequenceDiagram autonumber participant AM as Account Manager participant S as session.rs participant Sa as Signer A (CEO of Acme) participant Sb as Signer B (CyberSkill CEO) participant I as idv.rs participant BK as broker.rs participant QTSP as eIDAS QTSP (GlobalSign) participant B as 🧠 BRAIN AM->>S: createSession(mode=sequential, signers=[A, B], deadline=14d) S->>B: append session.created row S->>Sa: email magic link (signer order_index=1) Sa->>I: opens link · IDV via email-link (T2 doc) I-->>Sa: identity verified Sa->>S: views + signs S->>BK: route signature(country=EU, doc_type=MSA) BK->>QTSP: sign call (cert chain, RFC 3161 timestamp) QTSP-->>BK: CAdES blob + cert chain + TSA token BK->>S: signature stored S->>B: append signer.signed row {A} S->>Sb: email magic link (order=2) Sb->>I: WebAuthn (CyberSkill member, AAL3) I-->>Sb: identity verified Sb->>S: views + signs S->>BK: route again BK->>QTSP: sign QTSP-->>BK: signature blob BK->>S: signature stored S->>S: all signers complete → session.complete S->>B: append session.completed row S->>S: trigger archive flow (Flow 5)

Sequential mode means signer B's magic link is not emitted until A signs. Parallel mode emits both at once; first-to-sign rule + reminder cadence still apply.

Flow 3 — Identity verification + sign with VNeID

sequenceDiagram autonumber participant S as Signer (VN citizen) participant SPA as DOC SPA participant I as idv.rs participant V as vneid.rs participant VNEID as 🇻🇳 VNeID API participant BK as broker.rs participant VNCA as VN CA (e.g., VnPay) participant B as 🧠 BRAIN S->>SPA: open signing page SPA->>I: getIdvChallenge(country=VN, risk=high) I->>V: prepare VNeID challenge (CCCD + biometric) V->>VNEID: createIdentityVerification VNEID-->>V: deeplink to VNeID app V-->>SPA: deeplink + QR S->>VNEID: open app, scan, biometric capture VNEID-->>V: idv_proof_id, attributes (full_name, CCCD, DOB) V->>I: pass idv I->>B: append idv.passed row {method:vneid, proof_id} I-->>SPA: ready to sign S->>SPA: confirm sign SPA->>BK: route signature (country=VN) BK->>VNCA: sign call (signer attrs from VNeID) VNCA-->>BK: CAdES blob + cert chain (VN root) BK->>B: append signed row

Flow 4 — Long-term archival (PAdES-B-LT + S3 Object-Lock)

sequenceDiagram autonumber participant S as session.rs (all signed) participant P as pades.rs participant A as archive.rs participant KMS as AWS KMS participant S3 as S3 Object-Lock Compliance participant TSA as RFC 3161 TSA participant B as 🧠 BRAIN S->>P: assemble PAdES-B-LT P->>P: embed cert chain (all signers) P->>P: embed OCSP responses (revocation info) P->>TSA: outer timestamp (long-term validation) TSA-->>P: TSA token P->>P: DSS dictionary + LTV P->>A: hand off PDF A->>KMS: encrypt at rest A->>S3: PutObject with Object-Lock retain-until = now + 10y; LegalHold=OFF S3-->>A: ETag + VersionId A->>B: append archive.completed row {s3_key, retention_until, sha256} A->>S: archive ready

Object-Lock Compliance mode means even the AWS account root cannot delete the object before retention expiry. Legal hold is a separate flag that can be applied later to extend protection.

Flow 5 — DocuSign migration (preserve original trail)

sequenceDiagram autonumber participant CLO as CLO participant M as migrate.rs participant DS as DocuSign API participant A as archive.rs participant S3 as S3 Object-Lock participant B as 🧠 BRAIN CLO->>M: cyberos-doc migrate-docusign --since 2020-01-01 M->>DS: list envelopes (paged) loop per envelope DS-->>M: envelope_id, signed PDF URL, audit log M->>DS: GET signed PDF + cert chain + audit JSON DS-->>M: bytes + metadata M->>M: validate DocuSign cert chain (AATL trust) M->>A: archive original PDF (no re-sign) A->>S3: PutObject (Object-Lock) M->>B: append migration.imported row {source:docusign, original_envelope_id, trust:external} end M->>CLO: report N migrated · 0 failures

Migration preserves the original DocuSign audit trail in audit_event.details_json. Documents are flagged trust=external so consumers know the signature was produced by another provider.

7

Signing-session lifecycle

A session traverses six states; the per-signer state machine sits inside Open. Every transition writes an audit event.

stateDiagram-v2 [*] --> Draft: document uploaded + template applied Draft --> Open: createSession() Open --> Completed: all signers signed Open --> Expired: deadline passed Open --> Cancelled: AM revoked OR signer rejected Completed --> Archived: PAdES-LT + S3 Object-Lock Archived --> [*] Expired --> [*] Cancelled --> [*] state Open { [*] --> Invited Invited --> Viewed: signer opens link Viewed --> IdvAttempted: starts identity verification IdvAttempted --> IdvPassed: verified IdvAttempted --> IdvFailed: too many retries IdvPassed --> Signed: signer captures signature IdvPassed --> Rejected: signer declines Signed --> [*] Rejected --> [*] IdvFailed --> [*] }

Per-state actions

StateTriggerSide-effects
Draftdocument + template readyAudit row template.applied; preview rendered.
OpencreateSession() successFirst signer notified (sequential) or all signers notified (parallel); reminders scheduled.
Invitedsigner email sentMagic-link token issued; expiry = session deadline.
Viewedsigner opens linkAudit row signer.viewed with IP + UA + device fingerprint.
IdvPassedidentity verifiedAudit row idv.passed with method + proof_id.
SignedQTSP signature returnedAudit row signer.signed with cert chain + TSA token.
Completedall signers signedTrigger archive flow; downstream consumers (CRM / HR / INV) notified.
ArchivedPAdES-LT written to S3 Object-LockAudit row archive.completed; retention timer starts.
Expireddeadline reached without all signingAudit row session.expired; AM notified; document remains in PG (no archive).
CancelledAM revoke OR signer rejectAudit row session.cancelled with reason; all signer tokens invalidated.
8

Functional Requirements

The CyberOS FR catalogue is being rebuilt one feature at a time via the open fr-author Agent Skill.

Previous FR enumerations were archived 2026-05-14 and are no longer reflected on this page. PRD/SRS narrative remains authoritative for the spec; specific FRs land here as they are re-authored.

9

Non-Functional Requirements

DOC NFRs centre on signature non-repudiation and long-term archival durability.

NFR IDConcernTargetMeasurement
N(FR pending)Signature non-repudiation (cosign verifies archive byte-for-byte)100% of archivesquarterly chaos audit (random 1%)
N(FR pending)Cross-tenant document leak= 0RLS verification harness
N(FR pending)Archive durability (no archive loss over 10 years)11x9s (S3 Object-Lock guarantee)S3 SLA
N(FR pending)Audit-chain integrity= 0 broken chainsnightly walker job
N(FR pending)uploadDocument server-canonical p95≤ 3 s (10 MB PDF)k6
N(FR pending)End-to-end sign (after IDV) p95≤ 8 sRUM
N(FR pending)QTSP partner round-trip p95≤ 5 s (network)per-partner SLO
N(FR pending)DOC availability≥ 99.9% (P4)SLO monitor
N(FR pending)QTSP partner failover RTO≤ 60 s on partner outagechaos test
N(FR pending)eIDAS QES conformity (annual audit)passedexternal auditor
N(FR pending)VN Decree 130/2018 cert chain validity100%VN CA SLA
10

Dependencies

DOC depends on AUTH (WebAuthn), BRAIN (audit), KMS + S3 (archival), and at least one QTSP partner per jurisdiction. Consumed by CRM (deal contracts), HR (employment contracts), INV (signed POs), and PORTAL (client signing).

graph LR subgraph upstream ["DOC depends on"] AUTH["🔐 AUTH
WebAuthn + RBAC"] BRAIN["🧠 BRAIN
audit chain"] OBS["👁 OBS"] KMS["🔑 AWS KMS"] S3["🗄 S3 Object-Lock"] VNEID["🇻🇳 VNeID API"] QTSP["🤝 QTSP partners
GlobalSign · DigiCert · VnPay · MK · Viettel-CA"] TSA["RFC 3161 TSA"] CRM["🏢 CRM
contact auto-fill"] HR_UP["👥 HR
member auto-fill"] end DOC["✍️ DOC"] subgraph downstream ["Used by"] CRM_D["🏢 CRM
deal contracts"] HR_D["👥 HR
employment contracts"] INV_D["💰 INV
signed POs"] PORTAL["🌐 PORTAL
client signing"] BRAIN_D["🧠 BRAIN
doc citations"] end AUTH --> DOC BRAIN --> DOC OBS --> DOC KMS --> DOC S3 --> DOC VNEID --> DOC QTSP --> DOC TSA --> DOC CRM --> DOC HR_UP --> DOC DOC --> CRM_D DOC --> HR_D DOC --> INV_D DOC --> PORTAL DOC --> BRAIN_D classDef planned fill:#fde68a,stroke:#78350f classDef partner fill:#fef2f2,stroke:#7f1d1d class AUTH,BRAIN,OBS,KMS,S3,CRM,HR_UP,DOC,CRM_D,HR_D,INV_D,PORTAL,BRAIN_D planned class VNEID,QTSP,TSA partner
11

Compliance scope

DOC is the most regulation-heavy module after AUTH. Signature legality across jurisdictions is its entire job.

Regulation / standardArticle / clauseDOC feature that satisfies it
eIDAS (EU Reg. 910/2014)Art. 25 — Legal effects of e-signaturesQES via partner QTSP for EU; AdES default for non-QES use cases.
eIDASArt. 32 — Validation of QESPAdES-B-LT embedded cert chain + OCSP + LTV timestamp.
eIDASArt. 34 — Long-term preservationS3 Object-Lock Compliance 10y; LTV outer timestamp.
EU ESI standardsETSI EN 319 142 — PAdES baselinePAdES-B-LT format implemented.
US ESIGN Act (15 U.S.C. §7001)Consent + intent + record retentionExplicit consent UI; intent captured at sign; 10-year retention.
US UETAState e-signature recognitionAATL cert chain via DigiCert.
Vietnam Decree 130/2018/NĐ-CPE-signature legal recognitionVN CA chain (VnPay / MK / Viettel-CA); compliant cert profile.
Vietnam Decision 06/2022/QĐ-TTgNational digital identity (VNeID)VNeID integration via vneid.rs for VN citizens.
Vietnam Law 91/2025/QH15 (PDPL)Art. 14 — DSARDSAR export bundles documents + audit chains.
GDPR (EU 2016/679)Art. 15 — Right of accessSame surface as PDPL.
GDPRArt. 17 — Right to erasurePurge supported with legal-hold + retention-period exemptions; audit fact of erasure remains.
ISO/IEC 27001:2022A.5.34 — Privacy in developmentDocuments encrypted at rest via KMS; access RLS-keyed.
ISO 14533-1 (PAdES)Long-term archival profilesPAdES-B-LT format.
SOC 2 Type IICC6.1 — Logical accessRBAC + multi-factor for high-value signing.
12

Risk entries

DOC-specific risks in the risk register.

IDRiskLikelihoodImpactOwnerMitigation
R-DOC-001Spoofing / Repudiation — forged signatureLowCatastrophicCLOeIDAS QTSP cert chain; WebAuthn binding; multi-factor for high-value docs; quarterly external audit.
R-DOC-002Notary-fraud / impersonation via SMS-OTP onlyMediumHighCSOSMS-OTP restricted to low-value docs; high-value requires WebAuthn or VNeID biometric.
R-DOC-003QTSP partner outage during signing campaignMediumMediumCTOMulti-partner per jurisdiction; broker.rs failover; 60s RTO chaos-tested.
R-DOC-004VNeID API breaking changeMediumHighCTOAdapter pattern in vneid.rs; integration tests on every release; VN CA fallback for non-biometric path.
R-DOC-005S3 Object-Lock misconfiguration allows premature deletionLowCatastrophicCSOCompliance mode (not Governance); CI test verifies retention-until; account-root cannot override.
R-DOC-006Legal-hold lift granted to non-CLOLowHighCSO(FR pending) scope=doc.legal_hold limited to CLO + DPO; quarterly access review.
R-DOC-007Cert chain expires; PAdES-LT cannot validate decades laterMediumHighCTOPAdES-B-LT includes LTV outer timestamp; periodic re-stamping job at year 9 (1y before retention end).
R-DOC-008Cross-tenant document leak via shared S3 bucketLowCatastrophicCSOPer-tenant bucket prefix; IAM scoped per tenant; pre-signed-URL audience-bound.
R-DOC-009Migration import accepts forged DocuSign trailLowHighCLOImports flagged trust=external; cert chain validated against AATL root; CLO approves import batches.
R-DOC-010GDPR Art. 17 purge collides with retention obligationMediumMediumDPOPurge requires CLO sign-off + retention-exempt classification; rejection logged with reason.
13

KPIs

DOC health rolls up into 9 KPIs covering signing speed, completion rate, audit integrity, and compliance posture.

KPIFormulaSourceTarget
Session completion ratecompleted / opened (per 30d)doc.signing_session≥ 75%
Time-to-first-signature p95histogramOBS≤ 24 h
Time-to-completion p95histogramOBS≤ 7 d
QTSP partner success ratesigned / attemptedbroker.rs≥ 99.5%
Identity-verification pass rateidv.passed / idv.attemptedidv.rs≥ 90%
Archive verification successquarterly chaos auditchaos job= 100%
Cosign chain validation successnightly walkerOBS= 100%
Fraud-detection alerts / monthcountfraud.rstracked
Migration trust-external flag rateexternal / totaldoc.documentdeclining trend
14

RACI matrix

DOC is owned by the CLO seat (legal effect) with CTO for engineering and DPO for data-subject rights.

ActivityCEOCLOCTOCSODPOCFO
Service design + specARRCCI
ImplementationICA/RCII
QTSP partner selection + contractsCA/RRCIC
Legal-hold application / liftCA/RICRI
Retention-policy review (10y default)CA/RIICI
eIDAS / Decree 130 conformity auditCA/RCRCI
Notary-fraud incident responseCRRACI
DSAR fulfilment (DOC scope)ICIIA/RI
Migration import (DocuSign / Adobe Sign)CARIII

R Responsible · A Accountable · C Consulted · I Informed.

15

Planned CLI surface

Admin CLI cyberos-doc. Every destructive action writes a chained BRAIN audit row.

1. Upload + apply template

$ cyberos-doc upload "Acme MSA.pdf" --template MSA-EU-v3 --deal deal-2026-0912

[uploaded]   doc_id=DOC-018824  sha256=…  bytes=412_223
[template]   MSA-EU-v3 applied; 4 fields auto-filled from CRM
[audit]      brain seq=21884 chain=…

2. Create a multi-party signing session

$ cyberos-doc session create \
    --doc DOC-018824 --mode sequential --deadline 14d \
    --signer "ceo@acme.com:Alice Smith:US:webauthn" \
    --signer "stephen@cyberskill.com:Stephen:VN:webauthn"

[session created]  S-009311  order: [1:alice, 2:stephen]
[invited]          alice@acme.com (magic link sent)
[reminder]         scheduled +3d, +7d, +13d

3. Check session status

$ cyberos-doc session status S-009311

[status]    open
[signers]
   1. alice@acme.com           [SIGNED · 2026-05-13 09:14 · WebAuthn AAL3 · GlobalSign QTSP]
   2. stephen@cyberskill.com   [VIEWED · 2026-05-13 11:02 · awaiting WebAuthn]
[deadline]  2026-05-27 (+13d)

4. Verify a signed-document archive

$ cyberos-doc verify --doc DOC-018824

[archive]   s3://cyberos-doc-archive-vn-hanoi/2026/05/DOC-018824.pdf
[sha256]    ✓ matches archive event
[chain]     ✓ 7 events, all chain-hashes valid
[certs]     ✓ GlobalSign QTSP root trusted
[ocsp]      ✓ revocation info valid
[tsa]       ✓ RFC 3161 token valid
[overall]   PASS

5. Export legal-discovery bundle

$ cyberos-doc bundle --doc DOC-018824 --output discovery.zip

[bundle]
  doc-018824.pdf                          412 KB  (PAdES-B-LT)
  doc-018824-audit.json                    18 KB  (7 chained events)
  doc-018824-cert-chain.pem                 6 KB  (full chain to root)
  doc-018824-tsa-token.tsr                  4 KB
  doc-018824-readme.md                      2 KB  (verification instructions)
[total]    442 KB
[written]  discovery.zip

6. Migrate DocuSign envelopes

$ cyberos-doc migrate docusign --since 2020-01-01 --account "Acme Corp"

[connect]   DocuSign OAuth ok
[scan]      324 envelopes since 2020-01-01
[import]    324 imported · 0 failures
[trust]     all flagged trust=external
[audit]     brain seq=21899 chain=…

7. Apply legal hold

$ cyberos-doc legal-hold --doc DOC-018824 --on --reason "Acme litigation 2026-104"

[hold applied]   DOC-018824 protected beyond retention window
[next purge]    blocked — legal_hold=true
[audit]          brain seq=21902 chain=…  (CLO co-sign required: stephen@cyberskill.com confirmed)

8. DSAR export for a signer

$ cyberos-doc dsar-export --subject alice@acme.com --output dsar.zip

[dsar] signed_documents: 12 (since 2024)
[dsar] audit_events:    96 rows
[dsar] cert_chains:     12 PEM files
[dsar] written:         dsar.zip (4.8 MB)
16

Phase status & estimates

Status
Planned
P4 long-term
Est. LoC (Rust)
~9,500
services/doc + PAdES + broker
Est. LoC (TS)
~3,200
signer SPA + template designer
Planned tests
140+
incl. eIDAS conformity suite
External libs
~20
pdfium · cms · oid-registry · CAdES
P4 budget
~$80/mo + $0.50–$2 / signature
Fargate + S3 + KMS + QTSP pass-thru
CapabilityStatus
Document upload + SHA-256 + KMS encryptplanned · P4
Template designer + auto-fill from CRM/HRplanned · P4
Multi-party signing (sequential + parallel)planned · P4
eIDAS QTSP integration (GlobalSign / Cryptomathic)planned · P4
Adobe AATL chain (DigiCert)planned · P4
VN CA chain (VnPay / MK Group / Viettel-CA)planned · P4
VNeID integration for VN citizensplanned · P4
WebAuthn / SMS-OTP / email-link IDVplanned · P4
PAdES-B-LT archival with LTV outer timestampplanned · P4
S3 Object-Lock Compliance, residency-pinnedplanned · P4
DocuSign / Adobe Sign / HelloSign migrationplanned · P4
Notary-fraud detection (velocity + device)planned · P4
Legal-hold + retention sweepplanned · P4
Cosign verification end-to-endplanned · P4
Quarterly external eIDAS auditplanned · P4+
17

References

  • PRD §9.20 — DOC — Document signing. FRs 001..005.
  • SRS §7.20 — Document management with e-signatures.
  • SRS §4 (FR pending)..006 — Formal requirements with verification methods.
  • eIDAS Regulation (EU 910/2014) — qualified e-signatures and trust services.
  • ETSI EN 319 142-1 — PAdES baseline profile.
  • ETSI TS 119 312 — PAdES long-term validation profiles.
  • RFC 3161 — Time-Stamp Protocol (TSP).
  • RFC 5126 (CAdES) — CMS Advanced Electronic Signatures.
  • US ESIGN Act (15 U.S.C. §7001) — Electronic Signatures in Global and National Commerce.
  • US UETA — Uniform Electronic Transactions Act.
  • Vietnam Decree 130/2018/NĐ-CP — Detailed regulations on electronic signatures.
  • Vietnam Decision 06/2022/QĐ-TTg — Project on developing the e-identification + e-authentication system (VNeID).
  • Vietnam Law 91/2025/QH15 (PDPL) — Personal Data Protection Law.
  • GDPR (EU 2016/679) — Art. 15, 17.
  • ISO 14533-1 — Long-term signature profile (PAdES).
  • Adobe AATL programme — Approved Trust List for non-EU jurisdictions.
  • S3 Object-Lock — AWS storage WORM compliance.
  • Architecture context: infrastructure.html#doc.
  • CRM modulecrm.html · upstream for deal contract auto-fill.
  • HR modulehr.html · upstream for employment-contract auto-fill.
  • AUTH moduleauth.html · WebAuthn for elevated-signer IDV.