前言

之前在逛 Daily.dev 时发现一个比较有趣的项目就是 DocuSeal,该项目基于 Ruby 开发的后端,并在 Github 上开源,支持 Self-hosted。

后来因为业务需要,就考虑用该套方案作为基础,与现有业务结合,通过 API 的方式为用户创建合同签订的服务!

接下来就分享一些服务部署,联调和遇到的坑。

部署

官方文档中,有比较简洁直观的说明。我这里主要是用 Dcoker Compose 的方式进行部署:

curl https://raw.githubusercontent.com/docusealco/docuseal/master/docker-compose.yml > docker-compose.yml

官方的 docker-compose.yaml 内容如下:

version: '3'

services:
  app:
    depends_on:
      postgres:
        condition: service_healthy
    image: docuseal/docuseal:latest
    ports:
      - 3000:3000
    volumes:
      - .:/data
    environment:
      - FORCE_SSL=${HOST}
      - DATABASE_URL=postgresql://postgres:postgres@postgres:5432/docuseal

  postgres:
    image: postgres:15
    volumes:
      - './pg_data:/var/lib/postgresql/data'
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: docuseal
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

  caddy:
    image: caddy:latest
    command: caddy reverse-proxy --from $HOST --to app:3000
    ports:
      - 80:80
      - 443:443
      - 443:443/udp
    volumes:
      - .:/data
    environment:
      - HOST=${HOST}

如果不打算给服务分配域名,只是用于本地开发,可以删除 caddy 容器,并删除 app 容器中的 FORCE_SSL 环境变量!

docker compose up -d

启动完成后,就可以通过 http://localhost:3000 访问 DocuSeal 了!

Sign-In

设置

Template

创建模板:

Create Template

Edit Template

Get Template

Get API Key

调用 API

调用方式可以参考官方 API 文档。这里用到的主要是 Create a submission API:

curl --location 'https://app.docuseal.orb.local/api/submissions' \
--header 'X-Auth-Token: cfKXy7c6PyciBqrZJsAiAEiCxXqMMfidEkvzTzkhZEH' \
--header 'Content-Type: application/json' \
--data-raw '{
    "template_id": 1,
    "send_email": true,
    "submitters": [
        {
            "name": "Betterde Inc.",
            "role": "甲方",
            "email": "george@betterde.com",
            "fields": [
                {
                    "name": "公司名称",
                    "default_value": "Betterde Inc."
                },
                {
                    "name": "经办人",
                    "default_value": "George"
                },
                {
                    "name": "联系电话",
                    "default_value": "021-3828272"
                }
            ]
        }
    ]
}'

Submissions

创建成功后,如果 SMTP 配置正确的话,上面的甲方应该会收到邮件,如果没有收到,你也可以通过在后台复制链接私信发给对方!

最终用户完成签订后会展示如下内容:

Completed

遇到的坑

由于字体原因,签署人录入的内容不能包含中文字符,否则会导致后端创建 PDF 失败,进而导致用户无法下载签订内容!

目前我的解决方案是自己在 Dockerfile 中集成中文字体:

FROM ruby:3.2.2-alpine3.18 as fonts

WORKDIR /fonts

COPY PingFang-zh-CN.ttf /fonts
COPY PingFang-zh-TW.ttf /fonts

RUN apk --no-cache add fontforge wget ttf-liberation &&  cp /usr/share/fonts/liberation/LiberationSans-Regular.ttf /usr/share/fonts/liberation/LiberationSans-Bold.ttf . && wget https://cdn.jsdelivr.net/gh/notofonts/notofonts.github.io/fonts/NotoSansArabic/hinted/ttf/NotoSansArabic-Regular.ttf && wget https://github.com/impallari/DancingScript/raw/master/fonts/DancingScript-Regular.otf && wget https://github.com/impallari/DancingScript/raw/master/OFL.txt

RUN fontforge -lang=py -c 'font1 = fontforge.open("LiberationSans-Regular.ttf"); font2 = fontforge.open("NotoSansArabic-Regular.ttf"); font3 = fontforge.open("PingFang-zh-CN.ttf"); font4 = fontforge.open("PingFang-zh-TW.ttf"); font1.mergeFonts(font2); font1.mergeFonts(font3); font1.mergeFonts(font4); font1.generate("LiberationSans-Regular.ttf")'

然后自己构建 Docker Image 即可!

I hope this is helpful, Happy hacking…