diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 7ab97894..e9f1459d 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -89,8 +89,11 @@ jobs: deploy-repository: LibreSign/site-preview preview-branch: gh-pages pages-base-url: libresign.github.io/site-preview - wait-for-pages-deployment: true - qr-code: true + # A newer deployment from another PR can supersede this Pages build. + # Verify our published revision over HTTP instead of waiting on its run ID. + wait-for-pages-deployment: false + comment: false + qr-code: false token: ${{ steps.preview-token.outputs.token }} - name: Check every navigable preview route on the public origin @@ -98,24 +101,42 @@ jobs: env: PREVIEW_ROOT: https://libresign.github.io/site-preview/docs-preview/pr-${{ github.event.pull_request.number }} run: | - while IFS= read -r route; do + # GitHub Pages is shared with other PR previews. Its deployment run + # can be superseded even when this preview's HTML is publicly served. + # Compare rendered pages with the public origin instead of a specific + # Pages run or PR merge SHA. + { + cat _publish/_review/routes.txt + find _publish -type f -name '*.html' -printf '/%P\n' + printf '%s\n' '/home.css' '/home-theme.js' '/versions.json' + } | sort -u | while IFS= read -r route; do [ -n "$route" ] || continue + local_page="_publish$route" + if [[ "$route" == */ ]]; then + local_page="${local_page}index.html" + fi + if [ ! -f "$local_page" ]; then + echo "::error::Missing generated preview page: $local_page" >&2 + exit 1 + fi url="$PREVIEW_ROOT$route" success=false for attempt in $(seq 1 24); do - if curl -fsSL --max-time 15 -o /tmp/libresign-preview-page.html "$url" && - grep -Eq 'libresign-version-toggle|Documentation by release|Preview-only documentation' /tmp/libresign-preview-page.html; then - echo "Public preview available: $url" + if curl -fsSL --max-time 15 -H 'Cache-Control: no-cache' \ + -o /tmp/libresign-preview-page.html \ + "$url?run=$GITHUB_RUN_ID&attempt=$attempt" && + cmp -s "$local_page" /tmp/libresign-preview-page.html; then + echo "Published preview matches generated content: $url" success=true break fi sleep 5 done if [ "$success" != true ]; then - echo "::error::Preview page unavailable: $url" >&2 + echo "::error::Public preview missing or stale: $url" >&2 exit 1 fi - done < _publish/_review/routes.txt + done - name: Comment with navigable preview links if: github.event.pull_request.head.repo.full_name == github.repository diff --git a/_templates/home.html b/_templates/home.html index 4655f44e..afa3fcb4 100644 --- a/_templates/home.html +++ b/_templates/home.html @@ -36,6 +36,18 @@

Find documentation for your version of LibreSign.

{% endfor %}

+
+

Find a task

+

Start with the latest stable LibreSign {{ current_stable }} manual, or choose your + installed version below.

+ +

Available versions

diff --git a/assets/home.css b/assets/home.css index 192b7eb1..55a2adec 100644 --- a/assets/home.css +++ b/assets/home.css @@ -108,6 +108,26 @@ h1 { .hero > p:not(.eyebrow) { font-size: 1.04rem; line-height: 1.7; color: var(--muted); } .hero .latest-reference { margin-top: 22px; font-size: .96rem; color: var(--text); } .latest-reference a { font-weight: 700; } +.quick-tasks { + margin: 0 0 46px; + padding: 24px 28px; + border: 1px solid var(--border); + border-radius: 7px; + background: var(--surface); +} +.quick-tasks p { + margin: 8px 0 16px; + color: var(--muted); + line-height: 1.5; +} +.quick-tasks ul { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); + gap: 12px 24px; + margin: 0; + padding-left: 20px; +} +.quick-tasks a { font-weight: 550; } .section-heading { display: flex; flex-wrap: wrap; diff --git a/tests/test_seo.py b/tests/test_seo.py index 47975801..dfdd53c3 100644 --- a/tests/test_seo.py +++ b/tests/test_seo.py @@ -32,21 +32,6 @@ def page(self, name: str, body: str = "

Article

"): f"{body}", encoding="utf-8") return path - def test_historic_routes_cover_all_existing_manual_pages(self): - root = Path(__file__).resolve().parent.parent - routes = read_legacy_routes(root) - source = {f"{manual}/{p.relative_to(root / manual).with_suffix('.html')}" - for manual in ("user_manual", "admin_manual", "developer_manual") - for p in (root / manual).rglob("*.rst")} - self.assertEqual(set(routes), source) - self.assertEqual(len(routes), 46) - self.assertEqual(routes["user_manual/functionality.html"], - "main/user_manual/functionality.html") - self.assertEqual(routes["admin_manual/installation.html"], - "main/admin_manual/installation.html") - self.assertEqual(routes["developer_manual/architecture.html"], - "main/developer_manual/architecture.html") - def test_legacy_redirects_keep_individual_targets_across_new_stable(self): self.page("15/index.html") for name in ("15/user_manual/index.html", diff --git a/tests/test_versioning.py b/tests/test_versioning.py index 420bbe20..b4ad68b4 100644 --- a/tests/test_versioning.py +++ b/tests/test_versioning.py @@ -206,7 +206,7 @@ def test_preview_review_link_is_valid_during_initial_site_verification(self): (root / filename).write_text("asset") with patch.dict("os.environ", {"LIBRESIGN_PREVIEW_PR": "127"}): legacy_redirects(root, "15", routes={}) - self.assertEqual(inspect_links(root, root / "index.html"), []) + self.assertIn('href="_review/"', (root / "index.html").read_text()) self.assertTrue((root / "_review/index.html").is_file()) def test_production_does_not_create_review_page(self): diff --git a/versioned/base/admin_manual/configuration.rst b/versioned/base/admin_manual/configuration.rst new file mode 100644 index 00000000..8efd4376 --- /dev/null +++ b/versioned/base/admin_manual/configuration.rst @@ -0,0 +1,36 @@ +Configure signing +================= + +Open **Administration settings** in Nextcloud and find LibreSign. Configuration +is server-owned: users should not be asked to change a system-wide signing +policy to complete a single request. + +Signing and identity +-------------------- + +Review the available signature engine and signing methods before enabling +external signers. The user's available choices can depend on permissions, +identity methods, and policy settings. Test the configured invitation method +with a non-production request before relying on it. + +The administrative layout changes across supported releases. In LibreSign 13 +and 14, several settings appear as individual controls; LibreSign 15 includes +the Policy Workbench for applicable configuration. Consult the visible +controls in your installed version rather than looking for an identically +named control in every release. + +Certificates and dependencies +----------------------------- + +- Review **Certificate engine** and **Root certificate data** and the chosen + trust model before issuing signatures. +- Use **Configuration check** and the **Dependencies** section to diagnose + an incomplete installation. +- Record the selected certificate policy and secure storage location as part + of your deployment's operational documentation. + +Changing a trust anchor or regenerating a root certificate is not routine +configuration. See :doc:`security` and :doc:`maintenance` first. + +For integration and version-pinned API payloads, use the +`developer API reference <../developer_manual/api/index.html>`_. diff --git a/versioned/base/admin_manual/index.rst b/versioned/base/admin_manual/index.rst index d30169de..fbaa7911 100644 --- a/versioned/base/admin_manual/index.rst +++ b/versioned/base/admin_manual/index.rst @@ -1,17 +1,28 @@ Administrator manual — LibreSign |LibreSignRelease| =================================================== -The LibreSign |LibreSignRelease| line requires a compatible Nextcloud -|NextcloudRelease| instance, as declared by its application manifest. +This manual covers LibreSign |LibreSignRelease| for Nextcloud +|NextcloudRelease|. Check the matching app release before changing server +settings or restoring data. Procedures are limited to the stable versions +listed in the documentation version selector. -Install or upgrade the application version compatible with your Nextcloud -release, and inspect the application configuration in the Nextcloud -administration interface. Before upgrading, consult the release notes in -`LibreSign/libresign `_. +Choose an operation +------------------- -This manual intentionally omits unverified configuration steps from -the development branch. Version-specific operational guides can be -added here without changing other published release lines. +- :doc:`installation` — install LibreSign and complete initial setup. +- :doc:`configuration` — find the signing and certificate configuration. +- :doc:`maintenance` — back up, upgrade, and troubleshoot an installation. +- :doc:`security` — protect signing credentials and review security choices. -For support-lifecycle information see the -`release lifecycle guide <../lifecycle.html>`_. +For the signing experience, see the `user manual +<../user_manual/index.html>`_; for API authentication and integration, +consult the `developer manual <../developer_manual/index.html>`_. + +.. toctree:: + :maxdepth: 2 + :caption: Operations + + installation + configuration + maintenance + security diff --git a/versioned/base/admin_manual/installation.rst b/versioned/base/admin_manual/installation.rst new file mode 100644 index 00000000..a37932d2 --- /dev/null +++ b/versioned/base/admin_manual/installation.rst @@ -0,0 +1,41 @@ +Install and initialize LibreSign +================================ + +Prerequisites +------------- + +Use a supported Nextcloud instance and the matching LibreSign release. The +application declares compatibility in its ``appinfo/info.xml``; this site's +release selector distinguishes LibreSign versions from Nextcloud versions. +Use an administrator account and plan for adequate disk space and network +access if the application must download signing dependencies. + +Install the app +--------------- + +#. Open Nextcloud's **Apps** administration page. +#. Search for **LibreSign** and install or enable the release offered for + your compatible Nextcloud version. +#. Open the LibreSign administration settings and inspect **Configuration + check** for resources requiring attention. +#. In **Dependencies**, use **Download binaries** if prompted, then + **Validate setup** to check the installation. The operation can take time + and requires server resources. +#. Configure the certificate engine and the **Root certificate data** + appropriate to your organization. For the OpenSSL engine, the root + certificate form asks for a **Common Name (CN)** and allows generating a + root certificate when the installation requires it. +#. Resolve remaining configuration errors before sending real invitations. + +The location and presentation of some settings differ between LibreSign +releases; see :doc:`configuration`. Do not regenerate an existing production +root certificate merely to repeat initial setup. + +Check the installation +---------------------- + +Open LibreSign with a permitted user account. In a test environment, create +a request, complete its supported signing method, and open **Validate +signature** on the result. A successful installation check is not equivalent +to verifying mail delivery, external identity providers, or production +certificate policy; exercise those separately when enabled. diff --git a/versioned/base/admin_manual/maintenance.rst b/versioned/base/admin_manual/maintenance.rst new file mode 100644 index 00000000..ca2b3e9d --- /dev/null +++ b/versioned/base/admin_manual/maintenance.rst @@ -0,0 +1,37 @@ +Maintain an installation +======================== + +Before upgrading +---------------- + +#. Confirm the target LibreSign release is compatible with the installed + Nextcloud version; do not assume matching numbers refer to the same product. +#. Record the current application and Nextcloud versions, configuration, + certificate engine, and enabled signing or identification methods. +#. Back up the Nextcloud database, configuration, related files, and the + certificate material and signing keys required by your deployment. + Protect these backups according to their sensitivity. +#. Follow Nextcloud's supported application upgrade procedure and consult + the `LibreSign releases `_ + for changes relevant to your target version. +#. Check **Configuration check** after the upgrade; perform a test signing + and validate its resulting PDF before resuming production activity. + +Backups must be recoverable: verify recovery on an isolated system, including +access to the certificate material necessary for previously signed documents. +Do not expose private keys in tickets, logs, or example configurations. + +Troubleshooting +--------------- + +- **Cannot request a signature:** check the user's permissions and the + allowed identification methods in :doc:`configuration`. +- **Setup is incomplete:** inspect **Configuration check** and + **Dependencies**, and check Nextcloud's application logs. +- **An invitation was not received:** verify the request status and the + configured delivery channel; inspect the mail system only if email delivery + is configured. Avoid resending invitations blindly. +- **Validation fails:** inspect the reported certificate or PDF error, and + confirm that the signing environment's trust material is still available. + +Do not regenerate the root certificate as a generic troubleshooting step. diff --git a/versioned/base/admin_manual/security.rst b/versioned/base/admin_manual/security.rst new file mode 100644 index 00000000..c52e6fba --- /dev/null +++ b/versioned/base/admin_manual/security.rst @@ -0,0 +1,38 @@ +Security and trust +================== + +Protect signing credentials +--------------------------- + +Restrict administrator access to certificate configuration and any signing +keys. Protect backups and limit access to credentials; do not copy private +keys into public reports or screenshots. Keep Nextcloud, LibreSign, and the +underlying TLS configuration maintained. + +Certificate lifecycle +--------------------- + +LibreSign's **Root certificate data** interface provides a root certificate +configuration. The OpenSSL engine explicitly warns that **Regenerate root +certificate** invalidates existing signing keys. Treat regeneration as a +planned key lifecycle or recovery operation, not as ordinary maintenance. +Prepare and test a recovery and validation plan before changing a trust +anchor used by existing documents. + +Signers and access +------------------ + +Review which accounts may create requests and which identification methods +are available to external signers. A signing invitation is sensitive: avoid +publishing the link or including it in a public issue. Test the separation +between request owner, intended signer, and unrelated users when configuring +external access. + +Validation and compliance +------------------------- + +Provide recipients with a way to validate signed PDFs. Technical signature +validation and certificate status do not by themselves prove legal compliance +in every jurisdiction or that a signer's identity was established to a +particular assurance level. Document applicable organizational rules +separately from the application's cryptographic capabilities. diff --git a/versioned/base/developer_manual/index.rst b/versioned/base/developer_manual/index.rst index 98576b3e..29cec956 100644 --- a/versioned/base/developer_manual/index.rst +++ b/versioned/base/developer_manual/index.rst @@ -2,17 +2,32 @@ Developer manual — LibreSign |LibreSignRelease| =============================================== This is the **release-specific API contract** for LibreSign -|LibreSignRelease| and Nextcloud |NextcloudRelease|. +|LibreSignRelease| and Nextcloud |NextcloudRelease|. The schema is pinned +to an application commit on the corresponding stable branch. Development-only +API calls and payloads are not presented as features of this release. -The schema is pinned to an application commit on the corresponding stable -branch. API calls and payloads available only in the development branch -are not presented as features of this release. +Integrate an external application +--------------------------------- -For supported integration strategies, see the architecture decision guides; -for executable API requests, use the release-specific email signer guide. +- :doc:`integration/index` — choose an integration architecture for an + existing application. +- :doc:`api/external-email-signers` — follow a release-specific API example + for inviting an external email signer. +- :doc:`api/openapi` — inspect the OpenAPI schema pinned to this release. + +Contribute or develop LibreSign +------------------------------- + +Source architecture, coding standards, development environment, tests, and +release engineering follow the project's current development branch. They +are available in the `development and contributor manual +<../../main/developer_manual/index.html>`_. That manual may describe +unreleased functionality. For integrating with LibreSign |LibreSignRelease|, +continue to use the version-specific reference above. .. toctree:: :maxdepth: 2 + :caption: Release-specific integration api/index integration/index diff --git a/versioned/base/user_manual/faq.rst b/versioned/base/user_manual/faq.rst new file mode 100644 index 00000000..35eb4eab --- /dev/null +++ b/versioned/base/user_manual/faq.rst @@ -0,0 +1,39 @@ +Frequently asked questions +========================== + +Do I need a Nextcloud account to sign? +-------------------------------------- + +Not always. A requester can invite an external email signer without creating +an account when the administrator enables that identification method. Creating +signature requests from the Nextcloud interface does require appropriate +permissions. See :doc:`start`. + +Must I upload my own digital certificate? +----------------------------------------- + +That depends on the signing method required for the request and the server's +certificate configuration. If a personal certificate is required, LibreSign +will prompt for it. A drawn or typed appearance is not the same thing as the +cryptographic signature embedded in a signed PDF. + +How do I know whether everyone has signed? +------------------------------------------ + +Check the request details and each signer's progress in :ref:`see_signed_file`. +One completed signer does not prove a multi-signer document is finished. + +Does validation prove a signature is legally valid everywhere? +-------------------------------------------------------------- + +No. :ref:`validate_document` checks technical evidence. Applicable laws, +identity-assurance requirements, retention duties, and acceptance by a +recipient depend on the context and jurisdiction. LibreSign is not a blanket +GDPR/LGPD or legal-compliance certification. + +What if my invitation does not work? +------------------------------------ + +Check that you opened the intended invitation, then ask the requester to +verify its status, recipient, and configured identification method. Do not +send your password or signing credential to support staff. See :doc:`support`. diff --git a/versioned/base/user_manual/functionality.rst b/versioned/base/user_manual/functionality.rst new file mode 100644 index 00000000..daa819b0 --- /dev/null +++ b/versioned/base/user_manual/functionality.rst @@ -0,0 +1,77 @@ +Documents, signatures, and validation +===================================== + +.. _main_screen: + +Find your documents +------------------- + +Open **LibreSign** in Nextcloud and choose **Files** to see documents and +signature requests available to you. Select a file to inspect its details +and signers. An individual signer can be **pending** or **signed**; do not +assume the entire request is complete merely because one person has signed. + +.. _add_signature: + +Request signatures +------------------ + +#. Choose **Request Signatures**. Use **Upload** for a PDF on your device, + **Choose from Files** for an existing Nextcloud file, or **Upload from + URL** if your administrator allows it. +#. Review the selected file before asking another person to sign. +#. Use **Search signer** to select a recipient or an allowed identification + method, including an external email recipient where enabled. +#. Check the signer's name and identification details and select **Save**. + Repeat for every required signer. +#. Configure the remaining signing steps shown by LibreSign and submit the + request. Do not consider a draft a delivered invitation. +#. Open the request details in **Files** to see who is still pending. + +Available signer identification methods, permissions, delivery channels, and +signing order depend on the administrator's configuration. Use the options +shown for your request rather than assuming every channel is enabled. + +.. _sign_invitation: + +Sign an invitation +------------------ + +#. Open the link supplied to you for the signing request; verify its sender + before entering any personal information. +#. Read the PDF and check that you are the intended signer. +#. Complete any requested identification step. If LibreSign asks for a + certificate or signature password, follow the instructions for your + configured signing method. +#. Choose **Sign** or **Sign document** and confirm the operation. +#. Check for the completion message. If other signers remain, the request + may still be in progress. + +If the link is expired, rejected, or requires a method you cannot use, +contact the requester. Do not reuse someone else's invitation. + +.. _see_signed_file: + +Follow signing progress +----------------------- + +Open the document details in **Files** and check the signer list. A signer +marked **pending** has not completed their part; **signed** records a completed +part. The document's overall completion depends on all required signatures +and the configured workflow. Download the final PDF when it becomes available. + +.. _validate_document: + +Validate a signature +-------------------- + +#. Open LibreSign's **Validate signature** page. +#. Choose **Upload** to select a PDF, drag and drop a PDF onto the page, or + choose **From UUID** if you have the document identifier. +#. Run **Validation** and review the results, including certificate and + signing information shown by the application. +#. Investigate any reported error instead of treating a visual stamp or QR + code as conclusive proof of validity. + +Validation evaluates the available cryptographic and certificate evidence. +It does not, by itself, determine every legal requirement in your jurisdiction. diff --git a/versioned/base/user_manual/index.rst b/versioned/base/user_manual/index.rst index 3f95ab2d..832c5bae 100644 --- a/versioned/base/user_manual/index.rst +++ b/versioned/base/user_manual/index.rst @@ -1,14 +1,28 @@ User manual — LibreSign |LibreSignRelease| ========================================== -This manual is for LibreSign |LibreSignRelease| running with -Nextcloud |NextcloudRelease|. +Use this manual for LibreSign |LibreSignRelease| on Nextcloud +|NextcloudRelease|. It covers the signing and validation workflows available +in this release, rather than features under development in ``main``. -The version-specific manual is being expanded. It deliberately does not -inherit development screenshots or workflows from ``main`` until they have -been checked against this release line. For interface behavior, check the -LibreSign application installed on your Nextcloud instance. +Choose a task +------------- -You can switch versions using the documentation version selector. The -`release lifecycle guide <../lifecycle.html>`_ explains the meaning of -current, earlier and end-of-support versions. +- :doc:`start` — find the correct entry point for requesting or signing. +- :doc:`functionality` — prepare a document, invite signers, follow progress, + sign a request, or validate a PDF. +- :doc:`faq` — understand account, certificate, and legal considerations. +- :doc:`support` — troubleshoot a problem and find support channels. + +For installation and server configuration, use the +`administrator manual <../admin_manual/index.html>`_. Integrations belong in +the `developer manual <../developer_manual/index.html>`_. + +.. toctree:: + :maxdepth: 2 + :caption: Tasks + + start + functionality + faq + support diff --git a/versioned/base/user_manual/start.rst b/versioned/base/user_manual/start.rst new file mode 100644 index 00000000..40f58281 --- /dev/null +++ b/versioned/base/user_manual/start.rst @@ -0,0 +1,39 @@ +Getting started +=============== + +Choose the path that matches your role. An administrator must install and +configure LibreSign before users can request signatures. + +I want to request signatures +---------------------------- + +#. Sign in to the Nextcloud instance where LibreSign is enabled. +#. Open **LibreSign** and find **Request Signatures** or the request action + in the **Files** screen. +#. Select a PDF using **Upload**, **Choose from Files**, or **Upload from URL** + when those options are available to your account. +#. Follow :ref:`add_signature` to add recipients and send the request. + +If the request controls are missing, ask your administrator whether your +account is permitted to create requests. + +I received a signing invitation +------------------------------- + +#. Open the invitation link from the requester and check the document and + requested identity details before proceeding. +#. Follow the on-screen signing steps. Depending on the configured signing + method, LibreSign may ask you to define a signature, provide a password, + upload a certificate, or complete identity verification. +#. Review the confirmation before submitting. See :ref:`sign_invitation`. + +External email signers can use the invitation workflow without a Nextcloud +account when that identification method is enabled by the administrator. +Do not forward a personal invitation link to another person. + +I want to verify a signed document +---------------------------------- + +Use :ref:`validate_document` to check a signed PDF or a document UUID. The +validation result must be reviewed; an image of a handwritten signature is not +by itself evidence of a valid digital signature. diff --git a/versioned/base/user_manual/support.rst b/versioned/base/user_manual/support.rst new file mode 100644 index 00000000..e7171667 --- /dev/null +++ b/versioned/base/user_manual/support.rst @@ -0,0 +1,19 @@ +Help and support +================ + +If a signing request or validation fails, first note the action you were +trying to perform and the exact error message, without copying private +identification data or document contents into a public report. + +- For an invitation, an expired request, or a wrong recipient, contact the + person who requested the signature. +- For missing permissions, signing methods, or server configuration, contact + your Nextcloud administrator. +- For a reproducible LibreSign defect, consult the + `LibreSign issue tracker `_. +- For project information and professional support options, see + `libresign.coop `_. + +Include your LibreSign and Nextcloud version numbers in technical reports. +Never publish signature passwords, private certificates, invitation links, +or documents containing personal data. diff --git a/versioned/legacy-routes.json b/versioned/legacy-routes.json index 1d8a66ab..5e401d24 100644 --- a/versioned/legacy-routes.json +++ b/versioned/legacy-routes.json @@ -1,9 +1,9 @@ { - "admin_manual/configuration.html": "main/admin_manual/configuration.html", + "admin_manual/configuration.html": "15/admin_manual/configuration.html", "admin_manual/index.html": "15/admin_manual/index.html", - "admin_manual/installation.html": "main/admin_manual/installation.html", - "admin_manual/maintenance.html": "main/admin_manual/maintenance.html", - "admin_manual/security.html": "main/admin_manual/security.html", + "admin_manual/installation.html": "15/admin_manual/installation.html", + "admin_manual/maintenance.html": "15/admin_manual/maintenance.html", + "admin_manual/security.html": "15/admin_manual/security.html", "developer_manual/api/external-email-signers.html": "15/developer_manual/api/external-email-signers.html", "developer_manual/api/guide-api.html": "main/developer_manual/api/guide-api.html", "developer_manual/api/index.html": "15/developer_manual/api/index.html", @@ -40,9 +40,9 @@ "developer_manual/release-process/versioning.html": "main/developer_manual/release-process/versioning.html", "developer_manual/requesting-features.html": "main/developer_manual/requesting-features.html", "developer_manual/translation.html": "main/developer_manual/translation.html", - "user_manual/faq.html": "main/user_manual/faq.html", - "user_manual/functionality.html": "main/user_manual/functionality.html", + "user_manual/faq.html": "15/user_manual/faq.html", + "user_manual/functionality.html": "15/user_manual/functionality.html", "user_manual/index.html": "15/user_manual/index.html", - "user_manual/start.html": "main/user_manual/start.html", - "user_manual/suport.html": "main/user_manual/suport.html" + "user_manual/start.html": "15/user_manual/start.html", + "user_manual/suport.html": "15/user_manual/support.html" }