You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
docuseal/REBRANDING.md

13 KiB

Rebranding Summary: DocuSeal → WaboSign

This document records the changes made when forking DocuSeal into WaboSign. It exists for transparency, to fulfil AGPLv3 §7(b) disclosure expectations, and as a reference for future maintainers tracing why a particular file was touched.

Scope: ~183 files modified. Decisions were made in a planning conversation before changes were applied; the final plan lives at .claude/plans/this-agpl-project-has-toasty-cake.md on the developer's machine.

Brand & identity

  • Ruby module DocusealWabosign (lib/wabosign.rb); Rails app module DocuSealWaboSign (config/application.rb)
  • All hardcoded DocuSeal strings in views, mailers, controllers, libs, JS/Vue replaced with Wabosign.product_name (or equivalents)
  • config/locales/i18n.yml: 168 user-facing strings sweep-replaced across all 14 languages
  • New favicons, apple-touch-icons, and logo SVG (a neutral "W" mark) generated via Inkscape
  • daisyUI theme renamed docusealwabosign in tailwind.config.js
  • Discord, Twitter, ChatGPT URLs removed entirely
  • New brand constants in lib/wabosign.rb:
    • PRODUCT_URL = 'https://sign.wabo.cc'
    • GITHUB_URL = 'https://github.com/wabolabs/wabosign'
    • SUPPORT_EMAIL = 'wabosign@wabo.cc'

AGPL §7(b) attribution

Freemium gates removed

Migrations & infrastructure

Intentionally preserved upstream references

Per AGPL §7(b) and downstream SDK compatibility, the following references remain. All are documented in NOTICE.

Verification status

  • Ruby syntax-checked all edited .rb files (lib, controllers, mailers, migration)
  • ERB-compiled the edited view partials
  • YAML-parsed config/locales/i18n.yml and docker-compose.yml
  • JSON-parsed docs/openapi.json
  • Webhook spec assertions updated to match new WaboSign Webhook user-agent

Full Rails boot requires Ruby 4.0.1, which was not available on the dev machine that performed the rebrand. Recommend running docker compose up --build to verify boot end-to-end before publishing.

Sync workflow

Upstream lives at docusealco/docuseal. Each upstream release is brought in by re-running a deterministic rebrand sweep on the upstream tree, then merging into master. The strategy details are in .claude/plans/come-up-with-a-foamy-flask.md; the short version follows.

Tooling

  • bin/rebrand-sync — Ruby script that performs the DocuSeal → WaboSign rename sweep across the working tree. Idempotent. Honors a deny-list (see §"Intentionally preserved upstream references" above) and sentinel-protects AGPL §7(b) attribution phrases, SDK custom-element names (docuseal-form, docuseal-builder), @docuseal/* npm packages, and the github.com/docusealco/{fields-detection,pdfium-binaries,turbo} binary URLs.
  • bin/rebrand-check — fails (exit 1) if any unintended DocuSeal text reference survives. Wired into CI as the Rebrand check job.
  • bin/fork-check — fails (exit 1) if any fork invariant is broken: re-introduced Pro gate, deleted fork code, overwritten brand asset, lost attribution, dangling partial render, or PRESERVE↔ALLOW_PATTERNS drift. Driven by the declarative manifest config/fork_invariants.yml. Wired into CI as the Fork invariants job. This is the executable form of the old manual post-merge checklist.
  • config/fork_invariants.yml — the data behind bin/fork-check. Extend this file (not the script) when upstream adds a new gate; every entry carries a why:.
  • config/brand_assets.sha256 — checksum baseline of the WaboSign "W" mark assets. The single source of truth for "what is a brand asset": bin/fork-check verifies it, bin/sync-upstream restores from it, and .gitattributes -merge should mirror it.
  • git config rerere.enabled true && git config rerere.autoupdate true — once-per-checkout setup; remembers semantic conflict resolutions so the same call is not re-made each release.
  • .gitattributes marks the brand binary assets as -merge (always keep ours; never blend an upstream version during a merge).

Runbook (for a human or AI agent)

The whole sync — fetch, branch from the tag, sweep, merge, restore brand assets, re-sweep, and run both gates — is automated:

bin/sync-upstream <tag>          # e.g. bin/sync-upstream 3.0.2
# RUN_TESTS=1 bin/sync-upstream <tag>   # also run rspec before declaring done

When it stops, decide based on which gate failed:

  1. Merge conflict — resolve it. rerere caches recurring resolutions.
  2. rebrand-check failed — un-rebranded DocuSeal text survived. If a token must be preserved, add it to PRESERVE (bin/rebrand-sync) and ALLOW_PATTERNS (bin/rebrand-check) together (see below).
  3. fork-check failed — a fork invariant broke. Each violation names the file + the why: from the manifest:
    • re-introduced gate → remove it;
    • brand asset overwritten → git checkout ORIG_HEAD -- <path>;
    • genuinely new upstream feature/gate → add a scoped invariant to config/fork_invariants.yml.
  4. Re-run bin/fork-check (and bin/rebrand-check) until both print ok.
  5. bundle install && yarn install, then tag + push only when both gates and rspec are green: git tag wabosign-synced-with-<tag> && git push origin master --tags.

The equivalent manual steps (if you are not using the script) are: branch from the tag, bin/rebrand-sync, commit, git merge --no-ff into master, restore the brand assets listed in config/brand_assets.sha256 from ORIG_HEAD, bin/rebrand-sync again, then bin/rebrand-check && bin/fork-check.

Adding new preserved tokens

When upstream introduces a new SDK identifier, binary URL, or attribution surface that must survive the sweep, edit PRESERVE in bin/rebrand-sync and ALLOW_PATTERNS in bin/rebrand-check together. The two must stay in sync — rebrand-sync decides what the sweep ignores, rebrand-check decides what CI tolerates. This pairing is now CI-enforced: bin/fork-check fails if a PRESERVE token containing "docuseal" has no matching ALLOW_PATTERN.

Adding a new fork invariant

When upstream re-introduces a gate, deletes fork code, or adds a brand asset, encode the rule in config/fork_invariants.yml — not in bin/fork-check. Use a path-scoped must_not_contain for re-added gates (never ban a token tree-wide unless it is genuinely unique to the gate — Wabosign.multitenant? is legitimate in ~19 views), must_exist/must_not_exist for files, and add new brand files to config/brand_assets.sha256 (and the .gitattributes -merge list). Always include a why: — it is the institutional memory the next sync will need.

Post-Merge Verification

Most of what used to be a 21-item manual checklist is now executed by CI. After a sync, the gates below must be green; only a short residue needs a human eye.

Automated (CI — must pass)

  • bin/rebrand-check — no unintended DocuSeal text survived the sweep.
  • bin/fork-check — every fork invariant holds. The assertions (and the rationale for each) live in config/fork_invariants.yml: attribution surfaces present; renamed identifiers + SDK tokens present; brand assets match config/brand_assets.sha256; no re-introduced Pro gates (ENTERPRISE_PATHS, console_redirect_index_path, the reminder multitenant? gate, …); placeholders / console_redirect_controller / lib/docuseal.rb absent; SMS stack + lib/ability.rb present; no dead paywall i18n keys; no dangling partial renders; PRESERVE↔ALLOW_PATTERNS in sync.
  • rspec — suite passes (also catches Zeitwerk module conflicts at boot).

When upstream changes something the manifest does not yet know about, extend the manifest (see "Adding a new fork invariant" above) rather than re-checking by hand. That way the next sync inherits the protection.

Human-judgment residue (not automatable)

  • The rendered WaboSign "W" mark looks right (checksum proves the file is unchanged; a human confirms it is the intended asset, e.g. after a deliberate brand update + baseline regen).
  • Upstream did not introduce a genuinely new feature or freemium gate that needs a fork-policy decision (free it, and add an invariant) — skim the merge diff for new multitenant? / Pro / Console / placeholder code.
  • New upstream UI strings read correctly after the sweep (the rename is mechanical; some phrasings need a human's rebranding nuance).