17 KiB
Admin Guide
Complete guide for administrators using Ackify to manage documents, expected signers, and email reminders.
Table of Contents
- Getting Admin Access
- Admin Dashboard
- Document Management
- Expected Signers
- Email Reminders
- Monitoring & Statistics
- Best Practices
- Troubleshooting
Getting Admin Access
Prerequisites
To access admin features, your email must be configured in the ACKIFY_ADMIN_EMAILS environment variable.
# In .env file
ACKIFY_ADMIN_EMAILS=admin@company.com,manager@company.com
After adding your email:
- Restart Ackify:
docker compose restart ackify-ce - Log out and log in again
- You should now see "Admin" link in the navigation
Verify Admin Access
Visit /admin - if you see the admin dashboard, you have admin access.
Admin Dashboard
URL: /admin
The admin dashboard provides:
- Total Documents: Number of documents in the system
- Expected Readers: Total number of expected signers across all documents
- Active Documents: Documents that are not soft-deleted
- Document List: Paginated list (20 per page) with search
Dashboard Features
Quick Stats
Three KPI cards at the top:
- Total documents count
- Total expected readers/signers
- Active documents (non-deleted)
Document Search
- Search by title, document ID, or URL
- Real-time filtering
Document List
Desktop view - Table with columns:
- Document ID
- Title
- URL
- Created date
- Creator
- Actions (View details)
Mobile view - Card layout with:
- Document ID and title
- Creation info
- Tap to view details
Pagination
- 20 documents per page
- Previous/Next buttons
- Current page indicator
Document Management
Creating a Document
From Admin Dashboard:
- Click "Create New Document" button
- Fill in the form:
- Reference (required): URL, file path, or custom ID
- Title (optional): Auto-generated from URL if empty
- Description (optional): Additional context
- Click "Create Document"
Automatic Features:
- Unique ID Generation: Collision-resistant base36 doc_id
- Title Extraction: Auto-extracts from URL if not provided
- Checksum Calculation: For remote URLs (if admin and file < 10MB)
Example:
Reference: https://docs.company.com/policy-2025.pdf
Title: Security Policy 2025 (auto-extracted or manual)
Description: Annual security compliance policy
Result:
- doc_id:
k7m2n4p8(auto-generated) - Checksum: Auto-calculated SHA-256 (if URL is accessible)
Viewing Document Details
URL: /admin/docs/{docId}
Provides comprehensive document information:
1. Metadata Section
Edit document information:
- Title
- URL
- Description
- Checksum (SHA-256, SHA-512, or MD5)
- Checksum Algorithm
To edit:
- Click "Edit Metadata" button
- Modify fields
- Click "Save Changes"
- Confirmation modal for critical changes (checksum, algorithm)
2. Statistics Panel
Real-time signature tracking:
- Expected: Number of expected signers
- Signed: Number who have signed
- Pending: Not yet signed
- Completion: Percentage complete
3. Expected Signers Section
Lists all expected signers with status:
- Email: Signer's email address
- Status: ✅ Signed or ⏳ Pending
- Added: Date when added to expected list
- Days Since Added: Time tracking
- Last Reminder: When last reminder was sent
- Reminder Count: Total reminders sent
- Actions: Remove signer button
Color coding:
- Green background: Signer has signed
- Default background: Pending signature
4. Unexpected Signatures
Shows users who signed but weren't on expected list:
- User email
- Signed date
- Indicates organic/unexpected participation
5. Actions
- Send Reminders: Email pending signers
- Share Link: Generate and copy signing link
- Delete Document: Soft delete (preserves signature history)
Updating Document Metadata
Important fields:
Title & Description:
- Can be changed freely
- No confirmation required
URL:
- Updates where document is located
- Confirmation modal shown
Checksum & Algorithm:
- Critical for integrity verification
- Confirmation modal warns of impact
- Change only if document version changed
Workflow:
- Click "Edit Metadata"
- Modify desired fields
- Click "Save Changes"
- If checksum/algorithm changed, confirm in modal
- Success notification displayed
Deleting a Document
Soft Delete Behavior:
- Document marked as deleted (
deleted_attimestamp set) - Signature history preserved
- Document no longer appears in public lists
- Admin can still view via direct URL
- Signatures CASCADE update (marked with
doc_deleted_at)
To delete:
- Go to document detail page (
/admin/docs/{docId}) - Click "Delete Document" button
- Confirm deletion in modal
- Document moved to deleted state
Note: There is no "undelete" - this is permanent soft delete.
Expected Signers
Expected signers are users you want to track for document completion.
Adding Expected Signers
From document detail page:
- Scroll to "Expected Signers" section
- Click "Add Expected Signer" button
- Enter email address(es):
- Single:
alice@company.com - Multiple: Comma-separated
alice@company.com,bob@company.com
- Single:
- Optionally add notes
- Click "Add"
API endpoint:
POST /api/v1/admin/documents/{docId}/signers
Content-Type: application/json
X-CSRF-Token: {token}
{
"emails": ["alice@company.com", "bob@company.com"],
"notes": "Board members - Q1 2025"
}
Constraints:
- Email must be valid format
- UNIQUE constraint: Cannot add same email twice to same document
- Added by current admin user (tracked in
added_by)
Removing Expected Signers
From document detail page:
- Find signer in Expected Signers list
- Click "Remove" button next to their email
- Confirm removal
API endpoint:
DELETE /api/v1/admin/documents/{docId}/signers/{email}
X-CSRF-Token: {token}
Effect:
- Signer removed from expected list
- Does NOT delete their signature if they already signed
- Reminder history preserved in
reminder_logs
Tracking Completion Status
Document Status API:
GET /api/v1/admin/documents/{docId}/status
Response:
{
"docId": "abc123",
"expectedCount": 10,
"signedCount": 7,
"pendingCount": 3,
"completionPercentage": 70.0
}
Visual indicators:
- Progress bar showing completion percentage
- Color-coded status: Green (signed), Orange (pending)
- Days since added (helps identify slow signers)
Email Reminders
Email reminders are sent asynchronously via the email_queue system.
Sending Reminders
From document detail page:
- Click "Send Reminders" button
- Modal opens with options:
- Send to: All pending OR specific emails
- Document URL: Pre-filled, can customize
- Language: en, fr, es, de, it
- Click "Send Reminders"
- Confirmation: "X reminders queued for sending"
API endpoint:
POST /api/v1/admin/documents/{docId}/reminders
Content-Type: application/json
X-CSRF-Token: {token}
{
"emails": ["alice@company.com"], // Optional: specific emails
"docURL": "https://docs.company.com/policy.pdf",
"locale": "en"
}
Behavior:
- Sends to ALL pending signers if
emailsnot specified - Sends to specific
emailsif provided (even if already signed) - Emails queued in
email_queuetable - Background worker processes queue
- Retry on failure (3 attempts, exponential backoff)
Email Templates
Location: backend/templates/emails/
Available templates:
reminder.html- HTML versionreminder.txt- Plain text version
Variables available in templates:
{{.DocTitle}}- Document title{{.DocURL}}- Document URL{{.RecipientEmail}}- Recipient's email{{.SenderName}}- Admin who sent reminder{{.OrganisationName}}- From ACKIFY_ORGANISATION
Locales: en, fr, es, de, it
- Template directory:
templates/emails/{locale}/ - Fallback to default locale if translation missing
Reminder History
View reminder log:
GET /api/v1/admin/documents/{docId}/reminders
Response:
{
"reminders": [
{
"id": 123,
"docId": "abc123",
"recipientEmail": "alice@company.com",
"sentAt": "2025-01-15T10:30:00Z",
"sentBy": "admin@company.com",
"templateUsed": "reminder",
"status": "sent",
"errorMessage": null
}
]
}
Status values:
queued- In email_queue, not yet processedsent- Successfully deliveredfailed- Delivery failed (check errorMessage)bounced- Email bounced back
Tracking:
- Last reminder sent date shown per signer
- Reminder count shown per signer
- Helps avoid over-sending
Email Queue Monitoring
Check queue status (PostgreSQL):
-- Pending emails
SELECT id, to_addresses, subject, status, scheduled_for
FROM email_queue
WHERE status IN ('pending', 'processing')
ORDER BY priority DESC, scheduled_for ASC;
-- Failed emails
SELECT id, to_addresses, last_error, retry_count
FROM email_queue
WHERE status = 'failed';
Worker configuration:
- Batch size: 10 emails
- Poll interval: 5 seconds
- Max retries: 3
- Cleanup: 7 days retention
Monitoring & Statistics
Document-Level Statistics
Completion tracking:
- Expected vs Signed counts
- Pending signer list
- Completion percentage
- Average time to sign
Reminder effectiveness:
- Reminders sent count
- Success/failure rates
- Time between reminder and signature
System-Wide Metrics
PostgreSQL queries:
-- Total documents
SELECT COUNT(*) FROM documents WHERE deleted_at IS NULL;
-- Total signatures
SELECT COUNT(*) FROM signatures;
-- Documents by completion status
SELECT
CASE
WHEN signed_count = expected_count THEN '100%'
WHEN signed_count >= expected_count * 0.75 THEN '75-99%'
WHEN signed_count >= expected_count * 0.50 THEN '50-74%'
ELSE '<50%'
END as completion_bracket,
COUNT(*) as doc_count
FROM (
SELECT
d.doc_id,
COUNT(DISTINCT es.email) as expected_count,
COUNT(DISTINCT s.user_email) as signed_count
FROM documents d
LEFT JOIN expected_signers es ON d.doc_id = es.doc_id
LEFT JOIN signatures s ON d.doc_id = s.doc_id AND s.user_email = es.email
WHERE d.deleted_at IS NULL
GROUP BY d.doc_id
) stats
GROUP BY completion_bracket;
-- Email queue statistics
SELECT status, COUNT(*), MIN(created_at), MAX(created_at)
FROM email_queue
GROUP BY status;
Export Data
Signatures for a document:
COPY (
SELECT s.user_email, s.user_name, s.signed_at, s.payload_hash
FROM signatures s
WHERE s.doc_id = 'your_doc_id'
ORDER BY s.signed_at
) TO '/tmp/signatures_export.csv' WITH CSV HEADER;
Expected signers status:
COPY (
SELECT
es.email,
CASE WHEN s.id IS NOT NULL THEN 'Signed' ELSE 'Pending' END as status,
es.added_at,
s.signed_at
FROM expected_signers es
LEFT JOIN signatures s ON es.doc_id = s.doc_id AND es.email = s.user_email
WHERE es.doc_id = 'your_doc_id'
) TO '/tmp/expected_signers_export.csv' WITH CSV HEADER;
Best Practices
1. Document Creation
✅ Do:
- Use descriptive titles
- Add clear descriptions
- Include document URL for easy access
- Store checksum for integrity verification
- Create expected signers list before sharing
❌ Don't:
- Use generic titles like "Document 1"
- Leave URL empty if document is accessible online
- Change checksums unless document actually changed
2. Expected Signers Management
✅ Do:
- Add expected signers before sending document link
- Use clear notes to explain why signers are expected
- Review pending signers regularly
- Remove signers who are no longer relevant
❌ Don't:
- Add hundreds of signers at once (use batches)
- Send reminders too frequently (max once per week)
- Remove signers who have already signed (preserve history)
3. Email Reminders
✅ Do:
- Wait 3-5 days before first reminder
- Send in recipient's preferred language
- Include clear document title and URL
- Track reminder history to avoid spam
- Send reminders during business hours
❌ Don't:
- Send daily reminders (causes fatigue)
- Send without checking if already signed
- Use generic subjects (personalize with doc title)
- Send outside business hours
4. Data Integrity
✅ Do:
- Regularly backup PostgreSQL database
- Verify checksums match actual documents
- Monitor email queue for failures
- Review unexpected signatures (may indicate broader interest)
- Export important signature data
❌ Don't:
- Delete documents with active signatures
- Modify timestamps manually in database
- Ignore failed email deliveries
- Change checksums without updating the document
5. Security
✅ Do:
- Limit admin access to trusted users only
- Use HTTPS in production (
ACKIFY_BASE_URL=https://...) - Rotate
ACKIFY_OAUTH_COOKIE_SECRETperiodically - Monitor admin actions via application logs
- Use OAuth allowed domain restrictions
❌ Don't:
- Share admin credentials
- Run without HTTPS in production
- Disable CSRF protection
- Ignore authentication failures in logs
Troubleshooting
Common Issues
1. Admin Link Not Visible
Problem: Can't see "Admin" link in navigation
Solutions:
- Verify email in
ACKIFY_ADMIN_EMAILSenvironment variable - Restart Ackify:
docker compose restart ackify-ce - Log out and log back in
- Check logs:
docker compose logs ackify-ce | grep admin
2. Emails Not Sending
Problem: Reminders queued but not delivered
Diagnosis:
SELECT * FROM email_queue WHERE status = 'failed' ORDER BY created_at DESC LIMIT 10;
Solutions:
- Check SMTP configuration (
ACKIFY_MAIL_HOST,ACKIFY_MAIL_USERNAME, etc.) - Verify SMTP credentials are correct
- Check email worker logs:
docker compose logs ackify-ce | grep email - Ensure
ACKIFY_MAIL_FROMis valid sender address - Test SMTP connection manually
3. Duplicate Signer Error
Problem: "Email already exists as expected signer"
Cause: UNIQUE constraint on (doc_id, email)
Solution: This is expected behavior - each email can only be added once per document
4. Checksum Mismatch
Problem: Users report checksum doesn't match
Solutions:
- Verify stored checksum matches actual document
- Check algorithm used (SHA-256, SHA-512, MD5)
- Recalculate checksum and update via Edit Metadata
- Ensure users are downloading correct version
5. Document Not Appearing
Problem: Created document doesn't show in list
Solutions:
- Check if document was soft-deleted (
deleted_at IS NOT NULL) - Verify creation succeeded (check response/logs)
- Clear browser cache
- Check database:
SELECT * FROM documents WHERE doc_id = 'your_id';
6. Signature Already Exists
Problem: User can't sign document again
Cause: UNIQUE constraint (doc_id, user_sub) - one signature per user per document
Solution: This is expected - users cannot sign the same document twice
Getting Help
Logs:
# Application logs
docker compose logs -f ackify-ce
# Database logs
docker compose logs -f ackify-db
# Email worker logs (grep email)
docker compose logs ackify-ce | grep -i email
Database inspection:
# Connect to PostgreSQL
docker compose exec ackify-db psql -U ackifyr ackify
# Useful queries
SELECT * FROM documents ORDER BY created_at DESC LIMIT 10;
SELECT * FROM expected_signers WHERE doc_id = 'your_doc_id';
SELECT * FROM email_queue WHERE status != 'sent' ORDER BY created_at DESC;
Report issues:
- GitHub: https://github.com/btouchard/ackify-ce/issues
- Include logs and error messages
- Describe expected vs actual behavior
Quick Reference
Environment Variables
ACKIFY_ADMIN_EMAILS=admin@company.com
ACKIFY_MAIL_HOST=smtp.gmail.com
ACKIFY_MAIL_FROM=noreply@company.com
Key Endpoints
GET /admin # Dashboard
GET /admin/docs/{docId} # Document detail
POST /admin/documents/{docId}/signers # Add signer
POST /admin/documents/{docId}/reminders # Send reminders
PUT /admin/documents/{docId}/metadata # Update metadata
Important Tables
documents- Document metadatasignatures- User signaturesexpected_signers- Who should signreminder_logs- Email historyemail_queue- Async email queue
Keyboard Shortcuts (Frontend)
- Search bar auto-focus on dashboard
- Enter to submit forms
- Esc to close modals
Last Updated: 2025-10-26 Version: 1.0.0