A synchronous, invite-based digital signature workspace. Workspace owners can upload PDFs, assign signature placeholders to invited members, and automatically merge signatures into a flattened PDF once all parties approve.
┌─────────────┐ ┌─────────────┐ ┌──────────┐
│ Frontend │────▶│ Backend │────▶│ PostgreSQL│
│ React+Vite │◀────│ Go + Gin │◀────│ │
└─────────────┘ └──────┬──────┘ └──────────┘
│
┌────▼────┐
│ AWS S3 │
│ (files) │
└─────────┘
- Frontend: React 19, TypeScript, Vite, react-pdf, Zustand
- Backend: Go 1.26, Gin, sqlx, pdfcpu
- Database: PostgreSQL 16
- Storage: AWS S3
- Testing: Ginkgo BDD
- Go 1.26+
- Node.js 20+
- PostgreSQL 16
- AWS S3 bucket (or use LocalStack for local dev)
cd backend
cp .env.example .env
# Edit .env with your database and S3 credentials
# Run migrations (auto-run on startup)
go mod tidy
go run main.goServer starts on :8080.
cd frontend
npm install
npm run devApp starts on http://localhost:3000 with API proxy to :8080.
docker-compose upStarts PostgreSQL, backend, and frontend.
| Method | Endpoint | Description |
|---|---|---|
| POST | /auth/login |
SSO login, returns JWT |
| GET | /users/me |
Get user profile |
| PUT | /users/me/signature |
Upload signature PNG |
| Method | Endpoint | Description |
|---|---|---|
| POST | /workspaces |
Create workspace |
| GET | /workspaces |
List user's workspaces |
| GET | /workspaces/:id |
Get workspace details |
| POST | /workspaces/:id/invites |
Generate invite token |
| Method | Endpoint | Description |
|---|---|---|
| POST | /invites/:token/accept |
Accept invite (requires signature) |
| Method | Endpoint | Description |
|---|---|---|
| POST | /workspaces/:id/documents |
Upload PDF |
| GET | /workspaces/:id/documents/:docId |
Get document + placeholders |
| POST | /workspaces/:id/documents/:docId/placeholders |
Create signature box |
| DELETE | /workspaces/:id/documents/:docId/placeholders/:phId |
Remove placeholder |
| POST | /workspaces/:id/documents/:docId/sign |
Approve & sign |
| POST | /workspaces/:id/documents/:docId/complete |
Finalize document |
- Owner creates a workspace and invites signers
- Signers accept invites (must upload signature first)
- Owner uploads a PDF and places signature boxes on it
- Signers review the document and click "Approve & Sign"
- Owner clicks "Complete Document" when all have signed
- System merges all signatures into a flattened PDF
- No async queues — all operations are synchronous
- No OCR — manual placeholder placement only
- Every user must upload a signature before interacting with documents
- Metadata in PostgreSQL, binaries in S3
- Standard JSON error format:
{"error": "message", "code": 400}