Digital Signatures
Overview
Signatures in the RestartiX system are handwritten signature images, not cryptographic digital signatures. This matches the current Strapi implementation and is standard for telemedicine platforms.
Signature Types
Specialist Signatures
Specialist signatures are uploaded images (typically PNG) captured via signature pad or canvas and stored in S3.
| Component | Implementation |
|---|---|
| Capture | Frontend captures signature via canvas/pad, uploads as PNG |
| Storage | specialist.signature_url - S3 URL to signature image |
| Access | S3 pre-signed URL with 15-minute expiry |
| Embedding in PDF | Signature image URL resolved → fetched → base64 encoded → embedded in HTML as <img src="data:image/png;base64,..." /> |
| Tamper proof | Not applicable to image signatures. Integrity guaranteed by form immutability (signed form + audit log) |
Patient Signatures (Form Fields)
Patient signatures for consent forms are captured as form field file uploads:
{
"key": "consent_signature",
"label": "Patient Signature",
"type": "file",
"required": true,
"accept": "image/png,image/jpeg"
}These are stored as form field files and rendered in PDFs like any other file upload.
Signature in PDF Templates
Specialist Signature Rendering
<footer class="doc-footer">
{{if .Specialist.SignatureURL}}
<div class="signature">
<img src="{{.Specialist.SignatureURL}}" alt="Signature" class="signature-img" />
<p class="signature-name">{{.Specialist.Title}} {{.Specialist.Name}}</p>
<p class="signature-date">Signed: {{formatDate .Document.SignedAt .Locale}}</p>
</div>
{{else}}
<div class="signature-placeholder">
<p>No signature on file</p>
</div>
{{end}}
</footer>Patient Signature (Consent Forms)
{{range .Form.Fields}}
{{if eq .Key "consent_signature"}}
<div class="patient-signature">
<h4>Patient Consent Signature</h4>
{{if .FileURL}}
<img src="{{.FileURL}}" alt="Patient Signature" class="signature-img" />
{{else}}
<p>Not signed</p>
{{end}}
</div>
{{end}}
{{end}}Signature Requirements
Reports
- Specialist signature: Included but not strictly required
- Patient signature: Optional (depends on form template)
- PDF generation: Proceeds even if signature is missing (shows placeholder)
Prescriptions
- Specialist signature: Required - PDF generation fails without it
- Patient signature: Not required
- Validation before generation:
func validatePrescriptionGeneration(doc *AppointmentDocument, specialist *Specialist) error {
if specialist.Signature == "" {
return ErrSpecialistSignatureRequired
}
if doc.Form == nil {
return ErrFormNotAttached
}
if doc.Form.Status != FormStatusSigned {
return ErrFormNotSigned
}
return nil
}Why Not Cryptographic Signatures (PKI)?
The platform uses image signatures rather than cryptographic signatures for several reasons:
- No regulatory requirement - The platform is not issuing legally binding digital signatures (no eIDAS, no qualified certificates)
- Specialist identity verified - Specialist identity is verified via Clerk authentication + audit trail
- Industry standard - Image signatures are the industry standard for telemedicine consultation reports in Romania
- Infrastructure complexity - Adding PKI would require certificate management infrastructure with no regulatory requirement
- Form immutability - Integrity is guaranteed by form signing workflow (signed form status + audit log)
If Regulations Change
If Romanian regulations require qualified electronic signatures (eIDAS), the system can add a document_signatures table with certificate references without changing the generation pipeline:
CREATE TABLE document_signatures (
id BIGSERIAL PRIMARY KEY,
document_id BIGINT NOT NULL REFERENCES appointment_documents(id),
signer_id BIGINT NOT NULL REFERENCES users(id),
certificate_dn TEXT NOT NULL,
signature_value BYTEA NOT NULL,
timestamp TIMESTAMPTZ NOT NULL,
tsa_url TEXT
);The visual signature image would remain for display, with the cryptographic signature applied to the final PDF.
Signature Audit Trail
Every document-related action is captured in the audit log:
- form.signed: { user_id, form_id, signed_at, ip_address }
- document.published: { user_id, document_id, published_at }
- document.pdf_generated: { user_id, document_id, audience, template_id, cached }
- document.pdf_accessed: { user_id, document_id, audience }This provides a complete chain:
- Who signed the form
- Who published the document
- Who generated the PDF
- Who accessed it
Patient Signing Flow
For forms that require patient signatures (consent, disclaimers):
- Patient fills out form fields
- Patient draws signature on canvas or uploads image
- Signature uploaded to S3 via form field file upload
- Form marked as completed (all required fields filled)
- Form signed via
POST /v1/forms/{id}/sign - Form status changes to "signed" (immutable)
- Document can now be published
Specialist Signature Upload
Specialists upload their signature once via the profile settings:
- Specialist draws signature on canvas
- Frontend converts canvas to PNG blob
- Upload to S3 via
PUT /v1/specialists/{id}/signature specialist.signature_urlupdated with S3 key- Signature available for all future documents
Signature Image Requirements
Format
- PNG or JPEG
- Transparent background (PNG recommended)
- White background acceptable for prescriptions
Dimensions
- Minimum: 300x100 pixels
- Maximum: 800x300 pixels
- Aspect ratio: 2:1 to 4:1 (width:height)
File Size
- Maximum: 500KB
- Recommended: < 100KB
Quality
- DPI: 150+ for print quality
- No watermarks or borders
- Clear, legible signature
Embedding Process
When generating a PDF:
- Load specialist signature URL from database
- Generate pre-signed S3 URL (15-minute expiry)
- Fetch image from S3
- Convert to base64 data URI
- Replace URL in template with data URI
- Render HTML to PDF (image is now embedded)
This ensures the PDF is self-contained with no external dependencies.
Security Considerations
Access Control
- Specialist signatures: Only accessible by specialists in the same organization
- Patient signatures: Only accessible by the patient who signed + specialists/admins in the organization
- S3 URLs: Pre-signed with short expiry (15 minutes)
- RLS policies: Enforce organization-level isolation
Integrity
- Form signing: Sets
signed_attimestamp and changes status to "signed" - Immutability: Signed forms cannot be edited (409 Conflict if attempted)
- Audit log: Every signature event recorded with user_id, timestamp, IP address
- PDF caching: Signed document PDFs are cached - regeneration produces identical output
HIPAA Compliance
- Audit trail: Complete chain of custody for all document actions
- Access logs: Every PDF access recorded
- Encryption: S3 server-side encryption (AES-256)
- Data retention: Signed documents retained per organization policy
Future Enhancements
Not in scope for initial release:
- Multi-factor signature - Require 2FA for signing prescriptions
- Biometric signatures - Capture signature pressure/velocity data
- QR code verification - Embed QR code in PDF linking to verification page
- Cryptographic signatures - eIDAS-compliant qualified electronic signatures if regulations require
- Time-stamping - Third-party timestamp authority for signature timestamp verification
- Signature expiry - Require specialist to re-sign if signature is older than X months