# Documenso Runbook

# Runbook: Documenso

**Service Type:** Document Signing Platform
**Container:** documenso (documenso/documenso:latest)
**Ports:** 3003 (external + internal)
**External URL:** https://sign.alai.no
**Database:** PostgreSQL 15 (documenso-db)
**Storage:** MinIO (S3-compatible object storage)
**Compose File:** ~/system/services/documenso/docker-compose.yml

---

## Service Info

Documenso is the document signing platform for BasicAS Group. Used for NDAs, contracts, proposals.

**Stack:**
- **documenso** - Main app (Next.js)
- **documenso-db** - PostgreSQL 15 (alpine)
- **documenso-minio** - MinIO (S3-compatible storage for PDFs)
- **documenso-minio-setup** - One-shot bucket creator (exits after setup)

**External Access:**
- Exposed via Cloudflare Tunnel: sign.alai.no
- SMTP via one.com (info@alai.no) for signature emails

**Admin Access:**
- **Web UI:** http://localhost:3003 (local) or https://sign.alai.no
- **Database:** PostgreSQL (credentials in .env)
- **MinIO Console:** http://localhost:9003 (minio/documenso_s3_2026)

---

## Status Check

### Container Health
```bash
docker ps | grep documenso
```

Expected output:
```
documenso          Up X hours
documenso-db       Up X hours (healthy)
documenso-minio    Up X hours
```

Note: `documenso-minio-setup` exits after creating bucket (normal).

### HTTP Check
```bash
curl -I http://localhost:3003
```

Expected: `200 OK` or `307 Temporary Redirect`

### External Access Check
```bash
curl -I https://sign.alai.no
```

Expected: `200 OK` or `307 Temporary Redirect`

### Database Check
```bash
docker exec documenso-db psql -U documenso_user -d documenso_db -c "SELECT count(*) FROM \"User\";"
```

(Use credentials from .env file)

### MinIO Check
```bash
curl -I http://localhost:9002/minio/health/live
```

Expected: `200 OK`

---

## Restart Procedure

### Quick Restart (Container Only)
```bash
docker restart documenso
```

### Full Stack Restart (All Services)
```bash
cd ~/system/services/documenso
docker compose down
docker compose up -d
```

Wait 30-60 seconds for database healthcheck, then verify:
```bash
docker ps | grep documenso
curl -I http://localhost:3003
```

---

## Troubleshooting

### Problem: Container won't start
**Check logs:**
```bash
docker logs documenso --tail 100
```

**Common causes:**
1. Database not ready - wait 30s and retry
2. Port 3003 already bound - check `lsof -i :3003`
3. Environment variables missing - check .env file
4. MinIO not accessible - check minio container

**Fix:**
```bash
cd ~/system/services/documenso
docker compose down
docker compose up -d database minio
sleep 30
docker compose up -d documenso
```

### Problem: Can't upload documents (500 error on upload)
**Check MinIO is running:**
```bash
docker ps | grep minio
```

**Check MinIO bucket exists:**
```bash
docker exec documenso-minio mc ls local/documenso
```

Expected: Bucket should exist (created by minio-setup).

**Recreate bucket if missing:**
```bash
docker exec documenso-minio mc mb local/documenso
```

**Check Documenso S3 config:**
```bash
docker exec documenso env | grep UPLOAD
```

Expected:
```
NEXT_PUBLIC_UPLOAD_TRANSPORT=s3
NEXT_PRIVATE_UPLOAD_ENDPOINT=http://host.docker.internal:9000
NEXT_PRIVATE_UPLOAD_BUCKET=documenso
NEXT_PRIVATE_UPLOAD_ACCESS_KEY_ID=documenso
```

### Problem: Signature emails not sending
**Check SMTP config:**
```bash
docker exec documenso env | grep SMTP
```

**Check .env file:**
```bash
cd ~/system/services/documenso
grep SMTP .env
```

Expected:
```
NEXT_PRIVATE_SMTP_HOST=send.one.com
NEXT_PRIVATE_SMTP_PORT=465
NEXT_PRIVATE_SMTP_USERNAME=info@alai.no
NEXT_PRIVATE_SMTP_PASSWORD=<password>
NEXT_PRIVATE_SMTP_FROM_ADDRESS=info@alai.no
```

**Test SMTP manually:**
```bash
openssl s_client -connect send.one.com:465 -crlf
```

### Problem: Database connection issues
**Check database health:**
```bash
docker exec documenso-db pg_isready -U documenso_user
```

**Check connection string:**
```bash
docker exec documenso env | grep DATABASE_URL
```

Expected: `postgresql://documenso_user:<password>@database:5432/documenso_db`

### Problem: Signing fails (certificate error)
**Check certificate exists:**
```bash
ls -lh ~/system/services/documenso/certs/cert.p12
```

**Check cert is mounted:**
```bash
docker exec documenso ls -lh /opt/documenso/cert.p12
```

**Check passphrase is set:**
```bash
docker exec documenso env | grep SIGNING_PASSPHRASE
```

---

## Webhook Integration

Documenso can send webhooks on document events (signed, completed, etc.).

**Setup:**
1. Login to Documenso UI
2. Go to Settings → Webhooks
3. Add webhook URL (e.g., Mattermost incoming webhook)
4. Select events (document.signed, document.completed)

**Task #311:** Integrate with Mattermost for signature notifications.

---

## Dependencies

- **Docker** - Service runtime
- **Cloudflare Tunnel** - External access (sign.alai.no)
- **one.com SMTP** - Email delivery (send.one.com:465)
- **MinIO** - Document storage (internal S3)

**No dependencies on other local services.**

---

## Backup

### Database Dump
```bash
docker exec documenso-db pg_dump -U documenso_user documenso_db | gzip > ~/backups/documenso-$(date +%Y%m%d-%H%M%S).sql.gz
```

### MinIO Data (PDFs and files)
```bash
docker exec documenso-minio mc mirror local/documenso /tmp/documenso-backup
docker cp documenso-minio:/tmp/documenso-backup ~/backups/documenso-minio-$(date +%Y%m%d-%H%M%S)
```

Or use docker volume:
```bash
docker run --rm -v documenso_minio_data:/data -v ~/backups:/backup alpine tar -czf /backup/documenso-minio-$(date +%Y%m%d-%H%M%S).tar.gz -C /data .
```

### Restore from Backup
```bash
# Stop service
cd ~/system/services/documenso
docker compose down

# Restore database
gunzip -c ~/backups/documenso-YYYYMMDD-HHMMSS.sql.gz | docker exec -i documenso-db psql -U documenso_user -d documenso_db

# Restore MinIO data
docker run --rm -v documenso_minio_data:/data -v ~/backups:/backup alpine tar -xzf /backup/documenso-minio-YYYYMMDD-HHMMSS.tar.gz -C /data

# Start service
docker compose up -d
```

---

## Configuration

### Key Environment Variables (.env file)
- `PORT` - App port (3003)
- `NEXTAUTH_SECRET` - NextAuth encryption key
- `NEXT_PRIVATE_ENCRYPTION_KEY` - Document encryption key
- `NEXT_PUBLIC_WEBAPP_URL` - External URL (https://sign.alai.no)
- `NEXT_PRIVATE_DATABASE_URL` - PostgreSQL connection string
- `NEXT_PUBLIC_UPLOAD_TRANSPORT` - Storage type (s3)
- `NEXT_PRIVATE_UPLOAD_ENDPOINT` - MinIO endpoint
- `NEXT_PRIVATE_SMTP_*` - Email settings
- `NEXT_PRIVATE_SIGNING_*` - Certificate settings
- `NEXT_PUBLIC_DISABLE_SIGNUP` - Disable public signup (false = open, true = invite-only)

**Security:** .env file contains secrets - NOT in git, NOT in docker-compose.yml.

Full config: ~/system/services/documenso/.env

---

## Notes

- **MinIO ports:** 9002 (API), 9003 (Console) - not exposed externally
- **Public signup:** Currently enabled (anyone can register) - consider disabling
- **Telemetry:** Disabled (DOCUMENSO_DISABLE_TELEMETRY=true)
- **Certificate:** Self-signed cert for PDF signatures at ~/system/services/documenso/certs/cert.p12
- **Task #252:** Complete webhook integration with Mattermost
- **Task #254:** Build template system (NDA, Contract, Proposal auto-fields)

---

**Last updated:** 2026-02-10
**Maintained by:** John (AI Director)