Move docs to material-mkdocs
							
								
								
									
										36
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -42,35 +42,13 @@ jobs: | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v3 | ||||
|       - | ||||
|         name: Install pipenv | ||||
|         run: | | ||||
|           pipx install pipenv==2022.10.12 | ||||
|       - | ||||
|         name: Set up Python | ||||
|         uses: actions/setup-python@v4 | ||||
|         with: | ||||
|           python-version: 3.9 | ||||
|           cache: "pipenv" | ||||
|           cache-dependency-path: 'Pipfile.lock' | ||||
|       - | ||||
|         name: Install dependencies | ||||
|         run: | | ||||
|           pipenv sync --dev | ||||
|       - | ||||
|         name: List installed Python dependencies | ||||
|         run: | | ||||
|           pipenv run pip list | ||||
|       - | ||||
|         name: Make documentation | ||||
|         run: | | ||||
|           cd docs/ | ||||
|           pipenv run make html | ||||
|       - | ||||
|         name: Upload artifact | ||||
|         uses: actions/upload-artifact@v3 | ||||
|         with: | ||||
|           name: documentation | ||||
|           path: docs/_build/html/ | ||||
|         name: Deploy docs | ||||
|         uses: mhausenblas/mkdocs-deploy-gh-pages@master | ||||
|         env: | ||||
|           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|           CUSTOM_DOMAIN: paperless-ngx.com | ||||
|           CONFIG_FILE: mkdocs.yml | ||||
|           EXTRA_PACKAGES: build-base | ||||
|  | ||||
|   tests-backend: | ||||
|     name: "Tests (${{ matrix.python-version }})" | ||||
|   | ||||
| @@ -1,16 +0,0 @@ | ||||
| # .readthedocs.yml | ||||
| # Read the Docs configuration file | ||||
| # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details | ||||
|  | ||||
| # Required | ||||
| version: 2 | ||||
|  | ||||
| # Build documentation in the docs/ directory with Sphinx | ||||
| sphinx: | ||||
|   configuration: docs/conf.py | ||||
|  | ||||
| # Optionally set the version of Python and requirements required to build your docs | ||||
| python: | ||||
|   version: "3.8" | ||||
|   install: | ||||
|     - requirements: docs/requirements.txt | ||||
							
								
								
									
										3
									
								
								Pipfile
									
									
									
									
									
								
							
							
						
						| @@ -71,10 +71,9 @@ pytest-django = "*" | ||||
| pytest-env = "*" | ||||
| pytest-sugar = "*" | ||||
| pytest-xdist = "*" | ||||
| sphinx = "~=5.3" | ||||
| sphinx_rtd_theme = "*" | ||||
| tox = "*" | ||||
| black = "*" | ||||
| pre-commit = "*" | ||||
| sphinx-autobuild = "*" | ||||
| myst-parser = "*" | ||||
| mkdocs-material = "*" | ||||
|   | ||||
							
								
								
									
										129
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							
							
						
						| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|     "_meta": { | ||||
|         "hash": { | ||||
|             "sha256": "9fefc737155e789ced61b41750b4273c7780ac7801c50cf36dc5925be3b85783" | ||||
|             "sha256": "0242e3e296e09b30fb69e0d7a2f2e8feb4c6a23d3c7ec99500f2883a032a8c84" | ||||
|         }, | ||||
|         "pipfile-spec": 6, | ||||
|         "requires": {}, | ||||
| @@ -99,6 +99,7 @@ | ||||
|                 "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac", | ||||
|                 "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "markers": "python_version < '3.9'", | ||||
|             "version": "==0.2.1" | ||||
|         }, | ||||
| @@ -218,7 +219,7 @@ | ||||
|                 "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", | ||||
|                 "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" | ||||
|             ], | ||||
|             "markers": "python_full_version >= '3.6.0'", | ||||
|             "markers": "python_version >= '3.6'", | ||||
|             "version": "==2.1.1" | ||||
|         }, | ||||
|         "click": { | ||||
| @@ -234,7 +235,7 @@ | ||||
|                 "sha256:a0713dc7a1de3f06bc0df5a9567ad19ead2d3d5689b434768a6145bff77c0667", | ||||
|                 "sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035" | ||||
|             ], | ||||
|             "markers": "python_full_version >= '3.6.2' and python_full_version < '4.0.0'", | ||||
|             "markers": "python_version < '4' and python_full_version >= '3.6.2'", | ||||
|             "version": "==0.3.0" | ||||
|         }, | ||||
|         "click-plugins": { | ||||
| @@ -1624,7 +1625,7 @@ | ||||
|                 "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa", | ||||
|                 "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.7'", | ||||
|             "markers": "python_version < '3.10'", | ||||
|             "version": "==4.4.0" | ||||
|         }, | ||||
|         "tzdata": { | ||||
| @@ -2054,7 +2055,7 @@ | ||||
|                 "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", | ||||
|                 "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" | ||||
|             ], | ||||
|             "markers": "python_full_version >= '3.6.0'", | ||||
|             "markers": "python_version >= '3.6'", | ||||
|             "version": "==2.1.1" | ||||
|         }, | ||||
|         "click": { | ||||
| @@ -2074,6 +2075,9 @@ | ||||
|             "version": "==0.4.6" | ||||
|         }, | ||||
|         "coverage": { | ||||
|             "extras": [ | ||||
|                 "toml" | ||||
|             ], | ||||
|             "hashes": [ | ||||
|                 "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79", | ||||
|                 "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a", | ||||
| @@ -2198,6 +2202,13 @@ | ||||
|             "index": "pypi", | ||||
|             "version": "==3.8.0" | ||||
|         }, | ||||
|         "ghp-import": { | ||||
|             "hashes": [ | ||||
|                 "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", | ||||
|                 "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343" | ||||
|             ], | ||||
|             "version": "==2.1.0" | ||||
|         }, | ||||
|         "identify": { | ||||
|             "hashes": [ | ||||
|                 "sha256:48b7925fe122720088aeb7a6c34f17b27e706b72c61070f27fe3789094233440", | ||||
| @@ -2222,6 +2233,14 @@ | ||||
|             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", | ||||
|             "version": "==1.4.1" | ||||
|         }, | ||||
|         "importlib-metadata": { | ||||
|             "hashes": [ | ||||
|                 "sha256:d5059f9f1e8e41f80e9c56c2ee58811450c31984dfa625329ffd7c0dad88a73b", | ||||
|                 "sha256:d84d17e21670ec07990e1044a99efe8d615d860fd176fc29ef5c306068fda313" | ||||
|             ], | ||||
|             "markers": "python_version < '3.10'", | ||||
|             "version": "==5.1.0" | ||||
|         }, | ||||
|         "iniconfig": { | ||||
|             "hashes": [ | ||||
|                 "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", | ||||
| @@ -2243,6 +2262,14 @@ | ||||
|             ], | ||||
|             "version": "==2.6.3" | ||||
|         }, | ||||
|         "markdown": { | ||||
|             "hashes": [ | ||||
|                 "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874", | ||||
|                 "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.6'", | ||||
|             "version": "==3.3.7" | ||||
|         }, | ||||
|         "markdown-it-py": { | ||||
|             "hashes": [ | ||||
|                 "sha256:93de681e5c021a432c63147656fe21790bc01231e0cd2da73626f1aa3ac0fe27", | ||||
| @@ -2313,6 +2340,38 @@ | ||||
|             "markers": "python_version >= '3.7'", | ||||
|             "version": "==0.1.2" | ||||
|         }, | ||||
|         "mergedeep": { | ||||
|             "hashes": [ | ||||
|                 "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", | ||||
|                 "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.6'", | ||||
|             "version": "==1.3.4" | ||||
|         }, | ||||
|         "mkdocs": { | ||||
|             "hashes": [ | ||||
|                 "sha256:8947af423a6d0facf41ea1195b8e1e8c85ad94ac95ae307fe11232e0424b11c5", | ||||
|                 "sha256:c8856a832c1e56702577023cd64cc5f84948280c1c0fcc6af4cd39006ea6aa8c" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.7'", | ||||
|             "version": "==1.4.2" | ||||
|         }, | ||||
|         "mkdocs-material": { | ||||
|             "hashes": [ | ||||
|                 "sha256:b0ea0513fd8cab323e8a825d6692ea07fa83e917bb5db042e523afecc7064ab7", | ||||
|                 "sha256:c907b4b052240a5778074a30a78f31a1f8ff82d7012356dc26898b97559f082e" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "version": "==8.5.11" | ||||
|         }, | ||||
|         "mkdocs-material-extensions": { | ||||
|             "hashes": [ | ||||
|                 "sha256:9c003da71e2cc2493d910237448c672e00cefc800d3d6ae93d2fc69979e3bd93", | ||||
|                 "sha256:e41d9f38e4798b6617ad98ca8f7f1157b1e4385ac1459ca1e4ea219b556df945" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.7'", | ||||
|             "version": "==1.1.1" | ||||
|         }, | ||||
|         "mypy-extensions": { | ||||
|             "hashes": [ | ||||
|                 "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", | ||||
| @@ -2400,6 +2459,14 @@ | ||||
|             "markers": "python_version >= '3.6'", | ||||
|             "version": "==2.13.0" | ||||
|         }, | ||||
|         "pymdown-extensions": { | ||||
|             "hashes": [ | ||||
|                 "sha256:0f8fb7b74a37a61cc34e90b2c91865458b713ec774894ffad64353a5fce85cfc", | ||||
|                 "sha256:ac698c15265680db5eb13cd4342abfcde2079ac01e5486028f47a1b41547b859" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.7'", | ||||
|             "version": "==9.9" | ||||
|         }, | ||||
|         "pyparsing": { | ||||
|             "hashes": [ | ||||
|                 "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", | ||||
| @@ -2516,6 +2583,14 @@ | ||||
|             ], | ||||
|             "version": "==6.0" | ||||
|         }, | ||||
|         "pyyaml-env-tag": { | ||||
|             "hashes": [ | ||||
|                 "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", | ||||
|                 "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.6'", | ||||
|             "version": "==0.1" | ||||
|         }, | ||||
|         "requests": { | ||||
|             "hashes": [ | ||||
|                 "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", | ||||
| @@ -2552,7 +2627,6 @@ | ||||
|                 "sha256:060ca5c9f7ba57a08a1219e547b269fadf125ae25b06b9fa7f66768efb652d6d", | ||||
|                 "sha256:51026de0a9ff9fc13c05d74913ad66047e104f56a129ff73e174eb5c3ee794b5" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "version": "==5.3.0" | ||||
|         }, | ||||
|         "sphinx-autobuild": { | ||||
| @@ -2640,7 +2714,7 @@ | ||||
|                 "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", | ||||
|                 "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" | ||||
|             ], | ||||
|             "markers": "python_full_version < '3.11.0a7'", | ||||
|             "markers": "python_version < '3.11' and python_version >= '3.7'", | ||||
|             "version": "==2.0.1" | ||||
|         }, | ||||
|         "tornado": { | ||||
| @@ -2673,7 +2747,7 @@ | ||||
|                 "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa", | ||||
|                 "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e" | ||||
|             ], | ||||
|             "markers": "python_version >= '3.7'", | ||||
|             "markers": "python_version < '3.10'", | ||||
|             "version": "==4.4.0" | ||||
|         }, | ||||
|         "urllib3": { | ||||
| @@ -2691,6 +2765,45 @@ | ||||
|             ], | ||||
|             "markers": "python_version >= '3.6'", | ||||
|             "version": "==20.16.6" | ||||
|         }, | ||||
|         "watchdog": { | ||||
|             "hashes": [ | ||||
|                 "sha256:083171652584e1b8829581f965b9b7723ca5f9a2cd7e20271edf264cfd7c1412", | ||||
|                 "sha256:117ffc6ec261639a0209a3252546b12800670d4bf5f84fbd355957a0595fe654", | ||||
|                 "sha256:186f6c55abc5e03872ae14c2f294a153ec7292f807af99f57611acc8caa75306", | ||||
|                 "sha256:195fc70c6e41237362ba720e9aaf394f8178bfc7fa68207f112d108edef1af33", | ||||
|                 "sha256:226b3c6c468ce72051a4c15a4cc2ef317c32590d82ba0b330403cafd98a62cfd", | ||||
|                 "sha256:247dcf1df956daa24828bfea5a138d0e7a7c98b1a47cf1fa5b0c3c16241fcbb7", | ||||
|                 "sha256:255bb5758f7e89b1a13c05a5bceccec2219f8995a3a4c4d6968fe1de6a3b2892", | ||||
|                 "sha256:43ce20ebb36a51f21fa376f76d1d4692452b2527ccd601950d69ed36b9e21609", | ||||
|                 "sha256:4f4e1c4aa54fb86316a62a87b3378c025e228178d55481d30d857c6c438897d6", | ||||
|                 "sha256:5952135968519e2447a01875a6f5fc8c03190b24d14ee52b0f4b1682259520b1", | ||||
|                 "sha256:64a27aed691408a6abd83394b38503e8176f69031ca25d64131d8d640a307591", | ||||
|                 "sha256:6b17d302850c8d412784d9246cfe8d7e3af6bcd45f958abb2d08a6f8bedf695d", | ||||
|                 "sha256:70af927aa1613ded6a68089a9262a009fbdf819f46d09c1a908d4b36e1ba2b2d", | ||||
|                 "sha256:7a833211f49143c3d336729b0020ffd1274078e94b0ae42e22f596999f50279c", | ||||
|                 "sha256:8250546a98388cbc00c3ee3cc5cf96799b5a595270dfcfa855491a64b86ef8c3", | ||||
|                 "sha256:97f9752208f5154e9e7b76acc8c4f5a58801b338de2af14e7e181ee3b28a5d39", | ||||
|                 "sha256:9f05a5f7c12452f6a27203f76779ae3f46fa30f1dd833037ea8cbc2887c60213", | ||||
|                 "sha256:a735a990a1095f75ca4f36ea2ef2752c99e6ee997c46b0de507ba40a09bf7330", | ||||
|                 "sha256:ad576a565260d8f99d97f2e64b0f97a48228317095908568a9d5c786c829d428", | ||||
|                 "sha256:b530ae007a5f5d50b7fbba96634c7ee21abec70dc3e7f0233339c81943848dc1", | ||||
|                 "sha256:bfc4d351e6348d6ec51df007432e6fe80adb53fd41183716017026af03427846", | ||||
|                 "sha256:d3dda00aca282b26194bdd0adec21e4c21e916956d972369359ba63ade616153", | ||||
|                 "sha256:d9820fe47c20c13e3c9dd544d3706a2a26c02b2b43c993b62fcd8011bcc0adb3", | ||||
|                 "sha256:ed80a1628cee19f5cfc6bb74e173f1b4189eb532e705e2a13e3250312a62e0c9", | ||||
|                 "sha256:ee3e38a6cc050a8830089f79cbec8a3878ec2fe5160cdb2dc8ccb6def8552658" | ||||
|             ], | ||||
|             "index": "pypi", | ||||
|             "version": "==2.1.9" | ||||
|         }, | ||||
|         "zipp": { | ||||
|             "hashes": [ | ||||
|                 "sha256:4fcb6f278987a6605757302a6e40e896257570d11c51628968ccb2a47e80c6c1", | ||||
|                 "sha256:7a7262fd930bd3e36c50b9a64897aec3fafff3dfdeec9623ae22b40e93f99bb8" | ||||
|             ], | ||||
|             "markers": "python_version < '3.9'", | ||||
|             "version": "==3.10.0" | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										181
									
								
								docs/Makefile
									
									
									
									
									
								
							
							
						
						| @@ -1,181 +0,0 @@ | ||||
| # Makefile for Sphinx documentation | ||||
| # | ||||
|  | ||||
| # You can set these variables from the command line. | ||||
| SPHINXOPTS    = | ||||
| SPHINXBUILD   = sphinx-build | ||||
| PAPER         = | ||||
| BUILDDIR      = _build | ||||
|  | ||||
| # User-friendly check for sphinx-build | ||||
| ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) | ||||
| $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) | ||||
| endif | ||||
|  | ||||
| # Internal variables. | ||||
| PAPEROPT_a4     = -D latex_paper_size=a4 | ||||
| PAPEROPT_letter = -D latex_paper_size=letter | ||||
| ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . | ||||
| # the i18n builder cannot share the environment and doctrees with the others | ||||
| I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . | ||||
|  | ||||
| .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext | ||||
|  | ||||
| help: | ||||
| 	@echo "Please use \`make <target>' where <target> is one of" | ||||
| 	@echo "  html       to make standalone HTML files" | ||||
| 	@echo "  livehtml   to preview changes with live reload in your browser" | ||||
| 	@echo "  dirhtml    to make HTML files named index.html in directories" | ||||
| 	@echo "  singlehtml to make a single large HTML file" | ||||
| 	@echo "  pickle     to make pickle files" | ||||
| 	@echo "  json       to make JSON files" | ||||
| 	@echo "  htmlhelp   to make HTML files and a HTML help project" | ||||
| 	@echo "  qthelp     to make HTML files and a qthelp project" | ||||
| 	@echo "  devhelp    to make HTML files and a Devhelp project" | ||||
| 	@echo "  epub       to make an epub" | ||||
| 	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter" | ||||
| 	@echo "  latexpdf   to make LaTeX files and run them through pdflatex" | ||||
| 	@echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx" | ||||
| 	@echo "  text       to make text files" | ||||
| 	@echo "  man        to make manual pages" | ||||
| 	@echo "  texinfo    to make Texinfo files" | ||||
| 	@echo "  info       to make Texinfo files and run them through makeinfo" | ||||
| 	@echo "  gettext    to make PO message catalogs" | ||||
| 	@echo "  changes    to make an overview of all changed/added/deprecated items" | ||||
| 	@echo "  xml        to make Docutils-native XML files" | ||||
| 	@echo "  pseudoxml  to make pseudoxml-XML files for display purposes" | ||||
| 	@echo "  linkcheck  to check all external links for integrity" | ||||
| 	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)" | ||||
|  | ||||
| clean: | ||||
| 	rm -rf $(BUILDDIR)/* | ||||
|  | ||||
| html: | ||||
| 	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html | ||||
| 	@echo | ||||
| 	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html." | ||||
|  | ||||
| livehtml: | ||||
| 	sphinx-autobuild "./" "$(BUILDDIR)" $(O) | ||||
|  | ||||
| dirhtml: | ||||
| 	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml | ||||
| 	@echo | ||||
| 	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." | ||||
|  | ||||
| singlehtml: | ||||
| 	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml | ||||
| 	@echo | ||||
| 	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." | ||||
|  | ||||
| pickle: | ||||
| 	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle | ||||
| 	@echo | ||||
| 	@echo "Build finished; now you can process the pickle files." | ||||
|  | ||||
| json: | ||||
| 	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json | ||||
| 	@echo | ||||
| 	@echo "Build finished; now you can process the JSON files." | ||||
|  | ||||
| htmlhelp: | ||||
| 	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp | ||||
| 	@echo | ||||
| 	@echo "Build finished; now you can run HTML Help Workshop with the" \ | ||||
| 	      ".hhp project file in $(BUILDDIR)/htmlhelp." | ||||
|  | ||||
| qthelp: | ||||
| 	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp | ||||
| 	@echo | ||||
| 	@echo "Build finished; now you can run "qcollectiongenerator" with the" \ | ||||
| 	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:" | ||||
| 	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/RIPEAtlasToolsMagellan.qhcp" | ||||
| 	@echo "To view the help file:" | ||||
| 	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/RIPEAtlasToolsMagellan.qhc" | ||||
|  | ||||
| devhelp: | ||||
| 	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp | ||||
| 	@echo | ||||
| 	@echo "Build finished." | ||||
| 	@echo "To view the help file:" | ||||
| 	@echo "# mkdir -p $$HOME/.local/share/devhelp/RIPEAtlasToolsMagellan" | ||||
| 	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/RIPEAtlasToolsMagellan" | ||||
| 	@echo "# devhelp" | ||||
|  | ||||
| epub: | ||||
| 	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub | ||||
| 	@echo | ||||
| 	@echo "Build finished. The epub file is in $(BUILDDIR)/epub." | ||||
|  | ||||
| latex: | ||||
| 	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex | ||||
| 	@echo | ||||
| 	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." | ||||
| 	@echo "Run \`make' in that directory to run these through (pdf)latex" \ | ||||
| 	      "(use \`make latexpdf' here to do that automatically)." | ||||
|  | ||||
| latexpdf: | ||||
| 	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex | ||||
| 	@echo "Running LaTeX files through pdflatex..." | ||||
| 	$(MAKE) -C $(BUILDDIR)/latex all-pdf | ||||
| 	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." | ||||
|  | ||||
| latexpdfja: | ||||
| 	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex | ||||
| 	@echo "Running LaTeX files through platex and dvipdfmx..." | ||||
| 	$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja | ||||
| 	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." | ||||
|  | ||||
| text: | ||||
| 	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text | ||||
| 	@echo | ||||
| 	@echo "Build finished. The text files are in $(BUILDDIR)/text." | ||||
|  | ||||
| man: | ||||
| 	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man | ||||
| 	@echo | ||||
| 	@echo "Build finished. The manual pages are in $(BUILDDIR)/man." | ||||
|  | ||||
| texinfo: | ||||
| 	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo | ||||
| 	@echo | ||||
| 	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." | ||||
| 	@echo "Run \`make' in that directory to run these through makeinfo" \ | ||||
| 	      "(use \`make info' here to do that automatically)." | ||||
|  | ||||
| info: | ||||
| 	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo | ||||
| 	@echo "Running Texinfo files through makeinfo..." | ||||
| 	make -C $(BUILDDIR)/texinfo info | ||||
| 	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." | ||||
|  | ||||
| gettext: | ||||
| 	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale | ||||
| 	@echo | ||||
| 	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." | ||||
|  | ||||
| changes: | ||||
| 	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes | ||||
| 	@echo | ||||
| 	@echo "The overview file is in $(BUILDDIR)/changes." | ||||
|  | ||||
| linkcheck: | ||||
| 	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck | ||||
| 	@echo | ||||
| 	@echo "Link check complete; look for any errors in the above output " \ | ||||
| 	      "or in $(BUILDDIR)/linkcheck/output.txt." | ||||
|  | ||||
| doctest: | ||||
| 	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest | ||||
| 	@echo "Testing of doctests in the sources finished, look at the " \ | ||||
| 	      "results in $(BUILDDIR)/doctest/output.txt." | ||||
|  | ||||
| xml: | ||||
| 	$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml | ||||
| 	@echo | ||||
| 	@echo "Build finished. The XML files are in $(BUILDDIR)/xml." | ||||
|  | ||||
| pseudoxml: | ||||
| 	$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml | ||||
| 	@echo | ||||
| 	@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." | ||||
							
								
								
									
										597
									
								
								docs/_static/css/custom.css
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1,597 +0,0 @@ | ||||
| /* Variables */ | ||||
| :root { | ||||
|   --color-text-body: #5c5962; | ||||
|   --color-text-body-light: #fcfcfc; | ||||
|   --color-text-anchor: #7253ed; | ||||
|   --color-text-alt: rgba(0, 0, 0, 0.3); | ||||
|   --color-text-title: #27262b; | ||||
|   --color-text-code-inline: #e74c3c; | ||||
|   --color-text-code-nt: #062873; | ||||
|   --color-text-selection: #b19eff; | ||||
|   --color-bg-body: #fcfcfc; | ||||
|   --color-bg-body-alt: #f3f6f6; | ||||
|   --color-bg-side-nav: #f5f6fa; | ||||
|   --color-bg-side-nav-hover: #ebedf5; | ||||
|   --color-bg-code-block: var(--color-bg-side-nav); | ||||
|   --color-border: #eeebee; | ||||
|   --color-btn-neutral-bg: #f3f6f6; | ||||
|   --color-btn-neutral-bg-hover: #e5ebeb; | ||||
|   --color-success-title: #1abc9c; | ||||
|   --color-success-body: #dbfaf4; | ||||
|   --color-warning-title: #f0b37e; | ||||
|   --color-warning-body: #ffedcc; | ||||
|   --color-danger-title: #f29f97; | ||||
|   --color-danger-body: #fdf3f2; | ||||
|   --color-info-title: #6ab0de; | ||||
|   --color-info-body: #e7f2fa; | ||||
| } | ||||
|  | ||||
| .dark-mode { | ||||
|   --color-text-body: #abb2bf; | ||||
|   --color-text-body-light: #9499a2; | ||||
|   --color-text-alt: rgba(0255, 255, 255, 0.5); | ||||
|   --color-text-title: var(--color-text-anchor); | ||||
|   --color-text-code-inline: #abb2bf; | ||||
|   --color-text-code-nt: #2063f3; | ||||
|   --color-text-selection: #030303; | ||||
|   --color-bg-body: #1d1d20 !important; | ||||
|   --color-bg-body-alt: #131315; | ||||
|   --color-bg-side-nav: #18181a; | ||||
|   --color-bg-side-nav-hover: #101216; | ||||
|   --color-bg-code-block: #101216; | ||||
|   --color-border: #47494f; | ||||
|   --color-btn-neutral-bg: #242529; | ||||
|   --color-btn-neutral-bg-hover: #101216; | ||||
|   --color-success-title: #02120f; | ||||
|   --color-success-body: #041b17; | ||||
|   --color-warning-title: #1b0e03; | ||||
|   --color-warning-body: #371d06; | ||||
|   --color-danger-title: #120902; | ||||
|   --color-danger-body: #1b0503; | ||||
|   --color-info-title: #020608; | ||||
|   --color-info-body: #06141e; | ||||
| } | ||||
|  | ||||
| * { | ||||
|   transition: background-color 0.3s ease, border-color 0.3s ease; | ||||
| } | ||||
|  | ||||
| /* Typography */ | ||||
| body { | ||||
|   font-family: system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif; | ||||
|   font-size: inherit; | ||||
|   line-height: 1.4; | ||||
|   color: var(--color-text-body); | ||||
| } | ||||
|  | ||||
| .rst-content p { | ||||
|   word-break: break-word; | ||||
| } | ||||
|  | ||||
| h1, h2, h3, h4, h5, h6 { | ||||
|   font-family: inherit; | ||||
| } | ||||
|  | ||||
| .rst-content .toctree-wrapper>p.caption, .rst-content h1, .rst-content h2, .rst-content h3, .rst-content h4, .rst-content h5, .rst-content h6 { | ||||
|   padding-top: .5em; | ||||
| } | ||||
|  | ||||
| p, .main-content-wrap, .rst-content .section ul, .rst-content .toctree-wrapper ul, .rst-content section ul, .wy-plain-list-disc, article ul { | ||||
|   line-height: 1.6; | ||||
| } | ||||
|  | ||||
| pre, .code, .rst-content .linenodiv pre, .rst-content div[class^=highlight] pre, .rst-content pre.literal-block { | ||||
|   font-family: "SFMono-Regular", Menlo,Consolas, Monospace; | ||||
|   font-size: 0.75em; | ||||
|   line-height: 1.8; | ||||
| } | ||||
|  | ||||
| .wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4 { | ||||
|   font-size: 1rem | ||||
| } | ||||
|  | ||||
| .rst-versions { | ||||
|   font-family: inherit; | ||||
|   line-height: 1; | ||||
| } | ||||
|  | ||||
| footer, footer p { | ||||
|   font-size: .8rem; | ||||
| } | ||||
|  | ||||
| footer .rst-footer-buttons { | ||||
|   font-size: 1rem; | ||||
| } | ||||
|  | ||||
| @media (max-width: 400px) { | ||||
|   /* break code lines on mobile */ | ||||
|   pre, code { | ||||
|     word-break: break-word; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Layout */ | ||||
| .wy-side-nav-search, .wy-menu-vertical { | ||||
|   width: auto; | ||||
| } | ||||
|  | ||||
| .wy-nav-side { | ||||
|   z-index: 0; | ||||
|   display: flex; | ||||
|   flex-wrap: wrap; | ||||
|   background-color: var(--color-bg-side-nav); | ||||
| } | ||||
|  | ||||
| .wy-side-scroll { | ||||
|   width: 100%; | ||||
|   overflow-y: auto; | ||||
| } | ||||
|  | ||||
| @media (min-width: 66.5rem) { | ||||
|   .wy-side-scroll { | ||||
|       width:264px | ||||
|   } | ||||
| } | ||||
|  | ||||
| @media (min-width: 50rem) { | ||||
|   .wy-nav-side { | ||||
|       flex-wrap: nowrap; | ||||
|       position: fixed; | ||||
|       width: 248px; | ||||
|       height: 100%; | ||||
|       flex-direction: column; | ||||
|       border-right: 1px solid var(--color-border); | ||||
|       align-items:flex-end | ||||
|   } | ||||
| } | ||||
|  | ||||
| @media (min-width: 66.5rem) { | ||||
|   .wy-nav-side { | ||||
|       width: calc((100% - 1064px) / 2 + 264px); | ||||
|       min-width:264px | ||||
|   } | ||||
| } | ||||
|  | ||||
| @media (min-width: 50rem) { | ||||
|   .wy-nav-content-wrap { | ||||
|       position: relative; | ||||
|       max-width: 800px; | ||||
|       margin-left:248px | ||||
|   } | ||||
| } | ||||
|  | ||||
| @media (min-width: 66.5rem) { | ||||
|   .wy-nav-content-wrap { | ||||
|       margin-left:calc((100% - 1064px) / 2 + 264px) | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Colors */ | ||||
| body.wy-body-for-nav, | ||||
| .wy-nav-content { | ||||
|   background: var(--color-bg-body); | ||||
| } | ||||
|  | ||||
| .wy-nav-side { | ||||
|   border-right: 1px solid var(--color-border); | ||||
| } | ||||
|  | ||||
| .wy-side-nav-search, .wy-nav-top { | ||||
|   background: var(--color-bg-side-nav); | ||||
|   border-bottom: 1px solid var(--color-border); | ||||
| } | ||||
|  | ||||
| .wy-nav-content-wrap { | ||||
|   background: inherit; | ||||
| } | ||||
|  | ||||
| .wy-side-nav-search > a, .wy-nav-top a, .wy-nav-top i { | ||||
|   color: var(--color-text-title); | ||||
| } | ||||
|  | ||||
| .wy-side-nav-search > a:hover, .wy-nav-top a:hover { | ||||
|   background: transparent; | ||||
| } | ||||
|  | ||||
| .wy-side-nav-search > div.version { | ||||
|   color: var(--color-text-alt) | ||||
| } | ||||
|  | ||||
| .wy-side-nav-search > div[role="search"] { | ||||
|   border-top: 1px solid var(--color-border); | ||||
| } | ||||
|  | ||||
| .wy-menu-vertical li.toctree-l2.current>a, .wy-menu-vertical li.toctree-l2.current li.toctree-l3>a, | ||||
| .wy-menu-vertical li.toctree-l3.current>a, .wy-menu-vertical li.toctree-l3.current li.toctree-l4>a { | ||||
|   background: var(--color-bg-side-nav); | ||||
| } | ||||
|  | ||||
| .rst-content .highlighted { | ||||
|   background: #eedd85; | ||||
|   box-shadow: 0 0 0 2px #eedd85; | ||||
|   font-weight: 600; | ||||
| } | ||||
|  | ||||
| .wy-side-nav-search input[type=text], | ||||
| html.writer-html5 .rst-content table.docutils th { | ||||
|   color: var(--color-text-body); | ||||
| } | ||||
|  | ||||
| .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td, | ||||
| .wy-table-backed, | ||||
| .wy-table-odd td, | ||||
| .wy-table-striped tr:nth-child(2n-1) td { | ||||
|   background-color: var(--color-bg-body-alt); | ||||
| } | ||||
|  | ||||
| .rst-content table.docutils, | ||||
| .wy-table-bordered-all, | ||||
| html.writer-html5 .rst-content table.docutils th, | ||||
| .rst-content table.docutils td, | ||||
| .wy-table-bordered-all td, | ||||
| hr { | ||||
|   border-color: var(--color-border) !important; | ||||
| } | ||||
|  | ||||
| ::selection { | ||||
|   background: var(--color-text-selection); | ||||
| } | ||||
|  | ||||
| /* Ridiculous rules are taken from sphinx_rtd */ | ||||
| .rst-content .admonition-title, | ||||
| .wy-alert-title { | ||||
|   color: var(--color-text-body-light); | ||||
| } | ||||
|  | ||||
| .rst-content .hint, | ||||
| .rst-content .important, | ||||
| .rst-content .tip, | ||||
| .rst-content .wy-alert-success, | ||||
| .wy-alert.wy-alert-success { | ||||
|   background: var(--color-success-body); | ||||
| } | ||||
|  | ||||
| .rst-content .hint .admonition-title, | ||||
| .rst-content .hint .wy-alert-title, | ||||
| .rst-content .important .admonition-title, | ||||
| .rst-content .important .wy-alert-title, | ||||
| .rst-content .tip .admonition-title, | ||||
| .rst-content .tip .wy-alert-title, | ||||
| .rst-content .wy-alert-success .admonition-title, | ||||
| .rst-content .wy-alert-success .wy-alert-title, | ||||
| .wy-alert.wy-alert-success .rst-content .admonition-title, | ||||
| .wy-alert.wy-alert-success .wy-alert-title { | ||||
|   background-color: var(--color-success-title); | ||||
| } | ||||
|  | ||||
| .rst-content .admonition-todo, | ||||
| .rst-content .attention, | ||||
| .rst-content .caution, | ||||
| .rst-content .warning, | ||||
| .rst-content .wy-alert-warning, | ||||
| .wy-alert.wy-alert-warning { | ||||
|   background: var(--color-warning-body); | ||||
| } | ||||
|  | ||||
| .rst-content .admonition-todo .admonition-title, | ||||
| .rst-content .admonition-todo .wy-alert-title, | ||||
| .rst-content .attention .admonition-title, | ||||
| .rst-content .attention .wy-alert-title, | ||||
| .rst-content .caution .admonition-title, | ||||
| .rst-content .caution .wy-alert-title, | ||||
| .rst-content .warning .admonition-title, | ||||
| .rst-content .warning .wy-alert-title, | ||||
| .rst-content .wy-alert-warning .admonition-title, | ||||
| .rst-content .wy-alert-warning .wy-alert-title, | ||||
| .rst-content .wy-alert.wy-alert-warning .admonition-title, | ||||
| .wy-alert.wy-alert-warning .rst-content .admonition-title, | ||||
| .wy-alert.wy-alert-warning .wy-alert-title { | ||||
|   background: var(--color-warning-title); | ||||
| } | ||||
|  | ||||
| .rst-content .danger, | ||||
| .rst-content .error, | ||||
| .rst-content .wy-alert-danger, | ||||
| .wy-alert.wy-alert-danger { | ||||
|   background: var(--color-danger-body); | ||||
| } | ||||
|  | ||||
| .rst-content .danger .admonition-title, | ||||
| .rst-content .danger .wy-alert-title, | ||||
| .rst-content .error .admonition-title, | ||||
| .rst-content .error .wy-alert-title, | ||||
| .rst-content .wy-alert-danger .admonition-title, | ||||
| .rst-content .wy-alert-danger .wy-alert-title, | ||||
| .wy-alert.wy-alert-danger .rst-content .admonition-title, | ||||
| .wy-alert.wy-alert-danger .wy-alert-title { | ||||
|   background: var(--color-danger-title); | ||||
| } | ||||
|  | ||||
| .rst-content .note, | ||||
| .rst-content .seealso, | ||||
| .rst-content .wy-alert-info, | ||||
| .wy-alert.wy-alert-info { | ||||
|   background: var(--color-info-body); | ||||
| } | ||||
|  | ||||
| .rst-content .note .admonition-title, | ||||
| .rst-content .note .wy-alert-title, | ||||
| .rst-content .seealso .admonition-title, | ||||
| .rst-content .seealso .wy-alert-title, | ||||
| .rst-content .wy-alert-info .admonition-title, | ||||
| .rst-content .wy-alert-info .wy-alert-title, | ||||
| .wy-alert.wy-alert-info .rst-content .admonition-title, | ||||
| .wy-alert.wy-alert-info .wy-alert-title { | ||||
|   background: var(--color-info-title); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* Links */ | ||||
| a, a:visited, | ||||
| .wy-menu-vertical a, | ||||
| a.icon.icon-home, | ||||
| .wy-menu-vertical li.toctree-l1.current > a.current { | ||||
|   color: var(--color-text-anchor); | ||||
|   text-decoration: none; | ||||
| } | ||||
|  | ||||
| a:hover, .wy-breadcrumbs-aside a { | ||||
|   color: var(--color-text-anchor); /* reset */ | ||||
| } | ||||
|  | ||||
| .rst-versions a, .rst-versions .rst-current-version { | ||||
|   color: #var(--color-text-anchor); | ||||
| } | ||||
|  | ||||
| .wy-nav-content a.reference, .wy-nav-content a:not([class]) { | ||||
|   background-image: linear-gradient(var(--color-border) 0%, var(--color-border) 100%); | ||||
|   background-repeat: repeat-x; | ||||
|   background-position: 0 100%; | ||||
|   background-size: 1px 1px; | ||||
| } | ||||
|  | ||||
| .wy-nav-content a.reference:hover, .wy-nav-content a:not([class]):hover { | ||||
|   background-image: linear-gradient(rgba(114,83,237,0.45) 0%, rgba(114,83,237,0.45) 100%); | ||||
|   background-size: 1px 1px; | ||||
| } | ||||
|  | ||||
| .wy-menu-vertical a:hover, | ||||
| .wy-menu-vertical li.current a:hover, | ||||
| .wy-menu-vertical a:active { | ||||
|   background: var(--color-bg-side-nav-hover) !important; | ||||
|   color: var(--color-text-body); | ||||
| } | ||||
|  | ||||
| .wy-menu-vertical li.toctree-l1.current>a, | ||||
| .wy-menu-vertical li.current>a, | ||||
| .wy-menu-vertical li.on a { | ||||
|   background-color: var(--color-bg-side-nav-hover); | ||||
|   border: none; | ||||
|   font-weight: normal; | ||||
| } | ||||
|  | ||||
| .wy-menu-vertical li.current { | ||||
|   background-color: inherit; | ||||
| } | ||||
|  | ||||
| .wy-menu-vertical li.current a { | ||||
|   border-right: none; | ||||
| } | ||||
|  | ||||
| .wy-menu-vertical li.toctree-l2 a, | ||||
| .wy-menu-vertical li.toctree-l3 a, | ||||
| .wy-menu-vertical li.toctree-l4 a, | ||||
| .wy-menu-vertical li.toctree-l5 a, | ||||
| .wy-menu-vertical li.toctree-l6 a, | ||||
| .wy-menu-vertical li.toctree-l7 a, | ||||
| .wy-menu-vertical li.toctree-l8 a, | ||||
| .wy-menu-vertical li.toctree-l9 a, | ||||
| .wy-menu-vertical li.toctree-l10 a { | ||||
|   color: var(--color-text-body); | ||||
| } | ||||
|  | ||||
| a.image-reference, a.image-reference:hover { | ||||
|   background: none !important; | ||||
| } | ||||
|  | ||||
| a.image-reference img { | ||||
|   cursor: zoom-in; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Code blocks */ | ||||
| .rst-content code, .rst-content tt, code { | ||||
|   padding: 0.25em; | ||||
|   font-weight: 400; | ||||
|   background-color: var(--color-bg-code-block); | ||||
|   border: 1px solid var(--color-border); | ||||
|   border-radius: 4px; | ||||
| } | ||||
|  | ||||
| .rst-content div[class^=highlight], .rst-content pre.literal-block { | ||||
|   padding: 0.7rem; | ||||
|   margin-top: 0; | ||||
|   margin-bottom: 0.75rem; | ||||
|   overflow-x: auto; | ||||
|   background-color: var(--color-bg-side-nav); | ||||
|   border-color: var(--color-border); | ||||
|   border-radius: 4px; | ||||
|   box-shadow: none; | ||||
| } | ||||
|  | ||||
| .rst-content .admonition-title, | ||||
| .rst-content div.admonition, | ||||
| .wy-alert-title { | ||||
|   padding: 10px 12px; | ||||
|   border-top-left-radius: 4px; | ||||
|   border-top-right-radius: 4px; | ||||
| } | ||||
|  | ||||
| .highlight .go { | ||||
|   color: inherit; | ||||
| } | ||||
|  | ||||
| .highlight .nt { | ||||
|   color: var(--color-text-code-nt); | ||||
| } | ||||
|  | ||||
| .rst-content code.literal, | ||||
| .rst-content tt.literal, | ||||
| html.writer-html5 .rst-content dl.footnote code { | ||||
|   border-color: var(--color-border); | ||||
|   background-color: var(--color-border); | ||||
|   color: var(--color-text-code-inline) | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Search */ | ||||
| .wy-side-nav-search input[type=text] { | ||||
|   border: none; | ||||
|   border-radius: 0; | ||||
|   background-color: transparent; | ||||
|   font-family: inherit; | ||||
|   font-size: .85rem; | ||||
|   box-shadow: none; | ||||
|   padding: .7rem 1rem .7rem 2.8rem; | ||||
|   margin: 0; | ||||
| } | ||||
|  | ||||
| #rtd-search-form { | ||||
|   position: relative; | ||||
| } | ||||
|  | ||||
| #rtd-search-form:before { | ||||
|   font: normal normal normal 14px/1 FontAwesome; | ||||
|   font-size: inherit; | ||||
|   text-rendering: auto; | ||||
|   -webkit-font-smoothing: antialiased; | ||||
|   -moz-osx-font-smoothing: grayscale; | ||||
|   content: "\f002"; | ||||
|   color: var(--color-text-alt); | ||||
|   position: absolute; | ||||
|   left: 1.5rem; | ||||
|   top: .7rem; | ||||
| } | ||||
|  | ||||
| /* Side nav */ | ||||
| .wy-side-nav-search { | ||||
|   padding: 1rem 0 0 0; | ||||
| } | ||||
|  | ||||
| .wy-menu-vertical li a button.toctree-expand { | ||||
|   float: right; | ||||
|   margin-right: -1.5em; | ||||
|   padding: 0 .5em; | ||||
| } | ||||
|  | ||||
| .wy-menu-vertical a, | ||||
| .wy-menu-vertical li.current>a, | ||||
| .wy-menu-vertical li.current li>a { | ||||
|   padding-right: 1.5em !important; | ||||
| } | ||||
|  | ||||
| .wy-menu-vertical li.current li>a.current { | ||||
|   font-weight: 600; | ||||
| } | ||||
|  | ||||
| /* Misc spacing */ | ||||
| .rst-content .admonition-title, .wy-alert-title { | ||||
|   padding: 10px 12px; | ||||
| } | ||||
|  | ||||
| /* Buttons */ | ||||
| .btn { | ||||
|   display: inline-block; | ||||
|   box-sizing: border-box; | ||||
|   padding: 0.3em 1em; | ||||
|   margin: 0; | ||||
|   font-family: inherit; | ||||
|   font-size: inherit; | ||||
|   font-weight: 500; | ||||
|   line-height: 1.5; | ||||
|   color: #var(--color-text-anchor); | ||||
|   text-decoration: none; | ||||
|   vertical-align: baseline; | ||||
|   background-color: #f7f7f7; | ||||
|   border-width: 0; | ||||
|   border-radius: 4px; | ||||
|   box-shadow: 0 1px 2px rgba(0,0,0,0.12),0 3px 10px rgba(0,0,0,0.08); | ||||
|   appearance: none; | ||||
| } | ||||
|  | ||||
| .btn:active { | ||||
|   padding: 0.3em 1em; | ||||
| } | ||||
|  | ||||
| .rst-content .btn:focus { | ||||
|   outline: 1px solid #ccc; | ||||
| } | ||||
|  | ||||
| .rst-content .btn-neutral, .rst-content .btn span.fa { | ||||
|   color: var(--color-text-body) !important; | ||||
| } | ||||
|  | ||||
| .btn-neutral { | ||||
|   background-color: var(--color-btn-neutral-bg) !important; | ||||
|   color: var(--color-btn-neutral-text) !important; | ||||
|   border: 1px solid var(--color-btn-neutral-bg); | ||||
| } | ||||
|  | ||||
| .btn:hover, .btn-neutral:hover { | ||||
|   background-color: var(--color-btn-neutral-bg-hover) !important; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Icon overrides */ | ||||
| .wy-side-nav-search a.icon-home:before { | ||||
|   display: none; | ||||
| } | ||||
|  | ||||
| .fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before { | ||||
|   content: "\f106"; /* fa-angle-up */ | ||||
| } | ||||
|  | ||||
| .fa-plus-square-o:before, .wy-menu-vertical li button.toctree-expand:before { | ||||
|   content: "\f107"; /* fa-angle-down */ | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Misc */ | ||||
| .wy-nav-top { | ||||
|   line-height: 36px; | ||||
| } | ||||
|  | ||||
| .wy-nav-top > i { | ||||
|   font-size: 24px; | ||||
|   padding: 8px 0 0 2px; | ||||
|   color:#var(--color-text-anchor); | ||||
| } | ||||
|  | ||||
| .rst-content table.docutils td, | ||||
| .rst-content table.docutils th, | ||||
| .rst-content table.field-list td, | ||||
| .rst-content table.field-list th, | ||||
| .wy-table td, | ||||
| .wy-table th { | ||||
|   padding: 8px 14px; | ||||
| } | ||||
|  | ||||
| .dark-mode-toggle { | ||||
|   position: absolute; | ||||
|   top: 14px; | ||||
|   right: 12px; | ||||
|   height: 20px; | ||||
|   width: 24px; | ||||
|   z-index: 10; | ||||
|   border: none; | ||||
|   background-color: transparent; | ||||
|   color: inherit; | ||||
|   opacity: 0.7; | ||||
| } | ||||
|  | ||||
| .wy-nav-content-wrap { | ||||
|   z-index: 20; | ||||
| } | ||||
							
								
								
									
										47
									
								
								docs/_static/js/darkmode.js
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1,47 +0,0 @@ | ||||
| let toggleButton | ||||
| let icon | ||||
|  | ||||
| function load() { | ||||
| 	'use strict' | ||||
|  | ||||
| 	toggleButton = document.createElement('button') | ||||
| 	toggleButton.setAttribute('title', 'Toggle dark mode') | ||||
| 	toggleButton.classList.add('dark-mode-toggle') | ||||
| 	icon = document.createElement('i') | ||||
| 	icon.classList.add('fa', darkModeState ? 'fa-sun-o' : 'fa-moon-o') | ||||
| 	toggleButton.appendChild(icon) | ||||
| 	document.body.prepend(toggleButton) | ||||
|  | ||||
| 	// Listen for changes in the OS settings | ||||
| 	// addListener is used because older versions of Safari don't support addEventListener | ||||
| 	// prefersDarkQuery set in <head> | ||||
| 	if (prefersDarkQuery) { | ||||
| 		prefersDarkQuery.addListener(function (evt) { | ||||
| 			toggleDarkMode(evt.matches) | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	// Initial setting depending on the prefers-color-mode or localstorage | ||||
| 	// darkModeState should be set in the document <head> to prevent flash | ||||
| 	if (darkModeState == undefined) darkModeState = false | ||||
| 	toggleDarkMode(darkModeState) | ||||
|  | ||||
| 	// Toggles the "dark-mode" class on click and sets localStorage state | ||||
| 	toggleButton.addEventListener('click', () => { | ||||
| 		darkModeState = !darkModeState | ||||
|  | ||||
| 		toggleDarkMode(darkModeState) | ||||
| 		localStorage.setItem('dark-mode', darkModeState) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| function toggleDarkMode(state) { | ||||
| 	document.documentElement.classList.toggle('dark-mode', state) | ||||
| 	document.documentElement.classList.toggle('light-mode', !state) | ||||
| 	icon.classList.remove('fa-sun-o') | ||||
| 	icon.classList.remove('fa-moon-o') | ||||
| 	icon.classList.add(state ? 'fa-sun-o' : 'fa-moon-o') | ||||
| 	darkModeState = state | ||||
| } | ||||
|  | ||||
| document.addEventListener('DOMContentLoaded', load) | ||||
							
								
								
									
										
											BIN
										
									
								
								docs/_static/screenshots/mail-rules-edited.png
									
									
									
									
										vendored
									
									
								
							
							
						
						| Before Width: | Height: | Size: 96 KiB | 
							
								
								
									
										13
									
								
								docs/_templates/layout.html
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1,13 +0,0 @@ | ||||
| {% extends "!layout.html" %} | ||||
| {% block extrahead %} | ||||
|     <script> | ||||
|         // MediaQueryList object | ||||
|         const prefersDarkQuery = window.matchMedia("(prefers-color-scheme: dark)"); | ||||
|         const lsDark = localStorage.getItem("dark-mode"); | ||||
|         let darkModeState = lsDark !== null ? lsDark == "true" : prefersDarkQuery.matches; | ||||
|  | ||||
|         document.documentElement.classList.toggle("dark-mode", darkModeState); | ||||
|         document.documentElement.classList.toggle("light-mode", !darkModeState); | ||||
|     </script> | ||||
|     {{ super() }} | ||||
| {% endblock %} | ||||
							
								
								
									
										503
									
								
								docs/administration.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,503 @@ | ||||
| # Administration | ||||
|  | ||||
| ## Making backups {#backup} | ||||
|  | ||||
| Multiple options exist for making backups of your paperless instance, | ||||
| depending on how you installed paperless. | ||||
|  | ||||
| Before making backups, make sure that paperless is not running. | ||||
|  | ||||
| Options available to any installation of paperless: | ||||
|  | ||||
| - Use the [document exporter](/administration#exporter). The document exporter exports all your documents, | ||||
|   thumbnails and metadata to a specific folder. You may import your | ||||
|   documents into a fresh instance of paperless again or store your | ||||
|   documents in another DMS with this export. | ||||
| - The document exporter is also able to update an already existing | ||||
|   export. Therefore, incremental backups with `rsync` are entirely | ||||
|   possible. | ||||
|  | ||||
| !!! caution | ||||
|  | ||||
|     You cannot import the export generated with one version of paperless in | ||||
|     a different version of paperless. The export contains an exact image of | ||||
|     the database, and migrations may change the database layout. | ||||
|  | ||||
| Options available to docker installations: | ||||
|  | ||||
| - Backup the docker volumes. These usually reside within | ||||
|   `/var/lib/docker/volumes` on the host and you need to be root in | ||||
|   order to access them. | ||||
|  | ||||
|   Paperless uses 4 volumes: | ||||
|  | ||||
|   - `paperless_media`: This is where your documents are stored. | ||||
|   - `paperless_data`: This is where auxillary data is stored. This | ||||
|     folder also contains the SQLite database, if you use it. | ||||
|   - `paperless_pgdata`: Exists only if you use PostgreSQL and | ||||
|     contains the database. | ||||
|   - `paperless_dbdata`: Exists only if you use MariaDB and contains | ||||
|     the database. | ||||
|  | ||||
| Options available to bare-metal and non-docker installations: | ||||
|  | ||||
| - Backup the entire paperless folder. This ensures that if your | ||||
|   paperless instance crashes at some point or your disk fails, you can | ||||
|   simply copy the folder back into place and it works. | ||||
|  | ||||
|   When using PostgreSQL or MariaDB, you'll also have to backup the | ||||
|   database. | ||||
|  | ||||
| ### Restoring {#migrating-restoring} | ||||
|  | ||||
| ## Updating Paperless {#updating} | ||||
|  | ||||
| ### Docker Route | ||||
|  | ||||
| If a new release of paperless-ngx is available, upgrading depends on how | ||||
| you installed paperless-ngx in the first place. The releases are | ||||
| available at the [release | ||||
| page](https://github.com/paperless-ngx/paperless-ngx/releases). | ||||
|  | ||||
| First of all, ensure that paperless is stopped. | ||||
|  | ||||
| ```shell-session | ||||
| $ cd /path/to/paperless | ||||
| $ docker-compose down | ||||
| ``` | ||||
|  | ||||
| After that, [make a backup](#backup). | ||||
|  | ||||
| A. If you pull the image from the docker hub, all you need to do is: | ||||
|  | ||||
|     ``` shell-session | ||||
|     $ docker-compose pull | ||||
|     $ docker-compose up | ||||
|     ``` | ||||
|  | ||||
|     The docker-compose files refer to the `latest` version, which is | ||||
|     always the latest stable release. | ||||
|  | ||||
| B. If you built the image yourself, do the following: | ||||
|  | ||||
|     ``` shell-session | ||||
|     $ git pull | ||||
|     $ docker-compose build | ||||
|     $ docker-compose up | ||||
|     ``` | ||||
|  | ||||
| Running `docker-compose up` will also apply any new database migrations. | ||||
| If you see everything working, press CTRL+C once to gracefully stop | ||||
| paperless. Then you can start paperless-ngx with `-d` to have it run in | ||||
| the background. | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     In version 0.9.14, the update process was changed. In 0.9.13 and | ||||
|     earlier, the docker-compose files specified exact versions and pull | ||||
|     won't automatically update to newer versions. In order to enable | ||||
|     updates as described above, either get the new `docker-compose.yml` | ||||
|     file from | ||||
|     [here](https://github.com/paperless-ngx/paperless-ngx/tree/master/docker/compose) | ||||
|     or edit the `docker-compose.yml` file, find the line that says | ||||
|  | ||||
|     ``` | ||||
|     image: ghcr.io/paperless-ngx/paperless-ngx:0.9.x | ||||
|     ``` | ||||
|  | ||||
|     and replace the version with `latest`: | ||||
|  | ||||
|     ``` | ||||
|     image: ghcr.io/paperless-ngx/paperless-ngx:latest | ||||
|     ``` | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     In version 1.7.1 and onwards, the Docker image can now be pinned to a | ||||
|     release series. This is often combined with automatic updaters such as | ||||
|     Watchtower to allow safer unattended upgrading to new bugfix releases | ||||
|     only. It is still recommended to always review release notes before | ||||
|     upgrading. To pin your install to a release series, edit the | ||||
|     `docker-compose.yml` find the line that says | ||||
|  | ||||
|     ``` | ||||
|     image: ghcr.io/paperless-ngx/paperless-ngx:latest | ||||
|     ``` | ||||
|  | ||||
|     and replace the version with the series you want to track, for | ||||
|     example: | ||||
|  | ||||
|     ``` | ||||
|     image: ghcr.io/paperless-ngx/paperless-ngx:1.7 | ||||
|     ``` | ||||
|  | ||||
| ### Bare Metal Route | ||||
|  | ||||
| After grabbing the new release and unpacking the contents, do the | ||||
| following: | ||||
|  | ||||
| 1.  Update dependencies. New paperless version may require additional | ||||
|     dependencies. The dependencies required are listed in the section | ||||
|     about | ||||
|     [bare metal installations](/setup#bare_metal). | ||||
|  | ||||
| 2.  Update python requirements. Keep in mind to activate your virtual | ||||
|     environment before that, if you use one. | ||||
|  | ||||
|     ```shell-session | ||||
|     $ pip install -r requirements.txt | ||||
|     ``` | ||||
|  | ||||
| 3.  Migrate the database. | ||||
|  | ||||
|     ```shell-session | ||||
|     $ cd src | ||||
|     $ python3 manage.py migrate | ||||
|     ``` | ||||
|  | ||||
|     This might not actually do anything. Not every new paperless version | ||||
|     comes with new database migrations. | ||||
|  | ||||
| ## Downgrading Paperless | ||||
|  | ||||
| Downgrades are possible. However, some updates also contain database | ||||
| migrations (these change the layout of the database and may move data). | ||||
| In order to move back from a version that applied database migrations, | ||||
| you'll have to revert the database migration _before_ downgrading, and | ||||
| then downgrade paperless. | ||||
|  | ||||
| This table lists the compatible versions for each database migration | ||||
| number. | ||||
|  | ||||
| | Migration number | Version range   | | ||||
| | ---------------- | --------------- | | ||||
| | 1011             | 1.0.0           | | ||||
| | 1012             | 1.1.0 - 1.2.1   | | ||||
| | 1014             | 1.3.0 - 1.3.1   | | ||||
| | 1016             | 1.3.2 - current | | ||||
|  | ||||
| Execute the following management command to migrate your database: | ||||
|  | ||||
| ```shell-session | ||||
| $ python3 manage.py migrate documents <migration number> | ||||
| ``` | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     Some migrations cannot be undone. The command will issue errors if that | ||||
|     happens. | ||||
|  | ||||
| ## Management utilities {#management-commands} | ||||
|  | ||||
| Paperless comes with some management commands that perform various | ||||
| maintenance tasks on your paperless instance. You can invoke these | ||||
| commands in the following way: | ||||
|  | ||||
| With docker-compose, while paperless is running: | ||||
|  | ||||
| ```shell-session | ||||
| $ cd /path/to/paperless | ||||
| $ docker-compose exec webserver <command> <arguments> | ||||
| ``` | ||||
|  | ||||
| With docker, while paperless is running: | ||||
|  | ||||
| ```shell-session | ||||
| $ docker exec -it <container-name> <command> <arguments> | ||||
| ``` | ||||
|  | ||||
| Bare metal: | ||||
|  | ||||
| ```shell-session | ||||
| $ cd /path/to/paperless/src | ||||
| $ python3 manage.py <command> <arguments> | ||||
| ``` | ||||
|  | ||||
| All commands have built-in help, which can be accessed by executing them | ||||
| with the argument `--help`. | ||||
|  | ||||
| ### Document exporter {#exporter} | ||||
|  | ||||
| The document exporter exports all your data from paperless into a folder | ||||
| for backup or migration to another DMS. | ||||
|  | ||||
| If you use the document exporter within a cronjob to backup your data | ||||
| you might use the `-T` flag behind exec to suppress "The input device | ||||
| is not a TTY" errors. For example: | ||||
| `docker-compose exec -T webserver document_exporter ../export` | ||||
|  | ||||
| ``` | ||||
| document_exporter target [-c] [-f] [-d] | ||||
|  | ||||
| optional arguments: | ||||
| -c, --compare-checksums | ||||
| -f, --use-filename-format | ||||
| -d, --delete | ||||
| ``` | ||||
|  | ||||
| `target` is a folder to which the data gets written. This includes | ||||
| documents, thumbnails and a `manifest.json` file. The manifest contains | ||||
| all metadata from the database (correspondents, tags, etc). | ||||
|  | ||||
| When you use the provided docker compose script, specify `../export` as | ||||
| the target. This path inside the container is automatically mounted on | ||||
| your host on the folder `export`. | ||||
|  | ||||
| If the target directory already exists and contains files, paperless | ||||
| will assume that the contents of the export directory are a previous | ||||
| export and will attempt to update the previous export. Paperless will | ||||
| only export changed and added files. Paperless determines whether a file | ||||
| has changed by inspecting the file attributes "date/time modified" and | ||||
| "size". If that does not work out for you, specify | ||||
| `--compare-checksums` and paperless will attempt to compare file | ||||
| checksums instead. This is slower. | ||||
|  | ||||
| Paperless will not remove any existing files in the export directory. If | ||||
| you want paperless to also remove files that do not belong to the | ||||
| current export such as files from deleted documents, specify `--delete`. | ||||
| Be careful when pointing paperless to a directory that already contains | ||||
| other files. | ||||
|  | ||||
| The filenames generated by this command follow the format | ||||
| `[date created] [correspondent] [title].[extension]`. If you want | ||||
| paperless to use `PAPERLESS_FILENAME_FORMAT` for exported filenames | ||||
| instead, specify `--use-filename-format`. | ||||
|  | ||||
| ### Document importer {#importer} | ||||
|  | ||||
| The document importer takes the export produced by the [Document | ||||
| exporter](#document-exporter) and imports it into paperless. | ||||
|  | ||||
| The importer works just like the exporter. You point it at a directory, | ||||
| and the script does the rest of the work: | ||||
|  | ||||
| ``` | ||||
| document_importer source | ||||
| ``` | ||||
|  | ||||
| When you use the provided docker compose script, put the export inside | ||||
| the `export` folder in your paperless source directory. Specify | ||||
| `../export` as the `source`. | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     Importing from a previous version of Paperless may work, but for best | ||||
|     results it is suggested to match the versions. | ||||
|  | ||||
| ### Document retagger {#retagger} | ||||
|  | ||||
| Say you've imported a few hundred documents and now want to introduce a | ||||
| tag or set up a new correspondent, and apply its matching to all of the | ||||
| currently-imported docs. This problem is common enough that there are | ||||
| tools for it. | ||||
|  | ||||
| ``` | ||||
| document_retagger [-h] [-c] [-T] [-t] [-i] [--use-first] [-f] | ||||
|  | ||||
| optional arguments: | ||||
| -c, --correspondent | ||||
| -T, --tags | ||||
| -t, --document_type | ||||
| -s, --storage_path | ||||
| -i, --inbox-only | ||||
| --use-first | ||||
| -f, --overwrite | ||||
| ``` | ||||
|  | ||||
| Run this after changing or adding matching rules. It'll loop over all | ||||
| of the documents in your database and attempt to match documents | ||||
| according to the new rules. | ||||
|  | ||||
| Specify any combination of `-c`, `-T`, `-t` and `-s` to have the | ||||
| retagger perform matching of the specified metadata type. If you don't | ||||
| specify any of these options, the document retagger won't do anything. | ||||
|  | ||||
| Specify `-i` to have the document retagger work on documents tagged with | ||||
| inbox tags only. This is useful when you don't want to mess with your | ||||
| already processed documents. | ||||
|  | ||||
| When multiple document types or correspondents match a single document, | ||||
| the retagger won't assign these to the document. Specify `--use-first` | ||||
| to override this behavior and just use the first correspondent or type | ||||
| it finds. This option does not apply to tags, since any amount of tags | ||||
| can be applied to a document. | ||||
|  | ||||
| Finally, `-f` specifies that you wish to overwrite already assigned | ||||
| correspondents, types and/or tags. The default behavior is to not assign | ||||
| correspondents and types to documents that have this data already | ||||
| assigned. `-f` works differently for tags: By default, only additional | ||||
| tags get added to documents, no tags will be removed. With `-f`, tags | ||||
| that don't match a document anymore get removed as well. | ||||
|  | ||||
| ### Managing the Automatic matching algorithm | ||||
|  | ||||
| The _Auto_ matching algorithm requires a trained neural network to work. | ||||
| This network needs to be updated whenever somethings in your data | ||||
| changes. The docker image takes care of that automatically with the task | ||||
| scheduler. You can manually renew the classifier by invoking the | ||||
| following management command: | ||||
|  | ||||
| ``` | ||||
| document_create_classifier | ||||
| ``` | ||||
|  | ||||
| This command takes no arguments. | ||||
|  | ||||
| ### Managing the document search index {#index} | ||||
|  | ||||
| The document search index is responsible for delivering search results | ||||
| for the website. The document index is automatically updated whenever | ||||
| documents get added to, changed, or removed from paperless. However, if | ||||
| the search yields non-existing documents or won't find anything, you | ||||
| may need to recreate the index manually. | ||||
|  | ||||
| ``` | ||||
| document_index {reindex,optimize} | ||||
| ``` | ||||
|  | ||||
| Specify `reindex` to have the index created from scratch. This may take | ||||
| some time. | ||||
|  | ||||
| Specify `optimize` to optimize the index. This updates certain aspects | ||||
| of the index and usually makes queries faster and also ensures that the | ||||
| autocompletion works properly. This command is regularly invoked by the | ||||
| task scheduler. | ||||
|  | ||||
| ### Managing filenames {#renamer} | ||||
|  | ||||
| If you use paperless' feature to | ||||
| [assign custom filenames to your documents](/advanced_usage#file_name_handling), you can use this command to move all your files after | ||||
| changing the naming scheme. | ||||
|  | ||||
| !!! warning | ||||
|  | ||||
|     Since this command moves your documents, it is advised to do a backup | ||||
|     beforehand. The renaming logic is robust and will never overwrite or | ||||
|     delete a file, but you can't ever be careful enough. | ||||
|  | ||||
| ``` | ||||
| document_renamer | ||||
| ``` | ||||
|  | ||||
| The command takes no arguments and processes all your documents at once. | ||||
|  | ||||
| Learn how to use | ||||
| `Management Utilities<utilities-management-commands>`{.interpreted-text | ||||
| role="ref"}. | ||||
|  | ||||
| ### Sanity checker {#sanity-checker} | ||||
|  | ||||
| Paperless has a built-in sanity checker that inspects your document | ||||
| collection for issues. | ||||
|  | ||||
| The issues detected by the sanity checker are as follows: | ||||
|  | ||||
| - Missing original files. | ||||
| - Missing archive files. | ||||
| - Inaccessible original files due to improper permissions. | ||||
| - Inaccessible archive files due to improper permissions. | ||||
| - Corrupted original documents by comparing their checksum against | ||||
|   what is stored in the database. | ||||
| - Corrupted archive documents by comparing their checksum against what | ||||
|   is stored in the database. | ||||
| - Missing thumbnails. | ||||
| - Inaccessible thumbnails due to improper permissions. | ||||
| - Documents without any content (warning). | ||||
| - Orphaned files in the media directory (warning). These are files | ||||
|   that are not referenced by any document im paperless. | ||||
|  | ||||
| ``` | ||||
| document_sanity_checker | ||||
| ``` | ||||
|  | ||||
| The command takes no arguments. Depending on the size of your document | ||||
| archive, this may take some time. | ||||
|  | ||||
| ### Fetching e-mail | ||||
|  | ||||
| Paperless automatically fetches your e-mail every 10 minutes by default. | ||||
| If you want to invoke the email consumer manually, call the following | ||||
| management command: | ||||
|  | ||||
| ``` | ||||
| mail_fetcher | ||||
| ``` | ||||
|  | ||||
| The command takes no arguments and processes all your mail accounts and | ||||
| rules. | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     As of October 2022 Microsoft no longer supports IMAP authentication | ||||
|     for Exchange servers, thus Exchange is no longer supported until a | ||||
|     solution is implemented in the Python IMAP library used by Paperless. | ||||
|     See | ||||
|  | ||||
| [learn.microsoft.com](https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/deprecation-of-basic-authentication-exchange-online) | ||||
|  | ||||
| ### Creating archived documents {#archiver} | ||||
|  | ||||
| Paperless stores archived PDF/A documents alongside your original | ||||
| documents. These archived documents will also contain selectable text | ||||
| for image-only originals. These documents are derived from the | ||||
| originals, which are always stored unmodified. If coming from an earlier | ||||
| version of paperless, your documents won't have archived versions. | ||||
|  | ||||
| This command creates PDF/A documents for your documents. | ||||
|  | ||||
| ``` | ||||
| document_archiver --overwrite --document <id> | ||||
| ``` | ||||
|  | ||||
| This command will only attempt to create archived documents when no | ||||
| archived document exists yet, unless `--overwrite` is specified. If | ||||
| `--document <id>` is specified, the archiver will only process that | ||||
| document. | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     This command essentially performs OCR on all your documents again, | ||||
|     according to your settings. If you run this with | ||||
|     `PAPERLESS_OCR_MODE=redo`, it will potentially run for a very long time. | ||||
|     You can cancel the command at any time, since this command will skip | ||||
|     already archived versions the next time it is run. | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     Some documents will cause errors and cannot be converted into PDF/A | ||||
|     documents, such as encrypted PDF documents. The archiver will skip over | ||||
|     these documents each time it sees them. | ||||
|  | ||||
| ### Managing encryption {#encyption} | ||||
|  | ||||
| Documents can be stored in Paperless using GnuPG encryption. | ||||
|  | ||||
| !!! warning | ||||
|  | ||||
|     Encryption is deprecated since paperless-ngx 0.9 and doesn't really | ||||
|     provide any additional security, since you have to store the passphrase | ||||
|     in a configuration file on the same system as the encrypted documents | ||||
|     for paperless to work. Furthermore, the entire text content of the | ||||
|     documents is stored plain in the database, even if your documents are | ||||
|     encrypted. Filenames are not encrypted as well. | ||||
|  | ||||
|     Also, the web server provides transparent access to your encrypted | ||||
|     documents. | ||||
|  | ||||
|     Consider running paperless on an encrypted filesystem instead, which | ||||
|     will then at least provide security against physical hardware theft. | ||||
|  | ||||
| #### Enabling encryption | ||||
|  | ||||
| Enabling encryption is no longer supported. | ||||
|  | ||||
| #### Disabling encryption | ||||
|  | ||||
| Basic usage to disable encryption of your document store: | ||||
|  | ||||
| (Note: If `PAPERLESS_PASSPHRASE` isn't set already, you need to specify | ||||
| it here) | ||||
|  | ||||
| ``` | ||||
| decrypt_documents [--passphrase SECR3TP4SSPHRA$E] | ||||
| ``` | ||||
| @@ -1,531 +0,0 @@ | ||||
|  | ||||
| ************** | ||||
| Administration | ||||
| ************** | ||||
|  | ||||
| .. _administration-backup: | ||||
|  | ||||
| Making backups | ||||
| ############## | ||||
|  | ||||
| Multiple options exist for making backups of your paperless instance, | ||||
| depending on how you installed paperless. | ||||
|  | ||||
| Before making backups, make sure that paperless is not running. | ||||
|  | ||||
| Options available to any installation of paperless: | ||||
|  | ||||
| *   Use the :ref:`document exporter <utilities-exporter>`. | ||||
|     The document exporter exports all your documents, thumbnails and | ||||
|     metadata to a specific folder. You may import your documents into a | ||||
|     fresh instance of paperless again or store your documents in another | ||||
|     DMS with this export. | ||||
| *   The document exporter is also able to update an already existing export. | ||||
|     Therefore, incremental backups with ``rsync`` are entirely possible. | ||||
|  | ||||
| .. caution:: | ||||
|  | ||||
|     You cannot import the export generated with one version of paperless in a | ||||
|     different version of paperless. The export contains an exact image of the | ||||
|     database, and migrations may change the database layout. | ||||
|  | ||||
| Options available to docker installations: | ||||
|  | ||||
| *   Backup the docker volumes. These usually reside within | ||||
|     ``/var/lib/docker/volumes`` on the host and you need to be root in order | ||||
|     to access them. | ||||
|  | ||||
|     Paperless uses 4 volumes: | ||||
|  | ||||
|     *   ``paperless_media``: This is where your documents are stored. | ||||
|     *   ``paperless_data``: This is where auxillary data is stored. This | ||||
|         folder also contains the SQLite database, if you use it. | ||||
|     *   ``paperless_pgdata``: Exists only if you use PostgreSQL and contains | ||||
|         the database. | ||||
|     *   ``paperless_dbdata``: Exists only if you use MariaDB and contains | ||||
|         the database. | ||||
|  | ||||
| Options available to bare-metal and non-docker installations: | ||||
|  | ||||
| *   Backup the entire paperless folder. This ensures that if your paperless instance | ||||
|     crashes at some point or your disk fails, you can simply copy the folder back | ||||
|     into place and it works. | ||||
|  | ||||
|     When using PostgreSQL or MariaDB, you'll also have to backup the database. | ||||
|  | ||||
| .. _migrating-restoring: | ||||
|  | ||||
| Restoring | ||||
| ========= | ||||
|  | ||||
| .. _administration-updating: | ||||
|  | ||||
| Updating Paperless | ||||
| ################## | ||||
|  | ||||
| Docker Route | ||||
| ============ | ||||
|  | ||||
| If a new release of paperless-ngx is available, upgrading depends on how you | ||||
| installed paperless-ngx in the first place. The releases are available at the | ||||
| `release page <https://github.com/paperless-ngx/paperless-ngx/releases>`_. | ||||
|  | ||||
| First of all, ensure that paperless is stopped. | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     $ cd /path/to/paperless | ||||
|     $ docker-compose down | ||||
|  | ||||
| After that, :ref:`make a backup <administration-backup>`. | ||||
|  | ||||
| A.  If you pull the image from the docker hub, all you need to do is: | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ docker-compose pull | ||||
|         $ docker-compose up | ||||
|  | ||||
|     The docker-compose files refer to the ``latest`` version, which is always the latest | ||||
|     stable release. | ||||
|  | ||||
| B.  If you built the image yourself, do the following: | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ git pull | ||||
|         $ docker-compose build | ||||
|         $ docker-compose up | ||||
|  | ||||
| Running ``docker-compose up`` will also apply any new database migrations. | ||||
| If you see everything working, press CTRL+C once to gracefully stop paperless. | ||||
| Then you can start paperless-ngx with ``-d`` to have it run in the background. | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         In version 0.9.14, the update process was changed. In 0.9.13 and earlier, the | ||||
|         docker-compose files specified exact versions and pull won't automatically | ||||
|         update to newer versions. In order to enable updates as described above, either | ||||
|         get the new ``docker-compose.yml`` file from `here <https://github.com/paperless-ngx/paperless-ngx/tree/master/docker/compose>`_ | ||||
|         or edit the ``docker-compose.yml`` file, find the line that says | ||||
|  | ||||
|             .. code:: | ||||
|  | ||||
|                 image: ghcr.io/paperless-ngx/paperless-ngx:0.9.x | ||||
|  | ||||
|         and replace the version with ``latest``: | ||||
|  | ||||
|             .. code:: | ||||
|  | ||||
|                 image: ghcr.io/paperless-ngx/paperless-ngx:latest | ||||
|  | ||||
|     .. note:: | ||||
|         In version 1.7.1 and onwards, the Docker image can now be pinned to a release series. | ||||
|         This is often combined with automatic updaters such as Watchtower to allow safer | ||||
|         unattended upgrading to new bugfix releases only.  It is still recommended to always | ||||
|         review release notes before upgrading.  To pin your install to a release series, edit | ||||
|         the ``docker-compose.yml`` find the line that says | ||||
|  | ||||
|             .. code:: | ||||
|  | ||||
|                 image: ghcr.io/paperless-ngx/paperless-ngx:latest | ||||
|  | ||||
|         and replace the version with the series you want to track, for example: | ||||
|  | ||||
|             .. code:: | ||||
|  | ||||
|                 image: ghcr.io/paperless-ngx/paperless-ngx:1.7 | ||||
|  | ||||
| Bare Metal Route | ||||
| ================ | ||||
|  | ||||
| After grabbing the new release and unpacking the contents, do the following: | ||||
|  | ||||
| 1.  Update dependencies. New paperless version may require additional | ||||
|     dependencies. The dependencies required are listed in the section about | ||||
|     :ref:`bare metal installations <setup-bare_metal>`. | ||||
|  | ||||
| 2.  Update python requirements. Keep in mind to activate your virtual environment | ||||
|     before that, if you use one. | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ pip install -r requirements.txt | ||||
|  | ||||
| 3.  Migrate the database. | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ cd src | ||||
|         $ python3 manage.py migrate | ||||
|  | ||||
|     This might not actually do anything. Not every new paperless version comes with new | ||||
|     database migrations. | ||||
|  | ||||
| Downgrading Paperless | ||||
| ##################### | ||||
|  | ||||
| Downgrades are possible. However, some updates also contain database migrations (these change the layout of the database and may move data). | ||||
| In order to move back from a version that applied database migrations, you'll have to revert the database migration *before* downgrading, | ||||
| and then downgrade paperless. | ||||
|  | ||||
| This table lists the compatible versions for each database migration number. | ||||
|  | ||||
| +------------------+-----------------+ | ||||
| | Migration number | Version range   | | ||||
| +------------------+-----------------+ | ||||
| | 1011             | 1.0.0           | | ||||
| +------------------+-----------------+ | ||||
| | 1012             | 1.1.0 - 1.2.1   | | ||||
| +------------------+-----------------+ | ||||
| | 1014             | 1.3.0 - 1.3.1   | | ||||
| +------------------+-----------------+ | ||||
| | 1016             | 1.3.2 - current | | ||||
| +------------------+-----------------+ | ||||
|  | ||||
| Execute the following management command to migrate your database: | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     $ python3 manage.py migrate documents <migration number> | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     Some migrations cannot be undone. The command will issue errors if that happens. | ||||
|  | ||||
| .. _utilities-management-commands: | ||||
|  | ||||
| Management utilities | ||||
| #################### | ||||
|  | ||||
| Paperless comes with some management commands that perform various maintenance | ||||
| tasks on your paperless instance. You can invoke these commands in the following way: | ||||
|  | ||||
| With docker-compose, while paperless is running: | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     $ cd /path/to/paperless | ||||
|     $ docker-compose exec webserver <command> <arguments> | ||||
|  | ||||
| With docker, while paperless is running: | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     $ docker exec -it <container-name> <command> <arguments> | ||||
|  | ||||
| Bare metal: | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     $ cd /path/to/paperless/src | ||||
|     $ python3 manage.py <command> <arguments> | ||||
|  | ||||
| All commands have built-in help, which can be accessed by executing them with | ||||
| the argument ``--help``. | ||||
|  | ||||
| .. _utilities-exporter: | ||||
|  | ||||
| Document exporter | ||||
| ================= | ||||
|  | ||||
| The document exporter exports all your data from paperless into a folder for | ||||
| backup or migration to another DMS. | ||||
|  | ||||
| If you use the document exporter within a cronjob to backup your data you might use the ``-T`` flag behind exec to suppress "The input device is not a TTY" errors. For example: ``docker-compose exec -T webserver document_exporter ../export`` | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     document_exporter target [-c] [-f] [-d] | ||||
|  | ||||
|     optional arguments: | ||||
|     -c, --compare-checksums | ||||
|     -f, --use-filename-format | ||||
|     -d, --delete | ||||
|  | ||||
| ``target`` is a folder to which the data gets written. This includes documents, | ||||
| thumbnails and a ``manifest.json`` file. The manifest contains all metadata from | ||||
| the database (correspondents, tags, etc). | ||||
|  | ||||
| When you use the provided docker compose script, specify ``../export`` as the | ||||
| target. This path inside the container is automatically mounted on your host on | ||||
| the folder ``export``. | ||||
|  | ||||
| If the target directory already exists and contains files, paperless will assume | ||||
| that the contents of the export directory are a previous export and will attempt | ||||
| to update the previous export. Paperless will only export changed and added files. | ||||
| Paperless determines whether a file has changed by inspecting the file attributes | ||||
| "date/time modified" and "size". If that does not work out for you, specify | ||||
| ``--compare-checksums`` and paperless will attempt to compare file checksums instead. | ||||
| This is slower. | ||||
|  | ||||
| Paperless will not remove any existing files in the export directory. If you want | ||||
| paperless to also remove files that do not belong to the current export such as files | ||||
| from deleted documents, specify ``--delete``. Be careful when pointing paperless to | ||||
| a directory that already contains other files. | ||||
|  | ||||
| The filenames generated by this command follow the format | ||||
| ``[date created] [correspondent] [title].[extension]``. | ||||
| If you want paperless to use ``PAPERLESS_FILENAME_FORMAT`` for exported filenames | ||||
| instead, specify ``--use-filename-format``. | ||||
|  | ||||
|  | ||||
| .. _utilities-importer: | ||||
|  | ||||
| Document importer | ||||
| ================= | ||||
|  | ||||
| The document importer takes the export produced by the `Document exporter`_ and | ||||
| imports it into paperless. | ||||
|  | ||||
| The importer works just like the exporter.  You point it at a directory, and | ||||
| the script does the rest of the work: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     document_importer source | ||||
|  | ||||
| When you use the provided docker compose script, put the export inside the | ||||
| ``export`` folder in your paperless source directory. Specify ``../export`` | ||||
| as the ``source``. | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     Importing from a previous version of Paperless may work, but for best results | ||||
|     it is suggested to match the versions. | ||||
|  | ||||
| .. _utilities-retagger: | ||||
|  | ||||
| Document retagger | ||||
| ================= | ||||
|  | ||||
| Say you've imported a few hundred documents and now want to introduce | ||||
| a tag or set up a new correspondent, and apply its matching to all of | ||||
| the currently-imported docs. This problem is common enough that | ||||
| there are tools for it. | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     document_retagger [-h] [-c] [-T] [-t] [-i] [--use-first] [-f] | ||||
|  | ||||
|     optional arguments: | ||||
|     -c, --correspondent | ||||
|     -T, --tags | ||||
|     -t, --document_type | ||||
|     -s, --storage_path | ||||
|     -i, --inbox-only | ||||
|     --use-first | ||||
|     -f, --overwrite | ||||
|  | ||||
| Run this after changing or adding matching rules. It'll loop over all | ||||
| of the documents in your database and attempt to match documents | ||||
| according to the new rules. | ||||
|  | ||||
| Specify any combination of ``-c``, ``-T``, ``-t`` and ``-s`` to have the | ||||
| retagger perform matching of the specified metadata type. If you don't | ||||
| specify any of these options, the document retagger won't do anything. | ||||
|  | ||||
| Specify ``-i`` to have the document retagger work on documents tagged | ||||
| with inbox tags only. This is useful when you don't want to mess with | ||||
| your already processed documents. | ||||
|  | ||||
| When multiple document types or correspondents match a single document, | ||||
| the retagger won't assign these to the document. Specify ``--use-first`` | ||||
| to override this behavior and just use the first correspondent or type | ||||
| it finds. This option does not apply to tags, since any amount of tags | ||||
| can be applied to a document. | ||||
|  | ||||
| Finally, ``-f`` specifies that you wish to overwrite already assigned | ||||
| correspondents, types and/or tags. The default behavior is to not | ||||
| assign correspondents and types to documents that have this data already | ||||
| assigned. ``-f`` works differently for tags: By default, only additional tags get | ||||
| added to documents, no tags will be removed. With ``-f``, tags that don't | ||||
| match a document anymore get removed as well. | ||||
|  | ||||
|  | ||||
| Managing the Automatic matching algorithm | ||||
| ========================================= | ||||
|  | ||||
| The *Auto* matching algorithm requires a trained neural network to work. | ||||
| This network needs to be updated whenever somethings in your data | ||||
| changes. The docker image takes care of that automatically with the task | ||||
| scheduler. You can manually renew the classifier by invoking the following | ||||
| management command: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     document_create_classifier | ||||
|  | ||||
| This command takes no arguments. | ||||
|  | ||||
| .. _`administration-index`: | ||||
|  | ||||
| Managing the document search index | ||||
| ================================== | ||||
|  | ||||
| The document search index is responsible for delivering search results for the | ||||
| website. The document index is automatically updated whenever documents get | ||||
| added to, changed, or removed from paperless. However, if the search yields | ||||
| non-existing documents or won't find anything, you may need to recreate the | ||||
| index manually. | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     document_index {reindex,optimize} | ||||
|  | ||||
| Specify ``reindex`` to have the index created from scratch. This may take some | ||||
| time. | ||||
|  | ||||
| Specify ``optimize`` to optimize the index. This updates certain aspects of | ||||
| the index and usually makes queries faster and also ensures that the | ||||
| autocompletion works properly. This command is regularly invoked by the task | ||||
| scheduler. | ||||
|  | ||||
| .. _utilities-renamer: | ||||
|  | ||||
| Managing filenames | ||||
| ================== | ||||
|  | ||||
| If you use paperless' feature to | ||||
| :ref:`assign custom filenames to your documents <advanced-file_name_handling>`, | ||||
| you can use this command to move all your files after changing | ||||
| the naming scheme. | ||||
|  | ||||
| .. warning:: | ||||
|  | ||||
|     Since this command moves your documents, it is advised to do | ||||
|     a backup beforehand. The renaming logic is robust and will never overwrite | ||||
|     or delete a file, but you can't ever be careful enough. | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     document_renamer | ||||
|  | ||||
| The command takes no arguments and processes all your documents at once. | ||||
|  | ||||
| Learn how to use :ref:`Management Utilities<utilities-management-commands>`. | ||||
|  | ||||
|  | ||||
| .. _utilities-sanity-checker: | ||||
|  | ||||
| Sanity checker | ||||
| ============== | ||||
|  | ||||
| Paperless has a built-in sanity checker that inspects your document collection for issues. | ||||
|  | ||||
| The issues detected by the sanity checker are as follows: | ||||
|  | ||||
| * Missing original files. | ||||
| * Missing archive files. | ||||
| * Inaccessible original files due to improper permissions. | ||||
| * Inaccessible archive files due to improper permissions. | ||||
| * Corrupted original documents by comparing their checksum against what is stored in the database. | ||||
| * Corrupted archive documents by comparing their checksum against what is stored in the database. | ||||
| * Missing thumbnails. | ||||
| * Inaccessible thumbnails due to improper permissions. | ||||
| * Documents without any content (warning). | ||||
| * Orphaned files in the media directory (warning). These are files that are not referenced by any document im paperless. | ||||
|  | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     document_sanity_checker | ||||
|  | ||||
| The command takes no arguments. Depending on the size of your document archive, this may take some time. | ||||
|  | ||||
|  | ||||
| Fetching e-mail | ||||
| =============== | ||||
|  | ||||
| Paperless automatically fetches your e-mail every 10 minutes by default. If | ||||
| you want to invoke the email consumer manually, call the following management | ||||
| command: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     mail_fetcher | ||||
|  | ||||
| The command takes no arguments and processes all your mail accounts and rules. | ||||
|  | ||||
|  .. note:: | ||||
|  | ||||
|     As of October 2022 Microsoft no longer supports IMAP authentication for Exchange | ||||
|     servers, thus Exchange is no longer supported until a solution is implemented in | ||||
|     the Python IMAP library used by Paperless. See  `learn.microsoft.com`_ | ||||
|  | ||||
| .. _learn.microsoft.com: https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/deprecation-of-basic-authentication-exchange-online | ||||
|  | ||||
| .. _utilities-archiver: | ||||
|  | ||||
| Creating archived documents | ||||
| =========================== | ||||
|  | ||||
| Paperless stores archived PDF/A documents alongside your original documents. | ||||
| These archived documents will also contain selectable text for image-only | ||||
| originals. | ||||
| These documents are derived from the originals, which are always stored | ||||
| unmodified. If coming from an earlier version of paperless, your documents | ||||
| won't have archived versions. | ||||
|  | ||||
| This command creates PDF/A documents for your documents. | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     document_archiver --overwrite --document <id> | ||||
|  | ||||
| This command will only attempt to create archived documents when no archived | ||||
| document exists yet, unless ``--overwrite`` is specified. If ``--document <id>`` | ||||
| is specified, the archiver will only process that document. | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     This command essentially performs OCR on all your documents again, | ||||
|     according to your settings. If you run this with ``PAPERLESS_OCR_MODE=redo``, | ||||
|     it will potentially run for a very long time. You can cancel the command | ||||
|     at any time, since this command will skip already archived versions the next time | ||||
|     it is run. | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     Some documents will cause errors and cannot be converted into PDF/A documents, | ||||
|     such as encrypted PDF documents. The archiver will skip over these documents | ||||
|     each time it sees them. | ||||
|  | ||||
| .. _utilities-encyption: | ||||
|  | ||||
| Managing encryption | ||||
| =================== | ||||
|  | ||||
| Documents can be stored in Paperless using GnuPG encryption. | ||||
|  | ||||
| .. danger:: | ||||
|  | ||||
|     Encryption is deprecated since paperless-ngx 0.9 and doesn't really provide any | ||||
|     additional security, since you have to store the passphrase in a configuration | ||||
|     file on the same system as the encrypted documents for paperless to work. | ||||
|     Furthermore, the entire text content of the documents is stored plain in the | ||||
|     database, even if your documents are encrypted. Filenames are not encrypted as | ||||
|     well. | ||||
|  | ||||
|     Also, the web server provides transparent access to your encrypted documents. | ||||
|  | ||||
|     Consider running paperless on an encrypted filesystem instead, which will then | ||||
|     at least provide security against physical hardware theft. | ||||
|  | ||||
|  | ||||
| Enabling encryption | ||||
| ------------------- | ||||
|  | ||||
| Enabling encryption is no longer supported. | ||||
|  | ||||
|  | ||||
| Disabling encryption | ||||
| -------------------- | ||||
|  | ||||
| Basic usage to disable encryption of your document store: | ||||
|  | ||||
| (Note: If ``PAPERLESS_PASSPHRASE`` isn't set already, you need to specify it here) | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     decrypt_documents [--passphrase SECR3TP4SSPHRA$E] | ||||
							
								
								
									
										464
									
								
								docs/advanced_usage.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,464 @@ | ||||
| # Advanced Topics | ||||
|  | ||||
| Paperless offers a couple features that automate certain tasks and make | ||||
| your life easier. | ||||
|  | ||||
| ## Matching tags, correspondents, document types, and storage paths {#matching} | ||||
|  | ||||
| Paperless will compare the matching algorithms defined by every tag, | ||||
| correspondent, document type, and storage path in your database to see | ||||
| if they apply to the text in a document. In other words, if you define a | ||||
| tag called `Home Utility` that had a `match` property of `bc hydro` and | ||||
| a `matching_algorithm` of `literal`, Paperless will automatically tag | ||||
| your newly-consumed document with your `Home Utility` tag so long as the | ||||
| text `bc hydro` appears in the body of the document somewhere. | ||||
|  | ||||
| The matching logic is quite powerful. It supports searching the text of | ||||
| your document with different algorithms, and as such, some | ||||
| experimentation may be necessary to get things right. | ||||
|  | ||||
| In order to have a tag, correspondent, document type, or storage path | ||||
| assigned automatically to newly consumed documents, assign a match and | ||||
| matching algorithm using the web interface. These settings define when | ||||
| to assign tags, correspondents, document types, and storage paths to | ||||
| documents. | ||||
|  | ||||
| The following algorithms are available: | ||||
|  | ||||
| - **Any:** Looks for any occurrence of any word provided in match in | ||||
|   the PDF. If you define the match as `Bank1 Bank2`, it will match | ||||
|   documents containing either of these terms. | ||||
| - **All:** Requires that every word provided appears in the PDF, | ||||
|   albeit not in the order provided. | ||||
| - **Literal:** Matches only if the match appears exactly as provided | ||||
|   (i.e. preserve ordering) in the PDF. | ||||
| - **Regular expression:** Parses the match as a regular expression and | ||||
|   tries to find a match within the document. | ||||
| - **Fuzzy match:** I don't know. Look at the source. | ||||
| - **Auto:** Tries to automatically match new documents. This does not | ||||
|   require you to set a match. See the notes below. | ||||
|  | ||||
| When using the _any_ or _all_ matching algorithms, you can search for | ||||
| terms that consist of multiple words by enclosing them in double quotes. | ||||
| For example, defining a match text of `"Bank of America" BofA` using the | ||||
| _any_ algorithm, will match documents that contain either "Bank of | ||||
| America" or "BofA", but will not match documents containing "Bank of | ||||
| South America". | ||||
|  | ||||
| Then just save your tag, correspondent, document type, or storage path | ||||
| and run another document through the consumer. Once complete, you should | ||||
| see the newly-created document, automatically tagged with the | ||||
| appropriate data. | ||||
|  | ||||
| ### Automatic matching {#automatic_matching} | ||||
|  | ||||
| Paperless-ngx comes with a new matching algorithm called _Auto_. This | ||||
| matching algorithm tries to assign tags, correspondents, document types, | ||||
| and storage paths to your documents based on how you have already | ||||
| assigned these on existing documents. It uses a neural network under the | ||||
| hood. | ||||
|  | ||||
| If, for example, all your bank statements of your account 123 at the | ||||
| Bank of America are tagged with the tag "bofa*123" and the matching | ||||
| algorithm of this tag is set to \_Auto*, this neural network will examine | ||||
| your documents and automatically learn when to assign this tag. | ||||
|  | ||||
| Paperless tries to hide much of the involved complexity with this | ||||
| approach. However, there are a couple caveats you need to keep in mind | ||||
| when using this feature: | ||||
|  | ||||
| - Changes to your documents are not immediately reflected by the | ||||
|   matching algorithm. The neural network needs to be _trained_ on your | ||||
|   documents after changes. Paperless periodically (default: once each | ||||
|   hour) checks for changes and does this automatically for you. | ||||
| - The Auto matching algorithm only takes documents into account which | ||||
|   are NOT placed in your inbox (i.e. have any inbox tags assigned to | ||||
|   them). This ensures that the neural network only learns from | ||||
|   documents which you have correctly tagged before. | ||||
| - The matching algorithm can only work if there is a correlation | ||||
|   between the tag, correspondent, document type, or storage path and | ||||
|   the document itself. Your bank statements usually contain your bank | ||||
|   account number and the name of the bank, so this works reasonably | ||||
|   well, However, tags such as "TODO" cannot be automatically | ||||
|   assigned. | ||||
| - The matching algorithm needs a reasonable number of documents to | ||||
|   identify when to assign tags, correspondents, storage paths, and | ||||
|   types. If one out of a thousand documents has the correspondent | ||||
|   "Very obscure web shop I bought something five years ago", it will | ||||
|   probably not assign this correspondent automatically if you buy | ||||
|   something from them again. The more documents, the better. | ||||
| - Paperless also needs a reasonable amount of negative examples to | ||||
|   decide when not to assign a certain tag, correspondent, document | ||||
|   type, or storage path. This will usually be the case as you start | ||||
|   filling up paperless with documents. Example: If all your documents | ||||
|   are either from "Webshop" and "Bank", paperless will assign one | ||||
|   of these correspondents to ANY new document, if both are set to | ||||
|   automatic matching. | ||||
|  | ||||
| ## Hooking into the consumption process | ||||
|  | ||||
| Sometimes you may want to do something arbitrary whenever a document is | ||||
| consumed. Rather than try to predict what you may want to do, Paperless | ||||
| lets you execute scripts of your own choosing just before or after a | ||||
| document is consumed using a couple simple hooks. | ||||
|  | ||||
| Just write a script, put it somewhere that Paperless can read & execute, | ||||
| and then put the path to that script in `paperless.conf` or | ||||
| `docker-compose.env` with the variable name of either | ||||
| `PAPERLESS_PRE_CONSUME_SCRIPT` or `PAPERLESS_POST_CONSUME_SCRIPT`. | ||||
|  | ||||
| !!! info | ||||
|  | ||||
|     These scripts are executed in a **blocking** process, which means that | ||||
|     if a script takes a long time to run, it can significantly slow down | ||||
|     your document consumption flow. If you want things to run | ||||
|     asynchronously, you'll have to fork the process in your script and | ||||
|     exit. | ||||
|  | ||||
| ### Pre-consumption script | ||||
|  | ||||
| Executed after the consumer sees a new document in the consumption | ||||
| folder, but before any processing of the document is performed. This | ||||
| script can access the following relevant environment variables set: | ||||
|  | ||||
| - `DOCUMENT_SOURCE_PATH` | ||||
|  | ||||
| A simple but common example for this would be creating a simple script | ||||
| like this: | ||||
|  | ||||
| `/usr/local/bin/ocr-pdf` | ||||
|  | ||||
| ```bash | ||||
| #!/usr/bin/env bash | ||||
| pdf2pdfocr.py -i ${DOCUMENT_SOURCE_PATH} | ||||
| ``` | ||||
|  | ||||
| `/etc/paperless.conf` | ||||
|  | ||||
| ```bash | ||||
| ... | ||||
| PAPERLESS_PRE_CONSUME_SCRIPT="/usr/local/bin/ocr-pdf" | ||||
| ... | ||||
| ``` | ||||
|  | ||||
| This will pass the path to the document about to be consumed to | ||||
| `/usr/local/bin/ocr-pdf`, which will in turn call | ||||
| [pdf2pdfocr.py](https://github.com/LeoFCardoso/pdf2pdfocr) on your | ||||
| document, which will then overwrite the file with an OCR'd version of | ||||
| the file and exit. At which point, the consumption process will begin | ||||
| with the newly modified file. | ||||
|  | ||||
| The script's stdout and stderr will be logged line by line to the | ||||
| webserver log, along with the exit code of the script. | ||||
|  | ||||
| ### Post-consumption script {#post_consume_script} | ||||
|  | ||||
| Executed after the consumer has successfully processed a document and | ||||
| has moved it into paperless. It receives the following environment | ||||
| variables: | ||||
|  | ||||
| - `DOCUMENT_ID` | ||||
| - `DOCUMENT_FILE_NAME` | ||||
| - `DOCUMENT_CREATED` | ||||
| - `DOCUMENT_MODIFIED` | ||||
| - `DOCUMENT_ADDED` | ||||
| - `DOCUMENT_SOURCE_PATH` | ||||
| - `DOCUMENT_ARCHIVE_PATH` | ||||
| - `DOCUMENT_THUMBNAIL_PATH` | ||||
| - `DOCUMENT_DOWNLOAD_URL` | ||||
| - `DOCUMENT_THUMBNAIL_URL` | ||||
| - `DOCUMENT_CORRESPONDENT` | ||||
| - `DOCUMENT_TAGS` | ||||
| - `DOCUMENT_ORIGINAL_FILENAME` | ||||
|  | ||||
| The script can be in any language, but for a simple shell script | ||||
| example, you can take a look at | ||||
| [post-consumption-example.sh](https://github.com/paperless-ngx/paperless-ngx/blob/main/scripts/post-consumption-example.sh) | ||||
| in this project. | ||||
|  | ||||
| The post consumption script cannot cancel the consumption process. | ||||
|  | ||||
| The script's stdout and stderr will be logged line by line to the | ||||
| webserver log, along with the exit code of the script. | ||||
|  | ||||
| #### Docker | ||||
|  | ||||
| Assumed you have | ||||
| `/home/foo/paperless-ngx/scripts/post-consumption-example.sh`. | ||||
|  | ||||
| You can pass that script into the consumer container via a host mount in | ||||
| your `docker-compose.yml`. | ||||
|  | ||||
| ```bash | ||||
| ... | ||||
| consumer: | ||||
|   ... | ||||
|   volumes: | ||||
|     ... | ||||
|     - /home/paperless-ngx/scripts:/path/in/container/scripts/ | ||||
| ... | ||||
| ``` | ||||
|  | ||||
| Example (docker-compose.yml): | ||||
| `- /home/foo/paperless-ngx/scripts:/usr/src/paperless/scripts` | ||||
|  | ||||
| which in turn requires the variable `PAPERLESS_POST_CONSUME_SCRIPT` in | ||||
| `docker-compose.env` to point to | ||||
| `/path/in/container/scripts/post-consumption-example.sh`. | ||||
|  | ||||
| Example (docker-compose.env): | ||||
| `PAPERLESS_POST_CONSUME_SCRIPT=/usr/src/paperless/scripts/post-consumption-example.sh` | ||||
|  | ||||
| Troubleshooting: | ||||
|  | ||||
| - Monitor the docker-compose log | ||||
|   `cd ~/paperless-ngx; docker-compose logs -f` | ||||
| - Check your script's permission e.g. in case of permission error | ||||
|   `sudo chmod 755 post-consumption-example.sh` | ||||
| - Pipe your scripts's output to a log file e.g. | ||||
|   `echo "${DOCUMENT_ID}" | tee --append /usr/src/paperless/scripts/post-consumption-example.log` | ||||
|  | ||||
| ## File name handling {#file_name_handling} | ||||
|  | ||||
| By default, paperless stores your documents in the media directory and | ||||
| renames them using the identifier which it has assigned to each | ||||
| document. You will end up getting files like `0000123.pdf` in your media | ||||
| directory. This isn't necessarily a bad thing, because you normally | ||||
| don't have to access these files manually. However, if you wish to name | ||||
| your files differently, you can do that by adjusting the | ||||
| `PAPERLESS_FILENAME_FORMAT` configuration option. Paperless adds the | ||||
| correct file extension e.g. `.pdf`, `.jpg` automatically. | ||||
|  | ||||
| This variable allows you to configure the filename (folders are allowed) | ||||
| using placeholders. For example, configuring this to | ||||
|  | ||||
| ```bash | ||||
| PAPERLESS_FILENAME_FORMAT={created_year}/{correspondent}/{title} | ||||
| ``` | ||||
|  | ||||
| will create a directory structure as follows: | ||||
|  | ||||
| ``` | ||||
| 2019/ | ||||
|   My bank/ | ||||
|     Statement January.pdf | ||||
|     Statement February.pdf | ||||
| 2020/ | ||||
|   My bank/ | ||||
|     Statement January.pdf | ||||
|     Letter.pdf | ||||
|     Letter_01.pdf | ||||
|   Shoe store/ | ||||
|     My new shoes.pdf | ||||
| ``` | ||||
|  | ||||
| !!! warning | ||||
|  | ||||
|     Do not manually move your files in the media folder. Paperless remembers | ||||
|     the last filename a document was stored as. If you do rename a file, | ||||
|     paperless will report your files as missing and won't be able to find | ||||
|     them. | ||||
|  | ||||
| Paperless provides the following placeholders within filenames: | ||||
|  | ||||
| - `{asn}`: The archive serial number of the document, or "none". | ||||
| - `{correspondent}`: The name of the correspondent, or "none". | ||||
| - `{document_type}`: The name of the document type, or "none". | ||||
| - `{tag_list}`: A comma separated list of all tags assigned to the | ||||
|   document. | ||||
| - `{title}`: The title of the document. | ||||
| - `{created}`: The full date (ISO format) the document was created. | ||||
| - `{created_year}`: Year created only, formatted as the year with | ||||
|   century. | ||||
| - `{created_year_short}`: Year created only, formatted as the year | ||||
|   without century, zero padded. | ||||
| - `{created_month}`: Month created only (number 01-12). | ||||
| - `{created_month_name}`: Month created name, as per locale | ||||
| - `{created_month_name_short}`: Month created abbreviated name, as per | ||||
|   locale | ||||
| - `{created_day}`: Day created only (number 01-31). | ||||
| - `{added}`: The full date (ISO format) the document was added to | ||||
|   paperless. | ||||
| - `{added_year}`: Year added only. | ||||
| - `{added_year_short}`: Year added only, formatted as the year without | ||||
|   century, zero padded. | ||||
| - `{added_month}`: Month added only (number 01-12). | ||||
| - `{added_month_name}`: Month added name, as per locale | ||||
| - `{added_month_name_short}`: Month added abbreviated name, as per | ||||
|   locale | ||||
| - `{added_day}`: Day added only (number 01-31). | ||||
|  | ||||
| Paperless will try to conserve the information from your database as | ||||
| much as possible. However, some characters that you can use in document | ||||
| titles and correspondent names (such as `: \ /` and a couple more) are | ||||
| not allowed in filenames and will be replaced with dashes. | ||||
|  | ||||
| If paperless detects that two documents share the same filename, | ||||
| paperless will automatically append `_01`, `_02`, etc to the filename. | ||||
| This happens if all the placeholders in a filename evaluate to the same | ||||
| value. | ||||
|  | ||||
| !!! tip | ||||
|  | ||||
|     You can affect how empty placeholders are treated by changing the | ||||
|     following setting to [true]{.title-ref}. | ||||
|  | ||||
|     ``` | ||||
|     PAPERLESS_FILENAME_FORMAT_REMOVE_NONE=True | ||||
|     ``` | ||||
|  | ||||
|     Doing this results in all empty placeholders resolving to "" instead | ||||
|     of "none" as stated above. Spaces before empty placeholders are | ||||
|     removed as well, empty directories are omitted. | ||||
|  | ||||
| !!! tip | ||||
|  | ||||
|     Paperless checks the filename of a document whenever it is saved. | ||||
|     Therefore, you need to update the filenames of your documents and move | ||||
|     them after altering this setting by invoking the | ||||
|     [`document renamer <utilities-renamer>`](). | ||||
|  | ||||
| !!! warning | ||||
|  | ||||
|     Make absolutely sure you get the spelling of the placeholders right, or | ||||
|     else paperless will use the default naming scheme instead. | ||||
|  | ||||
| !!! caution | ||||
|  | ||||
|     As of now, you could totally tell paperless to store your files anywhere | ||||
|     outside the media directory by setting | ||||
|  | ||||
|     ``` | ||||
|     PAPERLESS_FILENAME_FORMAT=../../my/custom/location/{title} | ||||
|     ``` | ||||
|  | ||||
|     However, keep in mind that inside docker, if files get stored outside of | ||||
|     the predefined volumes, they will be lost after a restart of paperless. | ||||
|  | ||||
| ## Storage paths | ||||
|  | ||||
| One of the best things in Paperless is that you can not only access the | ||||
| documents via the web interface, but also via the file system. | ||||
|  | ||||
| When as single storage layout is not sufficient for your use case, | ||||
| storage paths come to the rescue. Storage paths allow you to configure | ||||
| more precisely where each document is stored in the file system. | ||||
|  | ||||
| - Each storage path is a [PAPERLESS_FILENAME_FORMAT]{.title-ref} and | ||||
|   follows the rules described above | ||||
| - Each document is assigned a storage path using the matching | ||||
|   algorithms described above, but can be overwritten at any time | ||||
|  | ||||
| For example, you could define the following two storage paths: | ||||
|  | ||||
| 1.  Normal communications are put into a folder structure sorted by | ||||
|     [year/correspondent]{.title-ref} | ||||
| 2.  Communications with insurance companies are stored in a flat | ||||
|     structure with longer file names, but containing the full date of | ||||
|     the correspondence. | ||||
|  | ||||
| ``` | ||||
| By Year = {created_year}/{correspondent}/{title} | ||||
| Insurances = Insurances/{correspondent}/{created_year}-{created_month}-{created_day} {title} | ||||
| ``` | ||||
|  | ||||
| If you then map these storage paths to the documents, you might get the | ||||
| following result. For simplicity, [By Year]{.title-ref} defines the same | ||||
| structure as in the previous example above. | ||||
|  | ||||
| ```text | ||||
| 2019/                                   # By Year | ||||
|    My bank/ | ||||
|      Statement January.pdf | ||||
|      Statement February.pdf | ||||
|  | ||||
|  Insurances/                           # Insurances | ||||
|    Healthcare 123/ | ||||
|      2022-01-01 Statement January.pdf | ||||
|      2022-02-02 Letter.pdf | ||||
|      2022-02-03 Letter.pdf | ||||
|    Dental 456/ | ||||
|      2021-12-01 New Conditions.pdf | ||||
| ``` | ||||
|  | ||||
| !!! tip | ||||
|  | ||||
|     Defining a storage path is optional. If no storage path is defined for a | ||||
|     document, the global [PAPERLESS_FILENAME_FORMAT]{.title-ref} is applied. | ||||
|  | ||||
| !!! warning | ||||
|  | ||||
|     If you adjust the format of an existing storage path, old documents | ||||
|     don't get relocated automatically. You need to run the | ||||
|     [document renamer](/administration#renamer) to | ||||
|     adjust their pathes. | ||||
|  | ||||
| ## Celery Monitoring {#celery-monitoring} | ||||
|  | ||||
| The monitoring tool | ||||
| [Flower](https://flower.readthedocs.io/en/latest/index.html) can be used | ||||
| to view more detailed information about the health of the celery workers | ||||
| used for asynchronous tasks. This includes details on currently running, | ||||
| queued and completed tasks, timing and more. Flower can also be used | ||||
| with Prometheus, as it exports metrics. For details on its capabilities, | ||||
| refer to the Flower documentation. | ||||
|  | ||||
| To configure Flower further, create a [flowerconfig.py]{.title-ref} and | ||||
| place it into the [src/paperless]{.title-ref} directory. For a Docker | ||||
| installation, you can use volumes to accomplish this: | ||||
|  | ||||
| ```yaml | ||||
| services: | ||||
|   # ... | ||||
|   webserver: | ||||
|     # ... | ||||
|     volumes: | ||||
|       - /path/to/my/flowerconfig.py:/usr/src/paperless/src/paperless/flowerconfig.py:ro | ||||
| ``` | ||||
|  | ||||
| ## Custom Container Initialization | ||||
|  | ||||
| The Docker image includes the ability to run custom user scripts during | ||||
| startup. This could be utilized for installing additional tools or | ||||
| Python packages, for example. | ||||
|  | ||||
| To utilize this, mount a folder containing your scripts to the custom | ||||
| initialization directory, [/custom-cont-init.d]{.title-ref} and place | ||||
| scripts you wish to run inside. For security, the folder and its | ||||
| contents must be owned by [root]{.title-ref}. Additionally, scripts must | ||||
| only be writable by [root]{.title-ref}. | ||||
|  | ||||
| Your scripts will be run directly before the webserver completes | ||||
| startup. Scripts will be run by the [root]{.title-ref} user. This is an | ||||
| advanced functionality with which you could break functionality or lose | ||||
| data. | ||||
|  | ||||
| For example, using Docker Compose: | ||||
|  | ||||
| ```yaml | ||||
| services: | ||||
|   # ... | ||||
|   webserver: | ||||
|     # ... | ||||
|     volumes: | ||||
|       - /path/to/my/scripts:/custom-cont-init.d:ro | ||||
| ``` | ||||
|  | ||||
| ## MySQL Caveats {#mysql-caveats} | ||||
|  | ||||
| ### Case Sensitivity | ||||
|  | ||||
| The database interface does not provide a method to configure a MySQL | ||||
| database to be case sensitive. This would prevent a user from creating a | ||||
| tag `Name` and `NAME` as they are considered the same. | ||||
|  | ||||
| Per Django documentation, to enable this requires manual intervention. | ||||
| To enable case sensetive tables, you can execute the following command | ||||
| against each table: | ||||
|  | ||||
| `ALTER TABLE <table_name> CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;` | ||||
|  | ||||
| You can also set the default for new tables (this does NOT affect | ||||
| existing tables) with: | ||||
|  | ||||
| `ALTER DATABASE <db_name> CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;` | ||||
| @@ -1,451 +0,0 @@ | ||||
| *************** | ||||
| Advanced topics | ||||
| *************** | ||||
|  | ||||
| Paperless offers a couple features that automate certain tasks and make your life | ||||
| easier. | ||||
|  | ||||
| .. _advanced-matching: | ||||
|  | ||||
| Matching tags, correspondents, document types, and storage paths | ||||
| ################################################################ | ||||
|  | ||||
| Paperless will compare the matching algorithms defined by every tag, correspondent, | ||||
| document type, and storage path in your database to see if they apply to the text | ||||
| in a document. In other words, if you define a tag called ``Home Utility`` | ||||
| that had a ``match`` property of ``bc hydro`` and a ``matching_algorithm`` of | ||||
| ``literal``, Paperless will automatically tag your newly-consumed document with | ||||
| your ``Home Utility`` tag so long as the text ``bc hydro`` appears in the body | ||||
| of the document somewhere. | ||||
|  | ||||
| The matching logic is quite powerful. It supports searching the text of your | ||||
| document with different algorithms, and as such, some experimentation may be | ||||
| necessary to get things right. | ||||
|  | ||||
| In order to have a tag, correspondent, document type, or storage path assigned | ||||
| automatically to newly consumed documents, assign a match and matching algorithm | ||||
| using the web interface. These settings define when to assign tags, correspondents, | ||||
| document types, and storage paths to documents. | ||||
|  | ||||
| The following algorithms are available: | ||||
|  | ||||
| * **Any:** Looks for any occurrence of any word provided in match in the PDF. | ||||
|   If you define the match as ``Bank1 Bank2``, it will match documents containing | ||||
|   either of these terms. | ||||
| * **All:** Requires that every word provided appears in the PDF, albeit not in the | ||||
|   order provided. | ||||
| * **Literal:** Matches only if the match appears exactly as provided (i.e. preserve ordering) in the PDF. | ||||
| * **Regular expression:** Parses the match as a regular expression and tries to | ||||
|   find a match within the document. | ||||
| * **Fuzzy match:** I don't know. Look at the source. | ||||
| * **Auto:** Tries to automatically match new documents. This does not require you | ||||
|   to set a match. See the notes below. | ||||
|  | ||||
| When using the *any* or *all* matching algorithms, you can search for terms | ||||
| that consist of multiple words by enclosing them in double quotes. For example, | ||||
| defining a match text of ``"Bank of America" BofA`` using the *any* algorithm, | ||||
| will match documents that contain either "Bank of America" or "BofA", but will | ||||
| not match documents containing "Bank of South America". | ||||
|  | ||||
| Then just save your tag, correspondent, document type, or storage path and run | ||||
| another document through the consumer.  Once complete, you should see the | ||||
| newly-created document, automatically tagged with the appropriate data. | ||||
|  | ||||
|  | ||||
| .. _advanced-automatic_matching: | ||||
|  | ||||
| Automatic matching | ||||
| ================== | ||||
|  | ||||
| Paperless-ngx comes with a new matching algorithm called *Auto*. This matching | ||||
| algorithm tries to assign tags, correspondents, document types, and storage paths | ||||
| to your documents based on how you have already assigned these on existing documents. | ||||
| It uses a neural network under the hood. | ||||
|  | ||||
| If, for example, all your bank statements of your account 123 at the Bank of | ||||
| America are tagged with the tag "bofa_123" and the matching algorithm of this | ||||
| tag is set to *Auto*, this neural network will examine your documents and | ||||
| automatically learn when to assign this tag. | ||||
|  | ||||
| Paperless tries to hide much of the involved complexity with this approach. | ||||
| However, there are a couple caveats you need to keep in mind when using this | ||||
| feature: | ||||
|  | ||||
| * Changes to your documents are not immediately reflected by the matching | ||||
|   algorithm. The neural network needs to be *trained* on your documents after | ||||
|   changes. Paperless periodically (default: once each hour) checks for changes | ||||
|   and does this automatically for you. | ||||
| * The Auto matching algorithm only takes documents into account which are NOT | ||||
|   placed in your inbox (i.e. have any inbox tags assigned to them). This ensures | ||||
|   that the neural network only learns from documents which you have correctly | ||||
|   tagged before. | ||||
| * The matching algorithm can only work if there is a correlation between the | ||||
|   tag, correspondent, document type, or storage path and the document itself. | ||||
|   Your bank statements usually contain your bank account number and the name | ||||
|   of the bank, so this works reasonably well, However, tags such as "TODO" | ||||
|   cannot be automatically assigned. | ||||
| * The matching algorithm needs a reasonable number of documents to identify when | ||||
|   to assign tags, correspondents, storage paths, and types. If one out of a | ||||
|   thousand documents has the correspondent "Very obscure web shop I bought | ||||
|   something five years ago", it will probably not assign this correspondent | ||||
|   automatically if you buy something from them again. The more documents, the better. | ||||
| * Paperless also needs a reasonable amount of negative examples to decide when | ||||
|   not to assign a certain tag, correspondent, document type, or storage path. This will | ||||
|   usually be the case as you start filling up paperless with documents. | ||||
|   Example: If all your documents are either from "Webshop" and "Bank", paperless | ||||
|   will assign one of these correspondents to ANY new document, if both are set | ||||
|   to automatic matching. | ||||
|  | ||||
| Hooking into the consumption process | ||||
| #################################### | ||||
|  | ||||
| Sometimes you may want to do something arbitrary whenever a document is | ||||
| consumed.  Rather than try to predict what you may want to do, Paperless lets | ||||
| you execute scripts of your own choosing just before or after a document is | ||||
| consumed using a couple simple hooks. | ||||
|  | ||||
| Just write a script, put it somewhere that Paperless can read & execute, and | ||||
| then put the path to that script in ``paperless.conf`` or ``docker-compose.env`` with the variable name | ||||
| of either ``PAPERLESS_PRE_CONSUME_SCRIPT`` or | ||||
| ``PAPERLESS_POST_CONSUME_SCRIPT``. | ||||
|  | ||||
| .. important:: | ||||
|  | ||||
|     These scripts are executed in a **blocking** process, which means that if | ||||
|     a script takes a long time to run, it can significantly slow down your | ||||
|     document consumption flow.  If you want things to run asynchronously, | ||||
|     you'll have to fork the process in your script and exit. | ||||
|  | ||||
|  | ||||
| Pre-consumption script | ||||
| ====================== | ||||
|  | ||||
| Executed after the consumer sees a new document in the consumption folder, but | ||||
| before any processing of the document is performed. This script can access the | ||||
| following relevant environment variables set: | ||||
|  | ||||
| * ``DOCUMENT_SOURCE_PATH`` | ||||
|  | ||||
| A simple but common example for this would be creating a simple script like | ||||
| this: | ||||
|  | ||||
| ``/usr/local/bin/ocr-pdf`` | ||||
|  | ||||
| .. code:: bash | ||||
|  | ||||
|     #!/usr/bin/env bash | ||||
|     pdf2pdfocr.py -i ${DOCUMENT_SOURCE_PATH} | ||||
|  | ||||
| ``/etc/paperless.conf`` | ||||
|  | ||||
| .. code:: bash | ||||
|  | ||||
|     ... | ||||
|     PAPERLESS_PRE_CONSUME_SCRIPT="/usr/local/bin/ocr-pdf" | ||||
|     ... | ||||
|  | ||||
| This will pass the path to the document about to be consumed to ``/usr/local/bin/ocr-pdf``, | ||||
| which will in turn call `pdf2pdfocr.py`_ on your document, which will then | ||||
| overwrite the file with an OCR'd version of the file and exit.  At which point, | ||||
| the consumption process will begin with the newly modified file. | ||||
|  | ||||
| The script's stdout and stderr will be logged line by line to the webserver log, along | ||||
| with the exit code of the script. | ||||
|  | ||||
| .. _pdf2pdfocr.py: https://github.com/LeoFCardoso/pdf2pdfocr | ||||
|  | ||||
| .. _advanced-post_consume_script: | ||||
|  | ||||
| Post-consumption script | ||||
| ======================= | ||||
|  | ||||
| Executed after the consumer has successfully processed a document and has moved it | ||||
| into paperless. It receives the following environment variables: | ||||
|  | ||||
| * ``DOCUMENT_ID`` | ||||
| * ``DOCUMENT_FILE_NAME`` | ||||
| * ``DOCUMENT_CREATED`` | ||||
| * ``DOCUMENT_MODIFIED`` | ||||
| * ``DOCUMENT_ADDED`` | ||||
| * ``DOCUMENT_SOURCE_PATH`` | ||||
| * ``DOCUMENT_ARCHIVE_PATH`` | ||||
| * ``DOCUMENT_THUMBNAIL_PATH`` | ||||
| * ``DOCUMENT_DOWNLOAD_URL`` | ||||
| * ``DOCUMENT_THUMBNAIL_URL`` | ||||
| * ``DOCUMENT_CORRESPONDENT`` | ||||
| * ``DOCUMENT_TAGS`` | ||||
| * ``DOCUMENT_ORIGINAL_FILENAME`` | ||||
|  | ||||
| The script can be in any language, but for a simple shell script | ||||
| example, you can take a look at `post-consumption-example.sh`_ in this project. | ||||
|  | ||||
| The post consumption script cannot cancel the consumption process. | ||||
|  | ||||
| The script's stdout and stderr will be logged line by line to the webserver log, along | ||||
| with the exit code of the script. | ||||
|  | ||||
|  | ||||
| Docker | ||||
| ------ | ||||
| Assumed you have ``/home/foo/paperless-ngx/scripts/post-consumption-example.sh``. | ||||
|  | ||||
| You can pass that script into the consumer container via a host mount in your ``docker-compose.yml``. | ||||
|  | ||||
| .. code:: bash | ||||
|  | ||||
|   ... | ||||
|   consumer: | ||||
|     ... | ||||
|     volumes: | ||||
|       ... | ||||
|       - /home/paperless-ngx/scripts:/path/in/container/scripts/ | ||||
|   ... | ||||
|  | ||||
| Example (docker-compose.yml): ``- /home/foo/paperless-ngx/scripts:/usr/src/paperless/scripts`` | ||||
|  | ||||
| which in turn requires the variable ``PAPERLESS_POST_CONSUME_SCRIPT`` in ``docker-compose.env``  to point to ``/path/in/container/scripts/post-consumption-example.sh``. | ||||
|  | ||||
| Example (docker-compose.env): ``PAPERLESS_POST_CONSUME_SCRIPT=/usr/src/paperless/scripts/post-consumption-example.sh`` | ||||
|  | ||||
| Troubleshooting: | ||||
|  | ||||
| - Monitor the docker-compose log ``cd ~/paperless-ngx; docker-compose logs -f`` | ||||
| - Check your script's permission e.g. in case of permission error ``sudo chmod 755 post-consumption-example.sh`` | ||||
| - Pipe your scripts's output to a log file e.g. ``echo "${DOCUMENT_ID}" | tee --append /usr/src/paperless/scripts/post-consumption-example.log`` | ||||
|  | ||||
| .. _post-consumption-example.sh: https://github.com/paperless-ngx/paperless-ngx/blob/main/scripts/post-consumption-example.sh | ||||
|  | ||||
| .. _advanced-file_name_handling: | ||||
|  | ||||
| File name handling | ||||
| ################## | ||||
|  | ||||
| By default, paperless stores your documents in the media directory and renames them | ||||
| using the identifier which it has assigned to each document. You will end up getting | ||||
| files like ``0000123.pdf`` in your media directory. This isn't necessarily a bad | ||||
| thing, because you normally don't have to access these files manually. However, if | ||||
| you wish to name your files differently, you can do that by adjusting the | ||||
| ``PAPERLESS_FILENAME_FORMAT`` configuration option. Paperless adds the correct | ||||
| file extension e.g. ``.pdf``, ``.jpg`` automatically. | ||||
|  | ||||
| This variable allows you to configure the filename (folders are allowed) using | ||||
| placeholders. For example, configuring this to | ||||
|  | ||||
| .. code:: bash | ||||
|  | ||||
|     PAPERLESS_FILENAME_FORMAT={created_year}/{correspondent}/{title} | ||||
|  | ||||
| will create a directory structure as follows: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     2019/ | ||||
|       My bank/ | ||||
|         Statement January.pdf | ||||
|         Statement February.pdf | ||||
|     2020/ | ||||
|       My bank/ | ||||
|         Statement January.pdf | ||||
|         Letter.pdf | ||||
|         Letter_01.pdf | ||||
|       Shoe store/ | ||||
|         My new shoes.pdf | ||||
|  | ||||
| .. danger:: | ||||
|  | ||||
|     Do not manually move your files in the media folder. Paperless remembers the | ||||
|     last filename a document was stored as. If you do rename a file, paperless will | ||||
|     report your files as missing and won't be able to find them. | ||||
|  | ||||
| Paperless provides the following placeholders within filenames: | ||||
|  | ||||
| * ``{asn}``: The archive serial number of the document, or "none". | ||||
| * ``{correspondent}``: The name of the correspondent, or "none". | ||||
| * ``{document_type}``: The name of the document type, or "none". | ||||
| * ``{tag_list}``: A comma separated list of all tags assigned to the document. | ||||
| * ``{title}``: The title of the document. | ||||
| * ``{created}``: The full date (ISO format) the document was created. | ||||
| * ``{created_year}``: Year created only, formatted as the year with century. | ||||
| * ``{created_year_short}``: Year created only, formatted as the year without century, zero padded. | ||||
| * ``{created_month}``: Month created only (number 01-12). | ||||
| * ``{created_month_name}``: Month created name, as per locale | ||||
| * ``{created_month_name_short}``: Month created abbreviated name, as per locale | ||||
| * ``{created_day}``: Day created only (number 01-31). | ||||
| * ``{added}``: The full date (ISO format) the document was added to paperless. | ||||
| * ``{added_year}``: Year added only. | ||||
| * ``{added_year_short}``: Year added only, formatted as the year without century, zero padded. | ||||
| * ``{added_month}``: Month added only (number 01-12). | ||||
| * ``{added_month_name}``: Month added name, as per locale | ||||
| * ``{added_month_name_short}``: Month added abbreviated name, as per locale | ||||
| * ``{added_day}``: Day added only (number 01-31). | ||||
|  | ||||
|  | ||||
| Paperless will try to conserve the information from your database as much as possible. | ||||
| However, some characters that you can use in document titles and correspondent names (such | ||||
| as ``: \ /`` and a couple more) are not allowed in filenames and will be replaced with dashes. | ||||
|  | ||||
| If paperless detects that two documents share the same filename, paperless will automatically | ||||
| append ``_01``, ``_02``, etc to the filename. This happens if all the placeholders in a filename | ||||
| evaluate to the same value. | ||||
|  | ||||
| .. hint:: | ||||
|     You can affect how empty placeholders are treated by changing the following setting to | ||||
|     `true`. | ||||
|  | ||||
|     .. code:: | ||||
|  | ||||
|         PAPERLESS_FILENAME_FORMAT_REMOVE_NONE=True | ||||
|  | ||||
|     Doing this results in all empty placeholders resolving to "" instead of "none" as stated above. | ||||
|     Spaces before empty placeholders are removed as well, empty directories are omitted. | ||||
|  | ||||
| .. hint:: | ||||
|  | ||||
|     Paperless checks the filename of a document whenever it is saved. Therefore, | ||||
|     you need to update the filenames of your documents and move them after altering | ||||
|     this setting by invoking the :ref:`document renamer <utilities-renamer>`. | ||||
|  | ||||
| .. warning:: | ||||
|  | ||||
|     Make absolutely sure you get the spelling of the placeholders right, or else | ||||
|     paperless will use the default naming scheme instead. | ||||
|  | ||||
| .. caution:: | ||||
|  | ||||
|     As of now, you could totally tell paperless to store your files anywhere outside | ||||
|     the media directory by setting | ||||
|  | ||||
|     .. code:: | ||||
|  | ||||
|         PAPERLESS_FILENAME_FORMAT=../../my/custom/location/{title} | ||||
|  | ||||
|     However, keep in mind that inside docker, if files get stored outside of the | ||||
|     predefined volumes, they will be lost after a restart of paperless. | ||||
|  | ||||
|  | ||||
| Storage paths | ||||
| ############# | ||||
|  | ||||
| One of the best things in Paperless is that you can not only access the documents via the | ||||
| web interface, but also via the file system. | ||||
|  | ||||
| When as single storage layout is not sufficient for your use case, storage paths come to | ||||
| the rescue. Storage paths allow you to configure more precisely where each document is stored | ||||
| in the file system. | ||||
|  | ||||
| - Each storage path is a `PAPERLESS_FILENAME_FORMAT` and follows the rules described above | ||||
| - Each document is assigned a storage path using the matching algorithms described above, but | ||||
|   can be overwritten at any time | ||||
|  | ||||
| For example, you could define the following two storage paths: | ||||
|  | ||||
| 1. Normal communications are put into a folder structure sorted by `year/correspondent` | ||||
| 2. Communications with insurance companies are stored in a flat structure with longer file names, | ||||
|    but containing the full date of the correspondence. | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     By Year = {created_year}/{correspondent}/{title} | ||||
|     Insurances = Insurances/{correspondent}/{created_year}-{created_month}-{created_day} {title} | ||||
|  | ||||
|  | ||||
| If you then map these storage paths to the documents, you might get the following result. | ||||
| For simplicity, `By Year` defines the same structure as in the previous example above. | ||||
|  | ||||
| .. code:: text | ||||
|  | ||||
|    2019/                                   # By Year | ||||
|       My bank/ | ||||
|         Statement January.pdf | ||||
|         Statement February.pdf | ||||
|  | ||||
|     Insurances/                           # Insurances | ||||
|       Healthcare 123/ | ||||
|         2022-01-01 Statement January.pdf | ||||
|         2022-02-02 Letter.pdf | ||||
|         2022-02-03 Letter.pdf | ||||
|       Dental 456/ | ||||
|         2021-12-01 New Conditions.pdf | ||||
|  | ||||
|  | ||||
| .. hint:: | ||||
|  | ||||
|     Defining a storage path is optional. If no storage path is defined for a document, the global | ||||
|     `PAPERLESS_FILENAME_FORMAT` is applied. | ||||
|  | ||||
| .. caution:: | ||||
|  | ||||
|     If you adjust the format of an existing storage path, old documents don't get relocated automatically. | ||||
|     You need to run the :ref:`document renamer <utilities-renamer>` to adjust their pathes. | ||||
|  | ||||
| .. _advanced-celery-monitoring: | ||||
|  | ||||
| Celery Monitoring | ||||
| ################# | ||||
|  | ||||
| The monitoring tool `Flower <https://flower.readthedocs.io/en/latest/index.html>`_ can be used to view more | ||||
| detailed information about the health of the celery workers used for asynchronous tasks.  This includes details | ||||
| on currently running, queued and completed tasks, timing and more.  Flower can also be used with Prometheus, as it | ||||
| exports metrics.  For details on its capabilities, refer to the Flower documentation. | ||||
|  | ||||
| To configure Flower further, create a `flowerconfig.py` and place it into the `src/paperless` directory.  For | ||||
| a Docker installation, you can use volumes to accomplish this: | ||||
|  | ||||
| .. code:: yaml | ||||
|  | ||||
|     services: | ||||
|       # ... | ||||
|       webserver: | ||||
|         # ... | ||||
|         volumes: | ||||
|           - /path/to/my/flowerconfig.py:/usr/src/paperless/src/paperless/flowerconfig.py:ro | ||||
|  | ||||
| Custom Container Initialization | ||||
| ############################### | ||||
|  | ||||
| The Docker image includes the ability to run custom user scripts during startup.  This could be | ||||
| utilized for installing additional tools or Python packages, for example. | ||||
|  | ||||
| To utilize this, mount a folder containing your scripts to the custom initialization directory, `/custom-cont-init.d` | ||||
| and place scripts you wish to run inside.  For security, the folder must be owned by `root` and should have permissions | ||||
| of `a=rx`.  Additionally, scripts must only be writable by `root`. | ||||
|  | ||||
| Your scripts will be run directly before the webserver completes startup.  Scripts will be run by the `root` user. | ||||
| If you would like to switch users, the utility `gosu` is available and preferred over `sudo`. | ||||
|  | ||||
| This is an advanced functionality with which you could break functionality or lose data.  If you experience issues, | ||||
| please disable any custom scripts and try again before reporting an issue. | ||||
|  | ||||
| For example, using Docker Compose: | ||||
|  | ||||
|  | ||||
| .. code:: yaml | ||||
|  | ||||
|     services: | ||||
|       # ... | ||||
|       webserver: | ||||
|         # ... | ||||
|         volumes: | ||||
|           - /path/to/my/scripts:/custom-cont-init.d:ro | ||||
|  | ||||
|  | ||||
| .. _advanced-mysql-caveats: | ||||
|  | ||||
| MySQL Caveats | ||||
| ############# | ||||
|  | ||||
| Case Sensitivity | ||||
| ================ | ||||
|  | ||||
| The database interface does not provide a method to configure a MySQL database to | ||||
| be case sensitive.  This would prevent a user from creating a tag ``Name`` and ``NAME`` | ||||
| as they are considered the same. | ||||
|  | ||||
| Per Django documentation, to enable this requires manual intervention.  To enable | ||||
| case sensetive tables, you can execute the following command against each table: | ||||
|  | ||||
| ``ALTER TABLE <table_name> CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`` | ||||
|  | ||||
| You can also set the default for new tables (this does NOT affect existing tables) with: | ||||
|  | ||||
| ``ALTER DATABASE <db_name> CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`` | ||||
							
								
								
									
										319
									
								
								docs/api.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,319 @@ | ||||
| # The REST API | ||||
|  | ||||
| Paperless makes use of the [Django REST | ||||
| Framework](http://django-rest-framework.org/) standard API interface. It | ||||
| provides a browsable API for most of its endpoints, which you can | ||||
| inspect at `http://<paperless-host>:<port>/api/`. This also documents | ||||
| most of the available filters and ordering fields. | ||||
|  | ||||
| The API provides 5 main endpoints: | ||||
|  | ||||
| - `/api/documents/`: Full CRUD support, except POSTing new documents. | ||||
|   See below. | ||||
| - `/api/correspondents/`: Full CRUD support. | ||||
| - `/api/document_types/`: Full CRUD support. | ||||
| - `/api/logs/`: Read-Only. | ||||
| - `/api/tags/`: Full CRUD support. | ||||
| - `/api/mail_accounts/`: Full CRUD support. | ||||
| - `/api/mail_rules/`: Full CRUD support. | ||||
|  | ||||
| All of these endpoints except for the logging endpoint allow you to | ||||
| fetch, edit and delete individual objects by appending their primary key | ||||
| to the path, for example `/api/documents/454/`. | ||||
|  | ||||
| The objects served by the document endpoint contain the following | ||||
| fields: | ||||
|  | ||||
| - `id`: ID of the document. Read-only. | ||||
| - `title`: Title of the document. | ||||
| - `content`: Plain text content of the document. | ||||
| - `tags`: List of IDs of tags assigned to this document, or empty | ||||
|   list. | ||||
| - `document_type`: Document type of this document, or null. | ||||
| - `correspondent`: Correspondent of this document or null. | ||||
| - `created`: The date time at which this document was created. | ||||
| - `created_date`: The date (YYYY-MM-DD) at which this document was | ||||
|   created. Optional. If also passed with created, this is ignored. | ||||
| - `modified`: The date at which this document was last edited in | ||||
|   paperless. Read-only. | ||||
| - `added`: The date at which this document was added to paperless. | ||||
|   Read-only. | ||||
| - `archive_serial_number`: The identifier of this document in a | ||||
|   physical document archive. | ||||
| - `original_file_name`: Verbose filename of the original document. | ||||
|   Read-only. | ||||
| - `archived_file_name`: Verbose filename of the archived document. | ||||
|   Read-only. Null if no archived document is available. | ||||
|  | ||||
| ## Downloading documents | ||||
|  | ||||
| In addition to that, the document endpoint offers these additional | ||||
| actions on individual documents: | ||||
|  | ||||
| - `/api/documents/<pk>/download/`: Download the document. | ||||
| - `/api/documents/<pk>/preview/`: Display the document inline, without | ||||
|   downloading it. | ||||
| - `/api/documents/<pk>/thumb/`: Download the PNG thumbnail of a | ||||
|   document. | ||||
|  | ||||
| Paperless generates archived PDF/A documents from consumed files and | ||||
| stores both the original files as well as the archived files. By | ||||
| default, the endpoints for previews and downloads serve the archived | ||||
| file, if it is available. Otherwise, the original file is served. Some | ||||
| document cannot be archived. | ||||
|  | ||||
| The endpoints correctly serve the response header fields | ||||
| `Content-Disposition` and `Content-Type` to indicate the filename for | ||||
| download and the type of content of the document. | ||||
|  | ||||
| In order to download or preview the original document when an archived | ||||
| document is available, supply the query parameter `original=true`. | ||||
|  | ||||
| !!! tip | ||||
|  | ||||
|     Paperless used to provide these functionality at `/fetch/<pk>/preview`, | ||||
|     `/fetch/<pk>/thumb` and `/fetch/<pk>/doc`. Redirects to the new URLs are | ||||
|     in place. However, if you use these old URLs to access documents, you | ||||
|     should update your app or script to use the new URLs. | ||||
|  | ||||
| ## Getting document metadata | ||||
|  | ||||
| The api also has an endpoint to retrieve read-only metadata about | ||||
| specific documents. this information is not served along with the | ||||
| document objects, since it requires reading files and would therefore | ||||
| slow down document lists considerably. | ||||
|  | ||||
| Access the metadata of a document with an ID `id` at | ||||
| `/api/documents/<id>/metadata/`. | ||||
|  | ||||
| The endpoint reports the following data: | ||||
|  | ||||
| - `original_checksum`: MD5 checksum of the original document. | ||||
| - `original_size`: Size of the original document, in bytes. | ||||
| - `original_mime_type`: Mime type of the original document. | ||||
| - `media_filename`: Current filename of the document, under which it | ||||
|   is stored inside the media directory. | ||||
| - `has_archive_version`: True, if this document is archived, false | ||||
|   otherwise. | ||||
| - `original_metadata`: A list of metadata associated with the original | ||||
|   document. See below. | ||||
| - `archive_checksum`: MD5 checksum of the archived document, or null. | ||||
| - `archive_size`: Size of the archived document in bytes, or null. | ||||
| - `archive_metadata`: Metadata associated with the archived document, | ||||
|   or null. See below. | ||||
|  | ||||
| File metadata is reported as a list of objects in the following form: | ||||
|  | ||||
| ```json | ||||
| [ | ||||
|   { | ||||
|     "namespace": "http://ns.adobe.com/pdf/1.3/", | ||||
|     "prefix": "pdf", | ||||
|     "key": "Producer", | ||||
|     "value": "SparklePDF, Fancy edition" | ||||
|   } | ||||
| ] | ||||
| ``` | ||||
|  | ||||
| `namespace` and `prefix` can be null. The actual metadata reported | ||||
| depends on the file type and the metadata available in that specific | ||||
| document. Paperless only reports PDF metadata at this point. | ||||
|  | ||||
| ## Authorization | ||||
|  | ||||
| The REST api provides three different forms of authentication. | ||||
|  | ||||
| 1.  Basic authentication | ||||
|  | ||||
|     Authorize by providing a HTTP header in the form | ||||
|  | ||||
|     ``` | ||||
|     Authorization: Basic <credentials> | ||||
|     ``` | ||||
|  | ||||
|     where `credentials` is a base64-encoded string of | ||||
|     `<username>:<password>` | ||||
|  | ||||
| 2.  Session authentication | ||||
|  | ||||
|     When you're logged into paperless in your browser, you're | ||||
|     automatically logged into the API as well and don't need to provide | ||||
|     any authorization headers. | ||||
|  | ||||
| 3.  Token authentication | ||||
|  | ||||
|     Paperless also offers an endpoint to acquire authentication tokens. | ||||
|  | ||||
|     POST a username and password as a form or json string to | ||||
|     `/api/token/` and paperless will respond with a token, if the login | ||||
|     data is correct. This token can be used to authenticate other | ||||
|     requests with the following HTTP header: | ||||
|  | ||||
|     ``` | ||||
|     Authorization: Token <token> | ||||
|     ``` | ||||
|  | ||||
|     Tokens can be managed and revoked in the paperless admin. | ||||
|  | ||||
| ## Searching for documents | ||||
|  | ||||
| Full text searching is available on the `/api/documents/` endpoint. Two | ||||
| specific query parameters cause the API to return full text search | ||||
| results: | ||||
|  | ||||
| - `/api/documents/?query=your%20search%20query`: Search for a document | ||||
|   using a full text query. For details on the syntax, see | ||||
|   `basic-usage_searching`{.interpreted-text role="ref"}. | ||||
| - `/api/documents/?more_like=1234`: Search for documents similar to | ||||
|   the document with id 1234. | ||||
|  | ||||
| Pagination works exactly the same as it does for normal requests on this | ||||
| endpoint. | ||||
|  | ||||
| Certain limitations apply to full text queries: | ||||
|  | ||||
| - Results are always sorted by search score. The results matching the | ||||
|   query best will show up first. | ||||
| - Only a small subset of filtering parameters are supported. | ||||
|  | ||||
| Furthermore, each returned document has an additional `__search_hit__` | ||||
| attribute with various information about the search results: | ||||
|  | ||||
| ``` | ||||
| { | ||||
|     "count": 31, | ||||
|     "next": "http://localhost:8000/api/documents/?page=2&query=test", | ||||
|     "previous": null, | ||||
|     "results": [ | ||||
|  | ||||
|         ... | ||||
|  | ||||
|         { | ||||
|             "id": 123, | ||||
|             "title": "title", | ||||
|             "content": "content", | ||||
|  | ||||
|             ... | ||||
|  | ||||
|             "__search_hit__": { | ||||
|                 "score": 0.343, | ||||
|                 "highlights": "text <span class="match">Test</span> text", | ||||
|                 "rank": 23 | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|         ... | ||||
|  | ||||
|     ] | ||||
| } | ||||
| ``` | ||||
|  | ||||
| - `score` is an indication how well this document matches the query | ||||
|   relative to the other search results. | ||||
| - `highlights` is an excerpt from the document content and highlights | ||||
|   the search terms with `<span>` tags as shown above. | ||||
| - `rank` is the index of the search results. The first result will | ||||
|   have rank 0. | ||||
|  | ||||
| ### `/api/search/autocomplete/` | ||||
|  | ||||
| Get auto completions for a partial search term. | ||||
|  | ||||
| Query parameters: | ||||
|  | ||||
| - `term`: The incomplete term. | ||||
| - `limit`: Amount of results. Defaults to 10. | ||||
|  | ||||
| Results returned by the endpoint are ordered by importance of the term | ||||
| in the document index. The first result is the term that has the highest | ||||
| Tf/Idf score in the index. | ||||
|  | ||||
| ```json | ||||
| ["term1", "term3", "term6", "term4"] | ||||
| ``` | ||||
|  | ||||
| ## POSTing documents {#api-file_uploads} | ||||
|  | ||||
| The API provides a special endpoint for file uploads: | ||||
|  | ||||
| `/api/documents/post_document/` | ||||
|  | ||||
| POST a multipart form to this endpoint, where the form field `document` | ||||
| contains the document that you want to upload to paperless. The filename | ||||
| is sanitized and then used to store the document in a temporary | ||||
| directory, and the consumer will be instructed to consume the document | ||||
| from there. | ||||
|  | ||||
| The endpoint supports the following optional form fields: | ||||
|  | ||||
| - `title`: Specify a title that the consumer should use for the | ||||
|   document. | ||||
| - `created`: Specify a DateTime where the document was created (e.g. | ||||
|   "2016-04-19" or "2016-04-19 06:15:00+02:00"). | ||||
| - `correspondent`: Specify the ID of a correspondent that the consumer | ||||
|   should use for the document. | ||||
| - `document_type`: Similar to correspondent. | ||||
| - `tags`: Similar to correspondent. Specify this multiple times to | ||||
|   have multiple tags added to the document. | ||||
|  | ||||
| The endpoint will immediately return "OK" if the document consumption | ||||
| process was started successfully. No additional status information about | ||||
| the consumption process itself is available, since that happens in a | ||||
| different process. | ||||
|  | ||||
| ## API Versioning | ||||
|  | ||||
| The REST API is versioned since Paperless-ngx 1.3.0. | ||||
|  | ||||
| - Versioning ensures that changes to the API don't break older | ||||
|   clients. | ||||
| - Clients specify the specific version of the API they wish to use | ||||
|   with every request and Paperless will handle the request using the | ||||
|   specified API version. | ||||
| - Even if the underlying data model changes, older API versions will | ||||
|   always serve compatible data. | ||||
| - If no version is specified, Paperless will serve version 1 to ensure | ||||
|   compatibility with older clients that do not request a specific API | ||||
|   version. | ||||
|  | ||||
| API versions are specified by submitting an additional HTTP `Accept` | ||||
| header with every request: | ||||
|  | ||||
| ``` | ||||
| Accept: application/json; version=6 | ||||
| ``` | ||||
|  | ||||
| If an invalid version is specified, Paperless 1.3.0 will respond with | ||||
| "406 Not Acceptable" and an error message in the body. Earlier | ||||
| versions of Paperless will serve API version 1 regardless of whether a | ||||
| version is specified via the `Accept` header. | ||||
|  | ||||
| If a client wishes to verify whether it is compatible with any given | ||||
| server, the following procedure should be performed: | ||||
|  | ||||
| 1.  Perform an _authenticated_ request against any API endpoint. If the | ||||
|     server is on version 1.3.0 or newer, the server will add two custom | ||||
|     headers to the response: | ||||
|  | ||||
|     ``` | ||||
|     X-Api-Version: 2 | ||||
|     X-Version: 1.3.0 | ||||
|     ``` | ||||
|  | ||||
| 2.  Determine whether the client is compatible with this server based on | ||||
|     the presence/absence of these headers and their values if present. | ||||
|  | ||||
| ### API Changelog | ||||
|  | ||||
| #### Version 1 | ||||
|  | ||||
| Initial API version. | ||||
|  | ||||
| #### Version 2 | ||||
|  | ||||
| - Added field `Tag.color`. This read/write string field contains a hex | ||||
|   color such as `#a6cee3`. | ||||
| - Added read-only field `Tag.text_color`. This field contains the text | ||||
|   color to use for a specific tag, which is either black or white | ||||
|   depending on the brightness of `Tag.color`. | ||||
| - Removed field `Tag.colour`. | ||||
							
								
								
									
										303
									
								
								docs/api.rst
									
									
									
									
									
								
							
							
						
						| @@ -1,303 +0,0 @@ | ||||
|  | ||||
| ************ | ||||
| The REST API | ||||
| ************ | ||||
|  | ||||
|  | ||||
| Paperless makes use of the `Django REST Framework`_ standard API interface. | ||||
| It provides a browsable API for most of its endpoints, which you can inspect | ||||
| at ``http://<paperless-host>:<port>/api/``. This also documents most of the | ||||
| available filters and ordering fields. | ||||
|  | ||||
| .. _Django REST Framework: http://django-rest-framework.org/ | ||||
|  | ||||
| The API provides 5 main endpoints: | ||||
|  | ||||
| *   ``/api/documents/``: Full CRUD support, except POSTing new documents. See below. | ||||
| *   ``/api/correspondents/``: Full CRUD support. | ||||
| *   ``/api/document_types/``: Full CRUD support. | ||||
| *   ``/api/logs/``: Read-Only. | ||||
| *   ``/api/tags/``: Full CRUD support. | ||||
|  | ||||
| All of these endpoints except for the logging endpoint | ||||
| allow you to fetch, edit and delete individual objects | ||||
| by appending their primary key to the path, for example ``/api/documents/454/``. | ||||
|  | ||||
| The objects served by the document endpoint contain the following fields: | ||||
|  | ||||
| *   ``id``: ID of the document. Read-only. | ||||
| *   ``title``: Title of the document. | ||||
| *   ``content``: Plain text content of the document. | ||||
| *   ``tags``: List of IDs of tags assigned to this document, or empty list. | ||||
| *   ``document_type``: Document type of this document, or null. | ||||
| *   ``correspondent``:  Correspondent of this document or null. | ||||
| *   ``created``: The date time at which this document was created. | ||||
| *   ``created_date``: The date (YYYY-MM-DD) at which this document was created. Optional. If also passed with created, this is ignored. | ||||
| *   ``modified``: The date at which this document was last edited in paperless. Read-only. | ||||
| *   ``added``: The date at which this document was added to paperless. Read-only. | ||||
| *   ``archive_serial_number``: The identifier of this document in a physical document archive. | ||||
| *   ``original_file_name``: Verbose filename of the original document. Read-only. | ||||
| *   ``archived_file_name``: Verbose filename of the archived document. Read-only. Null if no archived document is available. | ||||
|  | ||||
|  | ||||
| Downloading documents | ||||
| ##################### | ||||
|  | ||||
| In addition to that, the document endpoint offers these additional actions on | ||||
| individual documents: | ||||
|  | ||||
| *   ``/api/documents/<pk>/download/``: Download the document. | ||||
| *   ``/api/documents/<pk>/preview/``: Display the document inline, | ||||
|     without downloading it. | ||||
| *   ``/api/documents/<pk>/thumb/``: Download the PNG thumbnail of a document. | ||||
|  | ||||
| Paperless generates archived PDF/A documents from consumed files and stores both | ||||
| the original files as well as the archived files. By default, the endpoints | ||||
| for previews and downloads serve the archived file, if it is available. | ||||
| Otherwise, the original file is served. | ||||
| Some document cannot be archived. | ||||
|  | ||||
| The endpoints correctly serve the response header fields ``Content-Disposition`` | ||||
| and ``Content-Type`` to indicate the filename for download and the type of content of | ||||
| the document. | ||||
|  | ||||
| In order to download or preview the original document when an archived document is available, | ||||
| supply the query parameter ``original=true``. | ||||
|  | ||||
| .. hint:: | ||||
|  | ||||
|     Paperless used to provide these functionality at ``/fetch/<pk>/preview``, | ||||
|     ``/fetch/<pk>/thumb`` and ``/fetch/<pk>/doc``. Redirects to the new URLs | ||||
|     are in place. However, if you use these old URLs to access documents, you | ||||
|     should update your app or script to use the new URLs. | ||||
|  | ||||
|  | ||||
| Getting document metadata | ||||
| ######################### | ||||
|  | ||||
| The api also has an endpoint to retrieve read-only metadata about specific documents. this | ||||
| information is not served along with the document objects, since it requires reading | ||||
| files and would therefore slow down document lists considerably. | ||||
|  | ||||
| Access the metadata of a document with an ID ``id`` at ``/api/documents/<id>/metadata/``. | ||||
|  | ||||
| The endpoint reports the following data: | ||||
|  | ||||
| *   ``original_checksum``: MD5 checksum of the original document. | ||||
| *   ``original_size``: Size of the original document, in bytes. | ||||
| *   ``original_mime_type``: Mime type of the original document. | ||||
| *   ``media_filename``: Current filename of the document, under which it is stored inside the media directory. | ||||
| *   ``has_archive_version``: True, if this document is archived, false otherwise. | ||||
| *   ``original_metadata``: A list of metadata associated with the original document. See below. | ||||
| *   ``archive_checksum``: MD5 checksum of the archived document, or null. | ||||
| *   ``archive_size``: Size of the archived document in bytes, or null. | ||||
| *   ``archive_metadata``: Metadata associated with the archived document, or null. See below. | ||||
|  | ||||
| File metadata is reported as a list of objects in the following form: | ||||
|  | ||||
| .. code:: json | ||||
|  | ||||
|     [ | ||||
|         { | ||||
|             "namespace": "http://ns.adobe.com/pdf/1.3/", | ||||
|             "prefix": "pdf", | ||||
|             "key": "Producer", | ||||
|             "value": "SparklePDF, Fancy edition" | ||||
|         }, | ||||
|     ] | ||||
|  | ||||
| ``namespace`` and ``prefix`` can be null. The actual metadata reported depends on the file type and the metadata | ||||
| available in that specific document. Paperless only reports PDF metadata at this point. | ||||
|  | ||||
| Authorization | ||||
| ############# | ||||
|  | ||||
| The REST api provides three different forms of authentication. | ||||
|  | ||||
| 1.  Basic authentication | ||||
|  | ||||
|     Authorize by providing a HTTP header in the form | ||||
|  | ||||
|     .. code:: | ||||
|  | ||||
|         Authorization: Basic <credentials> | ||||
|  | ||||
|     where ``credentials`` is a base64-encoded string of ``<username>:<password>`` | ||||
|  | ||||
| 2.  Session authentication | ||||
|  | ||||
|     When you're logged into paperless in your browser, you're automatically | ||||
|     logged into the API as well and don't need to provide any authorization | ||||
|     headers. | ||||
|  | ||||
| 3.  Token authentication | ||||
|  | ||||
|     Paperless also offers an endpoint to acquire authentication tokens. | ||||
|  | ||||
|     POST a username and password as a form or json string to ``/api/token/`` | ||||
|     and paperless will respond with a token, if the login data is correct. | ||||
|     This token can be used to authenticate other requests with the | ||||
|     following HTTP header: | ||||
|  | ||||
|     .. code:: | ||||
|  | ||||
|         Authorization: Token <token> | ||||
|  | ||||
|     Tokens can be managed and revoked in the paperless admin. | ||||
|  | ||||
| Searching for documents | ||||
| ####################### | ||||
|  | ||||
| Full text searching is available on the ``/api/documents/`` endpoint. Two specific | ||||
| query parameters cause the API to return full text search results: | ||||
|  | ||||
| *   ``/api/documents/?query=your%20search%20query``: Search for a document using a full text query. | ||||
|     For details on the syntax, see :ref:`basic-usage_searching`. | ||||
|  | ||||
| *   ``/api/documents/?more_like=1234``: Search for documents similar to the document with id 1234. | ||||
|  | ||||
| Pagination works exactly the same as it does for normal requests on this endpoint. | ||||
|  | ||||
| Certain limitations apply to full text queries: | ||||
|  | ||||
| *   Results are always sorted by search score. The results matching the query best will show up first. | ||||
|  | ||||
| *   Only a small subset of filtering parameters are supported. | ||||
|  | ||||
| Furthermore, each returned document has an additional ``__search_hit__`` attribute with various information | ||||
| about the search results: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     { | ||||
|         "count": 31, | ||||
|         "next": "http://localhost:8000/api/documents/?page=2&query=test", | ||||
|         "previous": null, | ||||
|         "results": [ | ||||
|  | ||||
|             ... | ||||
|  | ||||
|             { | ||||
|                 "id": 123, | ||||
|                 "title": "title", | ||||
|                 "content": "content", | ||||
|  | ||||
|                 ... | ||||
|  | ||||
|                 "__search_hit__": { | ||||
|                     "score": 0.343, | ||||
|                     "highlights": "text <span class=\"match\">Test</span> text", | ||||
|                     "rank": 23 | ||||
|                 } | ||||
|             }, | ||||
|  | ||||
|             ... | ||||
|  | ||||
|         ] | ||||
|     } | ||||
|  | ||||
| *   ``score`` is an indication how well this document matches the query relative to the other search results. | ||||
| *   ``highlights`` is an excerpt from the document content and highlights the search terms with ``<span>`` tags as shown above. | ||||
| *   ``rank`` is the index of the search results. The first result will have rank 0. | ||||
|  | ||||
| ``/api/search/autocomplete/`` | ||||
| ============================= | ||||
|  | ||||
| Get auto completions for a partial search term. | ||||
|  | ||||
| Query parameters: | ||||
|  | ||||
| *   ``term``: The incomplete term. | ||||
| *   ``limit``: Amount of results. Defaults to 10. | ||||
|  | ||||
| Results returned by the endpoint are ordered by importance of the term in the | ||||
| document index. The first result is the term that has the highest Tf/Idf score | ||||
| in the index. | ||||
|  | ||||
| .. code:: json | ||||
|  | ||||
|     [ | ||||
|         "term1", | ||||
|         "term3", | ||||
|         "term6", | ||||
|         "term4" | ||||
|     ] | ||||
|  | ||||
|  | ||||
| .. _api-file_uploads: | ||||
|  | ||||
| POSTing documents | ||||
| ################# | ||||
|  | ||||
| The API provides a special endpoint for file uploads: | ||||
|  | ||||
| ``/api/documents/post_document/`` | ||||
|  | ||||
| POST a multipart form to this endpoint, where the form field ``document`` contains | ||||
| the document that you want to upload to paperless. The filename is sanitized and | ||||
| then used to store the document in a temporary directory, and the consumer will | ||||
| be instructed to consume the document from there. | ||||
|  | ||||
| The endpoint supports the following optional form fields: | ||||
|  | ||||
| *   ``title``: Specify a title that the consumer should use for the document. | ||||
| *   ``created``: Specify a DateTime where the document was created (e.g. "2016-04-19" or "2016-04-19 06:15:00+02:00"). | ||||
| *   ``correspondent``: Specify the ID of a correspondent that the consumer should use for the document. | ||||
| *   ``document_type``: Similar to correspondent. | ||||
| *   ``tags``: Similar to correspondent. Specify this multiple times to have multiple tags added | ||||
|     to the document. | ||||
|  | ||||
|  | ||||
| The endpoint will immediately return "OK" if the document consumption process | ||||
| was started successfully. No additional status information about the consumption | ||||
| process itself is available, since that happens in a different process. | ||||
|  | ||||
|  | ||||
| .. _api-versioning: | ||||
|  | ||||
| API Versioning | ||||
| ############## | ||||
|  | ||||
| The REST API is versioned since Paperless-ngx 1.3.0. | ||||
|  | ||||
| * Versioning ensures that changes to the API don't break older clients. | ||||
| * Clients specify the specific version of the API they wish to use with every request and Paperless will handle the request using the specified API version. | ||||
| * Even if the underlying data model changes, older API versions will always serve compatible data. | ||||
| * If no version is specified, Paperless will serve version 1 to ensure compatibility with older clients that do not request a specific API version. | ||||
|  | ||||
| API versions are specified by submitting an additional HTTP ``Accept`` header with every request: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     Accept: application/json; version=6 | ||||
|  | ||||
| If an invalid version is specified, Paperless 1.3.0 will respond with "406 Not Acceptable" and an error message in the body. | ||||
| Earlier versions of Paperless will serve API version 1 regardless of whether a version is specified via the ``Accept`` header. | ||||
|  | ||||
| If a client wishes to verify whether it is compatible with any given server, the following procedure should be performed: | ||||
|  | ||||
| 1.  Perform an *authenticated* request against any API endpoint. If the server is on version 1.3.0 or newer, the server will | ||||
|     add two custom headers to the response: | ||||
|  | ||||
|     .. code:: | ||||
|  | ||||
|         X-Api-Version: 2 | ||||
|         X-Version: 1.3.0 | ||||
|  | ||||
| 2.  Determine whether the client is compatible with this server based on the presence/absence of these headers and their values if present. | ||||
|  | ||||
|  | ||||
| API Changelog | ||||
| ============= | ||||
|  | ||||
| Version 1 | ||||
| --------- | ||||
|  | ||||
| Initial API version. | ||||
|  | ||||
| Version 2 | ||||
| --------- | ||||
|  | ||||
| * Added field ``Tag.color``. This read/write string field contains a hex color such as ``#a6cee3``. | ||||
| * Added read-only field ``Tag.text_color``. This field contains the text color to use for a specific tag, which is either black or white depending on the brightness of ``Tag.color``. | ||||
| * Removed field ``Tag.colour``. | ||||
							
								
								
									
										36
									
								
								docs/assets/extra.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,36 @@ | ||||
| :root > * { | ||||
|     --md-primary-fg-color: #17541f; | ||||
|     --md-primary-fg-color--dark: #17541f; | ||||
|     --md-primary-fg-color--light: #17541f; | ||||
|     --md-accent-fg-color: #2b8a38; | ||||
|     --md-typeset-a-color: #21652a; | ||||
| } | ||||
|  | ||||
| [data-md-color-scheme="slate"] { | ||||
|     --md-hue: 222; | ||||
| } | ||||
|  | ||||
| @media (min-width: 400px) { | ||||
|     .grid-left { | ||||
|         width: 33%; | ||||
|         float: left; | ||||
|     } | ||||
|     .grid-right { | ||||
|         width: 62%; | ||||
|         margin-left: 4%; | ||||
|         float: left; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .grid-left > p { | ||||
|     margin-bottom: 2rem; | ||||
| } | ||||
|  | ||||
|  | ||||
| .grid-right p { | ||||
|     margin: 0; | ||||
| } | ||||
|  | ||||
| .index-callout { | ||||
|     margin-right: .5rem; | ||||
| } | ||||
							
								
								
									
										12
									
								
								docs/assets/logo.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,12 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 27.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 1000 1000" style="enable-background:new 0 0 1000 1000;" xml:space="preserve"> | ||||
| <style type="text/css"> | ||||
| 	.st0{fill:#FFFFFF;} | ||||
| </style> | ||||
| <path class="st0" d="M299,891.7c-4.2-19.8-12.5-59.6-13.6-59.6c-176.7-105.7-155.8-288.7-97.3-393.4 | ||||
| 	c12.5,131.8,245.8,222.8,109.8,383.9c-1.1,2,6.2,27.2,12.5,50.2c27.2-46,68-101.4,65.8-106.7C208.9,358.2,731.9,326.9,840.6,73.7 | ||||
| 	c49.1,244.8-25.1,623.5-445.5,719.7c-2,1.1-76.3,131.8-79.5,132.9c0-2-31.4-1.1-27.2-11.5C290.7,908.4,294.8,900.1,299,891.7 | ||||
| 	L299,891.7z M293.8,793.4c53.3-61.8-9.4-167.4-47.1-201.9C310.5,701.3,306.3,765.1,293.8,793.4L293.8,793.4z"/> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 869 B | 
							
								
								
									
										68
									
								
								docs/assets/logo_full_black.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,68 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 27.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 2962.2 860.2" style="enable-background:new 0 0 2962.2 860.2;" xml:space="preserve"> | ||||
| <style type="text/css"> | ||||
| 	.st0{fill:#17541F;stroke:#000000;stroke-miterlimit:10;} | ||||
| </style> | ||||
| <path d="M1055.6,639.7v-20.6c-18,20-43.1,30.1-75.4,30.1c-22.4,0-42.8-5.8-61-17.5c-18.3-11.7-32.5-27.8-42.9-48.3 | ||||
| 	c-10.3-20.5-15.5-43.3-15.5-68.4c0-25.1,5.2-48,15.5-68.5s24.6-36.6,42.9-48.3s38.6-17.5,61-17.5c32.3,0,57.5,10,75.4,30.1v-20.6 | ||||
| 	h85.3v249.6L1055.6,639.7L1055.6,639.7z M1059.1,514.9c0-17.4-5.2-31.9-15.5-43.8c-10.3-11.8-23.9-17.7-40.6-17.7 | ||||
| 	c-16.8,0-30.2,5.9-40.4,17.7c-10.2,11.8-15.3,26.4-15.3,43.8c0,17.4,5.1,31.9,15.3,43.8c10.2,11.8,23.6,17.7,40.4,17.7 | ||||
| 	c16.8,0,30.3-5.9,40.6-17.7C1054,546.9,1059.1,532.3,1059.1,514.9z"/> | ||||
| <path d="M1417.8,398.2c18.3,11.7,32.5,27.8,42.9,48.3c10.3,20.5,15.5,43.3,15.5,68.5c0,25.1-5.2,48-15.5,68.4 | ||||
| 	c-10.3,20.5-24.6,36.6-42.9,48.3s-38.6,17.5-61,17.5c-32.3,0-57.5-10-75.4-30.1v165.6h-85.3V390.2h85.3v20.6 | ||||
| 	c18-20,43.1-30.1,75.4-30.1C1379.2,380.7,1399.5,386.6,1417.8,398.2z M1389.5,514.9c0-17.4-5.1-31.9-15.3-43.8 | ||||
| 	c-10.2-11.8-23.6-17.7-40.4-17.7s-30.2,5.9-40.4,17.7c-10.2,11.8-15.3,26.4-15.3,43.8c0,17.4,5.1,31.9,15.3,43.8 | ||||
| 	c10.2,11.8,23.6,17.7,40.4,17.7s30.2-5.9,40.4-17.7S1389.5,532.3,1389.5,514.9z"/> | ||||
| <path d="M1713.6,555.3l53,49.4c-28.1,29.6-66.7,44.4-115.8,44.4c-28.1,0-53-5.8-74.5-17.5s-38.2-27.7-49.8-48 | ||||
| 	c-11.7-20.3-17.7-43.2-18-68.7c0-24.8,5.9-47.5,17.7-68c11.8-20.5,28.1-36.7,48.7-48.5s43.5-17.7,68.7-17.7 | ||||
| 	c24.8,0,47.6,6.1,68.2,18.2s37,29.5,49.1,52.3c12.1,22.7,18.2,49.1,18.2,79l-0.4,11.7h-181.8c3.6,11.4,10.5,20.7,20.9,28.1 | ||||
| 	c10.3,7.3,21.3,11,33,11c14.4,0,26.3-2.2,35.7-6.5C1695.8,570.1,1704.9,563.7,1713.6,555.3z M1596.9,486.2h92.9 | ||||
| 	c-2.1-12.3-7.5-22.1-16.2-29.4s-18.7-11-30.1-11s-21.5,3.7-30.3,11S1599,473.9,1596.9,486.2z"/> | ||||
| <path d="M1908.8,418.4c7.8-10.8,17.2-19,28.3-24.7s22-8.5,32.8-8.5c11.4,0,20,1.6,26,4.9l-10.8,72.7c-8.4-2.1-15.7-3.1-22-3.1 | ||||
| 	c-17.1,0-30.4,4.3-39.9,12.8c-9.6,8.5-14.4,24.2-14.4,46.9v120.3h-85.3V390.2h85.3V418.4L1908.8,418.4z"/> | ||||
| <path d="M2113,258.2v381.5h-85.3V258.2H2113z"/> | ||||
| <path d="M2360.8,555.3l53,49.4c-28.1,29.6-66.7,44.4-115.8,44.4c-28.1,0-53-5.8-74.5-17.5s-38.2-27.7-49.8-48 | ||||
| 	c-11.7-20.3-17.7-43.2-18-68.7c0-24.8,5.9-47.5,17.7-68s28.1-36.7,48.7-48.5c20.6-11.8,43.5-17.7,68.7-17.7 | ||||
| 	c24.8,0,47.6,6.1,68.2,18.2c20.6,12.1,37,29.5,49.1,52.3c12.1,22.7,18.2,49.1,18.2,79l-0.4,11.7h-181.8 | ||||
| 	c3.6,11.4,10.5,20.7,20.9,28.1c10.3,7.3,21.3,11,33,11c14.4,0,26.3-2.2,35.7-6.5C2343.1,570.1,2352.1,563.7,2360.8,555.3z | ||||
| 	 M2244.1,486.2h92.9c-2.1-12.3-7.5-22.1-16.2-29.4s-18.7-11-30.1-11s-21.5,3.7-30.3,11C2251.7,464.1,2246.2,473.9,2244.1,486.2z"/> | ||||
| <path d="M2565.9,446.3c-9.9,0-17.1,1.1-21.5,3.4c-4.5,2.2-6.7,5.9-6.7,11s3.4,8.8,10.3,11.2c6.9,2.4,18,4.9,33.2,7.6 | ||||
| 	c20,3,37,6.7,50.9,11.2s26,12.1,36.1,22.9c10.2,10.8,15.3,25.9,15.3,45.3c0,29.9-10.9,52.4-32.8,67.6 | ||||
| 	c-21.8,15.1-50.3,22.7-85.3,22.7c-25.7,0-49.5-3.7-71.4-11c-21.8-7.3-37.4-14.7-46.7-22.2l33.7-60.6c10.2,9,23.4,15.8,39.7,20.4 | ||||
| 	c16.3,4.6,31.3,7,45.1,7c19.7,0,29.6-5.2,29.6-15.7c0-5.4-3.3-9.4-9.9-11.9c-6.6-2.5-17.2-5.2-31.9-7.9c-18.9-3.3-34.9-7.2-48-11.7 | ||||
| 	c-13.2-4.5-24.6-12.2-34.3-23.1c-9.7-10.9-14.6-26-14.6-45.1c0-27.2,9.7-48.5,29-63.7c19.3-15.3,46-22.9,80.1-22.9 | ||||
| 	c23.3,0,44.4,3.6,63.3,10.8c18.9,7.2,34,14.5,45.3,22l-32.8,58.8c-10.8-7.5-23.2-13.7-37.3-18.6 | ||||
| 	C2590.5,448.7,2577.6,446.3,2565.9,446.3z"/> | ||||
| <path d="M2817.3,446.3c-9.9,0-17.1,1.1-21.5,3.4c-4.5,2.2-6.7,5.9-6.7,11s3.4,8.8,10.3,11.2c6.9,2.4,18,4.9,33.2,7.6 | ||||
| 	c20,3,37,6.7,50.9,11.2s26,12.1,36.1,22.9c10.2,10.8,15.3,25.9,15.3,45.3c0,29.9-10.9,52.4-32.8,67.6 | ||||
| 	c-21.8,15.1-50.3,22.7-85.3,22.7c-25.7,0-49.5-3.7-71.4-11c-21.8-7.3-37.4-14.7-46.7-22.2l33.7-60.6c10.2,9,23.4,15.8,39.7,20.4 | ||||
| 	c16.3,4.6,31.3,7,45.1,7c19.8,0,29.6-5.2,29.6-15.7c0-5.4-3.3-9.4-9.9-11.9c-6.6-2.5-17.2-5.2-31.9-7.9c-18.9-3.3-34.9-7.2-48-11.7 | ||||
| 	c-13.2-4.5-24.6-12.2-34.3-23.1c-9.7-10.9-14.6-26-14.6-45.1c0-27.2,9.7-48.5,29-63.7c19.3-15.3,46-22.9,80.1-22.9 | ||||
| 	c23.3,0,44.4,3.6,63.3,10.8c18.9,7.2,34,14.5,45.3,22l-32.8,58.8c-10.8-7.5-23.2-13.7-37.3-18.6 | ||||
| 	C2841.8,448.7,2828.9,446.3,2817.3,446.3z"/> | ||||
| <g> | ||||
| 	<path d="M2508,724h60.2v17.3H2508V724z"/> | ||||
| 	<path d="M2629.2,694.4c4.9-2,10.2-3.1,16-3.1c10.9,0,19.5,3.4,25.9,10.2s9.6,16.7,9.6,29.6v57.3h-19.6v-52.6 | ||||
| 		c0-9.3-1.7-16.2-5.1-20.7c-3.4-4.5-9.1-6.7-17-6.7c-6.5,0-11.8,2.4-16.1,7.1c-4.3,4.8-6.4,11.5-6.4,20.2v52.6h-19.6v-94.6h19.6v9.5 | ||||
| 		C2620.2,699.4,2624.4,696.4,2629.2,694.4z"/> | ||||
| 	<path d="M2790.3,833.2c-8.6,6.8-19.4,10.2-32.3,10.2c-7.9,0-15.2-1.4-21.9-4.1s-12.1-6.8-16.3-12.2s-6.6-11.9-7.1-19.6h19.6 | ||||
| 		c0.7,6.1,3.5,10.8,8.4,13.9c4.9,3.2,10.7,4.8,17.4,4.8c7,0,13.1-2,18.2-6c5.1-4,7.7-10.3,7.7-18.9v-24.7c-3.6,3.4-8,6.2-13.3,8.2 | ||||
| 		c-5.2,2.1-10.7,3.1-16.3,3.1c-8.7,0-16.6-2.1-23.7-6.4c-7.1-4.3-12.6-10-16.7-17.3c-4-7.3-6-15.5-6-24.6s2-17.3,6-24.7 | ||||
| 		s9.6-13.2,16.7-17.4c7.1-4.3,15-6.4,23.7-6.4c5.7,0,11.1,1,16.3,3.1s9.6,4.8,13.3,8.2v-8.8h19.4v107.8 | ||||
| 		C2803.2,815.9,2798.9,826.4,2790.3,833.2z M2782.2,755.7c2.6-4.7,3.8-10,3.8-15.9s-1.3-11.2-3.8-16c-2.6-4.8-6.1-8.5-10.5-11.1 | ||||
| 		c-4.5-2.7-9.5-4-15.1-4c-5.8,0-10.9,1.4-15.4,4.3c-4.5,2.8-7.9,6.6-10.3,11.4c-2.4,4.8-3.6,9.9-3.6,15.5c0,5.4,1.2,10.5,3.6,15.3 | ||||
| 		c2.4,4.8,5.8,8.6,10.3,11.5s9.6,4.3,15.4,4.3c5.6,0,10.6-1.4,15.1-4.1C2776.1,764.1,2779.6,760.4,2782.2,755.7z"/> | ||||
| 	<path d="M2843.5,788.4h-21.6l37.9-48l-36.4-46.6h22.6l25.7,33.3l25.8-33.3h21.6l-36.2,45.9l37.9,48.6h-22.6l-27.4-35L2843.5,788.4z | ||||
| 		"/> | ||||
| </g> | ||||
| <path d="M835.8,319.2c-11.5-18.9-27.4-33.7-47.6-44.7c-20.2-10.9-43-16.4-68.5-16.4h-90.6c-8.6,39.6-21.3,77.2-38,112.4 | ||||
| 	c-10,21-21.3,41-33.9,59.9v209.2H647v-135h72.7c25.4,0,48.3-5.5,68.5-16.4s36.1-25.8,47.6-44.7c11.5-18.9,17.3-39.5,17.3-61.9 | ||||
| 	C853.1,358.9,847.4,338.1,835.8,319.2z M747,416.6c-9.4,9-21.8,13.5-37,13.5l-62.8,0.4v-93.4l62.8-0.4c15.3,0,27.6,4.5,37,13.5 | ||||
| 	s14.1,20,14.1,33.2C761.1,396.6,756.4,407.7,747,416.6z"/> | ||||
| <path class="st0" d="M164.7,698.7c-3.5-16.5-10.4-49.6-11.3-49.6c-147.1-88-129.7-240.3-81-327.4C82.8,431.4,277,507.1,163.8,641.2 | ||||
| 	c-0.9,1.7,5.2,22.6,10.4,41.8c22.6-38.3,56.6-84.4,54.8-88.8C89.7,254.7,525,228.6,615.5,17.9c40.9,203.7-20.9,518.9-370.8,599 | ||||
| 	c-1.7,0.9-63.5,109.7-66.2,110.6c0-1.7-26.1-0.9-22.6-9.6C157.8,712.6,161.2,705.7,164.7,698.7L164.7,698.7z M160.4,616.9 | ||||
| 	c44.4-51.4-7.8-139.3-39.2-168C174.3,540.2,170.8,593.3,160.4,616.9L160.4,616.9z"/> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 6.3 KiB | 
							
								
								
									
										69
									
								
								docs/assets/logo_full_white.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,69 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 27.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 2962.2 860.2" style="enable-background:new 0 0 2962.2 860.2;" xml:space="preserve"> | ||||
| <style type="text/css"> | ||||
| 	.st0{fill:#FFFFFF;stroke:#000000;stroke-miterlimit:10;} | ||||
| 	.st1{fill:#17541F;stroke:#000000;stroke-miterlimit:10;} | ||||
| </style> | ||||
| <path class="st0" d="M1055.6,639.7v-20.6c-18,20-43.1,30.1-75.4,30.1c-22.4,0-42.8-5.8-61-17.5c-18.3-11.7-32.5-27.8-42.9-48.3 | ||||
| 	c-10.3-20.5-15.5-43.3-15.5-68.4c0-25.1,5.2-48,15.5-68.5s24.6-36.6,42.9-48.3s38.6-17.5,61-17.5c32.3,0,57.5,10,75.4,30.1v-20.6 | ||||
| 	h85.3v249.6L1055.6,639.7L1055.6,639.7z M1059.1,514.9c0-17.4-5.2-31.9-15.5-43.8c-10.3-11.8-23.9-17.7-40.6-17.7 | ||||
| 	c-16.8,0-30.2,5.9-40.4,17.7c-10.2,11.8-15.3,26.4-15.3,43.8c0,17.4,5.1,31.9,15.3,43.8c10.2,11.8,23.6,17.7,40.4,17.7 | ||||
| 	c16.8,0,30.3-5.9,40.6-17.7C1054,546.9,1059.1,532.3,1059.1,514.9z"/> | ||||
| <path class="st0" d="M1417.8,398.2c18.3,11.7,32.5,27.8,42.9,48.3c10.3,20.5,15.5,43.3,15.5,68.5c0,25.1-5.2,48-15.5,68.4 | ||||
| 	c-10.3,20.5-24.6,36.6-42.9,48.3s-38.6,17.5-61,17.5c-32.3,0-57.5-10-75.4-30.1v165.6h-85.3V390.2h85.3v20.6 | ||||
| 	c18-20,43.1-30.1,75.4-30.1C1379.2,380.7,1399.5,386.6,1417.8,398.2z M1389.5,514.9c0-17.4-5.1-31.9-15.3-43.8 | ||||
| 	c-10.2-11.8-23.6-17.7-40.4-17.7s-30.2,5.9-40.4,17.7c-10.2,11.8-15.3,26.4-15.3,43.8c0,17.4,5.1,31.9,15.3,43.8 | ||||
| 	c10.2,11.8,23.6,17.7,40.4,17.7s30.2-5.9,40.4-17.7S1389.5,532.3,1389.5,514.9z"/> | ||||
| <path class="st0" d="M1713.6,555.3l53,49.4c-28.1,29.6-66.7,44.4-115.8,44.4c-28.1,0-53-5.8-74.5-17.5s-38.2-27.7-49.8-48 | ||||
| 	c-11.7-20.3-17.7-43.2-18-68.7c0-24.8,5.9-47.5,17.7-68c11.8-20.5,28.1-36.7,48.7-48.5s43.5-17.7,68.7-17.7 | ||||
| 	c24.8,0,47.6,6.1,68.2,18.2s37,29.5,49.1,52.3c12.1,22.7,18.2,49.1,18.2,79l-0.4,11.7h-181.8c3.6,11.4,10.5,20.7,20.9,28.1 | ||||
| 	c10.3,7.3,21.3,11,33,11c14.4,0,26.3-2.2,35.7-6.5C1695.8,570.1,1704.9,563.7,1713.6,555.3z M1596.9,486.2h92.9 | ||||
| 	c-2.1-12.3-7.5-22.1-16.2-29.4s-18.7-11-30.1-11s-21.5,3.7-30.3,11S1599,473.9,1596.9,486.2z"/> | ||||
| <path class="st0" d="M1908.8,418.4c7.8-10.8,17.2-19,28.3-24.7s22-8.5,32.8-8.5c11.4,0,20,1.6,26,4.9l-10.8,72.7 | ||||
| 	c-8.4-2.1-15.7-3.1-22-3.1c-17.1,0-30.4,4.3-39.9,12.8c-9.6,8.5-14.4,24.2-14.4,46.9v120.3h-85.3V390.2h85.3V418.4L1908.8,418.4z"/> | ||||
| <path class="st0" d="M2113,258.2v381.5h-85.3V258.2H2113z"/> | ||||
| <path class="st0" d="M2360.8,555.3l53,49.4c-28.1,29.6-66.7,44.4-115.8,44.4c-28.1,0-53-5.8-74.5-17.5s-38.2-27.7-49.8-48 | ||||
| 	c-11.7-20.3-17.7-43.2-18-68.7c0-24.8,5.9-47.5,17.7-68s28.1-36.7,48.7-48.5c20.6-11.8,43.5-17.7,68.7-17.7 | ||||
| 	c24.8,0,47.6,6.1,68.2,18.2c20.6,12.1,37,29.5,49.1,52.3c12.1,22.7,18.2,49.1,18.2,79l-0.4,11.7h-181.8 | ||||
| 	c3.6,11.4,10.5,20.7,20.9,28.1c10.3,7.3,21.3,11,33,11c14.4,0,26.3-2.2,35.7-6.5C2343.1,570.1,2352.1,563.7,2360.8,555.3z | ||||
| 	 M2244.1,486.2h92.9c-2.1-12.3-7.5-22.1-16.2-29.4s-18.7-11-30.1-11s-21.5,3.7-30.3,11C2251.7,464.1,2246.2,473.9,2244.1,486.2z"/> | ||||
| <path class="st0" d="M2565.9,446.3c-9.9,0-17.1,1.1-21.5,3.4c-4.5,2.2-6.7,5.9-6.7,11s3.4,8.8,10.3,11.2c6.9,2.4,18,4.9,33.2,7.6 | ||||
| 	c20,3,37,6.7,50.9,11.2s26,12.1,36.1,22.9c10.2,10.8,15.3,25.9,15.3,45.3c0,29.9-10.9,52.4-32.8,67.6 | ||||
| 	c-21.8,15.1-50.3,22.7-85.3,22.7c-25.7,0-49.5-3.7-71.4-11c-21.8-7.3-37.4-14.7-46.7-22.2l33.7-60.6c10.2,9,23.4,15.8,39.7,20.4 | ||||
| 	c16.3,4.6,31.3,7,45.1,7c19.7,0,29.6-5.2,29.6-15.7c0-5.4-3.3-9.4-9.9-11.9c-6.6-2.5-17.2-5.2-31.9-7.9c-18.9-3.3-34.9-7.2-48-11.7 | ||||
| 	c-13.2-4.5-24.6-12.2-34.3-23.1c-9.7-10.9-14.6-26-14.6-45.1c0-27.2,9.7-48.5,29-63.7c19.3-15.3,46-22.9,80.1-22.9 | ||||
| 	c23.3,0,44.4,3.6,63.3,10.8c18.9,7.2,34,14.5,45.3,22l-32.8,58.8c-10.8-7.5-23.2-13.7-37.3-18.6 | ||||
| 	C2590.5,448.7,2577.6,446.3,2565.9,446.3z"/> | ||||
| <path class="st0" d="M2817.3,446.3c-9.9,0-17.1,1.1-21.5,3.4c-4.5,2.2-6.7,5.9-6.7,11s3.4,8.8,10.3,11.2c6.9,2.4,18,4.9,33.2,7.6 | ||||
| 	c20,3,37,6.7,50.9,11.2s26,12.1,36.1,22.9c10.2,10.8,15.3,25.9,15.3,45.3c0,29.9-10.9,52.4-32.8,67.6 | ||||
| 	c-21.8,15.1-50.3,22.7-85.3,22.7c-25.7,0-49.5-3.7-71.4-11c-21.8-7.3-37.4-14.7-46.7-22.2l33.7-60.6c10.2,9,23.4,15.8,39.7,20.4 | ||||
| 	c16.3,4.6,31.3,7,45.1,7c19.8,0,29.6-5.2,29.6-15.7c0-5.4-3.3-9.4-9.9-11.9c-6.6-2.5-17.2-5.2-31.9-7.9c-18.9-3.3-34.9-7.2-48-11.7 | ||||
| 	c-13.2-4.5-24.6-12.2-34.3-23.1c-9.7-10.9-14.6-26-14.6-45.1c0-27.2,9.7-48.5,29-63.7c19.3-15.3,46-22.9,80.1-22.9 | ||||
| 	c23.3,0,44.4,3.6,63.3,10.8c18.9,7.2,34,14.5,45.3,22l-32.8,58.8c-10.8-7.5-23.2-13.7-37.3-18.6 | ||||
| 	C2841.8,448.7,2828.9,446.3,2817.3,446.3z"/> | ||||
| <g> | ||||
| 	<path class="st0" d="M2508,724h60.2v17.3H2508V724z"/> | ||||
| 	<path class="st0" d="M2629.2,694.4c4.9-2,10.2-3.1,16-3.1c10.9,0,19.5,3.4,25.9,10.2s9.6,16.7,9.6,29.6v57.3h-19.6v-52.6 | ||||
| 		c0-9.3-1.7-16.2-5.1-20.7c-3.4-4.5-9.1-6.7-17-6.7c-6.5,0-11.8,2.4-16.1,7.1c-4.3,4.8-6.4,11.5-6.4,20.2v52.6h-19.6v-94.6h19.6v9.5 | ||||
| 		C2620.2,699.4,2624.4,696.4,2629.2,694.4z"/> | ||||
| 	<path class="st0" d="M2790.3,833.2c-8.6,6.8-19.4,10.2-32.3,10.2c-7.9,0-15.2-1.4-21.9-4.1s-12.1-6.8-16.3-12.2s-6.6-11.9-7.1-19.6 | ||||
| 		h19.6c0.7,6.1,3.5,10.8,8.4,13.9c4.9,3.2,10.7,4.8,17.4,4.8c7,0,13.1-2,18.2-6c5.1-4,7.7-10.3,7.7-18.9v-24.7 | ||||
| 		c-3.6,3.4-8,6.2-13.3,8.2c-5.2,2.1-10.7,3.1-16.3,3.1c-8.7,0-16.6-2.1-23.7-6.4c-7.1-4.3-12.6-10-16.7-17.3c-4-7.3-6-15.5-6-24.6 | ||||
| 		s2-17.3,6-24.7s9.6-13.2,16.7-17.4c7.1-4.3,15-6.4,23.7-6.4c5.7,0,11.1,1,16.3,3.1s9.6,4.8,13.3,8.2v-8.8h19.4v107.8 | ||||
| 		C2803.2,815.9,2798.9,826.4,2790.3,833.2z M2782.2,755.7c2.6-4.7,3.8-10,3.8-15.9s-1.3-11.2-3.8-16c-2.6-4.8-6.1-8.5-10.5-11.1 | ||||
| 		c-4.5-2.7-9.5-4-15.1-4c-5.8,0-10.9,1.4-15.4,4.3c-4.5,2.8-7.9,6.6-10.3,11.4c-2.4,4.8-3.6,9.9-3.6,15.5c0,5.4,1.2,10.5,3.6,15.3 | ||||
| 		c2.4,4.8,5.8,8.6,10.3,11.5s9.6,4.3,15.4,4.3c5.6,0,10.6-1.4,15.1-4.1C2776.1,764.1,2779.6,760.4,2782.2,755.7z"/> | ||||
| 	<path class="st0" d="M2843.5,788.4h-21.6l37.9-48l-36.4-46.6h22.6l25.7,33.3l25.8-33.3h21.6l-36.2,45.9l37.9,48.6h-22.6l-27.4-35 | ||||
| 		L2843.5,788.4z"/> | ||||
| </g> | ||||
| <path class="st0" d="M835.8,319.2c-11.5-18.9-27.4-33.7-47.6-44.7c-20.2-10.9-43-16.4-68.5-16.4h-90.6c-8.6,39.6-21.3,77.2-38,112.4 | ||||
| 	c-10,21-21.3,41-33.9,59.9v209.2H647v-135h72.7c25.4,0,48.3-5.5,68.5-16.4s36.1-25.8,47.6-44.7c11.5-18.9,17.3-39.5,17.3-61.9 | ||||
| 	C853.1,358.9,847.4,338.1,835.8,319.2z M747,416.6c-9.4,9-21.8,13.5-37,13.5l-62.8,0.4v-93.4l62.8-0.4c15.3,0,27.6,4.5,37,13.5 | ||||
| 	s14.1,20,14.1,33.2C761.1,396.6,756.4,407.7,747,416.6z"/> | ||||
| <path class="st1" d="M164.7,698.7c-3.5-16.5-10.4-49.6-11.3-49.6c-147.1-88-129.7-240.3-81-327.4C82.8,431.4,277,507.1,163.8,641.2 | ||||
| 	c-0.9,1.7,5.2,22.6,10.4,41.8c22.6-38.3,56.6-84.4,54.8-88.8C89.7,254.7,525,228.6,615.5,17.9c40.9,203.7-20.9,518.9-370.8,599 | ||||
| 	c-1.7,0.9-63.5,109.7-66.2,110.6c0-1.7-26.1-0.9-22.6-9.6C157.8,712.6,161.2,705.7,164.7,698.7L164.7,698.7z M160.4,616.9 | ||||
| 	c44.4-51.4-7.8-139.3-39.2-168C174.3,540.2,170.8,593.3,160.4,616.9L160.4,616.9z"/> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 6.5 KiB | 
| Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB | 
| Before Width: | Height: | Size: 661 KiB After Width: | Height: | Size: 661 KiB | 
| Before Width: | Height: | Size: 457 KiB After Width: | Height: | Size: 457 KiB | 
| Before Width: | Height: | Size: 436 KiB After Width: | Height: | Size: 436 KiB | 
| Before Width: | Height: | Size: 462 KiB After Width: | Height: | Size: 462 KiB | 
| Before Width: | Height: | Size: 608 KiB After Width: | Height: | Size: 608 KiB | 
| Before Width: | Height: | Size: 698 KiB After Width: | Height: | Size: 698 KiB | 
| Before Width: | Height: | Size: 706 KiB After Width: | Height: | Size: 706 KiB | 
| Before Width: | Height: | Size: 480 KiB After Width: | Height: | Size: 480 KiB | 
| Before Width: | Height: | Size: 680 KiB After Width: | Height: | Size: 680 KiB | 
| Before Width: | Height: | Size: 686 KiB After Width: | Height: | Size: 686 KiB | 
| Before Width: | Height: | Size: 848 KiB After Width: | Height: | Size: 848 KiB | 
| Before Width: | Height: | Size: 703 KiB After Width: | Height: | Size: 703 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docs/assets/screenshots/mail-rules-edited.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 76 KiB | 
| Before Width: | Height: | Size: 388 KiB After Width: | Height: | Size: 388 KiB | 
| Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB | 
| Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB | 
| Before Width: | Height: | Size: 517 KiB After Width: | Height: | Size: 517 KiB | 
| @@ -577,7 +577,7 @@ | ||||
|  | ||||
| - Allow setting more than one tag in mail rules | ||||
|   [\@jonasc](https://github.com/jonasc) ([\#270](https://github.com/paperless-ngx/paperless-ngx/pull/270)) | ||||
| - Global drag\'n\'drop [\@shamoon](https://github.com/shamoon) | ||||
| - Global drag'n'drop [\@shamoon](https://github.com/shamoon) | ||||
|   ([\#283](https://github.com/paperless-ngx/paperless-ngx/pull/283)) | ||||
| - Fix: download buttons should disable while waiting | ||||
|   [\@shamoon](https://github.com/shamoon) ([\#630](https://github.com/paperless-ngx/paperless-ngx/pull/630)) | ||||
| @@ -607,7 +607,7 @@ | ||||
|  | ||||
| ### Bug Fixes | ||||
|  | ||||
| - Add \"localhost\" to ALLOWED_HOSTS | ||||
| - Add "localhost" to ALLOWED_HOSTS | ||||
|   [\@gador](https://github.com/gador) ([\#700](https://github.com/paperless-ngx/paperless-ngx/pull/700)) | ||||
| - Fix: scanners table [\@qcasey](https://github.com/qcasey) ([\#690](https://github.com/paperless-ngx/paperless-ngx/pull/690)) | ||||
| - Adds wait for file before consuming | ||||
| @@ -644,7 +644,7 @@ | ||||
|   ([\#393](https://github.com/paperless-ngx/paperless-ngx/pull/393)) | ||||
| - Fix filterable dropdown buttons arent translated | ||||
|   [\@shamoon](https://github.com/shamoon) ([\#366](https://github.com/paperless-ngx/paperless-ngx/pull/366)) | ||||
| - Fix 224: \"Auto-detected date is day before receipt date\" | ||||
| - Fix 224: "Auto-detected date is day before receipt date" | ||||
|   [\@a17t](https://github.com/a17t) ([\#246](https://github.com/paperless-ngx/paperless-ngx/pull/246)) | ||||
| - Fix minor sphinx errors [\@shamoon](https://github.com/shamoon) | ||||
|   ([\#322](https://github.com/paperless-ngx/paperless-ngx/pull/322)) | ||||
| @@ -706,7 +706,7 @@ This is the first release of the revived paperless-ngx project 🎉. Thank | ||||
| you to everyone on the paperless-ngx team for your initiative and | ||||
| excellent teamwork! | ||||
|  | ||||
| Version 1.6.0 merges several pending PRs from jonaswinkler\'s repo and | ||||
| Version 1.6.0 merges several pending PRs from jonaswinkler's repo and | ||||
| includes new feature updates and bug fixes. Major backend and UI changes | ||||
| include: | ||||
|  | ||||
| @@ -726,14 +726,14 @@ include: | ||||
|   when document list is reloading ([jonaswinkler\#1297](https://github.com/jonaswinkler/paperless-ng/pull/1297)). | ||||
| - [\@shamoon](https://github.com/shamoon) improved the PDF viewer on | ||||
|   mobile ([\#2](https://github.com/paperless-ngx/paperless-ngx/pull/2)). | ||||
| - [\@shamoon](https://github.com/shamoon) added \'any\' / \'all\' and | ||||
|   \'not\' filtering with tags ([\#10](https://github.com/paperless-ngx/paperless-ngx/pull/10)). | ||||
| - [\@shamoon](https://github.com/shamoon) added 'any' / 'all' and | ||||
|   'not' filtering with tags ([\#10](https://github.com/paperless-ngx/paperless-ngx/pull/10)). | ||||
| - [\@shamoon](https://github.com/shamoon) added warnings for unsaved | ||||
|   changes, with smart edit buttons ([\#13](https://github.com/paperless-ngx/paperless-ngx/pull/13)). | ||||
| - [\@benjaminfrank](https://github.com/benjaminfrank) enabled a | ||||
|   non-root access to port 80 via systemd ([\#18](https://github.com/paperless-ngx/paperless-ngx/pull/18)). | ||||
| - [\@tribut](https://github.com/tribut) added simple \"delete to | ||||
|   trash\" functionality ([\#24](https://github.com/paperless-ngx/paperless-ngx/pull/24)). See `PAPERLESS_TRASH_DIR`. | ||||
| - [\@tribut](https://github.com/tribut) added simple "delete to | ||||
|   trash" functionality ([\#24](https://github.com/paperless-ngx/paperless-ngx/pull/24)). See `PAPERLESS_TRASH_DIR`. | ||||
| - [\@amenk](https://github.com/amenk) fixed the search box overlay | ||||
|   menu on mobile ([\#32](https://github.com/paperless-ngx/paperless-ngx/pull/32)). | ||||
| - [\@dblitt](https://github.com/dblitt) updated the login form to not | ||||
| @@ -909,26 +909,22 @@ This is a maintenance release. | ||||
| - Changes | ||||
|   - Firefox only: Highlight search query in PDF previews. | ||||
|   - New URL pattern for accessing documents by ASN directly | ||||
|     (<http://>\<paperless\>/asn/123) | ||||
|     (<http://><paperless>/asn/123) | ||||
|   - Added logging when executing pre\* and post-consume scripts. | ||||
|   - Better error logging during document consumption. | ||||
|   - Updated python dependencies. | ||||
|   - Automatically inserts typed text when opening \"Create new\" | ||||
|   - Automatically inserts typed text when opening "Create new" | ||||
|     dialogs on the document details page. | ||||
| - Fixes | ||||
|   - Fixed an issue with null characters in the document content. | ||||
|  | ||||
| ::: {.note} | ||||
| ::: {.title} | ||||
| Note | ||||
| ::: | ||||
| !!! note | ||||
|  | ||||
| The changed to the full text searching require you to reindex your | ||||
| documents. _The docker image does this automatically, you don\'t need to | ||||
| documents. _The docker image does this automatically, you don't need to | ||||
| do anything._ To do this, execute the `document_index reindex` | ||||
| management command (see `administration-index`{.interpreted-text | ||||
| role="ref"}). | ||||
| ::: | ||||
|  | ||||
| ### paperless-ng 1.3.2 | ||||
|  | ||||
| @@ -1031,7 +1027,7 @@ This release contains new database migrations. | ||||
|   worker processes of the web server. See | ||||
|   `configuration-docker`{.interpreted-text role="ref"}. | ||||
| - Some more memory usage optimizations. | ||||
| - Don\'t show inbox statistics if no inbox tag is defined. | ||||
| - Don't show inbox statistics if no inbox tag is defined. | ||||
|  | ||||
| ### paperless-ng 1.1.2 | ||||
|  | ||||
| @@ -1051,8 +1047,8 @@ This release contains new database migrations. | ||||
|  | ||||
| This release contains new database migrations. | ||||
|  | ||||
| - Fixed a bug in the sanity checker that would cause it to display \"x | ||||
|   not in list\" errors instead of actual issues. | ||||
| - Fixed a bug in the sanity checker that would cause it to display "x | ||||
|   not in list" errors instead of actual issues. | ||||
| - Fixed a bug with filename generation for archive filenames that | ||||
|   would cause the archive files of two documents to overlap. | ||||
|   - This happened when `PAPERLESS_FILENAME_FORMAT` is used and the | ||||
| @@ -1061,8 +1057,8 @@ This release contains new database migrations. | ||||
|   - Paperless will now store the archive filename in the database as | ||||
|     well instead of deriving it from the original filename, and use | ||||
|     the same logic for detecting and avoiding filename clashes | ||||
|     that\'s also used for original filenames. | ||||
|   - The migrations will repair any missing archive files. If you\'re | ||||
|     that's also used for original filenames. | ||||
|   - The migrations will repair any missing archive files. If you're | ||||
|     using tika, ensure that tika is running while performing the | ||||
|     migration. Docker-compose will take care of that. | ||||
| - Fixed a bug with thumbnail regeneration when TIKA integration was | ||||
| @@ -1070,8 +1066,8 @@ This release contains new database migrations. | ||||
| - Added ASN as a placeholder field to the filename format. | ||||
| - The docker image now comes with built-in shortcuts for most | ||||
|   management commands. These are now the recommended way to execute | ||||
|   management commands, since these also ensure that they\'re always | ||||
|   executed as the paperless user and you\'re less likely to run into | ||||
|   management commands, since these also ensure that they're always | ||||
|   executed as the paperless user and you're less likely to run into | ||||
|   permission issues. See | ||||
|   `utilities-management-commands`{.interpreted-text role="ref"}. | ||||
|  | ||||
| @@ -1093,10 +1089,7 @@ This release contains new database migrations. | ||||
| - Live updates to document lists and saved views when new documents | ||||
|   are added. | ||||
|  | ||||
|   ::: {.hint} | ||||
|   ::: {.title} | ||||
|   Hint | ||||
|   ::: | ||||
|   !!! tip | ||||
|  | ||||
|   For status notifications and live updates to work, paperless now | ||||
|   requires an [ASGI](https://asgi.readthedocs.io/en/latest/)-enabled | ||||
| @@ -1119,7 +1112,6 @@ This release contains new database migrations. | ||||
|  | ||||
|   Apache `mod_wsgi` users, see | ||||
|   `this note <faq-mod_wsgi>`{.interpreted-text role="ref"}. | ||||
|   ::: | ||||
|  | ||||
| - Paperless now offers suggestions for tags, correspondents and types | ||||
|   on the document detail page. | ||||
| @@ -1143,8 +1135,8 @@ This release contains new database migrations. | ||||
|   - Better icon for document previews. | ||||
|   - Better info section in the side bar. | ||||
|   - Paperless no longer logs to the database. Instead, logs are | ||||
|     written to rotating log files. This solves many \"database is | ||||
|     locked\" issues on Raspberry Pi, especially when SQLite is used. | ||||
|     written to rotating log files. This solves many "database is | ||||
|     locked" issues on Raspberry Pi, especially when SQLite is used. | ||||
|   - By default, log files are written to `PAPERLESS_DATA_DIR/log/`. | ||||
|     Logging settings can be adjusted with `PAPERLESS_LOGGING_DIR`, | ||||
|     `PAPERLESS_LOGROTATE_MAX_SIZE` and | ||||
| @@ -1173,7 +1165,7 @@ bug reports coming in, I think that this is reasonably stable. | ||||
|   - Range selection with shift clicking is now possible in the | ||||
|     document list. | ||||
|   - Filtering correspondent, type and tag management pages by name. | ||||
|   - Focus \"Name\" field in dialogs by default. | ||||
|   - Focus "Name" field in dialogs by default. | ||||
|  | ||||
| ### paperless-ng 0.9.14 | ||||
|  | ||||
| @@ -1235,8 +1227,8 @@ paperless. | ||||
|   - Fixed an issue with filenames of downloaded files: Dates where | ||||
|     off by one day due to timezone issues. | ||||
|   - Searching will continue to work even when the index returns | ||||
|     non-existing documents. This resulted in \"Document does not | ||||
|     exist\" errors before. Instead, a warning is logged, indicating | ||||
|     non-existing documents. This resulted in "Document does not | ||||
|     exist" errors before. Instead, a warning is logged, indicating | ||||
|     the issue. | ||||
|   - An issue with the consumer crashing when invalid regular | ||||
|     expression were used was fixed. | ||||
| @@ -1277,11 +1269,11 @@ paperless. | ||||
|     new ASN to a document. | ||||
|   - Form field validation: When providing invalid input in a form | ||||
|     (such as a duplicate ASN or no name), paperless now has visual | ||||
|     indicators and clearer error messages about what\'s wrong. | ||||
|     indicators and clearer error messages about what's wrong. | ||||
|   - Paperless disables buttons with network actions (such as save | ||||
|     and delete) when a network action is active. This indicates that | ||||
|     something is happening and prevents double clicking. | ||||
|   - When using \"Save & next\", the title field is focussed | ||||
|   - When using "Save & next", the title field is focussed | ||||
|     automatically to better support keyboard editing. | ||||
|   - E-Mail: Added filter rule parameters to allow inline attachments | ||||
|     (watch out for mails with inlined images!) and attachment | ||||
| @@ -1290,11 +1282,11 @@ paperless. | ||||
|     Shamoon](https://github.com/shamoon). This is useful for hiding | ||||
|     Paperless behind single sign on applications such as | ||||
|     [authelia](https://www.authelia.com/). | ||||
|   - \"Clear filters\" has been renamed to \"Reset filters\" and now | ||||
|   - "Clear filters" has been renamed to "Reset filters" and now | ||||
|     correctly restores the default filters on saved views. Thanks to | ||||
|     [Michael Shamoon](https://github.com/shamoon) | ||||
| - Fixes | ||||
|   - Paperless was unable to save views when \"Not assigned\" was | ||||
|   - Paperless was unable to save views when "Not assigned" was | ||||
|     chosen in one of the filter dropdowns. | ||||
|   - Clearer error messages when pre and post consumption scripts do | ||||
|     not exist. | ||||
| @@ -1310,7 +1302,7 @@ paperless. | ||||
| ### paperless-ng 0.9.10 | ||||
|  | ||||
| - Bulk editing | ||||
|   - Thanks to [Michael Shamoon](https://github.com/shamoon), we\'ve | ||||
|   - Thanks to [Michael Shamoon](https://github.com/shamoon), we've | ||||
|     got a new interface for the bulk editor. | ||||
|   - There are some configuration options in the settings to alter | ||||
|     the behavior. | ||||
| @@ -1319,7 +1311,7 @@ paperless. | ||||
|     publishes a webmanifest, which is useful for adding the | ||||
|     application to home screens on mobile devices. | ||||
|   - The Paperless-ng logo now navigates to the dashboard. | ||||
|   - Filter for documents that don\'t have any correspondents, types | ||||
|   - Filter for documents that don't have any correspondents, types | ||||
|     or tags assigned. | ||||
|   - Tags, types and correspondents are now sorted case insensitive. | ||||
|   - Lots of preparation work for localization support. | ||||
| @@ -1333,10 +1325,7 @@ paperless. | ||||
|   - The consumer used to stop working when encountering an | ||||
|     incomplete classifier model file. | ||||
|  | ||||
| ::: {.note} | ||||
| ::: {.title} | ||||
| Note | ||||
| ::: | ||||
| !!! note | ||||
|  | ||||
| The bulk delete operations did not update the search index. Therefore, | ||||
| documents that you deleted remained in the index and caused the search | ||||
| @@ -1347,7 +1336,6 @@ However, this change is not retroactive: If you used the delete method | ||||
| of the bulk editor, you need to reindex your search index by | ||||
| `running the management command document_index with the argument reindex <administration-index>`{.interpreted-text | ||||
| role="ref"}. | ||||
| ::: | ||||
|  | ||||
| ### paperless-ng 0.9.9 | ||||
|  | ||||
| @@ -1358,18 +1346,18 @@ Christmas release! | ||||
|   - The following operations are available: Add and remove | ||||
|     correspondents, tags, document types from selected documents, as | ||||
|     well as mass-deleting documents. | ||||
|   - We\'ve got a more fancy UI in the works that makes these | ||||
|     features more accessible, but that\'s not quite ready yet. | ||||
|   - We've got a more fancy UI in the works that makes these | ||||
|     features more accessible, but that's not quite ready yet. | ||||
| - Searching | ||||
|   - Paperless now supports searching for similar documents (\"More | ||||
|     like this\") both from the document detail page as well as from | ||||
|   - Paperless now supports searching for similar documents ("More | ||||
|     like this") both from the document detail page as well as from | ||||
|     individual search results. | ||||
|   - A search score indicates how well a document matches the search | ||||
|     query, or how similar a document is to a given reference | ||||
|     document. | ||||
| - Other additions and changes | ||||
|   - Clarification in the UI that the fields \"Match\" and \"Is | ||||
|     insensitive\" are not relevant for the Auto matching algorithm. | ||||
|   - Clarification in the UI that the fields "Match" and "Is | ||||
|     insensitive" are not relevant for the Auto matching algorithm. | ||||
|   - New select interface for tags, types and correspondents allows | ||||
|     filtering. This also improves tag selection. Thanks again to | ||||
|     [Michael Shamoon](https://github.com/shamoon)! | ||||
| @@ -1450,11 +1438,11 @@ This release focusses primarily on many small issues with the UI. | ||||
|   - Paperless now has proper window titles. | ||||
|   - Fixed an issue with the small cards when more than 7 tags were | ||||
|     used. | ||||
|   - Navigation of the \"Show all\" links adjusted. They navigate to | ||||
|   - Navigation of the "Show all" links adjusted. They navigate to | ||||
|     the saved view now, if available in the sidebar. | ||||
|   - Some indication on the document lists that a filter is active | ||||
|     was added. | ||||
|   - There\'s a new filter to filter for documents that do _not_ have | ||||
|   - There's a new filter to filter for documents that do _not_ have | ||||
|     a certain tag. | ||||
|   - The file upload box now shows upload progress. | ||||
|   - The document edit page was reorganized. | ||||
| @@ -1479,15 +1467,11 @@ This release focusses primarily on many small issues with the UI. | ||||
|     filenames anymore. It will rather append `_01`, `_02`, etc when | ||||
|     it detects duplicate filenames. | ||||
|  | ||||
| ::: {.note} | ||||
| ::: {.title} | ||||
| Note | ||||
| ::: | ||||
| !!! note | ||||
|  | ||||
| The changes to the filename format will apply to newly added documents | ||||
| and changed documents. If you want all files to reflect these changes, | ||||
| execute the `document_renamer` management command. | ||||
| ::: | ||||
|  | ||||
| ### paperless-ng 0.9.5 | ||||
|  | ||||
| @@ -1570,7 +1554,7 @@ primarily. | ||||
|     need to do this once, since the schema of the search index | ||||
|     changed. Paperless keeps the index updated after that whenever | ||||
|     something changes. | ||||
|   - Paperless now has spelling corrections (\"Did you mean\") for | ||||
|   - Paperless now has spelling corrections ("Did you mean") for | ||||
|     miss-typed queries. | ||||
|   - The documentation contains | ||||
|     `information about the query syntax <basic-searching>`{.interpreted-text | ||||
| @@ -1640,7 +1624,7 @@ primarily. | ||||
|   role="ref"} This features will most likely be removed in future | ||||
|   versions. | ||||
| - **Added:** New frontend. Features: | ||||
|   - Single page application: It\'s much more responsive than the | ||||
|   - Single page application: It's much more responsive than the | ||||
|     django admin pages. | ||||
|   - Dashboard. Shows recently scanned documents, or todo notes, or | ||||
|     other documents at wish. Allows uploading of documents. Shows | ||||
| @@ -1662,7 +1646,7 @@ primarily. | ||||
| - **Added:** Archive serial numbers. Assign these to quickly find | ||||
|   documents stored in physical binders. | ||||
| - **Added:** Enabled the internal user management of django. This | ||||
|   isn\'t really a multi user solution, however, it allows more than | ||||
|   isn't really a multi user solution, however, it allows more than | ||||
|   one user to access the website and set some basic permissions / | ||||
|   renew passwords. | ||||
| - **Modified \[breaking\]:** All new mail consumer with customizable | ||||
| @@ -1717,7 +1701,7 @@ primarily. | ||||
| - **Settings:** | ||||
|   - `PAPERLESS_FORGIVING_OCR` is now default and gone. Reason: Even | ||||
|     if `langdetect` fails to detect a language, tesseract still does | ||||
|     a very good job at ocr\'ing a document with the default | ||||
|     a very good job at ocr'ing a document with the default | ||||
|     language. Certain language specifics such as umlauts may not get | ||||
|     picked up properly. | ||||
|   - `PAPERLESS_DEBUG` defaults to `false`. | ||||
| @@ -1798,34 +1782,34 @@ primarily. | ||||
|   [\#442](https://github.com/the-paperless-project/paperless/pull/442). | ||||
| - Added a `.editorconfig` file to better specify coding style. | ||||
| - [Joshua Taillon](https://github.com/jat255) also added some logic to | ||||
|   tie Paperless\' date guessing logic into how it parses file names on | ||||
|   tie Paperless' date guessing logic into how it parses file names on | ||||
|   import. | ||||
|   [\#440](https://github.com/the-paperless-project/paperless/pull/440) | ||||
|  | ||||
| ### 2.5.0 | ||||
|  | ||||
| - **New dependency**: Paperless now optimises thumbnail generation | ||||
|   with [optipng](http://optipng.sourceforge.net/), so you\'ll need to | ||||
|   with [optipng](http://optipng.sourceforge.net/), so you'll need to | ||||
|   install that somewhere in your PATH or declare its location in | ||||
|   `PAPERLESS_OPTIPNG_BINARY`. The Docker image has already been | ||||
|   updated on the Docker Hub, so you just need to pull the latest one | ||||
|   from there if you\'re a Docker user. | ||||
| - \"Login free\" instances of Paperless were breaking whenever you | ||||
|   from there if you're a Docker user. | ||||
| - "Login free" instances of Paperless were breaking whenever you | ||||
|   tried to edit objects in the admin: adding/deleting tags or | ||||
|   correspondents, or even fixing spelling. This was due to the \"user | ||||
|   hack\" we were applying to sessions that weren\'t using a login, as | ||||
|   that hack user didn\'t have a valid id. The fix was to attribute the | ||||
|   correspondents, or even fixing spelling. This was due to the "user | ||||
|   hack" we were applying to sessions that weren't using a login, as | ||||
|   that hack user didn't have a valid id. The fix was to attribute the | ||||
|   first user id in the system to this hack user. | ||||
|   [\#394](https://github.com/the-paperless-project/paperless/issues/394) | ||||
| - A problem in how we handle slug values on Tags and Correspondents | ||||
|   required a few changes to how we handle this field | ||||
|   [\#393](https://github.com/the-paperless-project/paperless/issues/393): | ||||
|   1.  Slugs are no longer editable. They\'re derived from the name of | ||||
|   1.  Slugs are no longer editable. They're derived from the name of | ||||
|       the tag or correspondent at save time, so if you wanna change | ||||
|       the slug, you have to change the name, and even then you\'re | ||||
|       the slug, you have to change the name, and even then you're | ||||
|       restricted to the rules of the `slugify()` function. The slug | ||||
|       value is still visible in the admin though. | ||||
|   2.  I\'ve added a migration to go over all existing tags & | ||||
|   2.  I've added a migration to go over all existing tags & | ||||
|       correspondents and rewrite the `.slug` values to ones conforming | ||||
|       to the `slugify()` rules. | ||||
|   3.  The consumption process now uses the same rules as `.save()` in | ||||
| @@ -1836,7 +1820,7 @@ primarily. | ||||
|   Thanks to [Andrew Peng](https://github.com/pengc99) for reporting | ||||
|   this. | ||||
|   [\#414](https://github.com/the-paperless-project/paperless/issues/414). | ||||
| - A bug in the Dockerfile meant that Tesseract language files weren\'t | ||||
| - A bug in the Dockerfile meant that Tesseract language files weren't | ||||
|   being installed correctly. [euri10](https://github.com/euri10) was | ||||
|   quick to provide a fix: | ||||
|   [\#406](https://github.com/the-paperless-project/paperless/issues/406), | ||||
| @@ -1851,13 +1835,13 @@ primarily. | ||||
| ### 2.4.0 | ||||
|  | ||||
| - A new set of actions are now available thanks to | ||||
|   [jonaswinkler](https://github.com/jonaswinkler)\'s very first pull | ||||
|   [jonaswinkler](https://github.com/jonaswinkler)'s very first pull | ||||
|   request! You can now do nifty things like tag documents in bulk, or | ||||
|   set correspondents in bulk. | ||||
|   [\#405](https://github.com/the-paperless-project/paperless/pull/405) | ||||
| - The import/export system is now a little smarter. By default, | ||||
|   documents are tagged as `unencrypted`, since exports are by their | ||||
|   nature unencrypted. It\'s now in the import step that we decide the | ||||
|   nature unencrypted. It's now in the import step that we decide the | ||||
|   storage type. This allows you to export from an encrypted system and | ||||
|   import into an unencrypted one, or vice-versa. | ||||
| - The migration history has been slightly modified to accommodate | ||||
| @@ -1875,7 +1859,7 @@ primarily. | ||||
|  | ||||
| - Support for consuming plain text & markdown documents was added by | ||||
|   [Joshua Taillon](https://github.com/jat255)! This was a | ||||
|   long-requested feature, and it\'s addition is likely to be greatly | ||||
|   long-requested feature, and it's addition is likely to be greatly | ||||
|   appreciated by the community: | ||||
|   [\#395](https://github.com/the-paperless-project/paperless/pull/395) | ||||
|   Thanks also to [David Martin](https://github.com/ddddavidmartin) for | ||||
| @@ -1916,7 +1900,7 @@ primarily. | ||||
|   lots of different tags: | ||||
|   [\#391](https://github.com/the-paperless-project/paperless/pull/391). | ||||
| - [Kilian Koeltzsch](https://github.com/kiliankoe) noticed a bug in | ||||
|   how we capture & automatically create tags, so that\'s fixed now | ||||
|   how we capture & automatically create tags, so that's fixed now | ||||
|   too: | ||||
|   [\#384](https://github.com/the-paperless-project/paperless/issues/384). | ||||
| - [erikarvstedt](https://github.com/erikarvstedt) tweaked the | ||||
| @@ -1932,7 +1916,7 @@ primarily. | ||||
| - [Enno Lohmeier](https://github.com/elohmeier) added three simple | ||||
|   features that make Paperless a lot more user (and developer) | ||||
|   friendly: | ||||
|   1.  There\'s a new search box on the front page: | ||||
|   1.  There's a new search box on the front page: | ||||
|       [\#374](https://github.com/the-paperless-project/paperless/pull/374). | ||||
|   2.  The correspondents & tags pages now have a column showing the | ||||
|       number of relevant documents: | ||||
| @@ -1942,18 +1926,18 @@ primarily. | ||||
|       environment: | ||||
|       [\#376](https://github.com/the-paperless-project/paperless/pull/376). | ||||
| - You now also have the ability to customise the interface to your | ||||
|   heart\'s content by creating a file called `overrides.css` and/or | ||||
|   heart's content by creating a file called `overrides.css` and/or | ||||
|   `overrides.js` in the root of your media directory. Thanks to [Mark | ||||
|   McFate](https://github.com/SummittDweller) for this idea: | ||||
|   [\#371](https://github.com/the-paperless-project/paperless/issues/371) | ||||
|  | ||||
| ### 2.0.0 | ||||
|  | ||||
| This is a big release as we\'ve changed a core-functionality of | ||||
| This is a big release as we've changed a core-functionality of | ||||
| Paperless: we no longer encrypt files with GPG by default. | ||||
|  | ||||
| The reasons for this are many, but it boils down to that the encryption | ||||
| wasn\'t really all that useful, as files on-disk were still accessible | ||||
| wasn't really all that useful, as files on-disk were still accessible | ||||
| so long as you had the key, and the key was most typically stored in the | ||||
| config file. In other words, your files are only as safe as the | ||||
| `paperless` user is. In addition to that, _the contents of the documents | ||||
| @@ -1965,7 +1949,7 @@ explicitly set a passphrase in your config file. | ||||
|  | ||||
| ### Migrating from 1.x | ||||
|  | ||||
| Encryption isn\'t gone, it\'s just off for new users. So long as you | ||||
| Encryption isn't gone, it's just off for new users. So long as you | ||||
| have `PAPERLESS_PASSPHRASE` set in your config or your environment, | ||||
| Paperless should continue to operate as it always has. If however, you | ||||
| want to drop encryption too, you only need to do two things: | ||||
| @@ -1995,7 +1979,7 @@ this big change. | ||||
|   for more information. | ||||
| - Refactor the use of travis/tox/pytest/coverage into two files: | ||||
|   `.travis.yml` and `setup.cfg`. | ||||
| - Start generating requirements.txt from a Pipfile. I\'ll probably | ||||
| - Start generating requirements.txt from a Pipfile. I'll probably | ||||
|   switch over to just using pipenv in the future. | ||||
| - All for a alternative FreeBSD-friendly location for | ||||
|   `paperless.conf`. Thanks to [Martin | ||||
| @@ -2015,7 +1999,7 @@ this big change. | ||||
|   [\#253](https://github.com/the-paperless-project/paperless/issues/253) | ||||
|   and | ||||
|   [\#323](https://github.com/the-paperless-project/paperless/issues/323), | ||||
|   we\'ve removed a few of the hardcoded URL values to make it easier | ||||
|   we've removed a few of the hardcoded URL values to make it easier | ||||
|   for people to host Paperless on a subdirectory. Thanks to [Quentin | ||||
|   Dawans](https://github.com/ovv) and [Kyle | ||||
|   Lucy](https://github.com/kmlucy) for helping to work this out. | ||||
| @@ -2028,7 +2012,7 @@ this big change. | ||||
|   very creating Bash skills: | ||||
|   [\#352](https://github.com/the-paperless-project/paperless/pull/352). | ||||
| - You can now use the search field to find documents by tag thanks to | ||||
|   [thinkjk](https://github.com/thinkjk)\'s _first ever issue_: | ||||
|   [thinkjk](https://github.com/thinkjk)'s _first ever issue_: | ||||
|   [\#354](https://github.com/the-paperless-project/paperless/issues/354). | ||||
| - Inotify is now being used to detect additions to the consume | ||||
|   directory thanks to some excellent work from | ||||
| @@ -2037,7 +2021,7 @@ this big change. | ||||
|  | ||||
| ### 1.3.0 | ||||
|  | ||||
| - You can now run Paperless without a login, though you\'ll still have | ||||
| - You can now run Paperless without a login, though you'll still have | ||||
|   to create at least one user. This is thanks to a pull-request from | ||||
|   [matthewmoto](https://github.com/matthewmoto): | ||||
|   [\#295](https://github.com/the-paperless-project/paperless/pull/295). | ||||
| @@ -2068,7 +2052,7 @@ this big change. | ||||
|   [\#312](https://github.com/the-paperless-project/paperless/pull/312) | ||||
|   to fix | ||||
|   [\#306](https://github.com/the-paperless-project/paperless/issues/306). | ||||
| - Patch the historical migrations to support MySQL\'s um, | ||||
| - Patch the historical migrations to support MySQL's um, | ||||
|   _interesting_ way of handing indexes | ||||
|   ([\#308](https://github.com/the-paperless-project/paperless/issues/308)). | ||||
|   Thanks to [Simon Taddiken](https://github.com/skuzzle) for reporting | ||||
| @@ -2090,7 +2074,7 @@ this big change. | ||||
|   already contains text. This can be overridden by setting | ||||
|   `PAPERLESS_OCR_ALWAYS=YES` either in your `paperless.conf` or in the | ||||
|   environment. Note that this also means that Paperless now requires | ||||
|   `libpoppler-cpp-dev` to be installed. **Important**: You\'ll need to | ||||
|   `libpoppler-cpp-dev` to be installed. **Important**: You'll need to | ||||
|   run `pip install -r requirements.txt` after the usual `git pull` to | ||||
|   properly update. | ||||
| - [BastianPoe](https://github.com/BastianPoe) has also contributed a | ||||
| @@ -2117,7 +2101,7 @@ this big change. | ||||
|  | ||||
| ### 1.0.0 | ||||
|  | ||||
| - Upgrade to Django 1.11. **You\'ll need to run \`\`pip install -r | ||||
| - Upgrade to Django 1.11. **You'll need to run \`\`pip install -r | ||||
|   requirements.txt\`\` after the usual \`\`git pull\`\` to properly | ||||
|   update**. | ||||
| - Replace the templatetag-based hack we had for document listing in | ||||
| @@ -2138,14 +2122,14 @@ this big change. | ||||
|   [Pit](https://github.com/pitkley) on | ||||
|   [\#268](https://github.com/the-paperless-project/paperless/pull/268). | ||||
| - Date fields in the admin are now expressed as HTML5 date fields | ||||
|   thanks to [Lukas Winkler](https://github.com/Findus23)\'s issue | ||||
|   thanks to [Lukas Winkler](https://github.com/Findus23)'s issue | ||||
|   [\#278](https://github.com/the-paperless-project/paperless/issues/248) | ||||
|  | ||||
| ### 0.8.0 | ||||
|  | ||||
| - Paperless can now run in a subdirectory on a host (`/paperless`), | ||||
|   rather than always running in the root (`/`) thanks to | ||||
|   [maphy-psd](https://github.com/maphy-psd)\'s work on | ||||
|   [maphy-psd](https://github.com/maphy-psd)'s work on | ||||
|   [\#255](https://github.com/the-paperless-project/paperless/pull/255). | ||||
|  | ||||
| ### 0.7.0 | ||||
| @@ -2154,14 +2138,14 @@ this big change. | ||||
|   [\#235](https://github.com/the-paperless-project/paperless/issues/235), | ||||
|   Paperless will no longer automatically delete documents attached to | ||||
|   correspondents when those correspondents are themselves deleted. | ||||
|   This was Django\'s default behaviour, but didn\'t make much sense in | ||||
|   Paperless\' case. Thanks to [Thomas | ||||
|   This was Django's default behaviour, but didn't make much sense in | ||||
|   Paperless' case. Thanks to [Thomas | ||||
|   Brueggemann](https://github.com/thomasbrueggemann) and [David | ||||
|   Martin](https://github.com/ddddavidmartin) for their input on this | ||||
|   one. | ||||
| - Fix for | ||||
|   [\#232](https://github.com/the-paperless-project/paperless/issues/232) | ||||
|   wherein Paperless wasn\'t recognising `.tif` files properly. Thanks | ||||
|   wherein Paperless wasn't recognising `.tif` files properly. Thanks | ||||
|   to [ayounggun](https://github.com/ayounggun) for reporting this one | ||||
|   and to [Kusti Skytén](https://github.com/kskyten) for posting the | ||||
|   correct solution in the Github issue. | ||||
| @@ -2172,12 +2156,12 @@ this big change. | ||||
|   favour of BasicAuth or Django session. | ||||
| - Fix the POST API so it actually works. | ||||
|   [\#236](https://github.com/the-paperless-project/paperless/issues/236) | ||||
| - **Breaking change**: We\'ve dropped the use of | ||||
| - **Breaking change**: We've dropped the use of | ||||
|   `PAPERLESS_SHARED_SECRET` as it was being used both for the API (now | ||||
|   replaced with a normal auth) and form email polling. Now that we\'re | ||||
|   replaced with a normal auth) and form email polling. Now that we're | ||||
|   only using it for email, this variable has been renamed to | ||||
|   `PAPERLESS_EMAIL_SECRET`. The old value will still work for a while, | ||||
|   but you should change your config if you\'ve been using the email | ||||
|   but you should change your config if you've been using the email | ||||
|   polling feature. Thanks to [Joshua | ||||
|   Gilman](https://github.com/jmgilman) for all the help with this | ||||
|   feature. | ||||
| @@ -2185,7 +2169,7 @@ this big change. | ||||
| ### 0.5.0 | ||||
|  | ||||
| - Support for fuzzy matching in the auto-tagger & auto-correspondent | ||||
|   systems thanks to [Jake Gysland](https://github.com/jgysland)\'s | ||||
|   systems thanks to [Jake Gysland](https://github.com/jgysland)'s | ||||
|   patch | ||||
|   [\#220](https://github.com/the-paperless-project/paperless/pull/220). | ||||
| - Modified the Dockerfile to prepare an export directory | ||||
| @@ -2214,7 +2198,7 @@ this big change. | ||||
|  | ||||
| - Fix for | ||||
|   [\#206](https://github.com/the-paperless-project/paperless/issues/206) | ||||
|   wherein the pluggable parser didn\'t recognise files with all-caps | ||||
|   wherein the pluggable parser didn't recognise files with all-caps | ||||
|   suffixes like `.PDF` | ||||
|  | ||||
| ### 0.4.0 | ||||
| @@ -2224,7 +2208,7 @@ this big change. | ||||
|   for more information, but the short explanation is that you can now | ||||
|   attach simple notes & times to documents which are made available | ||||
|   via the API. Currently, the default API (basically just the Django | ||||
|   admin) doesn\'t really make use of this, but [Thomas | ||||
|   admin) doesn't really make use of this, but [Thomas | ||||
|   Brueggemann](https://github.com/thomasbrueggemann) over at | ||||
|   [Paperless | ||||
|   Desktop](https://github.com/thomasbrueggemann/paperless-desktop) has | ||||
| @@ -2234,16 +2218,16 @@ this big change. | ||||
|  | ||||
| - Fix for | ||||
|   [\#200](https://github.com/the-paperless-project/paperless/issues/200) | ||||
|   (!!) where the API wasn\'t configured to allow updating the | ||||
|   (!!) where the API wasn't configured to allow updating the | ||||
|   correspondent or the tags for a document. | ||||
| - The `content` field is now optional, to allow for the edge case of a | ||||
|   purely graphical document. | ||||
| - You can no longer add documents via the admin. This never worked in | ||||
|   the first place, so all I\'ve done here is remove the link to the | ||||
|   the first place, so all I've done here is remove the link to the | ||||
|   broken form. | ||||
| - The consumer code has been heavily refactored to support a pluggable | ||||
|   interface. Install a paperless consumer via pip and tell paperless | ||||
|   about it with an environment variable, and you\'re good to go. | ||||
|   about it with an environment variable, and you're good to go. | ||||
|   Proper documentation is on its way. | ||||
|  | ||||
| ### 0.3.5 | ||||
| @@ -2264,10 +2248,10 @@ this big change. | ||||
| - Removal of django-suit due to a licensing conflict I bumped into in | ||||
|   0.3.3. Note that you _can_ use Django Suit with Paperless, but only | ||||
|   in a non-profit situation as their free license prohibits for-profit | ||||
|   use. As a result, I can\'t bundle Suit with Paperless without | ||||
|   use. As a result, I can't bundle Suit with Paperless without | ||||
|   conflicting with the GPL. Further development will be done against | ||||
|   the stock Django admin. | ||||
| - I shrunk the thumbnails a little \'cause they were too big for me, | ||||
| - I shrunk the thumbnails a little 'cause they were too big for me, | ||||
|   even on my high-DPI monitor. | ||||
| - BasicAuth support for document and thumbnail downloads, as well as | ||||
|   the Push API thanks to \@thomasbrueggemann. See | ||||
| @@ -2294,14 +2278,14 @@ this big change. | ||||
| ### 0.3.0 | ||||
|  | ||||
| - Updated to using django-filter 1.x | ||||
| - Added some system checks so new users aren\'t confused by | ||||
| - Added some system checks so new users aren't confused by | ||||
|   misconfigurations. | ||||
| - Consumer loop time is now configurable for systems with slow writes. | ||||
|   Just set `PAPERLESS_CONSUMER_LOOP_TIME` to a number of seconds. The | ||||
|   default is 10. | ||||
| - As per | ||||
|   [\#44](https://github.com/the-paperless-project/paperless/issues/44), | ||||
|   we\'ve removed support for `PAPERLESS_CONVERT`, `PAPERLESS_CONSUME`, | ||||
|   we've removed support for `PAPERLESS_CONVERT`, `PAPERLESS_CONSUME`, | ||||
|   and `PAPERLESS_SECRET`. Please use `PAPERLESS_CONVERT_BINARY`, | ||||
|   `PAPERLESS_CONSUMPTION_DIR`, and `PAPERLESS_SHARED_SECRET` | ||||
|   respectively instead. | ||||
| @@ -2316,17 +2300,17 @@ this big change. | ||||
| - [\#146](https://github.com/the-paperless-project/paperless/issues/146): | ||||
|   Fixed a bug that allowed unauthorised access to the `/fetch` URL. | ||||
| - [\#131](https://github.com/the-paperless-project/paperless/issues/131): | ||||
|   Document files are now automatically removed from disk when they\'re | ||||
|   Document files are now automatically removed from disk when they're | ||||
|   deleted in Paperless. | ||||
| - [\#121](https://github.com/the-paperless-project/paperless/issues/121): | ||||
|   Fixed a bug where Paperless wasn\'t setting document creation time | ||||
|   Fixed a bug where Paperless wasn't setting document creation time | ||||
|   based on the file naming scheme. | ||||
| - [\#81](https://github.com/the-paperless-project/paperless/issues/81): | ||||
|   Added a hook to run an arbitrary script after every document is | ||||
|   consumed. | ||||
| - [\#98](https://github.com/the-paperless-project/paperless/issues/98): | ||||
|   Added optional environment variables for ImageMagick so that it | ||||
|   doesn\'t explode when handling Very Large Documents or when it\'s | ||||
|   doesn't explode when handling Very Large Documents or when it's | ||||
|   just running on a low-memory system. Thanks to [Florian | ||||
|   Harr](https://github.com/evils) for his help on this one. | ||||
| - [\#89](https://github.com/the-paperless-project/paperless/issues/89) | ||||
| @@ -2345,8 +2329,8 @@ this big change. | ||||
|  | ||||
| ### 0.1.1 | ||||
|  | ||||
| - Potentially **Breaking Change**: All references to \"sender\" in the | ||||
|   code have been renamed to \"correspondent\" to better reflect the | ||||
| - Potentially **Breaking Change**: All references to "sender" in the | ||||
|   code have been renamed to "correspondent" to better reflect the | ||||
|   nature of the property (one could quite reasonably scan a document | ||||
|   before sending it to someone.) | ||||
| - [\#67](https://github.com/the-paperless-project/paperless/issues/67): | ||||
| @@ -2360,7 +2344,7 @@ this big change. | ||||
|   contributing conversation that lead to this change. | ||||
| - [\#20](https://github.com/the-paperless-project/paperless/issues/20): | ||||
|   Added _unpaper_ support to help in cleaning up the scanned image | ||||
|   before it\'s OCR\'d. Thanks to [Pit](https://github.com/pitkley) for | ||||
|   before it's OCR'd. Thanks to [Pit](https://github.com/pitkley) for | ||||
|   this one. | ||||
| - [\#71](https://github.com/the-paperless-project/paperless/issues/71) | ||||
|   Added (encrypted) thumbnails in anticipation of a proper UI. | ||||
|   | ||||
							
								
								
									
										337
									
								
								docs/conf.py
									
									
									
									
									
								
							
							
						
						| @@ -1,337 +0,0 @@ | ||||
| import sphinx_rtd_theme | ||||
|  | ||||
|  | ||||
| __version__ = None | ||||
| __full_version_str__ = None | ||||
| __major_minor_version_str__ = None | ||||
| exec(open("../src/paperless/version.py").read()) | ||||
|  | ||||
|  | ||||
| extensions = [ | ||||
|     "sphinx.ext.autodoc", | ||||
|     "sphinx.ext.intersphinx", | ||||
|     "sphinx.ext.todo", | ||||
|     "sphinx.ext.imgmath", | ||||
|     "sphinx.ext.viewcode", | ||||
|     "sphinx_rtd_theme", | ||||
|     "myst_parser", | ||||
| ] | ||||
|  | ||||
| # Add any paths that contain templates here, relative to this directory. | ||||
| templates_path = ["_templates"] | ||||
|  | ||||
| # The suffix of source filenames. | ||||
| source_suffix = { | ||||
|     ".rst": "restructuredtext", | ||||
|     ".md": "markdown", | ||||
| } | ||||
|  | ||||
| # The encoding of source files. | ||||
| # source_encoding = 'utf-8-sig' | ||||
|  | ||||
| # The master toctree document. | ||||
| master_doc = "index" | ||||
|  | ||||
| # General information about the project. | ||||
| project = "Paperless-ngx" | ||||
| copyright = "2015-2022, Daniel Quinn, Jonas Winkler, and the paperless-ngx team" | ||||
|  | ||||
| # The version info for the project you're documenting, acts as replacement for | ||||
| # |version| and |release|, also used in various other places throughout the | ||||
| # built documents. | ||||
| # | ||||
|  | ||||
| # | ||||
| # If the build process ever explodes here, it's because you've set the version | ||||
| # number in paperless.version to a tuple with 3 numbers in it. | ||||
| # | ||||
|  | ||||
| # The short X.Y version. | ||||
| version = __major_minor_version_str__ | ||||
| # The full version, including alpha/beta/rc tags. | ||||
| release = __full_version_str__ | ||||
|  | ||||
| # The language for content autogenerated by Sphinx. Refer to documentation | ||||
| # for a list of supported languages. | ||||
| # language = None | ||||
|  | ||||
| # There are two options for replacing |today|: either, you set today to some | ||||
| # non-false value, then it is used: | ||||
| # today = '' | ||||
| # Else, today_fmt is used as the format for a strftime call. | ||||
| # today_fmt = '%B %d, %Y' | ||||
|  | ||||
| # List of patterns, relative to source directory, that match files and | ||||
| # directories to ignore when looking for source files. | ||||
| exclude_patterns = ["_build"] | ||||
|  | ||||
| # The reST default role (used for this markup: `text`) to use for all | ||||
| # documents. | ||||
| # default_role = None | ||||
|  | ||||
| # If true, '()' will be appended to :func: etc. cross-reference text. | ||||
| # add_function_parentheses = True | ||||
|  | ||||
| # If true, the current module name will be prepended to all description | ||||
| # unit titles (such as .. function::). | ||||
| # add_module_names = True | ||||
|  | ||||
| # If true, sectionauthor and moduleauthor directives will be shown in the | ||||
| # output. They are ignored by default. | ||||
| # show_authors = False | ||||
|  | ||||
| # The name of the Pygments (syntax highlighting) style to use. | ||||
| pygments_style = "sphinx" | ||||
|  | ||||
| # A list of ignored prefixes for module index sorting. | ||||
| # modindex_common_prefix = [] | ||||
|  | ||||
| # If true, keep warnings as "system message" paragraphs in the built documents. | ||||
| # keep_warnings = False | ||||
|  | ||||
|  | ||||
| # -- Options for HTML output ---------------------------------------------- | ||||
|  | ||||
| # The theme to use for HTML and HTML Help pages.  See the documentation for | ||||
| # a list of builtin themes. | ||||
| html_theme = "sphinx_rtd_theme" | ||||
|  | ||||
| # Theme options are theme-specific and customize the look and feel of a theme | ||||
| # further.  For a list of options available for each theme, see the | ||||
| # documentation. | ||||
| # html_theme_options = {} | ||||
|  | ||||
| # Add any paths that contain custom themes here, relative to this directory. | ||||
| html_theme_path = [] | ||||
|  | ||||
| # The name for this set of Sphinx documents.  If None, it defaults to | ||||
| # "<project> v<release> documentation". | ||||
| # html_title = None | ||||
|  | ||||
| # A shorter title for the navigation bar.  Default is the same as html_title. | ||||
| # html_short_title = None | ||||
|  | ||||
| # The name of an image file (relative to this directory) to place at the top | ||||
| # of the sidebar. | ||||
| # html_logo = None | ||||
|  | ||||
| # The name of an image file (within the static path) to use as favicon of the | ||||
| # docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32 | ||||
| # pixels large. | ||||
| # html_favicon = None | ||||
|  | ||||
| # Add any paths that contain custom static files (such as style sheets) here, | ||||
| # relative to this directory. They are copied after the builtin static files, | ||||
| # so a file named "default.css" will overwrite the builtin "default.css". | ||||
| html_static_path = ["_static"] | ||||
|  | ||||
| # These paths are either relative to html_static_path | ||||
| # or fully qualified paths (eg. https://...) | ||||
| html_css_files = [ | ||||
|     "css/custom.css", | ||||
| ] | ||||
|  | ||||
| html_js_files = [ | ||||
|     "js/darkmode.js", | ||||
| ] | ||||
|  | ||||
| # Add any extra paths that contain custom files (such as robots.txt or | ||||
| # .htaccess) here, relative to this directory. These files are copied | ||||
| # directly to the root of the documentation. | ||||
| # html_extra_path = [] | ||||
|  | ||||
| # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, | ||||
| # using the given strftime format. | ||||
| # html_last_updated_fmt = '%b %d, %Y' | ||||
|  | ||||
| # If true, SmartyPants will be used to convert quotes and dashes to | ||||
| # typographically correct entities. | ||||
| # html_use_smartypants = True | ||||
|  | ||||
| # Custom sidebar templates, maps document names to template names. | ||||
| # html_sidebars = {} | ||||
|  | ||||
| # Additional templates that should be rendered to pages, maps page names to | ||||
| # template names. | ||||
| # html_additional_pages = {} | ||||
|  | ||||
| # If false, no module index is generated. | ||||
| # html_domain_indices = True | ||||
|  | ||||
| # If false, no index is generated. | ||||
| # html_use_index = True | ||||
|  | ||||
| # If true, the index is split into individual pages for each letter. | ||||
| # html_split_index = False | ||||
|  | ||||
| # If true, links to the reST sources are added to the pages. | ||||
| # html_show_sourcelink = True | ||||
|  | ||||
| # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. | ||||
| # html_show_sphinx = True | ||||
|  | ||||
| # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. | ||||
| # html_show_copyright = True | ||||
|  | ||||
| # If true, an OpenSearch description file will be output, and all pages will | ||||
| # contain a <link> tag referring to it.  The value of this option must be the | ||||
| # base URL from which the finished HTML is served. | ||||
| # html_use_opensearch = '' | ||||
|  | ||||
| # This is the file name suffix for HTML files (e.g. ".xhtml"). | ||||
| # html_file_suffix = None | ||||
|  | ||||
| # Output file base name for HTML help builder. | ||||
| htmlhelp_basename = "paperless" | ||||
|  | ||||
| # -- Options for LaTeX output --------------------------------------------- | ||||
|  | ||||
| latex_elements = { | ||||
|     # The paper size ('letterpaper' or 'a4paper'). | ||||
|     #'papersize': 'letterpaper', | ||||
|     # The font size ('10pt', '11pt' or '12pt'). | ||||
|     #'pointsize': '10pt', | ||||
|     # Additional stuff for the LaTeX preamble. | ||||
|     #'preamble': '', | ||||
| } | ||||
|  | ||||
| # Grouping the document tree into LaTeX files. List of tuples | ||||
| # (source start file, target name, title, | ||||
| #  author, documentclass [howto, manual, or own class]). | ||||
| latex_documents = [ | ||||
|     ("index", "paperless.tex", "Paperless Documentation", "Daniel Quinn", "manual"), | ||||
| ] | ||||
|  | ||||
| # The name of an image file (relative to this directory) to place at the top of | ||||
| # the title page. | ||||
| # latex_logo = None | ||||
|  | ||||
| # For "manual" documents, if this is true, then toplevel headings are parts, | ||||
| # not chapters. | ||||
| # latex_use_parts = False | ||||
|  | ||||
| # If true, show page references after internal links. | ||||
| # latex_show_pagerefs = False | ||||
|  | ||||
| # If true, show URL addresses after external links. | ||||
| # latex_show_urls = False | ||||
|  | ||||
| # Documents to append as an appendix to all manuals. | ||||
| # latex_appendices = [] | ||||
|  | ||||
| # If false, no module index is generated. | ||||
| # latex_domain_indices = True | ||||
|  | ||||
|  | ||||
| # -- Options for manual page output --------------------------------------- | ||||
|  | ||||
| # One entry per manual page. List of tuples | ||||
| # (source start file, name, description, authors, manual section). | ||||
| man_pages = [("index", "paperless", "Paperless Documentation", ["Daniel Quinn"], 1)] | ||||
|  | ||||
| # If true, show URL addresses after external links. | ||||
| # man_show_urls = False | ||||
|  | ||||
|  | ||||
| # -- Options for Texinfo output ------------------------------------------- | ||||
|  | ||||
| # Grouping the document tree into Texinfo files. List of tuples | ||||
| # (source start file, target name, title, author, | ||||
| #  dir menu entry, description, category) | ||||
| texinfo_documents = [ | ||||
|     ( | ||||
|         "index", | ||||
|         "Paperless", | ||||
|         "Paperless Documentation", | ||||
|         "Daniel Quinn", | ||||
|         "paperless", | ||||
|         "Scan, index, and archive all of your paper documents.", | ||||
|         "Miscellaneous", | ||||
|     ), | ||||
| ] | ||||
|  | ||||
| # Documents to append as an appendix to all manuals. | ||||
| # texinfo_appendices = [] | ||||
|  | ||||
| # If false, no module index is generated. | ||||
| # texinfo_domain_indices = True | ||||
|  | ||||
| # How to display URL addresses: 'footnote', 'no', or 'inline'. | ||||
| # texinfo_show_urls = 'footnote' | ||||
|  | ||||
| # If true, do not generate a @detailmenu in the "Top" node's menu. | ||||
| # texinfo_no_detailmenu = False | ||||
|  | ||||
|  | ||||
| # -- Options for Epub output ---------------------------------------------- | ||||
|  | ||||
| # Bibliographic Dublin Core info. | ||||
| epub_title = "Paperless" | ||||
| epub_author = "Daniel Quinn" | ||||
| epub_publisher = "Daniel Quinn" | ||||
| epub_copyright = "2015, Daniel Quinn" | ||||
|  | ||||
| # The basename for the epub file. It defaults to the project name. | ||||
| # epub_basename = u'Paperless' | ||||
|  | ||||
| # The HTML theme for the epub output. Since the default themes are not optimized | ||||
| # for small screen space, using the same theme for HTML and epub output is | ||||
| # usually not wise. This defaults to 'epub', a theme designed to save visual | ||||
| # space. | ||||
| # epub_theme = 'epub' | ||||
|  | ||||
| # The language of the text. It defaults to the language option | ||||
| # or en if the language is not set. | ||||
| # epub_language = '' | ||||
|  | ||||
| # The scheme of the identifier. Typical schemes are ISBN or URL. | ||||
| # epub_scheme = '' | ||||
|  | ||||
| # The unique identifier of the text. This can be a ISBN number | ||||
| # or the project homepage. | ||||
| # epub_identifier = '' | ||||
|  | ||||
| # A unique identification for the text. | ||||
| # epub_uid = '' | ||||
|  | ||||
| # A tuple containing the cover image and cover page html template filenames. | ||||
| # epub_cover = () | ||||
|  | ||||
| # A sequence of (type, uri, title) tuples for the guide element of content.opf. | ||||
| # epub_guide = () | ||||
|  | ||||
| # HTML files that should be inserted before the pages created by sphinx. | ||||
| # The format is a list of tuples containing the path and title. | ||||
| # epub_pre_files = [] | ||||
|  | ||||
| # HTML files shat should be inserted after the pages created by sphinx. | ||||
| # The format is a list of tuples containing the path and title. | ||||
| # epub_post_files = [] | ||||
|  | ||||
| # A list of files that should not be packed into the epub file. | ||||
| epub_exclude_files = ["search.html"] | ||||
|  | ||||
| # The depth of the table of contents in toc.ncx. | ||||
| # epub_tocdepth = 3 | ||||
|  | ||||
| # Allow duplicate toc entries. | ||||
| # epub_tocdup = True | ||||
|  | ||||
| # Choose between 'default' and 'includehidden'. | ||||
| # epub_tocscope = 'default' | ||||
|  | ||||
| # Fix unsupported image types using the PIL. | ||||
| # epub_fix_images = False | ||||
|  | ||||
| # Scale large images. | ||||
| # epub_max_image_width = 0 | ||||
|  | ||||
| # How to display URL addresses: 'footnote', 'no', or 'inline'. | ||||
| # epub_show_urls = 'inline' | ||||
|  | ||||
| # If false, no index is generated. | ||||
| # epub_use_index = True | ||||
|  | ||||
|  | ||||
| # Example configuration for intersphinx: refer to the Python standard library. | ||||
| intersphinx_mapping = {"http://docs.python.org/": None} | ||||
							
								
								
									
										1037
									
								
								docs/configuration.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -1,931 +0,0 @@ | ||||
| .. _configuration: | ||||
|  | ||||
| ************* | ||||
| Configuration | ||||
| ************* | ||||
|  | ||||
| Paperless provides a wide range of customizations. | ||||
| Depending on how you run paperless, these settings have to be defined in different | ||||
| places. | ||||
|  | ||||
| *   If you run paperless on docker, ``paperless.conf`` is not used. Rather, configure | ||||
|     paperless by copying necessary options to ``docker-compose.env``. | ||||
| *   If you are running paperless on anything else, paperless will search for the | ||||
|     configuration file in these locations and use the first one it finds: | ||||
|  | ||||
|     .. code:: | ||||
|  | ||||
|         /path/to/paperless/paperless.conf | ||||
|         /etc/paperless.conf | ||||
|         /usr/local/etc/paperless.conf | ||||
|  | ||||
|  | ||||
| Required services | ||||
| ################# | ||||
|  | ||||
| PAPERLESS_REDIS=<url> | ||||
|     This is required for processing scheduled tasks such as email fetching, index | ||||
|     optimization and for training the automatic document matcher. | ||||
|  | ||||
|     * If your Redis server needs login credentials PAPERLESS_REDIS = ``redis://<username>:<password>@<host>:<port>`` | ||||
|  | ||||
|     * With the requirepass option PAPERLESS_REDIS = ``redis://:<password>@<host>:<port>`` | ||||
|  | ||||
|     `More information on securing your Redis Instance <https://redis.io/docs/getting-started/#securing-redis>`_. | ||||
|  | ||||
|     Defaults to redis://localhost:6379. | ||||
|  | ||||
| PAPERLESS_DBENGINE=<engine_name> | ||||
|     Optional, gives the ability to choose Postgres or MariaDB for database engine. | ||||
|     Available options are `postgresql` and `mariadb`. | ||||
|  | ||||
|     Default is `postgresql`. | ||||
|  | ||||
|     .. warning:: | ||||
|  | ||||
|       Using MariaDB comes with some caveats.  See :ref:`advanced-mysql-caveats` for details. | ||||
|  | ||||
|  | ||||
| PAPERLESS_DBHOST=<hostname> | ||||
|     By default, sqlite is used as the database backend. This can be changed here. | ||||
|  | ||||
|     Set PAPERLESS_DBHOST and another database will be used instead of sqlite. | ||||
|  | ||||
| PAPERLESS_DBPORT=<port> | ||||
|     Adjust port if necessary. | ||||
|  | ||||
|     Default is 5432. | ||||
|  | ||||
| PAPERLESS_DBNAME=<name> | ||||
|     Database name in PostgreSQL or MariaDB. | ||||
|  | ||||
|     Defaults to "paperless". | ||||
|  | ||||
| PAPERLESS_DBUSER=<name> | ||||
|     Database user in PostgreSQL or MariaDB. | ||||
|  | ||||
|     Defaults to "paperless". | ||||
|  | ||||
| PAPERLESS_DBPASS=<password> | ||||
|     Database password for PostgreSQL or MariaDB. | ||||
|  | ||||
|     Defaults to "paperless". | ||||
|  | ||||
| PAPERLESS_DBSSLMODE=<mode> | ||||
|     SSL mode to use when connecting to PostgreSQL. | ||||
|  | ||||
|     See `the official documentation about sslmode <https://www.postgresql.org/docs/current/libpq-ssl.html>`_. | ||||
|  | ||||
|     Default is ``prefer``. | ||||
|  | ||||
| PAPERLESS_DB_TIMEOUT=<float> | ||||
|     Amount of time for a database connection to wait for the database to unlock. | ||||
|     Mostly applicable for an sqlite based installation, consider changing to postgresql | ||||
|     if you need to increase this. | ||||
|  | ||||
|     Defaults to unset, keeping the Django defaults. | ||||
|  | ||||
| Paths and folders | ||||
| ################# | ||||
|  | ||||
| PAPERLESS_CONSUMPTION_DIR=<path> | ||||
|     This where your documents should go to be consumed.  Make sure that it exists | ||||
|     and that the user running the paperless service can read/write its contents | ||||
|     before you start Paperless. | ||||
|  | ||||
|     Don't change this when using docker, as it only changes the path within the | ||||
|     container. Change the local consumption directory in the docker-compose.yml | ||||
|     file instead. | ||||
|  | ||||
|     Defaults to "../consume/", relative to the "src" directory. | ||||
|  | ||||
| PAPERLESS_DATA_DIR=<path> | ||||
|     This is where paperless stores all its data (search index, SQLite database, | ||||
|     classification model, etc). | ||||
|  | ||||
|     Defaults to "../data/", relative to the "src" directory. | ||||
|  | ||||
| PAPERLESS_TRASH_DIR=<path> | ||||
|     Instead of removing deleted documents, they are moved to this directory. | ||||
|  | ||||
|     This must be writeable by the user running paperless. When running inside | ||||
|     docker, ensure that this path is within a permanent volume (such as | ||||
|     "../media/trash") so it won't get lost on upgrades. | ||||
|  | ||||
|     Defaults to empty (i.e. really delete documents). | ||||
|  | ||||
| PAPERLESS_MEDIA_ROOT=<path> | ||||
|     This is where your documents and thumbnails are stored. | ||||
|  | ||||
|     You can set this and PAPERLESS_DATA_DIR to the same folder to have paperless | ||||
|     store all its data within the same volume. | ||||
|  | ||||
|     Defaults to "../media/", relative to the "src" directory. | ||||
|  | ||||
| PAPERLESS_STATICDIR=<path> | ||||
|     Override the default STATIC_ROOT here.  This is where all static files | ||||
|     created using "collectstatic" manager command are stored. | ||||
|  | ||||
|     Unless you're doing something fancy, there is no need to override this. | ||||
|  | ||||
|     Defaults to "../static/", relative to the "src" directory. | ||||
|  | ||||
| PAPERLESS_FILENAME_FORMAT=<format> | ||||
|     Changes the filenames paperless uses to store documents in the media directory. | ||||
|     See :ref:`advanced-file_name_handling` for details. | ||||
|  | ||||
|     Default is none, which disables this feature. | ||||
|  | ||||
| PAPERLESS_FILENAME_FORMAT_REMOVE_NONE=<bool> | ||||
|     Tells paperless to replace placeholders in `PAPERLESS_FILENAME_FORMAT` that would resolve | ||||
|     to 'none' to be omitted from the resulting filename. This also holds true for directory | ||||
|     names. | ||||
|     See :ref:`advanced-file_name_handling` for details. | ||||
|  | ||||
|     Defaults to `false` which disables this feature. | ||||
|  | ||||
| PAPERLESS_LOGGING_DIR=<path> | ||||
|     This is where paperless will store log files. | ||||
|  | ||||
|     Defaults to "``PAPERLESS_DATA_DIR``/log/". | ||||
|  | ||||
|  | ||||
| Logging | ||||
| ####### | ||||
|  | ||||
| PAPERLESS_LOGROTATE_MAX_SIZE=<num> | ||||
|     Maximum file size for log files before they are rotated, in bytes. | ||||
|  | ||||
|     Defaults to 1 MiB. | ||||
|  | ||||
| PAPERLESS_LOGROTATE_MAX_BACKUPS=<num> | ||||
|     Number of rotated log files to keep. | ||||
|  | ||||
|     Defaults to 20. | ||||
|  | ||||
| .. _hosting-and-security: | ||||
|  | ||||
| Hosting & Security | ||||
| ################## | ||||
|  | ||||
| PAPERLESS_SECRET_KEY=<key> | ||||
|     Paperless uses this to make session tokens. If you expose paperless on the | ||||
|     internet, you need to change this, since the default secret is well known. | ||||
|  | ||||
|     Use any sequence of characters. The more, the better. You don't need to | ||||
|     remember this. Just face-roll your keyboard. | ||||
|  | ||||
|     Default is listed in the file ``src/paperless/settings.py``. | ||||
|  | ||||
| PAPERLESS_URL=<url> | ||||
|     This setting can be used to set the three options below (ALLOWED_HOSTS, | ||||
|     CORS_ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS). If the other options are | ||||
|     set the values will be combined with this one. Do not include a trailing | ||||
|     slash. E.g. https://paperless.domain.com | ||||
|  | ||||
|     Defaults to empty string, leaving the other settings unaffected. | ||||
|  | ||||
| PAPERLESS_CSRF_TRUSTED_ORIGINS=<comma-separated-list> | ||||
|     A list of trusted origins for unsafe requests (e.g. POST). As of Django 4.0 | ||||
|     this is required to access the Django admin via the web. | ||||
|     See https://docs.djangoproject.com/en/4.0/ref/settings/#csrf-trusted-origins | ||||
|  | ||||
|     Can also be set using PAPERLESS_URL (see above). | ||||
|  | ||||
|     Defaults to empty string, which does not add any origins to the trusted list. | ||||
|  | ||||
| PAPERLESS_ALLOWED_HOSTS=<comma-separated-list> | ||||
|     If you're planning on putting Paperless on the open internet, then you | ||||
|     really should set this value to the domain name you're using.  Failing to do | ||||
|     so leaves you open to HTTP host header attacks: | ||||
|     https://docs.djangoproject.com/en/3.1/topics/security/#host-header-validation | ||||
|  | ||||
|     Just remember that this is a comma-separated list, so "example.com" is fine, | ||||
|     as is "example.com,www.example.com", but NOT " example.com" or "example.com," | ||||
|  | ||||
|     Can also be set using PAPERLESS_URL (see above). | ||||
|  | ||||
|     If manually set, please remember to include "localhost". Otherwise docker | ||||
|     healthcheck will fail. | ||||
|  | ||||
|     Defaults to "*", which is all hosts. | ||||
|  | ||||
| PAPERLESS_CORS_ALLOWED_HOSTS=<comma-separated-list> | ||||
|     You need to add your servers to the list of allowed hosts that can do CORS | ||||
|     calls. Set this to your public domain name. | ||||
|  | ||||
|     Can also be set using PAPERLESS_URL (see above). | ||||
|  | ||||
|     Defaults to "http://localhost:8000". | ||||
|  | ||||
| PAPERLESS_FORCE_SCRIPT_NAME=<path> | ||||
|     To host paperless under a subpath url like example.com/paperless you set | ||||
|     this value to /paperless. No trailing slash! | ||||
|  | ||||
|     Defaults to none, which hosts paperless at "/". | ||||
|  | ||||
| PAPERLESS_STATIC_URL=<path> | ||||
|     Override the STATIC_URL here.  Unless you're hosting Paperless off a | ||||
|     subdomain like /paperless/, you probably don't need to change this. | ||||
|     If you do change it, be sure to include the trailing slash. | ||||
|  | ||||
|     Defaults to "/static/". | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         When hosting paperless behind a reverse proxy like Traefik or Nginx at a subpath e.g. | ||||
|         example.com/paperlessngx you will also need to set ``PAPERLESS_FORCE_SCRIPT_NAME`` | ||||
|         (see above). | ||||
|  | ||||
| PAPERLESS_AUTO_LOGIN_USERNAME=<username> | ||||
|     Specify a username here so that paperless will automatically perform login | ||||
|     with the selected user. | ||||
|  | ||||
|     .. danger:: | ||||
|  | ||||
|         Do not use this when exposing paperless on the internet. There are no | ||||
|         checks in place that would prevent you from doing this. | ||||
|  | ||||
|     Defaults to none, which disables this feature. | ||||
|  | ||||
| PAPERLESS_ADMIN_USER=<username> | ||||
|     If this environment variable is specified, Paperless automatically creates | ||||
|     a superuser with the provided username at start. This is useful in cases | ||||
|     where you can not run the `createsuperuser` command separately, such as Kubernetes | ||||
|     or AWS ECS. | ||||
|  | ||||
|     Requires `PAPERLESS_ADMIN_PASSWORD` to be set. | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         This will not change an existing [super]user's password, nor will | ||||
|         it recreate a user that already exists. You can leave this throughout | ||||
|         the lifecycle of the containers. | ||||
|  | ||||
| PAPERLESS_ADMIN_MAIL=<email> | ||||
|     (Optional) Specify superuser email address. Only used when | ||||
|     `PAPERLESS_ADMIN_USER` is set. | ||||
|  | ||||
|     Defaults to ``root@localhost``. | ||||
|  | ||||
| PAPERLESS_ADMIN_PASSWORD=<password> | ||||
|     Only used when `PAPERLESS_ADMIN_USER` is set. | ||||
|     This will be the password of the automatically created superuser. | ||||
|  | ||||
|  | ||||
| PAPERLESS_COOKIE_PREFIX=<str> | ||||
|     Specify a prefix that is added to the cookies used by paperless to identify | ||||
|     the currently logged in user. This is useful for when you're running two | ||||
|     instances of paperless on the same host. | ||||
|  | ||||
|     After changing this, you will have to login again. | ||||
|  | ||||
|     Defaults to ``""``, which does not alter the cookie names. | ||||
|  | ||||
| PAPERLESS_ENABLE_HTTP_REMOTE_USER=<bool> | ||||
|     Allows authentication via HTTP_REMOTE_USER which is used by some SSO | ||||
|     applications. | ||||
|  | ||||
|     .. warning:: | ||||
|  | ||||
|         This will allow authentication by simply adding a ``Remote-User: <username>`` header | ||||
|         to a request. Use with care! You especially *must* ensure that any such header is not | ||||
|         passed from your proxy server to paperless. | ||||
|  | ||||
|         If you're exposing paperless to the internet directly, do not use this. | ||||
|  | ||||
|         Also see the warning `in the official documentation <https://docs.djangoproject.com/en/3.1/howto/auth-remote-user/#configuration>`. | ||||
|  | ||||
|     Defaults to `false` which disables this feature. | ||||
|  | ||||
| PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME=<str> | ||||
|     If `PAPERLESS_ENABLE_HTTP_REMOTE_USER` is enabled, this property allows to | ||||
|     customize the name of the HTTP header from which the authenticated username | ||||
|     is extracted. Values are in terms of | ||||
|     [HttpRequest.META](https://docs.djangoproject.com/en/3.1/ref/request-response/#django.http.HttpRequest.META). | ||||
|     Thus, the configured value must start with `HTTP_` followed by the | ||||
|     normalized actual header name. | ||||
|  | ||||
|     Defaults to `HTTP_REMOTE_USER`. | ||||
|  | ||||
| PAPERLESS_LOGOUT_REDIRECT_URL=<str> | ||||
|     URL to redirect the user to after a logout. This can be used together with | ||||
|     `PAPERLESS_ENABLE_HTTP_REMOTE_USER` to redirect the user back to the SSO | ||||
|     application's logout page. | ||||
|  | ||||
|     Defaults to None, which disables this feature. | ||||
|  | ||||
| .. _configuration-ocr: | ||||
|  | ||||
| OCR settings | ||||
| ############ | ||||
|  | ||||
| Paperless uses `OCRmyPDF <https://ocrmypdf.readthedocs.io/en/latest/>`_ for | ||||
| performing OCR on documents and images. Paperless uses sensible defaults for | ||||
| most settings, but all of them can be configured to your needs. | ||||
|  | ||||
| PAPERLESS_OCR_LANGUAGE=<lang> | ||||
|     Customize the language that paperless will attempt to use when | ||||
|     parsing documents. | ||||
|  | ||||
|     It should be a 3-letter language code consistent with ISO | ||||
|     639: https://www.loc.gov/standards/iso639-2/php/code_list.php | ||||
|  | ||||
|     Set this to the language most of your documents are written in. | ||||
|  | ||||
|     This can be a combination of multiple languages such as ``deu+eng``, | ||||
|     in which case tesseract will use whatever language matches best. | ||||
|     Keep in mind that tesseract uses much more cpu time with multiple | ||||
|     languages enabled. | ||||
|  | ||||
|     Defaults to "eng". | ||||
|  | ||||
| 		Note: If your language contains a '-' such as chi-sim, you must use chi_sim | ||||
|  | ||||
| PAPERLESS_OCR_MODE=<mode> | ||||
|     Tell paperless when and how to perform ocr on your documents. Four modes | ||||
|     are available: | ||||
|  | ||||
|     *   ``skip``: Paperless skips all pages and will perform ocr only on pages | ||||
|         where no text is present. This is the safest option. | ||||
|     *   ``skip_noarchive``: In addition to skip, paperless won't create an | ||||
|         archived version of your documents when it finds any text in them. | ||||
|         This is useful if you don't want to have two almost-identical versions | ||||
|         of your digital documents in the media folder. This is the fastest option. | ||||
|     *   ``redo``: Paperless will OCR all pages of your documents and attempt to | ||||
|         replace any existing text layers with new text. This will be useful for | ||||
|         documents from scanners that already performed OCR with insufficient | ||||
|         results. It will also perform OCR on purely digital documents. | ||||
|  | ||||
|         This option may fail on some documents that have features that cannot | ||||
|         be removed, such as forms. In this case, the text from the document is | ||||
|         used instead. | ||||
|     *   ``force``: Paperless rasterizes your documents, converting any text | ||||
|         into images and puts the OCRed text on top. This works for all documents, | ||||
|         however, the resulting document may be significantly larger and text | ||||
|         won't appear as sharp when zoomed in. | ||||
|  | ||||
|     The default is ``skip``, which only performs OCR when necessary and always | ||||
|     creates archived documents. | ||||
|  | ||||
|     Read more about this in the `OCRmyPDF documentation <https://ocrmypdf.readthedocs.io/en/latest/advanced.html#when-ocr-is-skipped>`_. | ||||
|  | ||||
| PAPERLESS_OCR_CLEAN=<mode> | ||||
|     Tells paperless to use ``unpaper`` to clean any input document before | ||||
|     sending it to tesseract. This uses more resources, but generally results | ||||
|     in better OCR results. The following modes are available: | ||||
|  | ||||
|     *   ``clean``: Apply unpaper. | ||||
|     *   ``clean-final``: Apply unpaper, and use the cleaned images to build the | ||||
|         output file instead of the original images. | ||||
|     *   ``none``: Do not apply unpaper. | ||||
|  | ||||
|     Defaults to ``clean``. | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         ``clean-final`` is incompatible with ocr mode ``redo``. When both | ||||
|         ``clean-final`` and the ocr mode ``redo`` is configured, ``clean`` | ||||
|         is used instead. | ||||
|  | ||||
| PAPERLESS_OCR_DESKEW=<bool> | ||||
|     Tells paperless to correct skewing (slight rotation of input images mainly | ||||
|     due to improper scanning) | ||||
|  | ||||
|     Defaults to ``true``, which enables this feature. | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         Deskewing is incompatible with ocr mode ``redo``. Deskewing will get | ||||
|         disabled automatically if ``redo`` is used as the ocr mode. | ||||
|  | ||||
| PAPERLESS_OCR_ROTATE_PAGES=<bool> | ||||
|     Tells paperless to correct page rotation (90°, 180° and 270° rotation). | ||||
|  | ||||
|     If you notice that paperless is not rotating incorrectly rotated | ||||
|     pages (or vice versa), try adjusting the threshold up or down (see below). | ||||
|  | ||||
|     Defaults to ``true``, which enables this feature. | ||||
|  | ||||
|  | ||||
| PAPERLESS_OCR_ROTATE_PAGES_THRESHOLD=<num> | ||||
|     Adjust the threshold for automatic page rotation by ``PAPERLESS_OCR_ROTATE_PAGES``. | ||||
|     This is an arbitrary value reported by tesseract. "15" is a very conservative value, | ||||
|     whereas "2" is a very aggressive option and will often result in correctly rotated pages | ||||
|     being rotated as well. | ||||
|  | ||||
|     Defaults to "12". | ||||
|  | ||||
| PAPERLESS_OCR_OUTPUT_TYPE=<type> | ||||
|     Specify the the type of PDF documents that paperless should produce. | ||||
|  | ||||
|     *   ``pdf``: Modify the PDF document as little as possible. | ||||
|     *   ``pdfa``: Convert PDF documents into PDF/A-2b documents, which is a | ||||
|         subset of the entire PDF specification and meant for storing | ||||
|         documents long term. | ||||
|     *   ``pdfa-1``, ``pdfa-2``, ``pdfa-3`` to specify the exact version of | ||||
|         PDF/A you wish to use. | ||||
|  | ||||
|     If not specified, ``pdfa`` is used. Remember that paperless also keeps | ||||
|     the original input file as well as the archived version. | ||||
|  | ||||
|  | ||||
| PAPERLESS_OCR_PAGES=<num> | ||||
|     Tells paperless to use only the specified amount of pages for OCR. Documents | ||||
|     with less than the specified amount of pages get OCR'ed completely. | ||||
|  | ||||
|     Specifying 1 here will only use the first page. | ||||
|  | ||||
|     When combined with ``PAPERLESS_OCR_MODE=redo`` or ``PAPERLESS_OCR_MODE=force``, | ||||
|     paperless will not modify any text it finds on excluded pages and copy it | ||||
|     verbatim. | ||||
|  | ||||
|     Defaults to 0, which disables this feature and always uses all pages. | ||||
|  | ||||
| PAPERLESS_OCR_IMAGE_DPI=<num> | ||||
|     Paperless will OCR any images you put into the system and convert them | ||||
|     into PDF documents. This is useful if your scanner produces images. | ||||
|     In order to do so, paperless needs to know the DPI of the image. | ||||
|     Most images from scanners will have this information embedded and | ||||
|     paperless will detect and use that information. In case this fails, it | ||||
|     uses this value as a fallback. | ||||
|  | ||||
|     Set this to the DPI your scanner produces images at. | ||||
|  | ||||
|     Default is none, which will automatically calculate image DPI so that | ||||
|     the produced PDF documents are A4 sized. | ||||
|  | ||||
| PAPERLESS_OCR_MAX_IMAGE_PIXELS=<num> | ||||
|     Paperless will raise a warning when OCRing images which are over this limit and | ||||
|     will not OCR images which are more than twice this limit.  Note this does not | ||||
|     prevent the document from being consumed, but could result in missing text content. | ||||
|  | ||||
|     If unset, will default to the value determined by | ||||
|     `Pillow <https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.MAX_IMAGE_PIXELS>`_. | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         Increasing this limit could cause Paperless to consume additional resources | ||||
|         when consuming a file.  Be sure you have sufficient system resources. | ||||
|  | ||||
|     .. caution:: | ||||
|  | ||||
|         The limit is intended to prevent malicious files from consuming system resources | ||||
|         and causing crashes and other errors.  Only increase this value if you are certain | ||||
|         your documents are not malicious and you need the text which was not OCRed | ||||
|  | ||||
| PAPERLESS_OCR_USER_ARGS=<json> | ||||
|     OCRmyPDF offers many more options. Use this parameter to specify any | ||||
|     additional arguments you wish to pass to OCRmyPDF. Since Paperless uses | ||||
|     the API of OCRmyPDF, you have to specify these in a format that can be | ||||
|     passed to the API. See `the API reference of OCRmyPDF <https://ocrmypdf.readthedocs.io/en/latest/api.html#reference>`_ | ||||
|     for valid parameters. All command line options are supported, but they | ||||
|     use underscores instead of dashes. | ||||
|  | ||||
|     .. caution:: | ||||
|  | ||||
|         Paperless has been tested to work with the OCR options provided | ||||
|         above. There are many options that are incompatible with each other, | ||||
|         so specifying invalid options may prevent paperless from consuming | ||||
|         any documents. | ||||
|  | ||||
|     Specify arguments as a JSON dictionary. Keep note of lower case booleans | ||||
|     and double quoted parameter names and strings. Examples: | ||||
|  | ||||
|     .. code:: json | ||||
|  | ||||
|         {"deskew": true, "optimize": 3, "unpaper_args": "--pre-rotate 90"} | ||||
|  | ||||
| .. _configuration-tika: | ||||
|  | ||||
| Tika settings | ||||
| ############# | ||||
|  | ||||
| Paperless can make use of `Tika <https://tika.apache.org/>`_ and | ||||
| `Gotenberg <https://gotenberg.dev/>`_ for parsing and | ||||
| converting "Office" documents (such as ".doc", ".xlsx" and ".odt"). If you | ||||
| wish to use this, you must provide a Tika server and a Gotenberg server, | ||||
| configure their endpoints, and enable the feature. | ||||
|  | ||||
| PAPERLESS_TIKA_ENABLED=<bool> | ||||
|     Enable (or disable) the Tika parser. | ||||
|  | ||||
|     Defaults to false. | ||||
|  | ||||
| PAPERLESS_TIKA_ENDPOINT=<url> | ||||
|     Set the endpoint URL were Paperless can reach your Tika server. | ||||
|  | ||||
|     Defaults to "http://localhost:9998". | ||||
|  | ||||
| PAPERLESS_TIKA_GOTENBERG_ENDPOINT=<url> | ||||
|     Set the endpoint URL were Paperless can reach your Gotenberg server. | ||||
|  | ||||
|     Defaults to "http://localhost:3000". | ||||
|  | ||||
| If you run paperless on docker, you can add those services to the docker-compose | ||||
| file (see the provided ``docker-compose.sqlite-tika.yml`` file for reference). The changes | ||||
| requires are as follows: | ||||
|  | ||||
| .. code:: yaml | ||||
|  | ||||
|     services: | ||||
|         # ... | ||||
|  | ||||
|         webserver: | ||||
|             # ... | ||||
|  | ||||
|             environment: | ||||
|                 # ... | ||||
|  | ||||
|                 PAPERLESS_TIKA_ENABLED: 1 | ||||
|                 PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000 | ||||
|                 PAPERLESS_TIKA_ENDPOINT: http://tika:9998 | ||||
|  | ||||
|         # ... | ||||
|  | ||||
|         gotenberg: | ||||
|             image: gotenberg/gotenberg:7.6 | ||||
|             restart: unless-stopped | ||||
|             command: | ||||
|                 - "gotenberg" | ||||
|                 - "--chromium-disable-routes=true" | ||||
|  | ||||
|         tika: | ||||
|             image: ghcr.io/paperless-ngx/tika:latest | ||||
|             restart: unless-stopped | ||||
|  | ||||
| Add the configuration variables to the environment of the webserver (alternatively | ||||
| put the configuration in the ``docker-compose.env`` file) and add the additional | ||||
| services below the webserver service. Watch out for indentation. | ||||
|  | ||||
| Make sure to use the correct format `PAPERLESS_TIKA_ENABLED = 1` so python_dotenv can parse the statement correctly. | ||||
|  | ||||
| Software tweaks | ||||
| ############### | ||||
|  | ||||
| PAPERLESS_TASK_WORKERS=<num> | ||||
|     Paperless does multiple things in the background: Maintain the search index, | ||||
|     maintain the automatic matching algorithm, check emails, consume documents, | ||||
|     etc. This variable specifies how many things it will do in parallel. | ||||
|  | ||||
|     Defaults to 1 | ||||
|  | ||||
|  | ||||
| PAPERLESS_THREADS_PER_WORKER=<num> | ||||
|     Furthermore, paperless uses multiple threads when consuming documents to | ||||
|     speed up OCR. This variable specifies how many pages paperless will process | ||||
|     in parallel on a single document. | ||||
|  | ||||
|     .. caution:: | ||||
|  | ||||
|         Ensure that the product | ||||
|  | ||||
|             PAPERLESS_TASK_WORKERS * PAPERLESS_THREADS_PER_WORKER | ||||
|  | ||||
|         does not exceed your CPU core count or else paperless will be extremely slow. | ||||
|         If you want paperless to process many documents in parallel, choose a high | ||||
|         worker count. If you want paperless to process very large documents faster, | ||||
|         use a higher thread per worker count. | ||||
|  | ||||
|     The default is a balance between the two, according to your CPU core count, | ||||
|     with a slight favor towards threads per worker: | ||||
|  | ||||
|     +----------------+---------+---------+ | ||||
|     | CPU core count | Workers | Threads | | ||||
|     +----------------+---------+---------+ | ||||
|     |              1 |       1 |       1 | | ||||
|     +----------------+---------+---------+ | ||||
|     |              2 |       2 |       1 | | ||||
|     +----------------+---------+---------+ | ||||
|     |              4 |       2 |       2 | | ||||
|     +----------------+---------+---------+ | ||||
|     |              6 |       2 |       3 | | ||||
|     +----------------+---------+---------+ | ||||
|     |              8 |       2 |       4 | | ||||
|     +----------------+---------+---------+ | ||||
|     |             12 |       3 |       4 | | ||||
|     +----------------+---------+---------+ | ||||
|     |             16 |       4 |       4 | | ||||
|     +----------------+---------+---------+ | ||||
|  | ||||
|     If you only specify PAPERLESS_TASK_WORKERS, paperless will adjust | ||||
|     PAPERLESS_THREADS_PER_WORKER automatically. | ||||
|  | ||||
|  | ||||
| PAPERLESS_WORKER_TIMEOUT=<num> | ||||
|     Machines with few cores or weak ones might not be able to finish OCR on | ||||
|     large documents within the default 1800 seconds. So extending this timeout | ||||
|     may prove to be useful on weak hardware setups. | ||||
|  | ||||
| PAPERLESS_WORKER_RETRY=<num> | ||||
|     If PAPERLESS_WORKER_TIMEOUT has been configured, the retry time for a task can | ||||
|     also be configured.  By default, this value will be set to 10s more than the | ||||
|     worker timeout.  This value should never be set less than the worker timeout. | ||||
|  | ||||
| PAPERLESS_TIME_ZONE=<timezone> | ||||
|     Set the time zone here. | ||||
|     See https://docs.djangoproject.com/en/3.1/ref/settings/#std:setting-TIME_ZONE | ||||
|     for details on how to set it. | ||||
|  | ||||
|     Defaults to UTC. | ||||
|  | ||||
|  | ||||
| .. _configuration-polling: | ||||
|  | ||||
| PAPERLESS_CONSUMER_POLLING=<num> | ||||
|     If paperless won't find documents added to your consume folder, it might | ||||
|     not be able to automatically detect filesystem changes. In that case, | ||||
|     specify a polling interval in seconds here, which will then cause paperless | ||||
|     to periodically check your consumption directory for changes. This will also | ||||
|     disable listening for file system changes with ``inotify``. | ||||
|  | ||||
|     Defaults to 0, which disables polling and uses filesystem notifications. | ||||
|  | ||||
| PAPERLESS_CONSUMER_POLLING_RETRY_COUNT=<num> | ||||
|     If consumer polling is enabled, sets the number of times paperless will check for a | ||||
|     file to remain unmodified. | ||||
|  | ||||
|     Defaults to 5. | ||||
|  | ||||
| PAPERLESS_CONSUMER_POLLING_DELAY=<num> | ||||
|     If consumer polling is enabled, sets the delay in seconds between each check (above) paperless | ||||
|     will do while waiting for a file to remain unmodified. | ||||
|  | ||||
|     Defaults to 5. | ||||
|  | ||||
| .. _configuration-inotify: | ||||
|  | ||||
| PAPERLESS_CONSUMER_INOTIFY_DELAY=<num> | ||||
|     Sets the time in seconds the consumer will wait for additional events | ||||
|     from inotify before the consumer will consider a file ready and begin consumption. | ||||
|     Certain scanners or network setups may generate multiple events for a single file, | ||||
|     leading to multiple consumers working on the same file.  Configure this to | ||||
|     prevent that. | ||||
|  | ||||
|     Defaults to 0.5 seconds. | ||||
|  | ||||
| PAPERLESS_CONSUMER_DELETE_DUPLICATES=<bool> | ||||
|     When the consumer detects a duplicate document, it will not touch the | ||||
|     original document. This default behavior can be changed here. | ||||
|  | ||||
|     Defaults to false. | ||||
|  | ||||
|  | ||||
| PAPERLESS_CONSUMER_RECURSIVE=<bool> | ||||
|     Enable recursive watching of the consumption directory. Paperless will | ||||
|     then pickup files from files in subdirectories within your consumption | ||||
|     directory as well. | ||||
|  | ||||
|     Defaults to false. | ||||
|  | ||||
|  | ||||
| PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=<bool> | ||||
|     Set the names of subdirectories as tags for consumed files. | ||||
|     E.g. <CONSUMPTION_DIR>/foo/bar/file.pdf will add the tags "foo" and "bar" to | ||||
|     the consumed file. Paperless will create any tags that don't exist yet. | ||||
|  | ||||
|     This is useful for sorting documents with certain tags such as ``car`` or | ||||
|     ``todo`` prior to consumption. These folders won't be deleted. | ||||
|  | ||||
|     PAPERLESS_CONSUMER_RECURSIVE must be enabled for this to work. | ||||
|  | ||||
|     Defaults to false. | ||||
|  | ||||
| PAPERLESS_CONSUMER_ENABLE_BARCODES=<bool> | ||||
|     Enables the scanning and page separation based on detected barcodes. | ||||
|     This allows for scanning and adding multiple documents per uploaded | ||||
|     file, which are separated by one or multiple barcode pages. | ||||
|  | ||||
|     For ease of use, it is suggested to use a standardized separation page, | ||||
|     e.g. `here <https://www.alliancegroup.co.uk/patch-codes.htm>`_. | ||||
|  | ||||
|     If no barcodes are detected in the uploaded file, no page separation | ||||
|     will happen. | ||||
|  | ||||
|     The original document will be removed and the separated pages will be | ||||
|     saved as pdf. | ||||
|  | ||||
|     Defaults to false. | ||||
|  | ||||
|  | ||||
| PAPERLESS_CONSUMER_BARCODE_TIFF_SUPPORT=<bool> | ||||
|     Whether TIFF image files should be scanned for barcodes. | ||||
|     This will automatically convert any TIFF image(s) to pdfs for later | ||||
|     processing. | ||||
|     This only has an effect, if PAPERLESS_CONSUMER_ENABLE_BARCODES has been | ||||
|     enabled. | ||||
|  | ||||
|     Defaults to false. | ||||
|  | ||||
| PAPERLESS_CONSUMER_BARCODE_STRING=PATCHT | ||||
|   Defines the string to be detected as a separator barcode. | ||||
|   If paperless is used with the PATCH-T separator pages, users | ||||
|   shouldn't change this. | ||||
|  | ||||
|   Defaults to "PATCHT" | ||||
|  | ||||
| PAPERLESS_CONVERT_MEMORY_LIMIT=<num> | ||||
|     On smaller systems, or even in the case of Very Large Documents, the consumer | ||||
|     may explode, complaining about how it's "unable to extend pixel cache".  In | ||||
|     such cases, try setting this to a reasonably low value, like 32.  The | ||||
|     default is to use whatever is necessary to do everything without writing to | ||||
|     disk, and units are in megabytes. | ||||
|  | ||||
|     For more information on how to use this value, you should search | ||||
|     the web for "MAGICK_MEMORY_LIMIT". | ||||
|  | ||||
|     Defaults to 0, which disables the limit. | ||||
|  | ||||
| PAPERLESS_CONVERT_TMPDIR=<path> | ||||
|     Similar to the memory limit, if you've got a small system and your OS mounts | ||||
|     /tmp as tmpfs, you should set this to a path that's on a physical disk, like | ||||
|     /home/your_user/tmp or something.  ImageMagick will use this as scratch space | ||||
|     when crunching through very large documents. | ||||
|  | ||||
|     For more information on how to use this value, you should search | ||||
|     the web for "MAGICK_TMPDIR". | ||||
|  | ||||
|     Default is none, which disables the temporary directory. | ||||
|  | ||||
| PAPERLESS_POST_CONSUME_SCRIPT=<filename> | ||||
|     After a document is consumed, Paperless can trigger an arbitrary script if | ||||
|     you like.  This script will be passed a number of arguments for you to work | ||||
|     with. For more information, take a look at :ref:`advanced-post_consume_script`. | ||||
|  | ||||
|     The default is blank, which means nothing will be executed. | ||||
|  | ||||
| PAPERLESS_FILENAME_DATE_ORDER=<format> | ||||
|     Paperless will check the document text for document date information. | ||||
|     Use this setting to enable checking the document filename for date | ||||
|     information. The date order can be set to any option as specified in | ||||
|     https://dateparser.readthedocs.io/en/latest/settings.html#date-order. | ||||
|     The filename will be checked first, and if nothing is found, the document | ||||
|     text will be checked as normal. | ||||
|  | ||||
|     A date in a filename must have some separators (`.`, `-`, `/`, etc) | ||||
|     for it to be parsed. | ||||
|  | ||||
|     Defaults to none, which disables this feature. | ||||
|  | ||||
| PAPERLESS_NUMBER_OF_SUGGESTED_DATES=<num> | ||||
|     Paperless searches an entire document for dates. The first date found will | ||||
|     be used as the initial value for the created date. When this variable is | ||||
|     greater than 0 (or left to it's default value), paperless will also suggest | ||||
|     other dates found in the document, up to a maximum of this setting. Note that | ||||
|     duplicates will be removed, which can result in fewer dates displayed in the | ||||
|     frontend than this setting value. | ||||
|  | ||||
|     The task to find all dates can be time-consuming and increases with a higher | ||||
|     (maximum) number of suggested dates and slower hardware. | ||||
|  | ||||
|     Defaults to 3. Set to 0 to disable this feature. | ||||
|  | ||||
| PAPERLESS_THUMBNAIL_FONT_NAME=<filename> | ||||
|     Paperless creates thumbnails for plain text files by rendering the content | ||||
|     of the file on an image and uses a predefined font for that. This | ||||
|     font can be changed here. | ||||
|  | ||||
|     Note that this won't have any effect on already generated thumbnails. | ||||
|  | ||||
|     Defaults to ``/usr/share/fonts/liberation/LiberationSerif-Regular.ttf``. | ||||
|  | ||||
| PAPERLESS_IGNORE_DATES=<string> | ||||
|     Paperless parses a documents creation date from filename and file content. | ||||
|     You may specify a comma separated list of dates that should be ignored during | ||||
|     this process. This is useful for special dates (like date of birth) that appear | ||||
|     in documents regularly but are very unlikely to be the documents creation date. | ||||
|  | ||||
|     The date is parsed using the order specified in PAPERLESS_DATE_ORDER | ||||
|  | ||||
|     Defaults to an empty string to not ignore any dates. | ||||
|  | ||||
| PAPERLESS_DATE_ORDER=<format> | ||||
|     Paperless will try to determine the document creation date from its contents. | ||||
|     Specify the date format Paperless should expect to see within your documents. | ||||
|  | ||||
|     This option defaults to DMY which translates to day first, month second, and year | ||||
|     last order. Characters D, M, or Y can be shuffled to meet the required order. | ||||
|  | ||||
| PAPERLESS_CONSUMER_IGNORE_PATTERNS=<json> | ||||
|     By default, paperless ignores certain files and folders in the consumption | ||||
|     directory, such as system files created by the Mac OS. | ||||
|  | ||||
|     This can be adjusted by configuring a custom json array with patterns to exclude. | ||||
|  | ||||
|     Defaults to ``[".DS_STORE/*", "._*", ".stfolder/*", ".stversions/*", ".localized/*", "desktop.ini"]``. | ||||
|  | ||||
| Binaries | ||||
| ######## | ||||
|  | ||||
| There are a few external software packages that Paperless expects to find on | ||||
| your system when it starts up.  Unless you've done something creative with | ||||
| their installation, you probably won't need to edit any of these.  However, | ||||
| if you've installed these programs somewhere where simply typing the name of | ||||
| the program doesn't automatically execute it (ie. the program isn't in your | ||||
| $PATH), then you'll need to specify the literal path for that program. | ||||
|  | ||||
| PAPERLESS_CONVERT_BINARY=<path> | ||||
|     Defaults to "convert". | ||||
|  | ||||
| PAPERLESS_GS_BINARY=<path> | ||||
|     Defaults to "gs". | ||||
|  | ||||
|  | ||||
| .. _configuration-docker: | ||||
|  | ||||
| Docker-specific options | ||||
| ####################### | ||||
|  | ||||
| These options don't have any effect in ``paperless.conf``. These options adjust | ||||
| the behavior of the docker container. Configure these in `docker-compose.env`. | ||||
|  | ||||
| PAPERLESS_WEBSERVER_WORKERS=<num> | ||||
|     The number of worker processes the webserver should spawn. More worker processes | ||||
|     usually result in the front end to load data much quicker. However, each worker process | ||||
|     also loads the entire application into memory separately, so increasing this value | ||||
|     will increase RAM usage. | ||||
|  | ||||
|     Defaults to 1. | ||||
|  | ||||
| PAPERLESS_BIND_ADDR=<ip address> | ||||
|     The IP address the webserver will listen on inside the container. There are | ||||
|     special setups where you may need to configure this value to restrict the | ||||
|     Ip address or interface the webserver listens on. | ||||
|  | ||||
|     Defaults to [::], meaning all interfaces, including IPv6. | ||||
|  | ||||
| PAPERLESS_PORT=<port> | ||||
|     The port number the webserver will listen on inside the container. There are | ||||
|     special setups where you may need this to avoid collisions with other | ||||
|     services (like using podman with multiple containers in one pod). | ||||
|  | ||||
|     Don't change this when using Docker. To change the port the webserver is | ||||
|     reachable outside of the container, instead refer to the "ports" key in | ||||
|     ``docker-compose.yml``. | ||||
|  | ||||
|     Defaults to 8000. | ||||
|  | ||||
| USERMAP_UID=<uid> | ||||
|     The ID of the paperless user in the container. Set this to your actual user ID on the | ||||
|     host system, which you can get by executing | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ id -u | ||||
|  | ||||
|     Paperless will change ownership on its folders to this user, so you need to get this right | ||||
|     in order to be able to write to the consumption directory. | ||||
|  | ||||
|     Defaults to 1000. | ||||
|  | ||||
| USERMAP_GID=<gid> | ||||
|     The ID of the paperless Group in the container. Set this to your actual group ID on the | ||||
|     host system, which you can get by executing | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ id -g | ||||
|  | ||||
|     Paperless will change ownership on its folders to this group, so you need to get this right | ||||
|     in order to be able to write to the consumption directory. | ||||
|  | ||||
|     Defaults to 1000. | ||||
|  | ||||
| PAPERLESS_OCR_LANGUAGES=<list> | ||||
|     Additional OCR languages to install. By default, paperless comes with | ||||
|     English, German, Italian, Spanish and French. If your language is not in this list, install | ||||
|     additional languages with this configuration option: | ||||
|  | ||||
|     .. code:: bash | ||||
|  | ||||
|         PAPERLESS_OCR_LANGUAGES=tur ces | ||||
|  | ||||
|     To actually use these languages, also set the default OCR language of paperless: | ||||
|  | ||||
|     .. code:: bash | ||||
|  | ||||
|         PAPERLESS_OCR_LANGUAGE=tur | ||||
|  | ||||
|     Defaults to none, which does not install any additional languages. | ||||
|  | ||||
| PAPERLESS_ENABLE_FLOWER=<defined> | ||||
|     If this environment variable is defined, the Celery monitoring tool | ||||
|     `Flower <https://flower.readthedocs.io/en/latest/index.html>`_ will | ||||
|     be started by the container. | ||||
|  | ||||
|     You can read more about this in the :ref:`advanced setup <advanced-celery-monitoring>` | ||||
|     documentation. | ||||
|  | ||||
|  | ||||
| .. _configuration-update-checking: | ||||
|  | ||||
| Update Checking | ||||
| ############### | ||||
|  | ||||
| PAPERLESS_ENABLE_UPDATE_CHECK=<bool> | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|             This setting was deprecated in favor of a frontend setting after v1.9.2. A one-time | ||||
|             migration is performed for users who have this setting set. This setting is always | ||||
|             ignored if the corresponding frontend setting has been set. | ||||
							
								
								
									
										469
									
								
								docs/development.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,469 @@ | ||||
| # Development | ||||
|  | ||||
| This section describes the steps you need to take to start development | ||||
| on paperless-ngx. | ||||
|  | ||||
| Check out the source from github. The repository is organized in the | ||||
| following way: | ||||
|  | ||||
| - `main` always represents the latest release and will only see | ||||
|   changes when a new release is made. | ||||
| - `dev` contains the code that will be in the next release. | ||||
| - `feature-X` contain bigger changes that will be in some release, but | ||||
|   not necessarily the next one. | ||||
|  | ||||
| When making functional changes to paperless, _always_ make your changes | ||||
| on the `dev` branch. | ||||
|  | ||||
| Apart from that, the folder structure is as follows: | ||||
|  | ||||
| - `docs/` - Documentation. | ||||
| - `src-ui/` - Code of the front end. | ||||
| - `src/` - Code of the back end. | ||||
| - `scripts/` - Various scripts that help with different parts of | ||||
|   development. | ||||
| - `docker/` - Files required to build the docker image. | ||||
|  | ||||
| ## Contributing to Paperless | ||||
|  | ||||
| Maybe you've been using Paperless for a while and want to add a feature | ||||
| or two, or maybe you've come across a bug that you have some ideas how | ||||
| to solve. The beauty of open source software is that you can see what's | ||||
| wrong and help to get it fixed for everyone! | ||||
|  | ||||
| Before contributing please review our [code of | ||||
| conduct](https://github.com/paperless-ngx/paperless-ngx/blob/main/CODE_OF_CONDUCT.md) | ||||
| and other important information in the [contributing | ||||
| guidelines](https://github.com/paperless-ngx/paperless-ngx/blob/main/CONTRIBUTING.md). | ||||
|  | ||||
| ## Code formatting with pre-commit Hooks | ||||
|  | ||||
| To ensure a consistent style and formatting across the project source, | ||||
| the project utilizes a Git [pre-commit]{.title-ref} hook to perform some | ||||
| formatting and linting before a commit is allowed. That way, everyone | ||||
| uses the same style and some common issues can be caught early on. See | ||||
| below for installation instructions. | ||||
|  | ||||
| Once installed, hooks will run when you commit. If the formatting isn't | ||||
| quite right or a linter catches something, the commit will be rejected. | ||||
| You'll need to look at the output and fix the issue. Some hooks, such | ||||
| as the Python formatting tool [black]{.title-ref}, will format failing | ||||
| files, so all you need to do is [git add]{.title-ref} those files again | ||||
| and retry your commit. | ||||
|  | ||||
| ## Initial setup and first start | ||||
|  | ||||
| After you forked and cloned the code from github you need to perform a | ||||
| first-time setup. To do the setup you need to perform the steps from the | ||||
| following chapters in a certain order: | ||||
|  | ||||
| 1.  Install prerequisites + pipenv as mentioned in | ||||
|     `[Bare metal route](/setup#bare_metal) | ||||
|  | ||||
| 2.  Copy `paperless.conf.example` to `paperless.conf` and enable debug | ||||
|     mode. | ||||
|  | ||||
| 3.  Install the Angular CLI interface: | ||||
|  | ||||
|     ```shell-session | ||||
|     $ npm install -g @angular/cli | ||||
|     ``` | ||||
|  | ||||
| 4.  Install pre-commit | ||||
|  | ||||
|     ```shell-session | ||||
|     pre-commit install | ||||
|     ``` | ||||
|  | ||||
| 5.  Create `consume` and `media` folders in the cloned root folder. | ||||
|  | ||||
|     ```shell-session | ||||
|     mkdir -p consume media | ||||
|     ``` | ||||
|  | ||||
| 6.  You can now either \... | ||||
|  | ||||
|     - install redis or | ||||
|  | ||||
|     - use the included scripts/start-services.sh to use docker to fire | ||||
|       up a redis instance (and some other services such as tika, | ||||
|       gotenberg and a database server) or | ||||
|  | ||||
|     - spin up a bare redis container | ||||
|  | ||||
|       > ```shell-session | ||||
|       > docker run -d -p 6379:6379 --restart unless-stopped redis:latest | ||||
|       > ``` | ||||
|  | ||||
| 7.  Install the python dependencies by performing in the src/ directory. | ||||
|  | ||||
|     ```shell-session | ||||
|     pipenv install --dev | ||||
|     ``` | ||||
|  | ||||
| > - Make sure you're using python 3.9.x or lower. Otherwise you might | ||||
| >   get issues with building dependencies. You can use | ||||
| >   [pyenv](https://github.com/pyenv/pyenv) to install a specific | ||||
| >   python version. | ||||
|  | ||||
| 8.  Generate the static UI so you can perform a login to get session | ||||
|     that is required for frontend development (this needs to be done one | ||||
|     time only). From src-ui directory: | ||||
|  | ||||
|     ```shell-session | ||||
|     npm install . | ||||
|     ./node_modules/.bin/ng build --configuration production | ||||
|     ``` | ||||
|  | ||||
| 9.  Apply migrations and create a superuser for your dev instance: | ||||
|  | ||||
|     ```shell-session | ||||
|     python3 manage.py migrate | ||||
|     python3 manage.py createsuperuser | ||||
|     ``` | ||||
|  | ||||
| 10. Now spin up the dev backend. Depending on which part of paperless | ||||
|     you're developing for, you need to have some or all of them | ||||
|     running. | ||||
|  | ||||
| > ```shell-session | ||||
| > python3 manage.py runserver & python3 manage.py document_consumer & celery --app paperless worker | ||||
| > ``` | ||||
|  | ||||
| 11. Login with the superuser credentials provided in step 8 at | ||||
|     `http://localhost:8000` to create a session that enables you to use | ||||
|     the backend. | ||||
|  | ||||
| Backend development environment is now ready, to start Frontend | ||||
| development go to `/src-ui` and run `ng serve`. From there you can use | ||||
| `http://localhost:4200` for a preview. | ||||
|  | ||||
| ## Back end development | ||||
|  | ||||
| The backend is a django application. PyCharm works well for development, | ||||
| but you can use whatever you want. | ||||
|  | ||||
| Configure the IDE to use the src/ folder as the base source folder. | ||||
| Configure the following launch configurations in your IDE: | ||||
|  | ||||
| - python3 manage.py runserver | ||||
| - celery \--app paperless worker | ||||
| - python3 manage.py document_consumer | ||||
|  | ||||
| To start them all: | ||||
|  | ||||
| ```shell-session | ||||
| python3 manage.py runserver & python3 manage.py document_consumer & celery --app paperless worker | ||||
| ``` | ||||
|  | ||||
| Testing and code style: | ||||
|  | ||||
| - Run `pytest` in the src/ directory to execute all tests. This also | ||||
|   generates a HTML coverage report. When runnings test, paperless.conf | ||||
|   is loaded as well. However: the tests rely on the default | ||||
|   configuration. This is not ideal. But for now, make sure no settings | ||||
|   except for DEBUG are overridden when testing. | ||||
|  | ||||
| - Coding style is enforced by the Git pre-commit hooks. These will | ||||
|   ensure your code is formatted and do some linting when you do a [git | ||||
|   commit]{.title-ref}. | ||||
|  | ||||
| - You can also run `black` manually to format your code | ||||
|  | ||||
|   !!! note | ||||
|  | ||||
|       The line length rule E501 is generally useful for getting multiple | ||||
|       source files next to each other on the screen. However, in some | ||||
|       cases, its just not possible to make some lines fit, especially | ||||
|       complicated IF cases. Append `# NOQA: E501` to disable this check | ||||
|       for certain lines. | ||||
|  | ||||
| ## Front end development | ||||
|  | ||||
| The front end is built using Angular. In order to get started, you need | ||||
| `npm`. Install the Angular CLI interface with | ||||
|  | ||||
| ```shell-session | ||||
| $ npm install -g @angular/cli | ||||
| ``` | ||||
|  | ||||
| and make sure that it's on your path. Next, in the src-ui/ directory, | ||||
| install the required dependencies of the project. | ||||
|  | ||||
| ```shell-session | ||||
| $ npm install | ||||
| ``` | ||||
|  | ||||
| You can launch a development server by running | ||||
|  | ||||
| ```shell-session | ||||
| $ ng serve | ||||
| ``` | ||||
|  | ||||
| This will automatically update whenever you save. However, in-place | ||||
| compilation might fail on syntax errors, in which case you need to | ||||
| restart it. | ||||
|  | ||||
| By default, the development server is available on | ||||
| `http://localhost:4200/` and is configured to access the API at | ||||
| `http://localhost:8000/api/`, which is the default of the backend. If | ||||
| you enabled DEBUG on the back end, several security overrides for | ||||
| allowed hosts, CORS and X-Frame-Options are in place so that the front | ||||
| end behaves exactly as in production. This also relies on you being | ||||
| logged into the back end. Without a valid session, The front end will | ||||
| simply not work. | ||||
|  | ||||
| Testing and code style: | ||||
|  | ||||
| - The frontend code (.ts, .html, .scss) use `prettier` for code | ||||
|   formatting via the Git `pre-commit` hooks which run automatically on | ||||
|   commit. See | ||||
|   [above](#code-formatting-with-pre-commit-hooks) for installation. You can also run this via cli with a | ||||
|   command such as | ||||
|  | ||||
|   ```shell-session | ||||
|   $ git ls-files -- '*.ts' | xargs pre-commit run prettier --files | ||||
|   ``` | ||||
|  | ||||
| - Frontend testing uses jest and cypress. There is currently a need | ||||
|   for significantly more frontend tests. Unit tests and e2e tests, | ||||
|   respectively, can be run non-interactively with: | ||||
|  | ||||
|   ```shell-session | ||||
|   $ ng test | ||||
|   $ npm run e2e:ci | ||||
|   ``` | ||||
|  | ||||
|   Cypress also includes a UI which can be run from within the `src-ui` | ||||
|   directory with | ||||
|  | ||||
|   ```shell-session | ||||
|   $ ./node_modules/.bin/cypress open | ||||
|   ``` | ||||
|  | ||||
| In order to build the front end and serve it as part of django, execute | ||||
|  | ||||
| ```shell-session | ||||
| $ ng build --prod | ||||
| ``` | ||||
|  | ||||
| This will build the front end and put it in a location from which the | ||||
| Django server will serve it as static content. This way, you can verify | ||||
| that authentication is working. | ||||
|  | ||||
| ## Localization | ||||
|  | ||||
| Paperless is available in many different languages. Since paperless | ||||
| consists both of a django application and an Angular front end, both | ||||
| these parts have to be translated separately. | ||||
|  | ||||
| ### Front end localization | ||||
|  | ||||
| - The Angular front end does localization according to the [Angular | ||||
|   documentation](https://angular.io/guide/i18n). | ||||
| - The source language of the project is "en_US". | ||||
| - The source strings end up in the file "src-ui/messages.xlf". | ||||
| - The translated strings need to be placed in the | ||||
|   "src-ui/src/locale/" folder. | ||||
| - In order to extract added or changed strings from the source files, | ||||
|   call `ng xi18n --ivy`. | ||||
|  | ||||
| Adding new languages requires adding the translated files in the | ||||
| "src-ui/src/locale/" folder and adjusting a couple files. | ||||
|  | ||||
| 1.  Adjust "src-ui/angular.json": | ||||
|  | ||||
|     ```json | ||||
|     "i18n": { | ||||
|         "sourceLocale": "en-US", | ||||
|         "locales": { | ||||
|             "de": "src/locale/messages.de.xlf", | ||||
|             "nl-NL": "src/locale/messages.nl_NL.xlf", | ||||
|             "fr": "src/locale/messages.fr.xlf", | ||||
|             "en-GB": "src/locale/messages.en_GB.xlf", | ||||
|             "pt-BR": "src/locale/messages.pt_BR.xlf", | ||||
|             "language-code": "language-file" | ||||
|         } | ||||
|     } | ||||
|     ``` | ||||
|  | ||||
| 2.  Add the language to the available options in | ||||
|     "src-ui/src/app/services/settings.service.ts": | ||||
|  | ||||
|     ```typescript | ||||
|     getLanguageOptions(): LanguageOption[] { | ||||
|         return [ | ||||
|             {code: "en-us", name: $localize`English (US)`, englishName: "English (US)", dateInputFormat: "mm/dd/yyyy"}, | ||||
|             {code: "en-gb", name: $localize`English (GB)`, englishName: "English (GB)", dateInputFormat: "dd/mm/yyyy"}, | ||||
|             {code: "de", name: $localize`German`, englishName: "German", dateInputFormat: "dd.mm.yyyy"}, | ||||
|             {code: "nl", name: $localize`Dutch`, englishName: "Dutch", dateInputFormat: "dd-mm-yyyy"}, | ||||
|             {code: "fr", name: $localize`French`, englishName: "French", dateInputFormat: "dd/mm/yyyy"}, | ||||
|             {code: "pt-br", name: $localize`Portuguese (Brazil)`, englishName: "Portuguese (Brazil)", dateInputFormat: "dd/mm/yyyy"} | ||||
|             // Add your new language here | ||||
|         ] | ||||
|     } | ||||
|     ``` | ||||
|  | ||||
|     `dateInputFormat` is a special string that defines the behavior of | ||||
|     the date input fields and absolutely needs to contain "dd", "mm" | ||||
|     and "yyyy". | ||||
|  | ||||
| 3.  Import and register the Angular data for this locale in | ||||
|     "src-ui/src/app/app.module.ts": | ||||
|  | ||||
|     ```typescript | ||||
|     import localeDe from '@angular/common/locales/de' | ||||
|     registerLocaleData(localeDe) | ||||
|     ``` | ||||
|  | ||||
| ### Back end localization | ||||
|  | ||||
| A majority of the strings that appear in the back end appear only when | ||||
| the admin is used. However, some of these are still shown on the front | ||||
| end (such as error messages). | ||||
|  | ||||
| - The django application does localization according to the [django | ||||
|   documentation](https://docs.djangoproject.com/en/3.1/topics/i18n/translation/). | ||||
| - The source language of the project is "en_US". | ||||
| - Localization files end up in the folder "src/locale/". | ||||
| - In order to extract strings from the application, call | ||||
|   `python3 manage.py makemessages -l en_US`. This is important after | ||||
|   making changes to translatable strings. | ||||
| - The message files need to be compiled for them to show up in the | ||||
|   application. Call `python3 manage.py compilemessages` to do this. | ||||
|   The generated files don't get committed into git, since these are | ||||
|   derived artifacts. The build pipeline takes care of executing this | ||||
|   command. | ||||
|  | ||||
| Adding new languages requires adding the translated files in the | ||||
| "src/locale/" folder and adjusting the file | ||||
| "src/paperless/settings.py" to include the new language: | ||||
|  | ||||
| ```python | ||||
| LANGUAGES = [ | ||||
|     ("en-us", _("English (US)")), | ||||
|     ("en-gb", _("English (GB)")), | ||||
|     ("de", _("German")), | ||||
|     ("nl-nl", _("Dutch")), | ||||
|     ("fr", _("French")), | ||||
|     ("pt-br", _("Portuguese (Brazil)")), | ||||
|     # Add language here. | ||||
| ] | ||||
| ``` | ||||
|  | ||||
| ## Building the documentation | ||||
|  | ||||
| The documentation is built using material-mkdocs, see their [documentation](https://squidfunk.github.io/mkdocs-material/reference/). If you want to build the documentation locally, this is how you do it: | ||||
|  | ||||
| 1.  Install python dependencies. | ||||
|  | ||||
|     ```shell-session | ||||
|     $ cd /path/to/paperless | ||||
|     $ pipenv install --dev | ||||
|     ``` | ||||
|  | ||||
| 2.  Build the documentation | ||||
|  | ||||
|     ```shell-session | ||||
|     $ cd /path/to/paperless | ||||
|     $ pipenv mkdocs build | ||||
|     ``` | ||||
|  | ||||
| ## Building the Docker image | ||||
|  | ||||
| The docker image is primarily built by the GitHub actions workflow, but | ||||
| it can be faster when developing to build and tag an image locally. | ||||
|  | ||||
| To provide the build arguments automatically, build the image using the | ||||
| helper script `build-docker-image.sh`. | ||||
|  | ||||
| Building the docker image from source: | ||||
|  | ||||
| > ```shell-session | ||||
| > ./build-docker-image.sh Dockerfile -t <your-tag> | ||||
| > ``` | ||||
|  | ||||
| ## Extending Paperless | ||||
|  | ||||
| Paperless does not have any fancy plugin systems and will probably never | ||||
| have. However, some parts of the application have been designed to allow | ||||
| easy integration of additional features without any modification to the | ||||
| base code. | ||||
|  | ||||
| ### Making custom parsers | ||||
|  | ||||
| Paperless uses parsers to add documents to paperless. A parser is | ||||
| responsible for: | ||||
|  | ||||
| - Retrieve the content from the original | ||||
| - Create a thumbnail | ||||
| - Optional: Retrieve a created date from the original | ||||
| - Optional: Create an archived document from the original | ||||
|  | ||||
| Custom parsers can be added to paperless to support more file types. In | ||||
| order to do that, you need to write the parser itself and announce its | ||||
| existence to paperless. | ||||
|  | ||||
| The parser itself must extend `documents.parsers.DocumentParser` and | ||||
| must implement the methods `parse` and `get_thumbnail`. You can provide | ||||
| your own implementation to `get_date` if you don't want to rely on | ||||
| paperless' default date guessing mechanisms. | ||||
|  | ||||
| ```python | ||||
| class MyCustomParser(DocumentParser): | ||||
|  | ||||
|     def parse(self, document_path, mime_type): | ||||
|         # This method does not return anything. Rather, you should assign | ||||
|         # whatever you got from the document to the following fields: | ||||
|  | ||||
|         # The content of the document. | ||||
|         self.text = "content" | ||||
|  | ||||
|         # Optional: path to a PDF document that you created from the original. | ||||
|         self.archive_path = os.path.join(self.tempdir, "archived.pdf") | ||||
|  | ||||
|         # Optional: "created" date of the document. | ||||
|         self.date = get_created_from_metadata(document_path) | ||||
|  | ||||
|     def get_thumbnail(self, document_path, mime_type): | ||||
|         # This should return the path to a thumbnail you created for this | ||||
|         # document. | ||||
|         return os.path.join(self.tempdir, "thumb.png") | ||||
| ``` | ||||
|  | ||||
| If you encounter any issues during parsing, raise a | ||||
| `documents.parsers.ParseError`. | ||||
|  | ||||
| The `self.tempdir` directory is a temporary directory that is guaranteed | ||||
| to be empty and removed after consumption finished. You can use that | ||||
| directory to store any intermediate files and also use it to store the | ||||
| thumbnail / archived document. | ||||
|  | ||||
| After that, you need to announce your parser to paperless. You need to | ||||
| connect a handler to the `document_consumer_declaration` signal. Have a | ||||
| look in the file `src/paperless_tesseract/apps.py` on how that's done. | ||||
| The handler is a method that returns information about your parser: | ||||
|  | ||||
| ```python | ||||
| def myparser_consumer_declaration(sender, **kwargs): | ||||
|     return { | ||||
|         "parser": MyCustomParser, | ||||
|         "weight": 0, | ||||
|         "mime_types": { | ||||
|             "application/pdf": ".pdf", | ||||
|             "image/jpeg": ".jpg", | ||||
|         } | ||||
|     } | ||||
| ``` | ||||
|  | ||||
| - `parser` is a reference to a class that extends `DocumentParser`. | ||||
| - `weight` is used whenever two or more parsers are able to parse a | ||||
|   file: The parser with the higher weight wins. This can be used to | ||||
|   override the parsers provided by paperless. | ||||
| - `mime_types` is a dictionary. The keys are the mime types your | ||||
|   parser supports and the value is the default file extension that | ||||
|   paperless should use when storing files and serving them for | ||||
|   download. We could guess that from the file extensions, but some | ||||
|   mime types have many extensions associated with them and the python | ||||
|   methods responsible for guessing the extension do not always return | ||||
|   the same value. | ||||
| @@ -1,431 +0,0 @@ | ||||
| .. _extending: | ||||
|  | ||||
| Paperless-ngx Development | ||||
| ######################### | ||||
|  | ||||
| This section describes the steps you need to take to start development on paperless-ngx. | ||||
|  | ||||
| Check out the source from github. The repository is organized in the following way: | ||||
|  | ||||
| *   ``main`` always represents the latest release and will only see changes | ||||
|     when a new release is made. | ||||
| *   ``dev`` contains the code that will be in the next release. | ||||
| *   ``feature-X`` contain bigger changes that will be in some release, but not | ||||
|     necessarily the next one. | ||||
|  | ||||
| When making functional changes to paperless, *always* make your changes on the ``dev`` branch. | ||||
|  | ||||
| Apart from that, the folder structure is as follows: | ||||
|  | ||||
| *   ``docs/`` - Documentation. | ||||
| *   ``src-ui/`` - Code of the front end. | ||||
| *   ``src/`` - Code of the back end. | ||||
| *   ``scripts/`` - Various scripts that help with different parts of development. | ||||
| *   ``docker/`` - Files required to build the docker image. | ||||
|  | ||||
| Contributing to Paperless | ||||
| ========================= | ||||
|  | ||||
| Maybe you've been using Paperless for a while and want to add a feature or two, | ||||
| or maybe you've come across a bug that you have some ideas how to solve.  The | ||||
| beauty of open source software is that you can see what's wrong and help to get | ||||
| it fixed for everyone! | ||||
|  | ||||
| Before contributing please review our `code of conduct`_ and other important | ||||
| information in the `contributing guidelines`_. | ||||
|  | ||||
| .. _code-formatting-with-pre-commit-hooks: | ||||
|  | ||||
| Code formatting with pre-commit Hooks | ||||
| ===================================== | ||||
|  | ||||
| To ensure a consistent style and formatting across the project source, the project | ||||
| utilizes a Git `pre-commit` hook to perform some formatting and linting before a | ||||
| commit is allowed. That way, everyone uses the same style and some common issues | ||||
| can be caught early on. See below for installation instructions. | ||||
|  | ||||
| Once installed, hooks will run when you commit. If the formatting isn't quite right | ||||
| or a linter catches something, the commit will be rejected. You'll need to look at the | ||||
| output and fix the issue. Some hooks, such as the Python formatting tool `black`, | ||||
| will format failing files, so all you need to do is `git add` those files again and | ||||
| retry your commit. | ||||
|  | ||||
| Initial setup and first start | ||||
| ============================= | ||||
|  | ||||
| After you forked and cloned the code from github you need to perform a first-time setup. | ||||
| To do the setup you need to perform the steps from the following chapters in a certain order: | ||||
|  | ||||
| 1.  Install prerequisites + pipenv as mentioned in :ref:`Bare metal route <setup-bare_metal>` | ||||
| 2.  Copy ``paperless.conf.example`` to ``paperless.conf`` and enable debug mode. | ||||
| 3.  Install the Angular CLI interface: | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ npm install -g @angular/cli | ||||
|  | ||||
| 4.  Install pre-commit | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         pre-commit install | ||||
|  | ||||
| 5.  Create ``consume`` and ``media`` folders in the cloned root folder. | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         mkdir -p consume media | ||||
|  | ||||
| 6.  You can now either ... | ||||
|  | ||||
|     *  install redis or | ||||
|     *  use the included scripts/start-services.sh to use docker to fire up a redis instance (and some other services such as tika, gotenberg and a database server) or | ||||
|     *  spin up a bare redis container | ||||
|  | ||||
|         .. code:: shell-session | ||||
|  | ||||
|             docker run -d -p 6379:6379 --restart unless-stopped redis:latest | ||||
|  | ||||
| 7.  Install the python dependencies by performing in the src/ directory. | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         pipenv install --dev | ||||
|  | ||||
|   * Make sure you're using python 3.9.x or lower. Otherwise you might get issues with building dependencies. You can use `pyenv <https://github.com/pyenv/pyenv>`_ to install a specific python version. | ||||
|  | ||||
| 8.  Generate the static UI so you can perform a login to get session that is required for frontend development (this needs to be done one time only). From src-ui directory: | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         npm install . | ||||
|         ./node_modules/.bin/ng build --configuration production | ||||
|  | ||||
| 9.  Apply migrations and create a superuser for your dev instance: | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         python3 manage.py migrate | ||||
|         python3 manage.py createsuperuser | ||||
|  | ||||
| 10.  Now spin up the dev backend. Depending on which part of paperless you're developing for, you need to have some or all of them running. | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         python3 manage.py runserver & python3 manage.py document_consumer & celery --app paperless worker | ||||
|  | ||||
| 11. Login with the superuser credentials provided in step 8 at ``http://localhost:8000`` to create a session that enables you to use the backend. | ||||
|  | ||||
| Backend development environment is now ready, to start Frontend development go to ``/src-ui`` and run ``ng serve``. From there you can use ``http://localhost:4200`` for a preview. | ||||
|  | ||||
| Back end development | ||||
| ==================== | ||||
|  | ||||
| The backend is a django application. PyCharm works well for development, but you can use whatever | ||||
| you want. | ||||
|  | ||||
| Configure the IDE to use the src/ folder as the base source folder. Configure the following | ||||
| launch configurations in your IDE: | ||||
|  | ||||
| *   python3 manage.py runserver | ||||
| *   celery --app paperless worker | ||||
| *   python3 manage.py document_consumer | ||||
|  | ||||
| To start them all: | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     python3 manage.py runserver & python3 manage.py document_consumer & celery --app paperless worker | ||||
|  | ||||
| Testing and code style: | ||||
|  | ||||
| *   Run ``pytest`` in the src/ directory to execute all tests. This also generates a HTML coverage | ||||
|     report. When runnings test, paperless.conf is loaded as well. However: the tests rely on the default | ||||
|     configuration. This is not ideal. But for now, make sure no settings except for DEBUG are overridden when testing. | ||||
| *   Coding style is enforced by the Git pre-commit hooks.  These will ensure your code is formatted and do some | ||||
|     linting when you do a `git commit`. | ||||
| *   You can also run ``black`` manually to format your code | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         The line length rule E501 is generally useful for getting multiple source files | ||||
|         next to each other on the screen. However, in some cases, its just not possible | ||||
|         to make some lines fit, especially complicated IF cases. Append ``# NOQA: E501`` | ||||
|         to disable this check for certain lines. | ||||
|  | ||||
| Front end development | ||||
| ===================== | ||||
|  | ||||
| The front end is built using Angular. In order to get started, you need ``npm``. | ||||
| Install the Angular CLI interface with | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     $ npm install -g @angular/cli | ||||
|  | ||||
| and make sure that it's on your path. Next, in the src-ui/ directory, install the | ||||
| required dependencies of the project. | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     $ npm install | ||||
|  | ||||
| You can launch a development server by running | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     $ ng serve | ||||
|  | ||||
| This will automatically update whenever you save. However, in-place compilation might fail | ||||
| on syntax errors, in which case you need to restart it. | ||||
|  | ||||
| By default, the development server is available on ``http://localhost:4200/`` and is configured | ||||
| to access the API at ``http://localhost:8000/api/``, which is the default of the backend. | ||||
| If you enabled DEBUG on the back end, several security overrides for allowed hosts, CORS and | ||||
| X-Frame-Options are in place so that the front end behaves exactly as in production. This also | ||||
| relies on you being logged into the back end. Without a valid session, The front end will simply | ||||
| not work. | ||||
|  | ||||
| Testing and code style: | ||||
|  | ||||
| *   The frontend code (.ts, .html, .scss) use ``prettier`` for code formatting via the Git | ||||
|     ``pre-commit`` hooks which run automatically on commit. See | ||||
|     :ref:`above <code-formatting-with-pre-commit-hooks>` for installation. You can also run this | ||||
|     via cli with a command such as | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ git ls-files -- '*.ts' | xargs pre-commit run prettier --files | ||||
|  | ||||
| *   Frontend testing uses jest and cypress. There is currently a need for significantly more | ||||
|     frontend tests. Unit tests and e2e tests, respectively, can be run non-interactively with: | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ ng test | ||||
|         $ npm run e2e:ci | ||||
|  | ||||
|     Cypress also includes a UI which can be run from within the ``src-ui`` directory with | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ ./node_modules/.bin/cypress open | ||||
|  | ||||
| In order to build the front end and serve it as part of django, execute | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     $ ng build --prod | ||||
|  | ||||
| This will build the front end and put it in a location from which the Django server will serve | ||||
| it as static content. This way, you can verify that authentication is working. | ||||
|  | ||||
|  | ||||
| Localization | ||||
| ============ | ||||
|  | ||||
| Paperless is available in many different languages. Since paperless consists both of a django | ||||
| application and an Angular front end, both these parts have to be translated separately. | ||||
|  | ||||
| Front end localization | ||||
| ---------------------- | ||||
|  | ||||
| *   The Angular front end does localization according to the `Angular documentation <https://angular.io/guide/i18n>`_. | ||||
| *   The source language of the project is "en_US". | ||||
| *   The source strings end up in the file "src-ui/messages.xlf". | ||||
| *   The translated strings need to be placed in the "src-ui/src/locale/" folder. | ||||
| *   In order to extract added or changed strings from the source files, call ``ng xi18n --ivy``. | ||||
|  | ||||
| Adding new languages requires adding the translated files in the "src-ui/src/locale/" folder and adjusting a couple files. | ||||
|  | ||||
| 1.  Adjust "src-ui/angular.json": | ||||
|  | ||||
|     .. code:: json | ||||
|  | ||||
|         "i18n": { | ||||
|             "sourceLocale": "en-US", | ||||
|             "locales": { | ||||
|                 "de": "src/locale/messages.de.xlf", | ||||
|                 "nl-NL": "src/locale/messages.nl_NL.xlf", | ||||
|                 "fr": "src/locale/messages.fr.xlf", | ||||
|                 "en-GB": "src/locale/messages.en_GB.xlf", | ||||
|                 "pt-BR": "src/locale/messages.pt_BR.xlf", | ||||
|                 "language-code": "language-file" | ||||
|             } | ||||
|         } | ||||
|  | ||||
| 2.  Add the language to the available options in "src-ui/src/app/services/settings.service.ts": | ||||
|  | ||||
|     .. code:: typescript | ||||
|  | ||||
|         getLanguageOptions(): LanguageOption[] { | ||||
|             return [ | ||||
|                 {code: "en-us", name: $localize`English (US)`, englishName: "English (US)", dateInputFormat: "mm/dd/yyyy"}, | ||||
|                 {code: "en-gb", name: $localize`English (GB)`, englishName: "English (GB)", dateInputFormat: "dd/mm/yyyy"}, | ||||
|                 {code: "de", name: $localize`German`, englishName: "German", dateInputFormat: "dd.mm.yyyy"}, | ||||
|                 {code: "nl", name: $localize`Dutch`, englishName: "Dutch", dateInputFormat: "dd-mm-yyyy"}, | ||||
|                 {code: "fr", name: $localize`French`, englishName: "French", dateInputFormat: "dd/mm/yyyy"}, | ||||
|                 {code: "pt-br", name: $localize`Portuguese (Brazil)`, englishName: "Portuguese (Brazil)", dateInputFormat: "dd/mm/yyyy"} | ||||
|                 // Add your new language here | ||||
|             ] | ||||
|         } | ||||
|  | ||||
|     ``dateInputFormat`` is a special string that defines the behavior of the date input fields and absolutely needs to contain "dd", "mm" and "yyyy". | ||||
|  | ||||
| 3.  Import and register the Angular data for this locale in "src-ui/src/app/app.module.ts": | ||||
|  | ||||
|     .. code:: typescript | ||||
|  | ||||
|         import localeDe from '@angular/common/locales/de'; | ||||
|         registerLocaleData(localeDe) | ||||
|  | ||||
| Back end localization | ||||
| --------------------- | ||||
|  | ||||
| A majority of the strings that appear in the back end appear only when the admin is used. However, | ||||
| some of these are still shown on the front end (such as error messages). | ||||
|  | ||||
| *   The django application does localization according to the `django documentation <https://docs.djangoproject.com/en/3.1/topics/i18n/translation/>`_. | ||||
| *   The source language of the project is "en_US". | ||||
| *   Localization files end up in the folder "src/locale/". | ||||
| *   In order to extract strings from the application, call ``python3 manage.py makemessages -l en_US``. This is important after making changes to translatable strings. | ||||
| *   The message files need to be compiled for them to show up in the application. Call ``python3 manage.py compilemessages`` to do this. The generated files don't get | ||||
|     committed into git, since these are derived artifacts. The build pipeline takes care of executing this command. | ||||
|  | ||||
| Adding new languages requires adding the translated files in the "src/locale/" folder and adjusting the file "src/paperless/settings.py" to include the new language: | ||||
|  | ||||
| .. code:: python | ||||
|  | ||||
|     LANGUAGES = [ | ||||
|         ("en-us", _("English (US)")), | ||||
|         ("en-gb", _("English (GB)")), | ||||
|         ("de", _("German")), | ||||
|         ("nl-nl", _("Dutch")), | ||||
|         ("fr", _("French")), | ||||
|         ("pt-br", _("Portuguese (Brazil)")), | ||||
|         # Add language here. | ||||
|     ] | ||||
|  | ||||
|  | ||||
| Building the documentation | ||||
| ========================== | ||||
|  | ||||
| The documentation is built using sphinx. I've configured ReadTheDocs to automatically build | ||||
| the documentation when changes are pushed. If you want to build the documentation locally, | ||||
| this is how you do it: | ||||
|  | ||||
| 1.  Install python dependencies. | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ cd /path/to/paperless | ||||
|         $ pipenv install --dev | ||||
|  | ||||
| 2.  Build the documentation | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ cd /path/to/paperless/docs | ||||
|         $ pipenv run make clean html | ||||
|  | ||||
| This will build the HTML documentation, and put the resulting files in the ``_build/html`` | ||||
| directory. | ||||
|  | ||||
| Building the Docker image | ||||
| ========================= | ||||
|  | ||||
| The docker image is primarily built by the GitHub actions workflow, but it can be | ||||
| faster when developing to build and tag an image locally. | ||||
|  | ||||
| To provide the build arguments automatically, build the image using the helper | ||||
| script ``build-docker-image.sh``. | ||||
|  | ||||
| Building the docker image from source: | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         ./build-docker-image.sh Dockerfile -t <your-tag> | ||||
|  | ||||
| Extending Paperless | ||||
| =================== | ||||
|  | ||||
| Paperless does not have any fancy plugin systems and will probably never have. However, | ||||
| some parts of the application have been designed to allow easy integration of additional | ||||
| features without any modification to the base code. | ||||
|  | ||||
| Making custom parsers | ||||
| --------------------- | ||||
|  | ||||
| Paperless uses parsers to add documents to paperless. A parser is responsible for: | ||||
|  | ||||
| *   Retrieve the content from the original | ||||
| *   Create a thumbnail | ||||
| *   Optional: Retrieve a created date from the original | ||||
| *   Optional: Create an archived document from the original | ||||
|  | ||||
| Custom parsers can be added to paperless to support more file types. In order to do that, | ||||
| you need to write the parser itself and announce its existence to paperless. | ||||
|  | ||||
| The parser itself must extend ``documents.parsers.DocumentParser`` and must implement the | ||||
| methods ``parse`` and ``get_thumbnail``. You can provide your own implementation to | ||||
| ``get_date`` if you don't want to rely on paperless' default date guessing mechanisms. | ||||
|  | ||||
| .. code:: python | ||||
|  | ||||
|     class MyCustomParser(DocumentParser): | ||||
|  | ||||
|         def parse(self, document_path, mime_type): | ||||
|             # This method does not return anything. Rather, you should assign | ||||
|             # whatever you got from the document to the following fields: | ||||
|  | ||||
|             # The content of the document. | ||||
|             self.text = "content" | ||||
|  | ||||
|             # Optional: path to a PDF document that you created from the original. | ||||
|             self.archive_path = os.path.join(self.tempdir, "archived.pdf") | ||||
|  | ||||
|             # Optional: "created" date of the document. | ||||
|             self.date = get_created_from_metadata(document_path) | ||||
|  | ||||
|         def get_thumbnail(self, document_path, mime_type): | ||||
|             # This should return the path to a thumbnail you created for this | ||||
|             # document. | ||||
|             return os.path.join(self.tempdir, "thumb.png") | ||||
|  | ||||
| If you encounter any issues during parsing, raise a ``documents.parsers.ParseError``. | ||||
|  | ||||
| The ``self.tempdir`` directory is a temporary directory that is guaranteed to be empty | ||||
| and removed after consumption finished. You can use that directory to store any | ||||
| intermediate files and also use it to store the thumbnail / archived document. | ||||
|  | ||||
| After that, you need to announce your parser to paperless. You need to connect a | ||||
| handler to the ``document_consumer_declaration`` signal. Have a look in the file | ||||
| ``src/paperless_tesseract/apps.py`` on how that's done. The handler is a method | ||||
| that returns information about your parser: | ||||
|  | ||||
| .. code:: python | ||||
|  | ||||
|     def myparser_consumer_declaration(sender, **kwargs): | ||||
|         return { | ||||
|             "parser": MyCustomParser, | ||||
|             "weight": 0, | ||||
|             "mime_types": { | ||||
|                 "application/pdf": ".pdf", | ||||
|                 "image/jpeg": ".jpg", | ||||
|             } | ||||
|         } | ||||
|  | ||||
| *   ``parser`` is a reference to a class that extends ``DocumentParser``. | ||||
|  | ||||
| *   ``weight`` is used whenever two or more parsers are able to parse a file: The parser with | ||||
|     the higher weight wins. This can be used to override the parsers provided by | ||||
|     paperless. | ||||
|  | ||||
| *   ``mime_types`` is a dictionary. The keys are the mime types your parser supports and the value | ||||
|     is the default file extension that paperless should use when storing files and serving them for | ||||
|     download. We could guess that from the file extensions, but some mime types have many extensions | ||||
|     associated with them and the python methods responsible for guessing the extension do not always | ||||
|     return the same value. | ||||
|  | ||||
| .. _code of conduct: https://github.com/paperless-ngx/paperless-ngx/blob/main/CODE_OF_CONDUCT.md | ||||
| .. _contributing guidelines: https://github.com/paperless-ngx/paperless-ngx/blob/main/CONTRIBUTING.md | ||||
							
								
								
									
										128
									
								
								docs/faq.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,128 @@ | ||||
| # Frequently Asked Questions | ||||
|  | ||||
| ### _What's the general plan for Paperless-ngx?_ | ||||
|  | ||||
| **A:** While Paperless-ngx is already considered largely | ||||
| "feature-complete" it is a community-driven project and development | ||||
| will be guided in this way. New features can be submitted via GitHub | ||||
| discussions and "up-voted" by the community but this is not a | ||||
| guarantee the feature will be implemented. This project will always be | ||||
| open to collaboration in the form of PRs, ideas etc. | ||||
|  | ||||
| ### _I'm using docker. Where are my documents?_ | ||||
|  | ||||
| **A:** Your documents are stored inside the docker volume | ||||
| `paperless_media`. Docker manages this volume automatically for you. It | ||||
| is a persistent storage and will persist as long as you don't | ||||
| explicitly delete it. The actual location depends on your host operating | ||||
| system. On Linux, chances are high that this location is | ||||
|  | ||||
| ``` | ||||
| /var/lib/docker/volumes/paperless_media/_data | ||||
| ``` | ||||
|  | ||||
| !!! warning | ||||
|  | ||||
|     Do not mess with this folder. Don't change permissions and don't move | ||||
|     files around manually. This folder is meant to be entirely managed by | ||||
|     docker and paperless. | ||||
|  | ||||
| ### Let's say I want to switch tools in a year. Can I easily move | ||||
|  | ||||
| to other systems?\* | ||||
|  | ||||
| **A:** Your documents are stored as plain files inside the media folder. | ||||
| You can always drag those files out of that folder to use them | ||||
| elsewhere. Here are a couple notes about that. | ||||
|  | ||||
| - Paperless-ngx never modifies your original documents. It keeps | ||||
|   checksums of all documents and uses a scheduled sanity checker to | ||||
|   check that they remain the same. | ||||
| - By default, paperless uses the internal ID of each document as its | ||||
|   filename. This might not be very convenient for export. However, you | ||||
|   can adjust the way files are stored in paperless by | ||||
|   `configuring the filename format <advanced-file_name_handling>`{.interpreted-text | ||||
|   role="ref"}. | ||||
| - `The exporter <utilities-exporter>`{.interpreted-text role="ref"} is | ||||
|   another easy way to get your files out of paperless with reasonable | ||||
|   file names. | ||||
|  | ||||
| ### _What file types does paperless-ngx support?_ | ||||
|  | ||||
| **A:** Currently, the following files are supported: | ||||
|  | ||||
| - PDF documents, PNG images, JPEG images, TIFF images and GIF images | ||||
|   are processed with OCR and converted into PDF documents. | ||||
| - Plain text documents are supported as well and are added verbatim to | ||||
|   paperless. | ||||
| - With the optional Tika integration enabled (see | ||||
|   `Configuration <configuration-tika>`{.interpreted-text role="ref"}), | ||||
|   Paperless also supports various Office documents (.docx, .doc, odt, | ||||
|   .ppt, .pptx, .odp, .xls, .xlsx, .ods). | ||||
|  | ||||
| Paperless-ngx determines the type of a file by inspecting its content. | ||||
| The file extensions do not matter. | ||||
|  | ||||
| ### _Will paperless-ngx run on Raspberry Pi?_ | ||||
|  | ||||
| **A:** The short answer is yes. I've tested it on a Raspberry Pi 3 B. | ||||
| The long answer is that certain parts of Paperless will run very slow, | ||||
| such as the OCR. On Raspberry Pi, try to OCR documents before feeding | ||||
| them into paperless so that paperless can reuse the text. The web | ||||
| interface is a lot snappier, since it runs in your browser and paperless | ||||
| has to do much less work to serve the data. | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     You can adjust some of the settings so that paperless uses less | ||||
|     processing power. See `setup-less_powerful_devices`{.interpreted-text | ||||
|     role="ref"} for details. | ||||
|  | ||||
| ### _How do I install paperless-ngx on Raspberry Pi?_ | ||||
|  | ||||
| **A:** Docker images are available for arm and arm64 hardware, so just | ||||
| follow the docker-compose instructions. Apart from more required disk | ||||
| space compared to a bare metal installation, docker comes with close to | ||||
| zero overhead, even on Raspberry Pi. | ||||
|  | ||||
| If you decide to got with the bare metal route, be aware that some of | ||||
| the python requirements do not have precompiled packages for ARM / | ||||
| ARM64. Installation of these will require additional development | ||||
| libraries and compilation will take a long time. | ||||
|  | ||||
| ### _How do I run this on Unraid?_ | ||||
|  | ||||
| **A:** Paperless-ngx is available as [community | ||||
| app](https://unraid.net/community/apps?q=paperless-ngx) in Unraid. [Uli | ||||
| Fahrer](https://github.com/Tooa) created a container template for that. | ||||
|  | ||||
| ### _How do I run this on my toaster?_ | ||||
|  | ||||
| **A:** I honestly don't know! As for all other devices that might be | ||||
| able to run paperless, you're a bit on your own. If you can't run the | ||||
| docker image, the documentation has instructions for bare metal | ||||
| installs. I'm running paperless on an i3 processor from 2015 or so. | ||||
| This is also what I use to test new releases with. Apart from that, I | ||||
| also have a Raspberry Pi, which I occasionally build the image on and | ||||
| see if it works. | ||||
|  | ||||
| ### _How do I proxy this with NGINX?_ | ||||
|  | ||||
| **A:** See `here <setup-nginx>`{.interpreted-text role="ref"}. | ||||
|  | ||||
| ### _How do I get WebSocket support with Apache mod_wsgi_? | ||||
|  | ||||
| **A:** `mod_wsgi` by itself does not support ASGI. Paperless will | ||||
| continue to work with WSGI, but certain features such as status | ||||
| notifications about document consumption won't be available. | ||||
|  | ||||
| If you want to continue using `mod_wsgi`, you will have to run an | ||||
| ASGI-enabled web server as well that processes WebSocket connections, | ||||
| and configure Apache to redirect WebSocket connections to this server. | ||||
| Multiple options for ASGI servers exist: | ||||
|  | ||||
| - `gunicorn` with `uvicorn` as the worker implementation (the default | ||||
|   of paperless) | ||||
| - `daphne` as a standalone server, which is the reference | ||||
|   implementation for ASGI. | ||||
| - `uvicorn` as a standalone server | ||||
							
								
								
									
										117
									
								
								docs/faq.rst
									
									
									
									
									
								
							
							
						
						| @@ -1,117 +0,0 @@ | ||||
|  | ||||
| ************************** | ||||
| Frequently asked questions | ||||
| ************************** | ||||
|  | ||||
| **Q:** *What's the general plan for Paperless-ngx?* | ||||
|  | ||||
| **A:** While Paperless-ngx is already considered largely "feature-complete" it is a community-driven | ||||
| project and development will be guided in this way. New features can be submitted via | ||||
| GitHub discussions and "up-voted" by the community but this is not a guarantee the feature | ||||
| will be implemented. This project will always be open to collaboration in the form of PRs, | ||||
| ideas etc. | ||||
|  | ||||
| **Q:** *I'm using docker. Where are my documents?* | ||||
|  | ||||
| **A:** Your documents are stored inside the docker volume ``paperless_media``. | ||||
| Docker manages this volume automatically for you. It is a persistent storage | ||||
| and will persist as long as you don't explicitly delete it. The actual location | ||||
| depends on your host operating system. On Linux, chances are high that this location | ||||
| is | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     /var/lib/docker/volumes/paperless_media/_data | ||||
|  | ||||
| .. caution:: | ||||
|  | ||||
|     Do not mess with this folder. Don't change permissions and don't move | ||||
|     files around manually. This folder is meant to be entirely managed by docker | ||||
|     and paperless. | ||||
|  | ||||
| **Q:** *Let's say I want to switch tools in a year. Can I easily move to other systems?* | ||||
|  | ||||
| **A:** Your documents are stored as plain files inside the media folder. You can always drag those files | ||||
| out of that folder to use them elsewhere. Here are a couple notes about that. | ||||
|  | ||||
| *   Paperless-ngx never modifies your original documents. It keeps checksums of all documents and uses a | ||||
|     scheduled sanity checker to check that they remain the same. | ||||
| *   By default, paperless uses the internal ID of each document as its filename. This might not be very | ||||
|     convenient for export. However, you can adjust the way files are stored in paperless by | ||||
|     :ref:`configuring the filename format <advanced-file_name_handling>`. | ||||
| *   :ref:`The exporter <utilities-exporter>` is another easy way to get your files out of paperless with reasonable file names. | ||||
|  | ||||
| **Q:** *What file types does paperless-ngx support?* | ||||
|  | ||||
| **A:** Currently, the following files are supported: | ||||
|  | ||||
| *   PDF documents, PNG images, JPEG images, TIFF images and GIF images are processed with OCR and converted into PDF documents. | ||||
| *   Plain text documents are supported as well and are added verbatim | ||||
|     to paperless. | ||||
| *   With the optional Tika integration enabled (see :ref:`Configuration <configuration-tika>`), Paperless also supports various | ||||
|     Office documents (.docx, .doc, odt, .ppt, .pptx, .odp, .xls, .xlsx, .ods). | ||||
|  | ||||
| Paperless-ngx determines the type of a file by inspecting its content. The | ||||
| file extensions do not matter. | ||||
|  | ||||
| **Q:** *Will paperless-ngx run on Raspberry Pi?* | ||||
|  | ||||
| **A:** The short answer is yes. I've tested it on a Raspberry Pi 3 B. | ||||
| The long answer is that certain parts of | ||||
| Paperless will run very slow, such as the OCR. On Raspberry Pi, | ||||
| try to OCR documents before feeding them into paperless so that paperless can | ||||
| reuse the text. The web interface is a lot snappier, since it runs | ||||
| in your browser and paperless has to do much less work to serve the data. | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     You can adjust some of the settings so that paperless uses less processing | ||||
|     power. See :ref:`setup-less_powerful_devices` for details. | ||||
|  | ||||
|  | ||||
| **Q:** *How do I install paperless-ngx on Raspberry Pi?* | ||||
|  | ||||
| **A:** Docker images are available for arm and arm64 hardware, so just follow | ||||
| the docker-compose instructions. Apart from more required disk space compared to | ||||
| a bare metal installation, docker comes with close to zero overhead, even on | ||||
| Raspberry Pi. | ||||
|  | ||||
| If you decide to got with the bare metal route, be aware that some of the | ||||
| python requirements do not have precompiled packages for ARM / ARM64. Installation | ||||
| of these will require additional development libraries and compilation will take | ||||
| a long time. | ||||
|  | ||||
| **Q:** *How do I run this on Unraid?* | ||||
|  | ||||
| **A:** Paperless-ngx is available as `community app <https://unraid.net/community/apps?q=paperless-ngx>`_ | ||||
| in Unraid. `Uli Fahrer <https://github.com/Tooa>`_ created a container template for that. | ||||
|  | ||||
| **Q:** *How do I run this on my toaster?* | ||||
|  | ||||
| **A:** I honestly don't know! As for all other devices that might be able | ||||
| to run paperless, you're a bit on your own. If you can't run the docker image, | ||||
| the documentation has instructions for bare metal installs. I'm running | ||||
| paperless on an i3 processor from 2015 or so. This is also what I use to test | ||||
| new releases with. Apart from that, I also have a Raspberry Pi, which I | ||||
| occasionally build the image on and see if it works. | ||||
|  | ||||
| **Q:** *How do I proxy this with NGINX?* | ||||
|  | ||||
| **A:** See :ref:`here <setup-nginx>`. | ||||
|  | ||||
| .. _faq-mod_wsgi: | ||||
|  | ||||
| **Q:** *How do I get WebSocket support with Apache mod_wsgi*? | ||||
|  | ||||
| **A:** ``mod_wsgi`` by itself does not support ASGI. Paperless will continue | ||||
| to work with WSGI, but certain features such as status notifications about | ||||
| document consumption won't be available. | ||||
|  | ||||
| If you want to continue using ``mod_wsgi``, you will have to run an ASGI-enabled | ||||
| web server as well that processes WebSocket connections, and configure Apache to | ||||
| redirect WebSocket connections to this server. Multiple options for ASGI servers | ||||
| exist: | ||||
|  | ||||
| * ``gunicorn`` with ``uvicorn`` as the worker implementation (the default of paperless) | ||||
| * ``daphne`` as a standalone server, which is the reference implementation for ASGI. | ||||
| * ``uvicorn`` as a standalone server | ||||
							
								
								
									
										138
									
								
								docs/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,138 @@ | ||||
| <div class="grid-left" markdown> | ||||
| {.index-logo} | ||||
| {.index-logo} | ||||
|  | ||||
| **Paperless-ngx** is a _community-supported_ open-source document management system that transforms your | ||||
| physical documents into a searchable online archive so you can keep, well, _less paper_. | ||||
|  | ||||
| [Get started](/setup/){ .md-button .md-button--primary .index-callout } | ||||
| [Demo](https://demo.paperless-ngx.com){ .md-button .md-button--secondary } | ||||
|  | ||||
| </div> | ||||
| <div class="grid-right" markdown> | ||||
| {.index-screenshot} | ||||
| {.index-screenshot} | ||||
| </div> | ||||
| <div class="clear"></div> | ||||
|  | ||||
| ## Why This Exists | ||||
|  | ||||
| Paper is a nightmare. Environmental issues aside, there's no excuse for | ||||
| it in the 21st century. It takes up space, collects dust, doesn't | ||||
| support any form of a search feature, indexing is tedious, it's heavy | ||||
| and prone to damage & loss. | ||||
|  | ||||
| This software is designed to make "going paperless" easier. No more worrying | ||||
| about finding stuff again, feed documents right from the post box into | ||||
| the scanner and then shred them. Perhaps you might find it useful too. | ||||
|  | ||||
| ## Paperless, a history | ||||
|  | ||||
| Paperless is a simple Django application running in two parts: a | ||||
| _Consumer_ (the thing that does the indexing) and the _Web server_ (the | ||||
| part that lets you search & download already-indexed documents). If you | ||||
| want to learn more about its functions keep on reading after the | ||||
| installation section. | ||||
|  | ||||
| Paperless-ngx is a document management system that transforms your | ||||
| physical documents into a searchable online archive so you can keep, | ||||
| well, _less paper_. | ||||
|  | ||||
| Paperless-ngx forked from paperless-ng to continue the great work and | ||||
| distribute responsibility of supporting and advancing the project among | ||||
| a team of people. | ||||
|  | ||||
| NG stands for both Angular (the framework used for the Frontend) and | ||||
| next-gen. Publishing this project under a different name also avoids | ||||
| confusion between paperless and paperless-ngx. | ||||
|  | ||||
| If you want to learn about what's different in paperless-ngx from | ||||
| Paperless, check out these resources in the documentation: | ||||
|  | ||||
| - [Some screenshots](#screenshots) of the new UI are available. | ||||
| - Read [this section](/advanced_usage/#advanced-automatic_matching) if you want to learn about how paperless automates all | ||||
|   tagging using machine learning. | ||||
| - Paperless now comes with a `[proper email consumer](/usage/#usage-email) that's fully tested and production ready. | ||||
| - Paperless creates searchable PDF/A documents from whatever you put into the consumption directory. This means | ||||
|   that you can select text in image-only documents coming from your scanner. | ||||
| - See [this note](/administration/#utilities-encyption) about GnuPG encryption in paperless-ngx. | ||||
| - Paperless is now integrated with a | ||||
|   [task processing queue](/setup#task_processor) that tells you at a glance when and why something is not working. | ||||
| - The [changelog](/changelog) contains a detailed list of all changes in paperless-ngx. | ||||
|  | ||||
| ## Screenshots | ||||
|  | ||||
| This is what Paperless-ngx looks like. | ||||
|  | ||||
| The dashboard shows customizable views on your document and allows | ||||
| document uploads: | ||||
|  | ||||
| [](assets/screenshots/dashboard.png) | ||||
|  | ||||
| The document list provides three different styles to scroll through your | ||||
| documents: | ||||
|  | ||||
| [](assets/screenshots/documents-table.png) | ||||
|  | ||||
| [](assets/screenshots/documents-smallcards.png) | ||||
|  | ||||
| [](assets/screenshots/documents-largecards.png) | ||||
|  | ||||
| Paperless-ngx also supports dark mode: | ||||
|  | ||||
| [](assets/screenshots/documents-smallcards-dark.png) | ||||
|  | ||||
| Extensive filtering mechanisms: | ||||
|  | ||||
| [](assets/screenshots/documents-filter.png) | ||||
|  | ||||
| Bulk editing of document tags, correspondents, etc.: | ||||
|  | ||||
| [](assets/screenshots/bulk-edit.png) | ||||
|  | ||||
| Side-by-side editing of documents: | ||||
|  | ||||
| [](assets/screenshots/editing.png) | ||||
|  | ||||
| Tag editing. This looks about the same for correspondents and document | ||||
| types. | ||||
|  | ||||
| [](assets/screenshots/new-tag.png) | ||||
|  | ||||
| Searching provides auto complete and highlights the results. | ||||
|  | ||||
| [](assets/screenshots/search-preview.png) | ||||
|  | ||||
| [](assets/screenshots/search-results.png) | ||||
|  | ||||
| Fancy mail filters! | ||||
|  | ||||
| [](assets/screenshots/mail-rules-edited.png) | ||||
|  | ||||
| Mobile devices are supported. | ||||
|  | ||||
| [](assets/screenshots/mobile.png) | ||||
|  | ||||
| ## Support | ||||
|  | ||||
| Community support is available via [GitHub Discussions](https://github.com/paperless-ngx/paperless-ngx/discussions/) and [the Matrix chat room](https://matrix.to/#/#paperless:matrix.org). | ||||
|  | ||||
| ### Feature Requests | ||||
|  | ||||
| Feature requests can be submitted via [GitHub Discussions](https://github.com/paperless-ngx/paperless-ngx/discussions/categories/feature-requests) where you can search for existing ideas, add your own and vote for the ones you care about. | ||||
|  | ||||
| ### Bugs | ||||
|  | ||||
| For bugs please [open an issue](https://github.com/paperless-ngx/paperless-ngx/issues) or [start a discussion](https://github.com/paperless-ngx/paperless-ngx/discussions/categories/support) if you have questions. | ||||
|  | ||||
| ## Contributing | ||||
|  | ||||
| People interested in continuing the work on paperless-ngx are encouraged to reach out on [GitHub](https://github.com/paperless-ngx/paperless-ngx) or [the Matrix chat room](https://matrix.to/#/#paperless:matrix.org). If you would like to contribute to the project on an ongoing basis there are multiple teams (frontend, ci/cd, etc) that could use your help so please reach out! | ||||
|  | ||||
| ### Translation | ||||
|  | ||||
| Paperless-ngx is available in many languages that are coordinated on [Crowdin](https://crwd.in/paperless-ngx). If you want to help out by translating paperless-ngx into your language, please head over to https://crwd.in/paperless-ngx, and thank you! | ||||
|  | ||||
| ## Scanners & Software | ||||
|  | ||||
| Paperless-ngx is compatible with many different scanners and scanning tools. A user-maintained list of scanners and other software is available on [the wiki](https://github.com/paperless-ngx/paperless-ngx/wiki/Scanner-&-Software-Recommendations). | ||||
| @@ -1,75 +0,0 @@ | ||||
| ********* | ||||
| Paperless | ||||
| ********* | ||||
|  | ||||
| Paperless is a simple Django application running in two parts: | ||||
| a *Consumer* (the thing that does the indexing) and | ||||
| the *Web server* (the part that lets you search & | ||||
| download already-indexed documents). If you want to learn more about its | ||||
| functions keep on reading after the installation section. | ||||
|  | ||||
|  | ||||
| Why This Exists | ||||
| =============== | ||||
|  | ||||
| Paper is a nightmare.  Environmental issues aside, there's no excuse for it in | ||||
| the 21st century.  It takes up space, collects dust, doesn't support any form | ||||
| of a search feature, indexing is tedious, it's heavy and prone to damage & | ||||
| loss. | ||||
|  | ||||
| I wrote this to make "going paperless" easier.  I do not have to worry about | ||||
| finding stuff again. I feed documents right from the post box into the scanner | ||||
| and then shred them.  Perhaps you might find it useful too. | ||||
|  | ||||
|  | ||||
| Paperless-ngx | ||||
| ============= | ||||
|  | ||||
| Paperless-ngx is a document management system that transforms your physical | ||||
| documents into a searchable online archive so you can keep, well, *less paper*. | ||||
|  | ||||
| Paperless-ngx forked from paperless-ng to continue the great work and | ||||
| distribute responsibility of supporting and advancing the project among a team | ||||
| of people. | ||||
|  | ||||
| NG stands for both Angular (the framework used for the | ||||
| Frontend) and next-gen. Publishing this project under a different name also | ||||
| avoids confusion between paperless and paperless-ngx. | ||||
|  | ||||
| If you want to learn about what's different in paperless-ngx from Paperless, check out these | ||||
| resources in the documentation: | ||||
|  | ||||
| *   :ref:`Some screenshots <screenshots>` of the new UI are available. | ||||
| *   Read :ref:`this section <advanced-automatic_matching>` if you want to | ||||
|     learn about how paperless automates all tagging using machine learning. | ||||
| *   Paperless now comes with a :ref:`proper email consumer <usage-email>` | ||||
|     that's fully tested and production ready. | ||||
| *   Paperless creates searchable PDF/A documents from whatever you put into | ||||
|     the consumption directory. This means that you can select text in | ||||
|     image-only documents coming from your scanner. | ||||
| *   See :ref:`this note <utilities-encyption>` about GnuPG encryption in | ||||
|     paperless-ngx. | ||||
| *   Paperless is now integrated with a | ||||
|     :ref:`task processing queue <setup-task_processor>` that tells you | ||||
|     at a glance when and why something is not working. | ||||
| *   The :doc:`changelog </changelog>` contains a detailed list of all changes | ||||
|     in paperless-ngx. | ||||
|  | ||||
| Contents | ||||
| ======== | ||||
|  | ||||
| .. toctree:: | ||||
|    :maxdepth: 1 | ||||
|  | ||||
|    setup | ||||
|    usage_overview | ||||
|    advanced_usage | ||||
|    administration | ||||
|    configuration | ||||
|    api | ||||
|    faq | ||||
|    troubleshooting | ||||
|    extending | ||||
|    scanners | ||||
|    screenshots | ||||
|    changelog | ||||
| @@ -1 +0,0 @@ | ||||
| myst-parser==0.18.1 | ||||
| @@ -1,8 +0,0 @@ | ||||
|  | ||||
| .. _scanners: | ||||
|  | ||||
| ******************* | ||||
| Scanners & Software | ||||
| ******************* | ||||
|  | ||||
| Paperless-ngx is compatible with many different scanners and scanning tools. A user-maintained list of scanners and other software is available on `the wiki <https://github.com/paperless-ngx/paperless-ngx/wiki/Scanner-&-Software-Recommendations>`_. | ||||
| @@ -1,63 +0,0 @@ | ||||
| .. _screenshots: | ||||
|  | ||||
| *********** | ||||
| Screenshots | ||||
| *********** | ||||
|  | ||||
| This is what Paperless-ngx looks like. | ||||
|  | ||||
| The dashboard shows customizable views on your document and allows document uploads: | ||||
|  | ||||
| .. image:: _static/screenshots/dashboard.png | ||||
|     :target: _static/screenshots/dashboard.png | ||||
|  | ||||
| The document list provides three different styles to scroll through your documents: | ||||
|  | ||||
| .. image:: _static/screenshots/documents-table.png | ||||
|     :target: _static/screenshots/documents-table.png | ||||
| .. image:: _static/screenshots/documents-smallcards.png | ||||
|     :target: _static/screenshots/documents-smallcards.png | ||||
| .. image:: _static/screenshots/documents-largecards.png | ||||
|     :target: _static/screenshots/documents-largecards.png | ||||
|  | ||||
| Paperless-ngx also supports "dark mode": | ||||
|  | ||||
| .. image:: _static/screenshots/documents-smallcards-dark.png | ||||
|     :target: _static/screenshots/documents-smallcards-dark.png | ||||
|  | ||||
| Extensive filtering mechanisms: | ||||
|  | ||||
| .. image:: _static/screenshots/documents-filter.png | ||||
|     :target: _static/screenshots/documents-filter.png | ||||
|  | ||||
| Bulk editing of document tags, correspondents, etc.: | ||||
|  | ||||
| .. image:: _static/screenshots/bulk-edit.png | ||||
|     :target: _static/screenshots/bulk-edit.png | ||||
|  | ||||
| Side-by-side editing of documents: | ||||
|  | ||||
| .. image:: _static/screenshots/editing.png | ||||
|     :target: _static/screenshots/editing.png | ||||
|  | ||||
| Tag editing. This looks about the same for correspondents and document types. | ||||
|  | ||||
| .. image:: _static/screenshots/new-tag.png | ||||
|     :target: _static/screenshots/new-tag.png | ||||
|  | ||||
| Searching provides auto complete and highlights the results. | ||||
|  | ||||
| .. image:: _static/screenshots/search-preview.png | ||||
|     :target: _static/screenshots/search-preview.png | ||||
| .. image:: _static/screenshots/search-results.png | ||||
|     :target: _static/screenshots/search-results.png | ||||
|  | ||||
| Fancy mail filters! | ||||
|  | ||||
| .. image:: _static/screenshots/mail-rules-edited.png | ||||
|     :target: _static/screenshots/mail-rules-edited.png | ||||
|  | ||||
| Mobile devices are supported. | ||||
|  | ||||
| .. image:: _static/screenshots/mobile.png | ||||
|     :target: _static/screenshots/mobile.png | ||||
							
								
								
									
										852
									
								
								docs/setup.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,852 @@ | ||||
| ## Installation | ||||
|  | ||||
| You can go multiple routes to setup and run Paperless: | ||||
|  | ||||
| - [Use the easy install docker script](/setup#docker_script) | ||||
| - [Pull the image from Docker Hub](/setup#docker_hub) | ||||
| - [Build the Docker image yourself](/setup#docker_build) | ||||
| - [Install Paperless directly on your system manually (bare metal)](/setup#bare_metal) | ||||
|  | ||||
| The Docker routes are quick & easy. These are the recommended routes. | ||||
| This configures all the stuff from the above automatically so that it | ||||
| just works and uses sensible defaults for all configuration options. | ||||
| Here you find a cheat-sheet for docker beginners: [CLI | ||||
| Basics](https://www.sehn.tech/refs/devops-with-docker/) | ||||
|  | ||||
| The bare metal route is complicated to setup but makes it easier should | ||||
| you want to contribute some code back. You need to configure and run the | ||||
| above mentioned components yourself. | ||||
|  | ||||
| ### Docker using the Installation Script {#docker_script} | ||||
|  | ||||
| Paperless provides an interactive installation script. This script will | ||||
| ask you for a couple configuration options, download and create the | ||||
| necessary configuration files, pull the docker image, start paperless | ||||
| and create your user account. This script essentially performs all the | ||||
| steps described in `setup-docker_hub`{.interpreted-text role="ref"} | ||||
| automatically. | ||||
|  | ||||
| 1.  Make sure that docker and docker-compose are installed. | ||||
|  | ||||
| 2.  Download and run the installation script: | ||||
|  | ||||
|     ```shell-session | ||||
|     $ bash -c "$(curl -L https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)" | ||||
|     ``` | ||||
|  | ||||
| ### From GHCR / Docker Hub {#docker_hub} | ||||
|  | ||||
| 1.  Login with your user and create a folder in your home-directory | ||||
|     [mkdir -v \~/paperless-ngx]{.title-ref} to have a place for your | ||||
|     configuration files and consumption directory. | ||||
|  | ||||
| 2.  Go to the [/docker/compose directory on the project | ||||
|     page](https://github.com/paperless-ngx/paperless-ngx/tree/master/docker/compose) | ||||
|     and download one of the [docker-compose.\*.yml]{.title-ref} files, | ||||
|     depending on which database backend you want to use. Rename this | ||||
|     file to [docker-compose.yml]{.title-ref}. If you want to enable | ||||
|     optional support for Office documents, download a file with | ||||
|     [-tika]{.title-ref} in the file name. Download the | ||||
|     `docker-compose.env` file and the `.env` file as well and store them | ||||
|     in the same directory. | ||||
|  | ||||
|     !!! tip | ||||
|  | ||||
|         For new installations, it is recommended to use PostgreSQL as the | ||||
|         database backend. | ||||
|  | ||||
| 3.  Install [Docker](https://www.docker.com/) and | ||||
|     [docker-compose](https://docs.docker.com/compose/install/). | ||||
|  | ||||
|     !!! warning | ||||
|  | ||||
|         If you want to use the included `docker-compose.*.yml` file, you | ||||
|         need to have at least Docker version **17.09.0** and docker-compose | ||||
|         version **1.17.0**. To check do: [docker-compose -v]{.title-ref} or | ||||
|         [docker -v]{.title-ref} | ||||
|  | ||||
|         See the [Docker installation guide]() on how to install the current | ||||
|         version of Docker for your operating system or Linux distribution of | ||||
|         choice. To get the latest version of docker-compose, follow the | ||||
|         [docker-compose installation guide]() if your package repository | ||||
|         doesn't include it. | ||||
|  | ||||
| 4.  Modify `docker-compose.yml` to your preferences. You may want to | ||||
|     change the path to the consumption directory. Find the line that | ||||
|     specifies where to mount the consumption directory: | ||||
|  | ||||
|     ``` | ||||
|     - ./consume:/usr/src/paperless/consume | ||||
|     ``` | ||||
|  | ||||
|     Replace the part BEFORE the colon with a local directory of your | ||||
|     choice: | ||||
|  | ||||
|     ``` | ||||
|     - /home/jonaswinkler/paperless-inbox:/usr/src/paperless/consume | ||||
|     ``` | ||||
|  | ||||
|     Don't change the part after the colon or paperless wont find your | ||||
|     documents. | ||||
|  | ||||
|     You may also need to change the default port that the webserver will | ||||
|     use from the default (8000): | ||||
|  | ||||
|     > ``` | ||||
|     > ports: | ||||
|     >   - 8000:8000 | ||||
|     > ``` | ||||
|  | ||||
|     Replace the part BEFORE the colon with a port of your choice: | ||||
|  | ||||
|     > ``` | ||||
|     > ports: | ||||
|     >   - 8010:8000 | ||||
|     > ``` | ||||
|  | ||||
|     Don't change the part after the colon or edit other lines that | ||||
|     refer to port 8000. Modifying the part before the colon will map | ||||
|     requests on another port to the webserver running on the default | ||||
|     port. | ||||
|  | ||||
|     **Rootless** | ||||
|  | ||||
|     If you want to run Paperless as a rootless container, you will need | ||||
|     to do the following in your `docker-compose.yml`: | ||||
|  | ||||
|     - set the `user` running the container to map to the `paperless` | ||||
|       user in the container. This value (`user_id` below), should be | ||||
|       the same id that `USERMAP_UID` and `USERMAP_GID` are set to in | ||||
|       the next step. See `USERMAP_UID` and `USERMAP_GID` | ||||
|       [here](/configuration#docker). | ||||
|  | ||||
|     Your entry for Paperless should contain something like: | ||||
|  | ||||
|     > ``` | ||||
|     > webserver: | ||||
|     >   image: ghcr.io/paperless-ngx/paperless-ngx:latest | ||||
|     >   user: <user_id> | ||||
|     > ``` | ||||
|  | ||||
| 5.  Modify `docker-compose.env`, following the comments in the file. The | ||||
|     most important change is to set `USERMAP_UID` and `USERMAP_GID` to | ||||
|     the uid and gid of your user on the host system. Use `id -u` and | ||||
|     `id -g` to get these. | ||||
|  | ||||
|     This ensures that both the docker container and you on the host | ||||
|     machine have write access to the consumption directory. If your UID | ||||
|     and GID on the host system is 1000 (the default for the first normal | ||||
|     user on most systems), it will work out of the box without any | ||||
|     modifications. [id "username"]{.title-ref} to check. | ||||
|  | ||||
|     !!! note | ||||
|  | ||||
|         You can copy any setting from the file `paperless.conf.example` and | ||||
|         paste it here. Have a look at `configuration`{.interpreted-text | ||||
|         role="ref"} to see what's available. | ||||
|  | ||||
|     !!! note | ||||
|  | ||||
|         You can utilize Docker secrets for some configuration settings by | ||||
|         appending [\_FILE]{.title-ref} to some configuration values. This is | ||||
|         supported currently only by: | ||||
|  | ||||
|         -   PAPERLESS_DBUSER | ||||
|         -   PAPERLESS_DBPASS | ||||
|         -   PAPERLESS_SECRET_KEY | ||||
|         -   PAPERLESS_AUTO_LOGIN_USERNAME | ||||
|         -   PAPERLESS_ADMIN_USER | ||||
|         -   PAPERLESS_ADMIN_MAIL | ||||
|         -   PAPERLESS_ADMIN_PASSWORD | ||||
|  | ||||
|     !!! warning | ||||
|  | ||||
|         Some file systems such as NFS network shares don't support file | ||||
|         system notifications with `inotify`. When storing the consumption | ||||
|         directory on such a file system, paperless will not pick up new | ||||
|         files with the default configuration. You will need to use | ||||
|         `PAPERLESS_CONSUMER_POLLING`, which will disable inotify. See | ||||
|         [here](/configuration#polling). | ||||
|  | ||||
| 6.  Run `docker-compose pull`, followed by `docker-compose up -d`. This | ||||
|     will pull the image, create and start the necessary containers. | ||||
|  | ||||
| 7.  To be able to login, you will need a super user. To create it, | ||||
|     execute the following command: | ||||
|  | ||||
|     ```shell-session | ||||
|     $ docker-compose run --rm webserver createsuperuser | ||||
|     ``` | ||||
|  | ||||
|     This will prompt you to set a username, an optional e-mail address | ||||
|     and finally a password (at least 8 characters). | ||||
|  | ||||
| 8.  The default `docker-compose.yml` exports the webserver on your local | ||||
|     port | ||||
|  | ||||
|     8000\. If you did not change this, you should now be able to visit | ||||
|     your Paperless instance at `http://127.0.0.1:8000` or your servers | ||||
|     IP-Address:8000. Use the login credentials you have created with the | ||||
|     previous step. | ||||
|  | ||||
| ### Build the Docker image yourself {#docker_build} | ||||
|  | ||||
| 1.  Clone the entire repository of paperless: | ||||
|  | ||||
|     ```shell-session | ||||
|     git clone https://github.com/paperless-ngx/paperless-ngx | ||||
|     ``` | ||||
|  | ||||
|     The master branch always reflects the latest stable version. | ||||
|  | ||||
| 2.  Copy one of the `docker/compose/docker-compose.*.yml` to | ||||
|     `docker-compose.yml` in the root folder, depending on which database | ||||
|     backend you want to use. Copy `docker-compose.env` into the project | ||||
|     root as well. | ||||
|  | ||||
| 3.  In the `docker-compose.yml` file, find the line that instructs | ||||
|     docker-compose to pull the paperless image from Docker Hub: | ||||
|  | ||||
|     ```yaml | ||||
|     webserver: | ||||
|       image: ghcr.io/paperless-ngx/paperless-ngx:latest | ||||
|     ``` | ||||
|  | ||||
|     and replace it with a line that instructs docker-compose to build | ||||
|     the image from the current working directory instead: | ||||
|  | ||||
|     ```yaml | ||||
|     webserver: | ||||
|       build: | ||||
|         context: . | ||||
|         args: | ||||
|           QPDF_VERSION: x.y.x | ||||
|           PIKEPDF_VERSION: x.y.z | ||||
|           PSYCOPG2_VERSION: x.y.z | ||||
|           JBIG2ENC_VERSION: 0.29 | ||||
|     ``` | ||||
|  | ||||
|     !!! note | ||||
|  | ||||
|         You should match the build argument versions to the version for the | ||||
|         release you have checked out. These are pre-built images with | ||||
|         certain, more updated software. If you want to build these images | ||||
|         your self, that is possible, but beyond the scope of these steps. | ||||
|  | ||||
| 4.  Follow steps 3 to 8 of `setup-docker_hub`{.interpreted-text | ||||
|     role="ref"}. When asked to run `docker-compose pull` to pull the | ||||
|     image, do | ||||
|  | ||||
|     ```shell-session | ||||
|     $ docker-compose build | ||||
|     ``` | ||||
|  | ||||
|     instead to build the image. | ||||
|  | ||||
| ### Bare Metal Route {#bare_metal} | ||||
|  | ||||
| Paperless runs on linux only. The following procedure has been tested on | ||||
| a minimal installation of Debian/Buster, which is the current stable | ||||
| release at the time of writing. Windows is not and will never be | ||||
| supported. | ||||
|  | ||||
| 1.  Install dependencies. Paperless requires the following packages. | ||||
|  | ||||
|     - `python3` 3.8, 3.9 | ||||
|     - `python3-pip` | ||||
|     - `python3-dev` | ||||
|     - `default-libmysqlclient-dev` for MariaDB | ||||
|     - `fonts-liberation` for generating thumbnails for plain text | ||||
|       files | ||||
|     - `imagemagick` >= 6 for PDF conversion | ||||
|     - `gnupg` for handling encrypted documents | ||||
|     - `libpq-dev` for PostgreSQL | ||||
|     - `libmagic-dev` for mime type detection | ||||
|     - `mariadb-client` for MariaDB compile time | ||||
|     - `mime-support` for mime type detection | ||||
|     - `libzbar0` for barcode detection | ||||
|     - `poppler-utils` for barcode detection | ||||
|  | ||||
|     Use this list for your preferred package management: | ||||
|  | ||||
|     ``` | ||||
|     python3 python3-pip python3-dev imagemagick fonts-liberation gnupg libpq-dev default-libmysqlclient-dev libmagic-dev mime-support libzbar0 poppler-utils | ||||
|     ``` | ||||
|  | ||||
|     These dependencies are required for OCRmyPDF, which is used for text | ||||
|     recognition. | ||||
|  | ||||
|     - `unpaper` | ||||
|     - `ghostscript` | ||||
|     - `icc-profiles-free` | ||||
|     - `qpdf` | ||||
|     - `liblept5` | ||||
|     - `libxml2` | ||||
|     - `pngquant` (suggested for certain PDF image optimizations) | ||||
|     - `zlib1g` | ||||
|     - `tesseract-ocr` >= 4.0.0 for OCR | ||||
|     - `tesseract-ocr` language packs (`tesseract-ocr-eng`, | ||||
|       `tesseract-ocr-deu`, etc) | ||||
|  | ||||
|     Use this list for your preferred package management: | ||||
|  | ||||
|     ``` | ||||
|     unpaper ghostscript icc-profiles-free qpdf liblept5 libxml2 pngquant zlib1g tesseract-ocr | ||||
|     ``` | ||||
|  | ||||
|     On Raspberry Pi, these libraries are required as well: | ||||
|  | ||||
|     - `libatlas-base-dev` | ||||
|     - `libxslt1-dev` | ||||
|  | ||||
|     You will also need `build-essential`, `python3-setuptools` and | ||||
|     `python3-wheel` for installing some of the python dependencies. | ||||
|  | ||||
| 2.  Install `redis` >= 6.0 and configure it to start automatically. | ||||
|  | ||||
| 3.  Optional. Install `postgresql` and configure a database, user and | ||||
|     password for paperless. If you do not wish to use PostgreSQL, | ||||
|     MariaDB and SQLite are available as well. | ||||
|  | ||||
|     !!! note | ||||
|  | ||||
|         On bare-metal installations using SQLite, ensure the [JSON1 | ||||
|         extension](https://code.djangoproject.com/wiki/JSON1Extension) is | ||||
|         enabled. This is usually the case, but not always. | ||||
|  | ||||
| 4.  Get the release archive from | ||||
|     <https://github.com/paperless-ngx/paperless-ngx/releases>. If you | ||||
|     clone the git repo as it is, you also have to compile the front end | ||||
|     by yourself. Extract the archive to a place from where you wish to | ||||
|     execute it, such as `/opt/paperless`. | ||||
|  | ||||
| 5.  Configure paperless. See `configuration`{.interpreted-text | ||||
|     role="ref"} for details. Edit the included `paperless.conf` and | ||||
|     adjust the settings to your needs. Required settings for getting | ||||
|     paperless running are: | ||||
|  | ||||
|     - `PAPERLESS_REDIS` should point to your redis server, such as | ||||
|       <redis://localhost:6379>. | ||||
|     - `PAPERLESS_DBENGINE` optional, and should be one of [postgres, | ||||
|       mariadb, or sqlite]{.title-ref} | ||||
|     - `PAPERLESS_DBHOST` should be the hostname on which your | ||||
|       PostgreSQL server is running. Do not configure this to use | ||||
|       SQLite instead. Also configure port, database name, user and | ||||
|       password as necessary. | ||||
|     - `PAPERLESS_CONSUMPTION_DIR` should point to a folder which | ||||
|       paperless should watch for documents. You might want to have | ||||
|       this somewhere else. Likewise, `PAPERLESS_DATA_DIR` and | ||||
|       `PAPERLESS_MEDIA_ROOT` define where paperless stores its data. | ||||
|       If you like, you can point both to the same directory. | ||||
|     - `PAPERLESS_SECRET_KEY` should be a random sequence of | ||||
|       characters. It's used for authentication. Failure to do so | ||||
|       allows third parties to forge authentication credentials. | ||||
|     - `PAPERLESS_URL` if you are behind a reverse proxy. This should | ||||
|       point to your domain. Please see | ||||
|       `configuration`{.interpreted-text role="ref"} for more | ||||
|       information. | ||||
|  | ||||
|     Many more adjustments can be made to paperless, especially the OCR | ||||
|     part. The following options are recommended for everyone: | ||||
|  | ||||
|     - Set `PAPERLESS_OCR_LANGUAGE` to the language most of your | ||||
|       documents are written in. | ||||
|     - Set `PAPERLESS_TIME_ZONE` to your local time zone. | ||||
|  | ||||
| 6.  Create a system user under which you wish to run paperless. | ||||
|  | ||||
|     ```shell-session | ||||
|     adduser paperless --system --home /opt/paperless --group | ||||
|     ``` | ||||
|  | ||||
| 7.  Ensure that these directories exist and that the paperless user has | ||||
|     write permissions to the following directories: | ||||
|  | ||||
|     - `/opt/paperless/media` | ||||
|     - `/opt/paperless/data` | ||||
|     - `/opt/paperless/consume` | ||||
|  | ||||
|     Adjust as necessary if you configured different folders. | ||||
|  | ||||
| 8.  Install python requirements from the `requirements.txt` file. It is | ||||
|     up to you if you wish to use a virtual environment or not. First you | ||||
|     should update your pip, so it gets the actual packages. | ||||
|  | ||||
|     ```shell-session | ||||
|     sudo -Hu paperless pip3 install --upgrade pip | ||||
|     ``` | ||||
|  | ||||
|     ```shell-session | ||||
|     sudo -Hu paperless pip3 install -r requirements.txt | ||||
|     ``` | ||||
|  | ||||
|     This will install all python dependencies in the home directory of | ||||
|     the new paperless user. | ||||
|  | ||||
| 9.  Go to `/opt/paperless/src`, and execute the following commands: | ||||
|  | ||||
|     ```bash | ||||
|     \# This creates the database schema. | ||||
|     sudo -Hu paperless python3 manage.py migrate | ||||
|  | ||||
|     \# This creates your first paperless user | ||||
|     sudo -Hu paperless python3 manage.py createsuperuser | ||||
|     ``` | ||||
|  | ||||
| 10. Optional: Test that paperless is working by executing | ||||
|  | ||||
|     ```bash | ||||
|     \# This collects static files from paperless and django. | ||||
|     sudo -Hu paperless python3 manage.py runserver | ||||
|     ``` | ||||
|  | ||||
|     and pointing your browser to <http://localhost:8000/>. | ||||
|  | ||||
|     !!! warning | ||||
|  | ||||
|         This is a development server which should not be used in production. | ||||
|         It is not audited for security and performance is inferior to | ||||
|         production ready web servers. | ||||
|  | ||||
|     !!! tip | ||||
|  | ||||
|         This will not start the consumer. Paperless does this in a separate | ||||
|         process. | ||||
|  | ||||
| 11. Setup systemd services to run paperless automatically. You may use | ||||
|     the service definition files included in the `scripts` folder as a | ||||
|     starting point. | ||||
|  | ||||
|     Paperless needs the `webserver` script to run the webserver, the | ||||
|     `consumer` script to watch the input folder, `taskqueue` for the | ||||
|     background workers used to handle things like document consumption | ||||
|     and the `scheduler` script to run tasks such as email checking at | ||||
|     certain times . | ||||
|  | ||||
|     !!! note | ||||
|  | ||||
|         The `socket` script enables `gunicorn` to run on port 80 without | ||||
|         root privileges. For this you need to uncomment the | ||||
|         `Require=paperless-webserver.socket` in the `webserver` script | ||||
|         and configure `gunicorn` to listen on port 80 (see | ||||
|         `paperless/gunicorn.conf.py`). | ||||
|  | ||||
|     You may need to adjust the path to the `gunicorn` executable. This | ||||
|     will be installed as part of the python dependencies, and is either | ||||
|     located in the `bin` folder of your virtual environment, or in | ||||
|     `~/.local/bin/` if no virtual environment is used. | ||||
|  | ||||
|     These services rely on redis and optionally the database server, but | ||||
|     don't need to be started in any particular order. The example files | ||||
|     depend on redis being started. If you use a database server, you | ||||
|     should add additional dependencies. | ||||
|  | ||||
|     !!! warning | ||||
|  | ||||
|         The included scripts run a `gunicorn` standalone server, which is | ||||
|         fine for running paperless. It does support SSL, however, the | ||||
|         documentation of GUnicorn states that you should use a proxy server | ||||
|         in front of gunicorn instead. | ||||
|  | ||||
|         For instructions on how to use nginx for that, | ||||
|         [see the instructions below](/setup#nginx). | ||||
|  | ||||
| 12. Optional: Install a samba server and make the consumption folder | ||||
|     available as a network share. | ||||
|  | ||||
| 13. Configure ImageMagick to allow processing of PDF documents. Most | ||||
|     distributions have this disabled by default, since PDF documents can | ||||
|     contain malware. If you don't do this, paperless will fall back to | ||||
|     ghostscript for certain steps such as thumbnail generation. | ||||
|  | ||||
|     Edit `/etc/ImageMagick-6/policy.xml` and adjust | ||||
|  | ||||
|     ``` | ||||
|     <policy domain="coder" rights="none" pattern="PDF" /> | ||||
|     ``` | ||||
|  | ||||
|     to | ||||
|  | ||||
|     ``` | ||||
|     <policy domain="coder" rights="read|write" pattern="PDF" /> | ||||
|     ``` | ||||
|  | ||||
| 14. Optional: Install the | ||||
|     [jbig2enc](https://ocrmypdf.readthedocs.io/en/latest/jbig2.html) | ||||
|     encoder. This will reduce the size of generated PDF documents. | ||||
|     You'll most likely need to compile this by yourself, because this | ||||
|     software has been patented until around 2017 and binary packages are | ||||
|     not available for most distributions. | ||||
|  | ||||
| 15. Optional: If using the NLTK machine learning processing (see | ||||
|     `PAPERLESS_ENABLE_NLTK` in `configuration`{.interpreted-text | ||||
|     role="ref"} for details), download the NLTK data for the Snowball | ||||
|     Stemmer, Stopwords and Punkt tokenizer to your | ||||
|     `PAPERLESS_DATA_DIR/nltk`. Refer to the [NLTK | ||||
|     instructions](https://www.nltk.org/data.html) for details on how to | ||||
|     download the data. | ||||
|  | ||||
| # Migrating to Paperless-ngx | ||||
|  | ||||
| Migration is possible both from Paperless-ng or directly from the | ||||
| 'original' Paperless. | ||||
|  | ||||
| ## Migrating from Paperless-ng | ||||
|  | ||||
| Paperless-ngx is meant to be a drop-in replacement for Paperless-ng and | ||||
| thus upgrading should be trivial for most users, especially when using | ||||
| docker. However, as with any major change, it is recommended to take a | ||||
| full backup first. Once you are ready, simply change the docker image to | ||||
| point to the new source. E.g. if using Docker Compose, edit | ||||
| `docker-compose.yml` and change: | ||||
|  | ||||
| ``` | ||||
| image: jonaswinkler/paperless-ng:latest | ||||
| ``` | ||||
|  | ||||
| to | ||||
|  | ||||
| ``` | ||||
| image: ghcr.io/paperless-ngx/paperless-ngx:latest | ||||
| ``` | ||||
|  | ||||
| and then run `docker-compose up -d` which will pull the new image | ||||
| recreate the container. That's it! | ||||
|  | ||||
| Users who installed with the bare-metal route should also update their | ||||
| Git clone to point to `https://github.com/paperless-ngx/paperless-ngx`, | ||||
| e.g. using the command | ||||
| `git remote set-url origin https://github.com/paperless-ngx/paperless-ngx` | ||||
| and then pull the lastest version. | ||||
|  | ||||
| ## Migrating from Paperless | ||||
|  | ||||
| At its core, paperless-ngx is still paperless and fully compatible. | ||||
| However, some things have changed under the hood, so you need to adapt | ||||
| your setup depending on how you installed paperless. | ||||
|  | ||||
| This setup describes how to update an existing paperless Docker | ||||
| installation. The important things to keep in mind are as follows: | ||||
|  | ||||
| - Read the [changelog](/changelog) and | ||||
|   take note of breaking changes. | ||||
| - You should decide if you want to stick with SQLite or want to | ||||
|   migrate your database to PostgreSQL. See | ||||
|   `setup-sqlite_to_psql`{.interpreted-text role="ref"} for details on | ||||
|   how to move your data from SQLite to PostgreSQL. Both work fine with | ||||
|   paperless. However, if you already have a database server running | ||||
|   for other services, you might as well use it for paperless as well. | ||||
| - The task scheduler of paperless, which is used to execute periodic | ||||
|   tasks such as email checking and maintenance, requires a | ||||
|   [redis](https://redis.io/) message broker instance. The | ||||
|   docker-compose route takes care of that. | ||||
| - The layout of the folder structure for your documents and data | ||||
|   remains the same, so you can just plug your old docker volumes into | ||||
|   paperless-ngx and expect it to find everything where it should be. | ||||
|  | ||||
| Migration to paperless-ngx is then performed in a few simple steps: | ||||
|  | ||||
| 1.  Stop paperless. | ||||
|  | ||||
|     ```bash | ||||
|     $ cd /path/to/current/paperless | ||||
|     $ docker-compose down | ||||
|     ``` | ||||
|  | ||||
| 2.  Do a backup for two purposes: If something goes wrong, you still | ||||
|     have your data. Second, if you don't like paperless-ngx, you can | ||||
|     switch back to paperless. | ||||
|  | ||||
| 3.  Download the latest release of paperless-ngx. You can either go with | ||||
|     the docker-compose files from | ||||
|     [here](https://github.com/paperless-ngx/paperless-ngx/tree/master/docker/compose) | ||||
|     or clone the repository to build the image yourself (see | ||||
|     [above](/setup#docker_build)). You can | ||||
|     either replace your current paperless folder or put paperless-ngx in | ||||
|     a different location. | ||||
|  | ||||
|     !!! warning | ||||
|  | ||||
|         Paperless-ngx includes a `.env` file. This will set the project name | ||||
|         for docker compose to `paperless`, which will also define the name | ||||
|         of the volumes by paperless-ngx. However, if you experience that | ||||
|         paperless-ngx is not using your old paperless volumes, verify the | ||||
|         names of your volumes with | ||||
|  | ||||
|         ``` shell-session | ||||
|         $ docker volume ls | grep _data | ||||
|         ``` | ||||
|  | ||||
|         and adjust the project name in the `.env` file so that it matches | ||||
|         the name of the volumes before the `_data` part. | ||||
|  | ||||
| 4.  Download the `docker-compose.sqlite.yml` file to | ||||
|     `docker-compose.yml`. If you want to switch to PostgreSQL, do that | ||||
|     after you migrated your existing SQLite database. | ||||
|  | ||||
| 5.  Adjust `docker-compose.yml` and `docker-compose.env` to your needs. | ||||
|     See `setup-docker_hub`{.interpreted-text role="ref"} for details on | ||||
|     which edits are advised. | ||||
|  | ||||
| 6.  [Update paperless.](/administration#updating) | ||||
|  | ||||
| 7.  In order to find your existing documents with the new search | ||||
|     feature, you need to invoke a one-time operation that will create | ||||
|     the search index: | ||||
|  | ||||
|     ```shell-session | ||||
|     $ docker-compose run --rm webserver document_index reindex | ||||
|     ``` | ||||
|  | ||||
|     This will migrate your database and create the search index. After | ||||
|     that, paperless will take care of maintaining the index by itself. | ||||
|  | ||||
| 8.  Start paperless-ngx. | ||||
|  | ||||
|     ```bash | ||||
|     $ docker-compose up -d | ||||
|     ``` | ||||
|  | ||||
|     This will run paperless in the background and automatically start it | ||||
|     on system boot. | ||||
|  | ||||
| 9.  Paperless installed a permanent redirect to `admin/` in your | ||||
|     browser. This redirect is still in place and prevents access to the | ||||
|     new UI. Clear your browsing cache in order to fix this. | ||||
|  | ||||
| 10. Optionally, follow the instructions below to migrate your existing | ||||
|     data to PostgreSQL. | ||||
|  | ||||
| ## Migrating from LinuxServer.io Docker Image | ||||
|  | ||||
| As with any upgrades and large changes, it is highly recommended to | ||||
| create a backup before starting. This assumes the image was running | ||||
| using Docker Compose, but the instructions are translatable to Docker | ||||
| commands as well. | ||||
|  | ||||
| 1.  Stop and remove the paperless container | ||||
| 2.  If using an external database, stop the container | ||||
| 3.  Update Redis configuration | ||||
|     a) If `REDIS_URL` is already set, change it to `PAPERLESS_REDIS` | ||||
|     and continue to step 4. | ||||
|     b) Otherwise, in the `docker-compose.yml` add a new service for | ||||
|     Redis, following [the example compose | ||||
|     files](https://github.com/paperless-ngx/paperless-ngx/tree/main/docker/compose) | ||||
|     c) Set the environment variable `PAPERLESS_REDIS` so it points to | ||||
|     the new Redis container | ||||
| 4.  Update user mapping | ||||
|     a) If set, change the environment variable `PUID` to `USERMAP_UID` | ||||
|     b) If set, change the environment variable `PGID` to `USERMAP_GID` | ||||
| 5.  Update configuration paths | ||||
|     a) Set the environment variable `PAPERLESS_DATA_DIR` to `/config` | ||||
| 6.  Update media paths | ||||
|     a) Set the environment variable `PAPERLESS_MEDIA_ROOT` to | ||||
|     `/data/media` | ||||
| 7.  Update timezone | ||||
|     a) Set the environment variable `PAPERLESS_TIME_ZONE` to the same | ||||
|     value as `TZ` | ||||
| 8.  Modify the `image:` to point to | ||||
|     `ghcr.io/paperless-ngx/paperless-ngx:latest` or a specific version | ||||
|     if preferred. | ||||
| 9.  Start the containers as before, using `docker-compose`. | ||||
|  | ||||
| ## Moving data from SQLite to PostgreSQL or MySQL/MariaDB {#sqlite_to_psql} | ||||
|  | ||||
| Moving your data from SQLite to PostgreSQL or MySQL/MariaDB is done via | ||||
| executing a series of django management commands as below. The commands | ||||
| below use PostgreSQL, but are applicable to MySQL/MariaDB with the | ||||
|  | ||||
| !!! warning | ||||
|  | ||||
|     Make sure that your SQLite database is migrated to the latest version. | ||||
|     Starting paperless will make sure that this is the case. If your try to | ||||
|     load data from an old database schema in SQLite into a newer database | ||||
|     schema in PostgreSQL, you will run into trouble. | ||||
|  | ||||
| !!! warning | ||||
|  | ||||
|     On some database fields, PostgreSQL enforces predefined limits on | ||||
|     maximum length, whereas SQLite does not. The fields in question are the | ||||
|     title of documents (128 characters), names of document types, tags and | ||||
|     correspondents (128 characters), and filenames (1024 characters). If you | ||||
|     have data in these fields that surpasses these limits, migration to | ||||
|     PostgreSQL is not possible and will fail with an error. | ||||
|  | ||||
| !!! warning | ||||
|  | ||||
|     MySQL is case insensitive by default, treating values like "Name" and | ||||
|     "NAME" as identical. See `advanced-mysql-caveats`{.interpreted-text | ||||
|     role="ref"} for details. | ||||
|  | ||||
| 1.  Stop paperless, if it is running. | ||||
|  | ||||
| 2.  Tell paperless to use PostgreSQL: | ||||
|  | ||||
|     a) With docker, copy the provided `docker-compose.postgres.yml` | ||||
|     file to `docker-compose.yml`. Remember to adjust the consumption | ||||
|     directory, if necessary. | ||||
|     b) Without docker, configure the database in your `paperless.conf` | ||||
|     file. See `configuration`{.interpreted-text role="ref"} for | ||||
|     details. | ||||
|  | ||||
| 3.  Open a shell and initialize the database: | ||||
|  | ||||
|     a) With docker, run the following command to open a shell within | ||||
|     the paperless container: | ||||
|  | ||||
|         ``` shell-session | ||||
|         $ cd /path/to/paperless | ||||
|         $ docker-compose run --rm webserver /bin/bash | ||||
|         ``` | ||||
|  | ||||
|         This will launch the container and initialize the PostgreSQL | ||||
|         database. | ||||
|  | ||||
|     b) Without docker, remember to activate any virtual environment, | ||||
|     switch to the `src` directory and create the database schema: | ||||
|  | ||||
|         ``` shell-session | ||||
|         $ cd /path/to/paperless/src | ||||
|         $ python3 manage.py migrate | ||||
|         ``` | ||||
|  | ||||
|         This will not copy any data yet. | ||||
|  | ||||
| 4.  Dump your data from SQLite: | ||||
|  | ||||
|     ```shell-session | ||||
|     $ python3 manage.py dumpdata --database=sqlite --exclude=contenttypes --exclude=auth.Permission > data.json | ||||
|     ``` | ||||
|  | ||||
| 5.  Load your data into PostgreSQL: | ||||
|  | ||||
|     ```shell-session | ||||
|     $ python3 manage.py loaddata data.json | ||||
|     ``` | ||||
|  | ||||
| 6.  If operating inside Docker, you may exit the shell now. | ||||
|  | ||||
|     ```shell-session | ||||
|     $ exit | ||||
|     ``` | ||||
|  | ||||
| 7.  Start paperless. | ||||
|  | ||||
| ## Moving back to Paperless | ||||
|  | ||||
| Lets say you migrated to Paperless-ngx and used it for a while, but | ||||
| decided that you don't like it and want to move back (If you do, send | ||||
| me a mail about what part you didn't like!), you can totally do that | ||||
| with a few simple steps. | ||||
|  | ||||
| Paperless-ngx modified the database schema slightly, however, these | ||||
| changes can be reverted while keeping your current data, so that your | ||||
| current data will be compatible with original Paperless. | ||||
|  | ||||
| Execute this: | ||||
|  | ||||
| ```shell-session | ||||
| $ cd /path/to/paperless | ||||
| $ docker-compose run --rm webserver migrate documents 0023 | ||||
| ``` | ||||
|  | ||||
| Or without docker: | ||||
|  | ||||
| ```shell-session | ||||
| $ cd /path/to/paperless/src | ||||
| $ python3 manage.py migrate documents 0023 | ||||
| ``` | ||||
|  | ||||
| After that, you need to clear your cookies (Paperless-ngx comes with | ||||
| updated dependencies that do cookie-processing differently) and probably | ||||
| your cache as well. | ||||
|  | ||||
| # Considerations for less powerful devices {#less_powerful_devices} | ||||
|  | ||||
| Paperless runs on Raspberry Pi. However, some things are rather slow on | ||||
| the Pi and configuring some options in paperless can help improve | ||||
| performance immensely: | ||||
|  | ||||
| - Stick with SQLite to save some resources. | ||||
| - Consider setting `PAPERLESS_OCR_PAGES` to 1, so that paperless will | ||||
|   only OCR the first page of your documents. In most cases, this page | ||||
|   contains enough information to be able to find it. | ||||
| - `PAPERLESS_TASK_WORKERS` and `PAPERLESS_THREADS_PER_WORKER` are | ||||
|   configured to use all cores. The Raspberry Pi models 3 and up have 4 | ||||
|   cores, meaning that paperless will use 2 workers and 2 threads per | ||||
|   worker. This may result in sluggish response times during | ||||
|   consumption, so you might want to lower these settings (example: 2 | ||||
|   workers and 1 thread to always have some computing power left for | ||||
|   other tasks). | ||||
| - Keep `PAPERLESS_OCR_MODE` at its default value `skip` and consider | ||||
|   OCR'ing your documents before feeding them into paperless. Some | ||||
|   scanners are able to do this! You might want to even specify | ||||
|   `skip_noarchive` to skip archive file generation for already ocr'ed | ||||
|   documents entirely. | ||||
| - If you want to perform OCR on the device, consider using | ||||
|   `PAPERLESS_OCR_CLEAN=none`. This will speed up OCR times and use | ||||
|   less memory at the expense of slightly worse OCR results. | ||||
| - If using docker, consider setting `PAPERLESS_WEBSERVER_WORKERS` to | ||||
|   1.  This will save some memory. | ||||
| - Consider setting `PAPERLESS_ENABLE_NLTK` to false, to disable the | ||||
|   more advanced language processing, which can take more memory and | ||||
|   processing time. | ||||
|  | ||||
| For details, refer to `configuration`{.interpreted-text role="ref"}. | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     Updating the | ||||
|     [automatic matching algorithm](/advanced_usage#automatic_matching) takes quite a bit of time. However, the update mechanism | ||||
|     checks if your data has changed before doing the heavy lifting. If you | ||||
|     experience the algorithm taking too much cpu time, consider changing the | ||||
|     schedule in the admin interface to daily. You can also manually invoke | ||||
|     the task by changing the date and time of the next run to today/now. | ||||
|  | ||||
|     The actual matching of the algorithm is fast and works on Raspberry Pi | ||||
|     as well as on any other device. | ||||
|  | ||||
| # Using nginx as a reverse proxy {#nginx} | ||||
|  | ||||
| If you want to expose paperless to the internet, you should hide it | ||||
| behind a reverse proxy with SSL enabled. | ||||
|  | ||||
| In addition to the usual configuration for SSL, the following | ||||
| configuration is required for paperless to operate: | ||||
|  | ||||
| ```nginx | ||||
| http { | ||||
|  | ||||
|     # Adjust as required. This is the maximum size for file uploads. | ||||
|     # The default value 1M might be a little too small. | ||||
|     client_max_body_size 10M; | ||||
|  | ||||
|     server { | ||||
|  | ||||
|         location / { | ||||
|  | ||||
|             # Adjust host and port as required. | ||||
|             proxy_pass http://localhost:8000/; | ||||
|  | ||||
|             # These configuration options are required for WebSockets to work. | ||||
|             proxy_http_version 1.1; | ||||
|             proxy_set_header Upgrade $http_upgrade; | ||||
|             proxy_set_header Connection "upgrade"; | ||||
|  | ||||
|             proxy_redirect off; | ||||
|             proxy_set_header Host $host; | ||||
|             proxy_set_header X-Real-IP $remote_addr; | ||||
|             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||||
|             proxy_set_header X-Forwarded-Host $server_name; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The `PAPERLESS_URL` configuration variable is also required when using a | ||||
| reverse proxy. Please refer to the | ||||
| `hosting-and-security`{.interpreted-text role="ref"} docs. | ||||
|  | ||||
| Also read | ||||
| [this](https://channels.readthedocs.io/en/stable/deploying.html#nginx-supervisor-ubuntu), | ||||
| towards the end of the section. | ||||
							
								
								
									
										894
									
								
								docs/setup.rst
									
									
									
									
									
								
							
							
						
						| @@ -1,894 +0,0 @@ | ||||
|  | ||||
| ***** | ||||
| Setup | ||||
| ***** | ||||
|  | ||||
| Overview of Paperless-ngx | ||||
| ######################### | ||||
|  | ||||
| Compared to paperless, paperless-ngx works a little different under the hood and has | ||||
| more moving parts that work together. While this increases the complexity of | ||||
| the system, it also brings many benefits. | ||||
|  | ||||
| Paperless consists of the following components: | ||||
|  | ||||
| *   **The webserver:** This is pretty much the same as in paperless. It serves | ||||
|     the administration pages, the API, and the new frontend. This is the main | ||||
|     tool you'll be using to interact with paperless. You may start the webserver | ||||
|     with | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ cd /path/to/paperless/src/ | ||||
|         $ gunicorn -c ../gunicorn.conf.py paperless.wsgi | ||||
|  | ||||
|     or by any other means such as Apache ``mod_wsgi``. | ||||
|  | ||||
| *   **The consumer:** This is what watches your consumption folder for documents. | ||||
|     However, the consumer itself does not really consume your documents. | ||||
|     Now it notifies a task processor that a new file is ready for consumption. | ||||
|     I suppose it should be named differently. | ||||
|     This was also used to check your emails, but that's now done elsewhere as well. | ||||
|  | ||||
|     Start the consumer with the management command ``document_consumer``: | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ cd /path/to/paperless/src/ | ||||
|         $ python3 manage.py document_consumer | ||||
|  | ||||
|     .. _setup-task_processor: | ||||
|  | ||||
| *   **The task processor:** Paperless relies on `Celery - Distributed Task Queue <https://docs.celeryq.dev/en/stable/index.html>`_ | ||||
|     for doing most of the heavy lifting. This is a task queue that accepts tasks from | ||||
|     multiple sources and processes these in parallel. It also comes with a scheduler that executes | ||||
|     certain commands periodically. | ||||
|  | ||||
|     This task processor is responsible for: | ||||
|  | ||||
|     *   Consuming documents. When the consumer finds new documents, it notifies the task processor to | ||||
|         start a consumption task. | ||||
|     *   The task processor also performs the consumption of any documents you upload through | ||||
|         the web interface. | ||||
|     *   Consuming emails. It periodically checks your configured accounts for new emails and | ||||
|         notifies the task processor to consume the attachment of an email. | ||||
|     *   Maintaining the search index and the automatic matching algorithm. These are things that paperless | ||||
|         needs to do from time to time in order to operate properly. | ||||
|  | ||||
|     This allows paperless to process multiple documents from your consumption folder in parallel! On | ||||
|     a modern multi core system, this makes the consumption process with full OCR blazingly fast. | ||||
|  | ||||
|     The task processor comes with a built-in admin interface that you can use to check whenever any of the | ||||
|     tasks fail and inspect the errors (i.e., wrong email credentials, errors during consuming a specific | ||||
|     file, etc). | ||||
|  | ||||
| *   A `redis <https://redis.io/>`_ message broker: This is a really lightweight service that is responsible | ||||
|     for getting the tasks from the webserver and the consumer to the task scheduler. These run in a different | ||||
|     process (maybe even on different machines!), and therefore, this is necessary. | ||||
|  | ||||
| *   Optional: A database server. Paperless supports PostgreSQL, MariaDB and SQLite for storing its data. | ||||
|  | ||||
|  | ||||
| Installation | ||||
| ############ | ||||
|  | ||||
| You can go multiple routes to setup and run Paperless: | ||||
|  | ||||
| * :ref:`Use the easy install docker script <setup-docker_script>` | ||||
| * :ref:`Pull the image from Docker Hub <setup-docker_hub>` | ||||
| * :ref:`Build the Docker image yourself <setup-docker_build>` | ||||
| * :ref:`Install Paperless directly on your system manually (bare metal) <setup-bare_metal>` | ||||
|  | ||||
| The Docker routes are quick & easy. These are the recommended routes. This configures all the stuff | ||||
| from the above automatically so that it just works and uses sensible defaults for all configuration options. | ||||
| Here you find a cheat-sheet for docker beginners: `CLI Basics <https://www.sehn.tech/refs/devops-with-docker/>`_ | ||||
|  | ||||
| The bare metal route is complicated to setup but makes it easier | ||||
| should you want to contribute some code back. You need to configure and | ||||
| run the above mentioned components yourself. | ||||
|  | ||||
| .. _CLI Basics: https://www.sehn.tech/refs/devops-with-docker/ | ||||
|  | ||||
| .. _setup-docker_script: | ||||
|  | ||||
| Install Paperless from Docker Hub using the installation script | ||||
| =============================================================== | ||||
|  | ||||
| Paperless provides an interactive installation script. This script will ask you | ||||
| for a couple configuration options, download and create the necessary configuration files, pull the docker image, start paperless and create your user account. This script essentially | ||||
| performs all the steps described in :ref:`setup-docker_hub` automatically. | ||||
|  | ||||
| 1.  Make sure that docker and docker-compose are installed. | ||||
| 2.  Download and run the installation script: | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ bash -c "$(curl -L https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)" | ||||
|  | ||||
| .. _setup-docker_hub: | ||||
|  | ||||
| Install Paperless from Docker Hub | ||||
| ================================= | ||||
|  | ||||
| 1.  Login with your user and create a folder in your home-directory `mkdir -v ~/paperless-ngx` to have a place for your configuration files and consumption directory. | ||||
|  | ||||
| 2.  Go to the `/docker/compose directory on the project page <https://github.com/paperless-ngx/paperless-ngx/tree/master/docker/compose>`_ | ||||
|     and download one of the `docker-compose.*.yml` files, depending on which database backend you | ||||
|     want to use. Rename this file to `docker-compose.yml`. | ||||
|     If you want to enable optional support for Office documents, download a file with `-tika` in the file name. | ||||
|     Download the ``docker-compose.env`` file and the ``.env`` file as well and store them | ||||
|     in the same directory. | ||||
|  | ||||
|     .. hint:: | ||||
|  | ||||
|         For new installations, it is recommended to use PostgreSQL as the database | ||||
|         backend. | ||||
|  | ||||
| 3.  Install `Docker`_ and `docker-compose`_. | ||||
|  | ||||
|     .. caution:: | ||||
|  | ||||
|         If you want to use the included ``docker-compose.*.yml`` file, you | ||||
|         need to have at least Docker version **17.09.0** and docker-compose | ||||
|         version **1.17.0**. | ||||
|         To check do: `docker-compose -v` or `docker -v` | ||||
|  | ||||
|         See the `Docker installation guide`_ on how to install the current | ||||
|         version of Docker for your operating system or Linux distribution of | ||||
|         choice. To get the latest version of docker-compose, follow the | ||||
|         `docker-compose installation guide`_ if your package repository doesn't | ||||
|         include it. | ||||
|  | ||||
|         .. _Docker installation guide: https://docs.docker.com/engine/installation/ | ||||
|         .. _docker-compose installation guide: https://docs.docker.com/compose/install/ | ||||
|  | ||||
| 4.  Modify ``docker-compose.yml`` to your preferences. You may want to change the path | ||||
|     to the consumption directory. Find the line that specifies where | ||||
|     to mount the consumption directory: | ||||
|  | ||||
|     .. code:: | ||||
|  | ||||
|         - ./consume:/usr/src/paperless/consume | ||||
|  | ||||
|     Replace the part BEFORE the colon with a local directory of your choice: | ||||
|  | ||||
|     .. code:: | ||||
|  | ||||
|         - /home/jonaswinkler/paperless-inbox:/usr/src/paperless/consume | ||||
|  | ||||
|     Don't change the part after the colon or paperless wont find your documents. | ||||
|  | ||||
|     You may also need to change the default port that the webserver will use | ||||
|     from the default (8000): | ||||
|  | ||||
|      .. code:: | ||||
|  | ||||
|         ports: | ||||
|           - 8000:8000 | ||||
|  | ||||
|     Replace the part BEFORE the colon with a port of your choice: | ||||
|  | ||||
|      .. code:: | ||||
|  | ||||
|         ports: | ||||
|           - 8010:8000 | ||||
|  | ||||
|     Don't change the part after the colon or edit other lines that refer to | ||||
|     port 8000. Modifying the part before the colon will map requests on another | ||||
|     port to the webserver running on the default port. | ||||
|  | ||||
|     **Rootless** | ||||
|  | ||||
|     If you want to run Paperless as a rootless container, you will need to do the | ||||
|     following in your ``docker-compose.yml``: | ||||
|  | ||||
|     - set the ``user`` running the container to map to the ``paperless`` user in the | ||||
|       container. | ||||
|       This value (``user_id`` below), should be the same id that ``USERMAP_UID`` and | ||||
|       ``USERMAP_GID`` are set to in the next step. | ||||
|       See ``USERMAP_UID`` and ``USERMAP_GID`` :ref:`here <configuration-docker>`. | ||||
|  | ||||
|     Your entry for Paperless should contain something like: | ||||
|  | ||||
|      .. code:: | ||||
|  | ||||
|         webserver: | ||||
|           image: ghcr.io/paperless-ngx/paperless-ngx:latest | ||||
|           user: <user_id> | ||||
|  | ||||
| 5.  Modify ``docker-compose.env``, following the comments in the file. The | ||||
|     most important change is to set ``USERMAP_UID`` and ``USERMAP_GID`` | ||||
|     to the uid and gid of your user on the host system. Use ``id -u`` and | ||||
|     ``id -g`` to get these. | ||||
|  | ||||
|     This ensures that | ||||
|     both the docker container and you on the host machine have write access | ||||
|     to the consumption directory. If your UID and GID on the host system is | ||||
|     1000 (the default for the first normal user on most systems), it will | ||||
|     work out of the box without any modifications. `id "username"` to check. | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         You can copy any setting from the file ``paperless.conf.example`` and paste it here. | ||||
|         Have a look at :ref:`configuration` to see what's available. | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         You can utilize Docker secrets for some configuration settings by | ||||
|         appending `_FILE` to some configuration values.  This is supported currently | ||||
|         only by: | ||||
|  | ||||
|           * PAPERLESS_DBUSER | ||||
|           * PAPERLESS_DBPASS | ||||
|           * PAPERLESS_SECRET_KEY | ||||
|           * PAPERLESS_AUTO_LOGIN_USERNAME | ||||
|           * PAPERLESS_ADMIN_USER | ||||
|           * PAPERLESS_ADMIN_MAIL | ||||
|           * PAPERLESS_ADMIN_PASSWORD | ||||
|  | ||||
|     .. caution:: | ||||
|  | ||||
|         Some file systems such as NFS network shares don't support file system | ||||
|         notifications with ``inotify``. When storing the consumption directory | ||||
|         on such a file system, paperless will not pick up new files | ||||
|         with the default configuration. You will need to use ``PAPERLESS_CONSUMER_POLLING``, | ||||
|         which will disable inotify. See :ref:`here <configuration-polling>`. | ||||
|  | ||||
| 6.  Run ``docker-compose pull``, followed by ``docker-compose up -d``. | ||||
|     This will pull the image, create and start the necessary containers. | ||||
|  | ||||
| 7.  To be able to login, you will need a super user. To create it, execute the | ||||
|     following command: | ||||
|  | ||||
|     .. code-block:: shell-session | ||||
|  | ||||
|         $ docker-compose run --rm webserver createsuperuser | ||||
|  | ||||
|     This will prompt you to set a username, an optional e-mail address and | ||||
|     finally a password (at least 8 characters). | ||||
|  | ||||
| 8.  The default ``docker-compose.yml`` exports the webserver on your local port | ||||
|     8000. If you did not change this, you should now be able to visit your | ||||
|     Paperless instance at ``http://127.0.0.1:8000`` or your servers IP-Address:8000. | ||||
|     Use the login credentials you have created with the previous step. | ||||
|  | ||||
| .. _Docker: https://www.docker.com/ | ||||
| .. _docker-compose: https://docs.docker.com/compose/install/ | ||||
|  | ||||
| .. _setup-docker_build: | ||||
|  | ||||
| Build the Docker image yourself | ||||
| =============================== | ||||
|  | ||||
| 1.  Clone the entire repository of paperless: | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         git clone https://github.com/paperless-ngx/paperless-ngx | ||||
|  | ||||
|     The master branch always reflects the latest stable version. | ||||
|  | ||||
| 2.  Copy one of the ``docker/compose/docker-compose.*.yml`` to ``docker-compose.yml`` in the root folder, | ||||
|     depending on which database backend you want to use. Copy | ||||
|     ``docker-compose.env`` into the project root as well. | ||||
|  | ||||
| 3.  In the ``docker-compose.yml`` file, find the line that instructs docker-compose to pull the paperless image from Docker Hub: | ||||
|  | ||||
|     .. code:: yaml | ||||
|  | ||||
|         webserver: | ||||
|             image: ghcr.io/paperless-ngx/paperless-ngx:latest | ||||
|  | ||||
|     and replace it with a line that instructs docker-compose to build the image from the current working directory instead: | ||||
|  | ||||
|     .. code:: yaml | ||||
|  | ||||
|         webserver: | ||||
|             build: | ||||
|               context: . | ||||
|               args: | ||||
|                 QPDF_VERSION: x.y.x | ||||
|                 PIKEPDF_VERSION: x.y.z | ||||
|                 PSYCOPG2_VERSION: x.y.z | ||||
|                 JBIG2ENC_VERSION: 0.29 | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         You should match the build argument versions to the version for the release you have | ||||
|         checked out.  These are pre-built images with certain, more updated software. | ||||
|         If you want to build these images your self, that is possible, but beyond | ||||
|         the scope of these steps. | ||||
|  | ||||
| 4.  Follow steps 3 to 8 of :ref:`setup-docker_hub`. When asked to run | ||||
|     ``docker-compose pull`` to pull the image, do | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ docker-compose build | ||||
|  | ||||
|     instead to build the image. | ||||
|  | ||||
| .. _setup-bare_metal: | ||||
|  | ||||
| Bare Metal Route | ||||
| ================ | ||||
|  | ||||
| Paperless runs on linux only. The following procedure has been tested on a minimal | ||||
| installation of Debian/Buster, which is the current stable release at the time of | ||||
| writing. Windows is not and will never be supported. | ||||
|  | ||||
| 1.  Install dependencies. Paperless requires the following packages. | ||||
|  | ||||
|     *   ``python3`` 3.8, 3.9 | ||||
|     *   ``python3-pip`` | ||||
|     *   ``python3-dev`` | ||||
|  | ||||
|     *   ``default-libmysqlclient-dev`` for MariaDB | ||||
|     *   ``fonts-liberation`` for generating thumbnails for plain text files | ||||
|     *   ``imagemagick`` >= 6 for PDF conversion | ||||
|     *   ``gnupg`` for handling encrypted documents | ||||
|     *   ``libpq-dev`` for PostgreSQL | ||||
|     *   ``libmagic-dev`` for mime type detection | ||||
|     *   ``mariadb-client`` for MariaDB compile time | ||||
|     *   ``mime-support`` for mime type detection | ||||
|     *   ``libzbar0`` for barcode detection | ||||
|     *   ``poppler-utils`` for barcode detection | ||||
|  | ||||
|     Use this list for your preferred package management: | ||||
|  | ||||
|     .. code:: | ||||
|  | ||||
|         python3 python3-pip python3-dev imagemagick fonts-liberation gnupg libpq-dev default-libmysqlclient-dev libmagic-dev mime-support libzbar0 poppler-utils | ||||
|  | ||||
|     These dependencies are required for OCRmyPDF, which is used for text recognition. | ||||
|  | ||||
|     *   ``unpaper`` | ||||
|     *   ``ghostscript`` | ||||
|     *   ``icc-profiles-free`` | ||||
|     *   ``qpdf`` | ||||
|     *   ``liblept5`` | ||||
|     *   ``libxml2`` | ||||
|     *   ``pngquant`` (suggested for certain PDF image optimizations) | ||||
|     *   ``zlib1g`` | ||||
|     *   ``tesseract-ocr`` >= 4.0.0 for OCR | ||||
|     *   ``tesseract-ocr`` language packs (``tesseract-ocr-eng``, ``tesseract-ocr-deu``, etc) | ||||
|  | ||||
|     Use this list for your preferred package management: | ||||
|  | ||||
|     .. code:: | ||||
|  | ||||
|         unpaper ghostscript icc-profiles-free qpdf liblept5 libxml2 pngquant zlib1g tesseract-ocr | ||||
|  | ||||
|     On Raspberry Pi, these libraries are required as well: | ||||
|  | ||||
|     *   ``libatlas-base-dev`` | ||||
|     *   ``libxslt1-dev`` | ||||
|  | ||||
|     You will also need ``build-essential``, ``python3-setuptools`` and ``python3-wheel`` | ||||
|     for installing some of the python dependencies. | ||||
|  | ||||
| 2.  Install ``redis`` >= 6.0 and configure it to start automatically. | ||||
|  | ||||
| 3.  Optional. Install ``postgresql`` and configure a database, user and password for paperless. If you do not wish | ||||
|     to use PostgreSQL, MariaDB and SQLite are available as well. | ||||
|  | ||||
|     .. note:: | ||||
|  | ||||
|         On bare-metal installations using SQLite, ensure the | ||||
|         `JSON1 extension <https://code.djangoproject.com/wiki/JSON1Extension>`_ is enabled. This is | ||||
|         usually the case, but not always. | ||||
|  | ||||
| 4.  Get the release archive from `<https://github.com/paperless-ngx/paperless-ngx/releases>`_. | ||||
|     If you clone the git repo as it is, you also have to compile the front end by yourself. | ||||
|     Extract the archive to a place from where you wish to execute it, such as ``/opt/paperless``. | ||||
|  | ||||
| 5.  Configure paperless. See :ref:`configuration` for details. Edit the included ``paperless.conf`` and adjust the | ||||
|     settings to your needs. Required settings for getting paperless running are: | ||||
|  | ||||
|     *   ``PAPERLESS_REDIS`` should point to your redis server, such as redis://localhost:6379. | ||||
|     *   ``PAPERLESS_DBENGINE`` optional, and should be one of `postgres, mariadb, or sqlite` | ||||
|     *   ``PAPERLESS_DBHOST`` should be the hostname on which your PostgreSQL server is running. Do not configure this | ||||
|         to use SQLite instead. Also configure port, database name, user and password as necessary. | ||||
|     *   ``PAPERLESS_CONSUMPTION_DIR`` should point to a folder which paperless should watch for documents. You might | ||||
|         want to have this somewhere else. Likewise, ``PAPERLESS_DATA_DIR`` and ``PAPERLESS_MEDIA_ROOT`` define where | ||||
|         paperless stores its data. If you like, you can point both to the same directory. | ||||
|     *   ``PAPERLESS_SECRET_KEY`` should be a random sequence of characters. It's used for authentication. Failure | ||||
|         to do so allows third parties to forge authentication credentials. | ||||
|     *   ``PAPERLESS_URL`` if you are behind a reverse proxy. This should point to your domain. Please see | ||||
|         :ref:`configuration` for more information. | ||||
|  | ||||
|     Many more adjustments can be made to paperless, especially the OCR part. The following options are recommended | ||||
|     for everyone: | ||||
|  | ||||
|     *   Set ``PAPERLESS_OCR_LANGUAGE`` to the language most of your documents are written in. | ||||
|     *   Set ``PAPERLESS_TIME_ZONE`` to your local time zone. | ||||
|  | ||||
| 6.  Create a system user under which you wish to run paperless. | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         adduser paperless --system --home /opt/paperless --group | ||||
|  | ||||
| 7.  Ensure that these directories exist | ||||
|     and that the paperless user has write permissions to the following directories: | ||||
|  | ||||
|     *   ``/opt/paperless/media`` | ||||
|     *   ``/opt/paperless/data`` | ||||
|     *   ``/opt/paperless/consume`` | ||||
|  | ||||
|     Adjust as necessary if you configured different folders. | ||||
|  | ||||
| 8.  Install python requirements from the ``requirements.txt`` file. | ||||
|     It is up to you if you wish to use a virtual environment or not. First you should update your pip, so it gets the actual packages. | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         sudo -Hu paperless pip3 install --upgrade pip | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         sudo -Hu paperless pip3 install -r requirements.txt | ||||
|  | ||||
|     This will install all python dependencies in the home directory of | ||||
|     the new paperless user. | ||||
|  | ||||
| 9.  Go to ``/opt/paperless/src``, and execute the following commands: | ||||
|  | ||||
|     .. code:: bash | ||||
|  | ||||
|         # This creates the database schema. | ||||
|         sudo -Hu paperless python3 manage.py migrate | ||||
|  | ||||
|         # This creates your first paperless user | ||||
|         sudo -Hu paperless python3 manage.py createsuperuser | ||||
|  | ||||
| 10. Optional: Test that paperless is working by executing | ||||
|  | ||||
|       .. code:: bash | ||||
|  | ||||
|         # This collects static files from paperless and django. | ||||
|         sudo -Hu paperless python3 manage.py runserver | ||||
|  | ||||
|     and pointing your browser to http://localhost:8000/. | ||||
|  | ||||
|     .. warning:: | ||||
|  | ||||
|         This is a development server which should not be used in | ||||
|         production. It is not audited for security and performance | ||||
|         is inferior to production ready web servers. | ||||
|  | ||||
|     .. hint:: | ||||
|  | ||||
|         This will not start the consumer. Paperless does this in a | ||||
|         separate process. | ||||
|  | ||||
| 11. Setup systemd services to run paperless automatically. You may | ||||
|     use the service definition files included in the ``scripts`` folder | ||||
|     as a starting point. | ||||
|  | ||||
|     Paperless needs the ``webserver`` script to run the webserver, the | ||||
|     ``consumer`` script to watch the input folder, ``taskqueue`` for the background workers | ||||
|     used to handle things like document consumption and the ``scheduler`` script to run tasks such as | ||||
|     email checking at certain times . | ||||
|  | ||||
| 		The ``socket`` script enables ``gunicorn`` to run on port 80 without | ||||
| 		root privileges. For this you need to uncomment the ``Require=paperless-webserver.socket`` | ||||
| 		in the ``webserver`` script and configure ``gunicorn`` to listen on port 80 (see ``paperless/gunicorn.conf.py``). | ||||
|  | ||||
|     You may need to adjust the path to the ``gunicorn`` executable. This | ||||
|     will be installed as part of the python dependencies, and is either located | ||||
|     in the ``bin`` folder of your virtual environment, or in ``~/.local/bin/`` if | ||||
|     no virtual environment is used. | ||||
|  | ||||
|     These services rely on redis and optionally the database server, but | ||||
|     don't need to be started in any particular order. The example files | ||||
|     depend on redis being started. If you use a database server, you should | ||||
|     add additional dependencies. | ||||
|  | ||||
|     .. caution:: | ||||
|  | ||||
|         The included scripts run a ``gunicorn`` standalone server, | ||||
|         which is fine for running paperless. It does support SSL, | ||||
|         however, the documentation of GUnicorn states that you should | ||||
|         use a proxy server in front of gunicorn instead. | ||||
|  | ||||
|         For instructions on how to use nginx for that, | ||||
|         :ref:`see the instructions below <setup-nginx>`. | ||||
|  | ||||
| 12. Optional: Install a samba server and make the consumption folder | ||||
|     available as a network share. | ||||
|  | ||||
| 13. Configure ImageMagick to allow processing of PDF documents. Most distributions have | ||||
|     this disabled by default, since PDF documents can contain malware. If | ||||
|     you don't do this, paperless will fall back to ghostscript for certain steps | ||||
|     such as thumbnail generation. | ||||
|  | ||||
|     Edit ``/etc/ImageMagick-6/policy.xml`` and adjust | ||||
|  | ||||
|     .. code:: | ||||
|  | ||||
|         <policy domain="coder" rights="none" pattern="PDF" /> | ||||
|  | ||||
|     to | ||||
|  | ||||
|     .. code:: | ||||
|  | ||||
|         <policy domain="coder" rights="read|write" pattern="PDF" /> | ||||
|  | ||||
| 14. Optional: Install the `jbig2enc <https://ocrmypdf.readthedocs.io/en/latest/jbig2.html>`_ | ||||
|     encoder. This will reduce the size of generated PDF documents. You'll most likely need | ||||
|     to compile this by yourself, because this software has been patented until around 2017 and | ||||
|     binary packages are not available for most distributions. | ||||
|  | ||||
| 15. Optional: If using the NLTK machine learning processing (see ``PAPERLESS_ENABLE_NLTK`` in | ||||
|     :ref:`configuration` for details), download the NLTK data for the Snowball Stemmer, Stopwords | ||||
|     and Punkt tokenizer to your ``PAPERLESS_DATA_DIR/nltk``.  Refer to | ||||
|     the `NLTK instructions <https://www.nltk.org/data.html>`_ for details on how to | ||||
|     download the data. | ||||
|  | ||||
|  | ||||
| Migrating to Paperless-ngx | ||||
| ########################## | ||||
|  | ||||
| Migration is possible both from Paperless-ng or directly from the 'original' Paperless. | ||||
|  | ||||
| Migrating from Paperless-ng | ||||
| =========================== | ||||
|  | ||||
| Paperless-ngx is meant to be a drop-in replacement for Paperless-ng and thus upgrading should be | ||||
| trivial for most users, especially when using docker. However, as with any major change, it is | ||||
| recommended to take a full backup first. Once you are ready, simply change the docker image to | ||||
| point to the new source. E.g. if using Docker Compose, edit ``docker-compose.yml`` and change: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|   image: jonaswinkler/paperless-ng:latest | ||||
|  | ||||
| to | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|   image: ghcr.io/paperless-ngx/paperless-ngx:latest | ||||
|  | ||||
| and then run ``docker-compose up -d`` which will pull the new image recreate the container. | ||||
| That's it! | ||||
|  | ||||
| Users who installed with the bare-metal route should also update their Git clone to point to | ||||
| ``https://github.com/paperless-ngx/paperless-ngx``, e.g. using the command | ||||
| ``git remote set-url origin https://github.com/paperless-ngx/paperless-ngx`` and then pull the | ||||
| lastest version. | ||||
|  | ||||
| Migrating from Paperless | ||||
| ======================== | ||||
|  | ||||
| At its core, paperless-ngx is still paperless and fully compatible. However, some | ||||
| things have changed under the hood, so you need to adapt your setup depending on | ||||
| how you installed paperless. | ||||
|  | ||||
| This setup describes how to update an existing paperless Docker installation. | ||||
| The important things to keep in mind are as follows: | ||||
|  | ||||
| * Read the :doc:`changelog </changelog>` and take note of breaking changes. | ||||
| * You should decide if you want to stick with SQLite or want to migrate your database | ||||
|   to PostgreSQL. See :ref:`setup-sqlite_to_psql` for details on how to move your data from | ||||
|   SQLite to PostgreSQL. Both work fine with paperless. However, if you already have a | ||||
|   database server running for other services, you might as well use it for paperless as well. | ||||
| * The task scheduler of paperless, which is used to execute periodic tasks | ||||
|   such as email checking and maintenance, requires a `redis`_ message broker | ||||
|   instance. The docker-compose route takes care of that. | ||||
| * The layout of the folder structure for your documents and data remains the | ||||
|   same, so you can just plug your old docker volumes into paperless-ngx and | ||||
|   expect it to find everything where it should be. | ||||
|  | ||||
| Migration to paperless-ngx is then performed in a few simple steps: | ||||
|  | ||||
| 1.  Stop paperless. | ||||
|  | ||||
|     .. code:: bash | ||||
|  | ||||
|         $ cd /path/to/current/paperless | ||||
|         $ docker-compose down | ||||
|  | ||||
| 2.  Do a backup for two purposes: If something goes wrong, you still have your | ||||
|     data. Second, if you don't like paperless-ngx, you can switch back to | ||||
|     paperless. | ||||
|  | ||||
| 3.  Download the latest release of paperless-ngx. You can either go with the | ||||
|     docker-compose files from `here <https://github.com/paperless-ngx/paperless-ngx/tree/master/docker/compose>`__ | ||||
|     or clone the repository to build the image yourself (see :ref:`above <setup-docker_build>`). | ||||
|     You can either replace your current paperless folder or put paperless-ngx | ||||
|     in a different location. | ||||
|  | ||||
|     .. caution:: | ||||
|  | ||||
|         Paperless-ngx includes a ``.env`` file. This will set the | ||||
|         project name for docker compose to ``paperless``, which will also define the name | ||||
|         of the volumes by paperless-ngx. However, if you experience that paperless-ngx | ||||
|         is not using your old paperless volumes, verify the names of your volumes with | ||||
|  | ||||
|         .. code:: shell-session | ||||
|  | ||||
|             $ docker volume ls | grep _data | ||||
|  | ||||
|         and adjust the project name in the ``.env`` file so that it matches the name | ||||
|         of the volumes before the ``_data`` part. | ||||
|  | ||||
|  | ||||
| 4.  Download the ``docker-compose.sqlite.yml`` file to ``docker-compose.yml``. | ||||
|     If you want to switch to PostgreSQL, do that after you migrated your existing | ||||
|     SQLite database. | ||||
|  | ||||
| 5.  Adjust ``docker-compose.yml`` and ``docker-compose.env`` to your needs. | ||||
|     See :ref:`setup-docker_hub` for details on which edits are advised. | ||||
|  | ||||
| 6.  :ref:`Update paperless. <administration-updating>` | ||||
|  | ||||
| 7.  In order to find your existing documents with the new search feature, you need | ||||
|     to invoke a one-time operation that will create the search index: | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ docker-compose run --rm webserver document_index reindex | ||||
|  | ||||
|     This will migrate your database and create the search index. After that, | ||||
|     paperless will take care of maintaining the index by itself. | ||||
|  | ||||
| 8.  Start paperless-ngx. | ||||
|  | ||||
|     .. code:: bash | ||||
|  | ||||
|         $ docker-compose up -d | ||||
|  | ||||
|     This will run paperless in the background and automatically start it on system boot. | ||||
|  | ||||
| 9.  Paperless installed a permanent redirect to ``admin/`` in your browser. This | ||||
|     redirect is still in place and prevents access to the new UI. Clear your | ||||
|     browsing cache in order to fix this. | ||||
|  | ||||
| 10.  Optionally, follow the instructions below to migrate your existing data to PostgreSQL. | ||||
|  | ||||
|  | ||||
| Migrating from LinuxServer.io Docker Image | ||||
| ========================================== | ||||
|  | ||||
| As with any upgrades and large changes, it is highly recommended to create a backup before | ||||
| starting.  This assumes the image was running using Docker Compose, but the instructions | ||||
| are translatable to Docker commands as well. | ||||
|  | ||||
| 1.  Stop and remove the paperless container | ||||
| 2.  If using an external database, stop the container | ||||
| 3.  Update Redis configuration | ||||
|  | ||||
|     a)  If ``REDIS_URL`` is already set, change it to ``PAPERLESS_REDIS`` and continue | ||||
|         to step 4. | ||||
|     b)  Otherwise, in the ``docker-compose.yml`` add a new service for Redis, | ||||
|         following `the example compose files <https://github.com/paperless-ngx/paperless-ngx/tree/main/docker/compose>`_ | ||||
|     c)  Set the environment variable ``PAPERLESS_REDIS`` so it points to the new Redis container | ||||
|  | ||||
| 4.  Update user mapping | ||||
|  | ||||
|     a)  If set, change the environment variable ``PUID`` to ``USERMAP_UID`` | ||||
|     b)  If set, change the environment variable ``PGID`` to ``USERMAP_GID`` | ||||
|  | ||||
| 5.  Update configuration paths | ||||
|  | ||||
|     a) Set the environment variable ``PAPERLESS_DATA_DIR`` | ||||
|        to ``/config`` | ||||
|  | ||||
| 6.  Update media paths | ||||
|  | ||||
|     a) Set the environment variable ``PAPERLESS_MEDIA_ROOT`` | ||||
|        to ``/data/media`` | ||||
|  | ||||
| 7.  Update timezone | ||||
|  | ||||
|     a) Set the environment variable ``PAPERLESS_TIME_ZONE`` | ||||
|        to the same value as ``TZ`` | ||||
|  | ||||
| 8.  Modify the ``image:`` to point to ``ghcr.io/paperless-ngx/paperless-ngx:latest`` or | ||||
|     a specific version if preferred. | ||||
|  | ||||
| 9.  Start the containers as before, using ``docker-compose``. | ||||
|  | ||||
| .. _setup-sqlite_to_psql: | ||||
|  | ||||
| Moving data from SQLite to PostgreSQL or MySQL/MariaDB | ||||
| ====================================================== | ||||
|  | ||||
| Moving your data from SQLite to PostgreSQL or MySQL/MariaDB is done via executing a series of django | ||||
| management commands as below.  The commands below use PostgreSQL, but are applicable to MySQL/MariaDB | ||||
| with the | ||||
|  | ||||
| .. caution:: | ||||
|  | ||||
|     Make sure that your SQLite database is migrated to the latest version. | ||||
|     Starting paperless will make sure that this is the case. If your try to | ||||
|     load data from an old database schema in SQLite into a newer database | ||||
|     schema in PostgreSQL, you will run into trouble. | ||||
|  | ||||
| .. warning:: | ||||
|  | ||||
|     On some database fields, PostgreSQL enforces predefined limits on maximum | ||||
|     length, whereas SQLite does not. The fields in question are the title of documents | ||||
|     (128 characters), names of document types, tags and correspondents (128 characters), | ||||
|     and filenames (1024 characters). If you have data in these fields that surpasses these | ||||
|     limits, migration to PostgreSQL is not possible and will fail with an error. | ||||
|  | ||||
| .. warning:: | ||||
|  | ||||
|     MySQL is case insensitive by default, treating values like "Name" and "NAME" as identical. | ||||
|     See :ref:`advanced-mysql-caveats` for details. | ||||
|  | ||||
|  | ||||
| 1.  Stop paperless, if it is running. | ||||
| 2.  Tell paperless to use PostgreSQL: | ||||
|  | ||||
|     a)  With docker, copy the provided ``docker-compose.postgres.yml`` file to | ||||
|         ``docker-compose.yml``. Remember to adjust the consumption directory, | ||||
|         if necessary. | ||||
|     b)  Without docker, configure the database in your ``paperless.conf`` file. | ||||
|         See :ref:`configuration` for details. | ||||
|  | ||||
| 3.  Open a shell and initialize the database: | ||||
|  | ||||
|     a)  With docker, run the following command to open a shell within the paperless | ||||
|         container: | ||||
|  | ||||
|         .. code:: shell-session | ||||
|  | ||||
|             $ cd /path/to/paperless | ||||
|             $ docker-compose run --rm webserver /bin/bash | ||||
|  | ||||
|         This will launch the container and initialize the PostgreSQL database. | ||||
|  | ||||
|     b)  Without docker, remember to activate any virtual environment, switch to | ||||
|         the ``src`` directory and create the database schema: | ||||
|  | ||||
|         .. code:: shell-session | ||||
|  | ||||
|             $ cd /path/to/paperless/src | ||||
|             $ python3 manage.py migrate | ||||
|  | ||||
|         This will not copy any data yet. | ||||
|  | ||||
| 4.  Dump your data from SQLite: | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ python3 manage.py dumpdata --database=sqlite --exclude=contenttypes --exclude=auth.Permission > data.json | ||||
|  | ||||
| 5.  Load your data into PostgreSQL: | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ python3 manage.py loaddata data.json | ||||
|  | ||||
| 6.  If operating inside Docker, you may exit the shell now. | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ exit | ||||
|  | ||||
| 7.  Start paperless. | ||||
|  | ||||
|  | ||||
| Moving back to Paperless | ||||
| ======================== | ||||
|  | ||||
| Lets say you migrated to Paperless-ngx and used it for a while, but decided that | ||||
| you don't like it and want to move back (If you do, send me a mail about what | ||||
| part you didn't like!), you can totally do that with a few simple steps. | ||||
|  | ||||
| Paperless-ngx modified the database schema slightly, however, these changes can | ||||
| be reverted while keeping your current data, so that your current data will | ||||
| be compatible with original Paperless. | ||||
|  | ||||
| Execute this: | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     $ cd /path/to/paperless | ||||
|     $ docker-compose run --rm webserver migrate documents 0023 | ||||
|  | ||||
| Or without docker: | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     $ cd /path/to/paperless/src | ||||
|     $ python3 manage.py migrate documents 0023 | ||||
|  | ||||
| After that, you need to clear your cookies (Paperless-ngx comes with updated | ||||
| dependencies that do cookie-processing differently) and probably your cache | ||||
| as well. | ||||
|  | ||||
| .. _setup-less_powerful_devices: | ||||
|  | ||||
|  | ||||
| Considerations for less powerful devices | ||||
| ######################################## | ||||
|  | ||||
| Paperless runs on Raspberry Pi. However, some things are rather slow on the Pi and | ||||
| configuring some options in paperless can help improve performance immensely: | ||||
|  | ||||
| *   Stick with SQLite to save some resources. | ||||
| *   Consider setting ``PAPERLESS_OCR_PAGES`` to 1, so that paperless will only OCR | ||||
|     the first page of your documents. In most cases, this page contains enough | ||||
|     information to be able to find it. | ||||
| *   ``PAPERLESS_TASK_WORKERS`` and ``PAPERLESS_THREADS_PER_WORKER`` are configured | ||||
|     to use all cores. The Raspberry Pi models 3 and up have 4 cores, meaning that | ||||
|     paperless will use 2 workers and 2 threads per worker. This may result in | ||||
|     sluggish response times during consumption, so you might want to lower these | ||||
|     settings (example: 2 workers and 1 thread to always have some computing power | ||||
|     left for other tasks). | ||||
| *   Keep ``PAPERLESS_OCR_MODE`` at its default value ``skip`` and consider OCR'ing | ||||
|     your documents before feeding them into paperless. Some scanners are able to | ||||
|     do this! You might want to even specify ``skip_noarchive`` to skip archive | ||||
|     file generation for already ocr'ed documents entirely. | ||||
| *   If you want to perform OCR on the device, consider using ``PAPERLESS_OCR_CLEAN=none``. | ||||
|     This will speed up OCR times and use less memory at the expense of slightly worse | ||||
|     OCR results. | ||||
| *   If using docker, consider setting ``PAPERLESS_WEBSERVER_WORKERS`` to | ||||
|     1. This will save some memory. | ||||
| *   Consider setting ``PAPERLESS_ENABLE_NLTK`` to false, to disable the more | ||||
|     advanced language processing, which can take more memory and processing time. | ||||
|  | ||||
| For details, refer to :ref:`configuration`. | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     Updating the :ref:`automatic matching algorithm <advanced-automatic_matching>` | ||||
|     takes quite a bit of time. However, the update mechanism checks if your | ||||
|     data has changed before doing the heavy lifting. If you experience the | ||||
|     algorithm taking too much cpu time, consider changing the schedule in the | ||||
|     admin interface to daily. You can also manually invoke the task | ||||
|     by changing the date and time of the next run to today/now. | ||||
|  | ||||
|     The actual matching of the algorithm is fast and works on Raspberry Pi as | ||||
|     well as on any other device. | ||||
|  | ||||
| .. _redis: https://redis.io/ | ||||
|  | ||||
|  | ||||
| .. _setup-nginx: | ||||
|  | ||||
| Using nginx as a reverse proxy | ||||
| ############################## | ||||
|  | ||||
| If you want to expose paperless to the internet, you should hide it behind a | ||||
| reverse proxy with SSL enabled. | ||||
|  | ||||
| In addition to the usual configuration for SSL, | ||||
| the following configuration is required for paperless to operate: | ||||
|  | ||||
| .. code:: nginx | ||||
|  | ||||
|     http { | ||||
|  | ||||
|         # Adjust as required. This is the maximum size for file uploads. | ||||
|         # The default value 1M might be a little too small. | ||||
|         client_max_body_size 10M; | ||||
|  | ||||
|         server { | ||||
|  | ||||
|             location / { | ||||
|  | ||||
|                 # Adjust host and port as required. | ||||
|                 proxy_pass http://localhost:8000/; | ||||
|  | ||||
|                 # These configuration options are required for WebSockets to work. | ||||
|                 proxy_http_version 1.1; | ||||
|                 proxy_set_header Upgrade $http_upgrade; | ||||
|                 proxy_set_header Connection "upgrade"; | ||||
|  | ||||
|                 proxy_redirect off; | ||||
|                 proxy_set_header Host $host; | ||||
|                 proxy_set_header X-Real-IP $remote_addr; | ||||
|                 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||||
|                 proxy_set_header X-Forwarded-Host $server_name; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| The ``PAPERLESS_URL`` configuration variable is also required when using a reverse proxy. Please refer to the :ref:`hosting-and-security` docs. | ||||
|  | ||||
| Also read `this <https://channels.readthedocs.io/en/stable/deploying.html#nginx-supervisor-ubuntu>`__, towards the end of the section. | ||||
							
								
								
									
										335
									
								
								docs/troubleshooting.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,335 @@ | ||||
| # Troubleshooting | ||||
|  | ||||
| ## No files are added by the consumer | ||||
|  | ||||
| Check for the following issues: | ||||
|  | ||||
| - Ensure that the directory you're putting your documents in is the | ||||
|   folder paperless is watching. With docker, this setting is performed | ||||
|   in the `docker-compose.yml` file. Without docker, look at the | ||||
|   `CONSUMPTION_DIR` setting. Don't adjust this setting if you're | ||||
|   using docker. | ||||
|  | ||||
| - Ensure that redis is up and running. Paperless does its task | ||||
|   processing asynchronously, and for documents to arrive at the task | ||||
|   processor, it needs redis to run. | ||||
|  | ||||
| - Ensure that the task processor is running. Docker does this | ||||
|   automatically. Manually invoke the task processor by executing | ||||
|  | ||||
|   ```shell-session | ||||
|   $ celery --app paperless worker | ||||
|   ``` | ||||
|  | ||||
| - Look at the output of paperless and inspect it for any errors. | ||||
|  | ||||
| - Go to the admin interface, and check if there are failed tasks. If | ||||
|   so, the tasks will contain an error message. | ||||
|  | ||||
| ## Consumer warns `OCR for XX failed` | ||||
|  | ||||
| If you find the OCR accuracy to be too low, and/or the document consumer | ||||
| warns that | ||||
| `OCR for XX failed, but we're going to stick with what we've got since FORGIVING_OCR is enabled`, | ||||
| then you might need to install the [Tesseract language | ||||
| files](http://packages.ubuntu.com/search?keywords=tesseract-ocr) | ||||
| marching your document's languages. | ||||
|  | ||||
| As an example, if you are running Paperless-ngx from any Ubuntu or | ||||
| Debian box, and your documents are written in Spanish you may need to | ||||
| run: | ||||
|  | ||||
|     apt-get install -y tesseract-ocr-spa | ||||
|  | ||||
| ## Consumer fails to pickup any new files | ||||
|  | ||||
| If you notice that the consumer will only pickup files in the | ||||
| consumption directory at startup, but won't find any other files added | ||||
| later, you will need to enable filesystem polling with the configuration | ||||
| option `PAPERLESS_CONSUMER_POLLING`, see | ||||
| `[here](/configuration#polling). | ||||
|  | ||||
| This will disable listening to filesystem changes with inotify and | ||||
| paperless will manually check the consumption directory for changes | ||||
| instead. | ||||
|  | ||||
| ## Paperless always redirects to /admin | ||||
|  | ||||
| You probably had the old paperless installed at some point. Paperless | ||||
| installed a permanent redirect to /admin in your browser, and you need | ||||
| to clear your browsing data / cache to fix that. | ||||
|  | ||||
| ## Operation not permitted | ||||
|  | ||||
| You might see errors such as: | ||||
|  | ||||
| ```shell-session | ||||
| chown: changing ownership of '../export': Operation not permitted | ||||
| ``` | ||||
|  | ||||
| The container tries to set file ownership on the listed directories. | ||||
| This is required so that the user running paperless inside docker has | ||||
| write permissions to these folders. This happens when pointing these | ||||
| directories to NFS shares, for example. | ||||
|  | ||||
| Ensure that `chown` is possible on these directories. | ||||
|  | ||||
| ## Classifier error: No training data available | ||||
|  | ||||
| This indicates that the Auto matching algorithm found no documents to | ||||
| learn from. This may have two reasons: | ||||
|  | ||||
| - You don't use the Auto matching algorithm: The error can be safely | ||||
|   ignored in this case. | ||||
| - You are using the Auto matching algorithm: The classifier explicitly | ||||
|   excludes documents with Inbox tags. Verify that there are documents | ||||
|   in your archive without inbox tags. The algorithm will only learn | ||||
|   from documents not in your inbox. | ||||
|  | ||||
| ## UserWarning in sklearn on every single document | ||||
|  | ||||
| You may encounter warnings like this: | ||||
|  | ||||
| ``` | ||||
| /usr/local/lib/python3.7/site-packages/sklearn/base.py:315: | ||||
| UserWarning: Trying to unpickle estimator CountVectorizer from version 0.23.2 when using version 0.24.0. | ||||
| This might lead to breaking code or invalid results. Use at your own risk. | ||||
| ``` | ||||
|  | ||||
| This happens when certain dependencies of paperless that are responsible | ||||
| for the auto matching algorithm are updated. After updating these, your | ||||
| current training data _might_ not be compatible anymore. This can be | ||||
| ignored in most cases. This warning will disappear automatically when | ||||
| paperless updates the training data. | ||||
|  | ||||
| If you want to get rid of the warning or actually experience issues with | ||||
| automatic matching, delete the file `classification_model.pickle` in the | ||||
| data directory and let paperless recreate it. | ||||
|  | ||||
| ## 504 Server Error: Gateway Timeout when adding Office documents | ||||
|  | ||||
| You may experience these errors when using the optional TIKA | ||||
| integration: | ||||
|  | ||||
| ``` | ||||
| requests.exceptions.HTTPError: 504 Server Error: Gateway Timeout for url: http://gotenberg:3000/forms/libreoffice/convert | ||||
| ``` | ||||
|  | ||||
| Gotenberg is a server that converts Office documents into PDF documents | ||||
| and has a default timeout of 30 seconds. When conversion takes longer, | ||||
| Gotenberg raises this error. | ||||
|  | ||||
| You can increase the timeout by configuring a command flag for Gotenberg | ||||
| (see also [here](https://gotenberg.dev/docs/modules/api#properties)). If | ||||
| using docker-compose, this is achieved by the following configuration | ||||
| change in the `docker-compose.yml` file: | ||||
|  | ||||
| ```yaml | ||||
| gotenberg: | ||||
|   image: gotenberg/gotenberg:7.6 | ||||
|   restart: unless-stopped | ||||
|   command: | ||||
|     - 'gotenberg' | ||||
|     - '--chromium-disable-routes=true' | ||||
|     - '--api-timeout=60' | ||||
| ``` | ||||
|  | ||||
| ## Permission denied errors in the consumption directory | ||||
|  | ||||
| You might encounter errors such as: | ||||
|  | ||||
| ```shell-session | ||||
| The following error occured while consuming document.pdf: [Errno 13] Permission denied: '/usr/src/paperless/src/../consume/document.pdf' | ||||
| ``` | ||||
|  | ||||
| This happens when paperless does not have permission to delete files | ||||
| inside the consumption directory. Ensure that `USERMAP_UID` and | ||||
| `USERMAP_GID` are set to the user id and group id you use on the host | ||||
| operating system, if these are different from `1000`. See | ||||
| `setup-docker_hub`{.interpreted-text role="ref"}. | ||||
|  | ||||
| Also ensure that you are able to read and write to the consumption | ||||
| directory on the host. | ||||
|  | ||||
| ## OSError: \[Errno 19\] No such device when consuming files | ||||
|  | ||||
| If you experience errors such as: | ||||
|  | ||||
| ```shell-session | ||||
| File "/usr/local/lib/python3.7/site-packages/whoosh/codec/base.py", line 570, in open_compound_file | ||||
| return CompoundStorage(dbfile, use_mmap=storage.supports_mmap) | ||||
| File "/usr/local/lib/python3.7/site-packages/whoosh/filedb/compound.py", line 75, in __init__ | ||||
| self._source = mmap.mmap(fileno, 0, access=mmap.ACCESS_READ) | ||||
| OSError: [Errno 19] No such device | ||||
|  | ||||
| During handling of the above exception, another exception occurred: | ||||
|  | ||||
| Traceback (most recent call last): | ||||
| File "/usr/local/lib/python3.7/site-packages/django_q/cluster.py", line 436, in worker | ||||
| res = f(*task["args"], **task["kwargs"]) | ||||
| File "/usr/src/paperless/src/documents/tasks.py", line 73, in consume_file | ||||
| override_tag_ids=override_tag_ids) | ||||
| File "/usr/src/paperless/src/documents/consumer.py", line 271, in try_consume_file | ||||
| raise ConsumerError(e) | ||||
| ``` | ||||
|  | ||||
| Paperless uses a search index to provide better and faster full text | ||||
| searching. This search index is stored inside the `data` folder. The | ||||
| search index uses memory-mapped files (mmap). The above error indicates | ||||
| that paperless was unable to create and open these files. | ||||
|  | ||||
| This happens when you're trying to store the data directory on certain | ||||
| file systems (mostly network shares) that don't support memory-mapped | ||||
| files. | ||||
|  | ||||
| ## Web-UI stuck at "Loading\..." | ||||
|  | ||||
| This might have multiple reasons. | ||||
|  | ||||
| 1.  If you built the docker image yourself or deployed using the bare | ||||
|     metal route, make sure that there are files in | ||||
|     `<paperless-root>/static/frontend/<lang-code>/`. If there are no | ||||
|     files, make sure that you executed `collectstatic` successfully, | ||||
|     either manually or as part of the docker image build. | ||||
|  | ||||
|     If the front end is still missing, make sure that the front end is | ||||
|     compiled (files present in `src/documents/static/frontend`). If it | ||||
|     is not, you need to compile the front end yourself or download the | ||||
|     release archive instead of cloning the repository. | ||||
|  | ||||
| 2.  Check the output of the web server. You might see errors like this: | ||||
|  | ||||
|     ``` | ||||
|     [2021-01-25 10:08:04 +0000] [40] [ERROR] Socket error processing request. | ||||
|     Traceback (most recent call last): | ||||
|     File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/sync.py", line 134, in handle | ||||
|         self.handle_request(listener, req, client, addr) | ||||
|     File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/sync.py", line 190, in handle_request | ||||
|         util.reraise(*sys.exc_info()) | ||||
|     File "/usr/local/lib/python3.7/site-packages/gunicorn/util.py", line 625, in reraise | ||||
|         raise value | ||||
|     File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/sync.py", line 178, in handle_request | ||||
|         resp.write_file(respiter) | ||||
|     File "/usr/local/lib/python3.7/site-packages/gunicorn/http/wsgi.py", line 396, in write_file | ||||
|         if not self.sendfile(respiter): | ||||
|     File "/usr/local/lib/python3.7/site-packages/gunicorn/http/wsgi.py", line 386, in sendfile | ||||
|         sent += os.sendfile(sockno, fileno, offset + sent, count) | ||||
|     OSError: [Errno 22] Invalid argument | ||||
|     ``` | ||||
|  | ||||
|     To fix this issue, add | ||||
|  | ||||
|     ``` | ||||
|     SENDFILE=0 | ||||
|     ``` | ||||
|  | ||||
|     to your [docker-compose.env]{.title-ref} file. | ||||
|  | ||||
| ## Error while reading metadata | ||||
|  | ||||
| You might find messages like these in your log files: | ||||
|  | ||||
| ``` | ||||
| [WARNING] [paperless.parsing.tesseract] Error while reading metadata | ||||
| ``` | ||||
|  | ||||
| This indicates that paperless failed to read PDF metadata from one of | ||||
| your documents. This happens when you open the affected documents in | ||||
| paperless for editing. Paperless will continue to work, and will simply | ||||
| not show the invalid metadata. | ||||
|  | ||||
| ## Consumer fails with a FileNotFoundError | ||||
|  | ||||
| You might find messages like these in your log files: | ||||
|  | ||||
| ``` | ||||
| [ERROR] [paperless.consumer] Error while consuming document SCN_0001.pdf: FileNotFoundError: [Errno 2] No such file or directory: '/tmp/ocrmypdf.io.yhk3zbv0/origin.pdf' | ||||
| Traceback (most recent call last): | ||||
|   File "/app/paperless/src/paperless_tesseract/parsers.py", line 261, in parse | ||||
|     ocrmypdf.ocr(**args) | ||||
|   File "/usr/local/lib/python3.8/dist-packages/ocrmypdf/api.py", line 337, in ocr | ||||
|     return run_pipeline(options=options, plugin_manager=plugin_manager, api=True) | ||||
|   File "/usr/local/lib/python3.8/dist-packages/ocrmypdf/_sync.py", line 385, in run_pipeline | ||||
|     exec_concurrent(context, executor) | ||||
|   File "/usr/local/lib/python3.8/dist-packages/ocrmypdf/_sync.py", line 302, in exec_concurrent | ||||
|     pdf = post_process(pdf, context, executor) | ||||
|   File "/usr/local/lib/python3.8/dist-packages/ocrmypdf/_sync.py", line 235, in post_process | ||||
|     pdf_out = metadata_fixup(pdf_out, context) | ||||
|   File "/usr/local/lib/python3.8/dist-packages/ocrmypdf/_pipeline.py", line 798, in metadata_fixup | ||||
|     with pikepdf.open(context.origin) as original, pikepdf.open(working_file) as pdf: | ||||
|   File "/usr/local/lib/python3.8/dist-packages/pikepdf/_methods.py", line 923, in open | ||||
|     pdf = Pdf._open( | ||||
| FileNotFoundError: [Errno 2] No such file or directory: '/tmp/ocrmypdf.io.yhk3zbv0/origin.pdf' | ||||
| ``` | ||||
|  | ||||
| This probably indicates paperless tried to consume the same file twice. | ||||
| This can happen for a number of reasons, depending on how documents are | ||||
| placed into the consume folder. If paperless is using inotify (the | ||||
| default) to check for documents, try adjusting the | ||||
| [inotify configuration](/configuration#inotify). If polling is enabled, try adjusting the | ||||
| [polling configuration](/configuration#polling). | ||||
|  | ||||
| ## Consumer fails waiting for file to remain unmodified. | ||||
|  | ||||
| You might find messages like these in your log files: | ||||
|  | ||||
| ``` | ||||
| [ERROR] [paperless.management.consumer] Timeout while waiting on file /usr/src/paperless/src/../consume/SCN_0001.pdf to remain unmodified. | ||||
| ``` | ||||
|  | ||||
| This indicates paperless timed out while waiting for the file to be | ||||
| completely written to the consume folder. Adjusting | ||||
| [polling configuration](/configuration#polling) values should resolve the issue. | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     The user will need to manually move the file out of the consume folder | ||||
|     and back in, for the initial failing file to be consumed. | ||||
|  | ||||
| ## Consumer fails reporting "OS reports file as busy still". | ||||
|  | ||||
| You might find messages like these in your log files: | ||||
|  | ||||
| ``` | ||||
| [WARNING] [paperless.management.consumer] Not consuming file /usr/src/paperless/src/../consume/SCN_0001.pdf: OS reports file as busy still | ||||
| ``` | ||||
|  | ||||
| This indicates paperless was unable to open the file, as the OS reported | ||||
| the file as still being in use. To prevent a crash, paperless did not | ||||
| try to consume the file. If paperless is using inotify (the default) to | ||||
| check for documents, try adjusting the | ||||
| [inotify configuration](/configuration#inotify). If polling is enabled, try adjusting the | ||||
| [polling configuration](/configuration#polling). | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     The user will need to manually move the file out of the consume folder | ||||
|     and back in, for the initial failing file to be consumed. | ||||
|  | ||||
| ## Log reports "Creating PaperlessTask failed". | ||||
|  | ||||
| You might find messages like these in your log files: | ||||
|  | ||||
| ``` | ||||
| [ERROR] [paperless.management.consumer] Creating PaperlessTask failed: db locked | ||||
| ``` | ||||
|  | ||||
| You are likely using an sqlite based installation, with an increased | ||||
| number of workers and are running into sqlite's concurrency | ||||
| limitations. Uploading or consuming multiple files at once results in | ||||
| many workers attempting to access the database simultaneously. | ||||
|  | ||||
| Consider changing to the PostgreSQL database if you will be processing | ||||
| many documents at once often. Otherwise, try tweaking the | ||||
| `PAPERLESS_DB_TIMEOUT` setting to allow more time for the database to | ||||
| unlock. This may have minor performance implications. | ||||
|  | ||||
| ## gunicorn fails to start with "is not a valid port number" | ||||
|  | ||||
| You are likely running using Kubernetes, which automatically creates an | ||||
| environment variable named [\${serviceName}\_PORT]{.title-ref}. This is | ||||
| the same environment variable which is used by Paperless to optionally | ||||
| change the port gunicorn listens on. | ||||
|  | ||||
| To fix this, set [PAPERLESS_PORT]{.title-ref} again to your desired | ||||
| port, or the default of 8000. | ||||
| @@ -1,328 +0,0 @@ | ||||
| *************** | ||||
| Troubleshooting | ||||
| *************** | ||||
|  | ||||
| No files are added by the consumer | ||||
| ################################## | ||||
|  | ||||
| Check for the following issues: | ||||
|  | ||||
| *   Ensure that the directory you're putting your documents in is the folder | ||||
|     paperless is watching. With docker, this setting is performed in the | ||||
|     ``docker-compose.yml`` file. Without docker, look at the ``CONSUMPTION_DIR`` | ||||
|     setting. Don't adjust this setting if you're using docker. | ||||
| *   Ensure that redis is up and running. Paperless does its task processing | ||||
|     asynchronously, and for documents to arrive at the task processor, it needs | ||||
|     redis to run. | ||||
| *   Ensure that the task processor is running. Docker does this automatically. | ||||
|     Manually invoke the task processor by executing | ||||
|  | ||||
|     .. code:: shell-session | ||||
|  | ||||
|         $ celery --app paperless worker | ||||
|  | ||||
| *   Look at the output of paperless and inspect it for any errors. | ||||
| *   Go to the admin interface, and check if there are failed tasks. If so, the | ||||
|     tasks will contain an error message. | ||||
|  | ||||
| Consumer warns ``OCR for XX failed`` | ||||
| #################################### | ||||
|  | ||||
| If you find the OCR accuracy to be too low, and/or the document consumer warns | ||||
| that ``OCR for XX failed, but we're going to stick with what we've got since | ||||
| FORGIVING_OCR is enabled``, then you might need to install the | ||||
| `Tesseract language files <http://packages.ubuntu.com/search?keywords=tesseract-ocr>`_ | ||||
| marching your document's languages. | ||||
|  | ||||
| As an example, if you are running Paperless-ngx from any Ubuntu or Debian | ||||
| box, and your documents are written in Spanish you may need to run:: | ||||
|  | ||||
|     apt-get install -y tesseract-ocr-spa | ||||
|  | ||||
| Consumer fails to pickup any new files | ||||
| ###################################### | ||||
|  | ||||
| If you notice that the consumer will only pickup files in the consumption | ||||
| directory at startup, but won't find any other files added later, you will need to | ||||
| enable filesystem polling with the configuration option | ||||
| ``PAPERLESS_CONSUMER_POLLING``, see :ref:`here <configuration-polling>`. | ||||
|  | ||||
| This will disable listening to filesystem changes with inotify and paperless will | ||||
| manually check the consumption directory for changes instead. | ||||
|  | ||||
|  | ||||
| Paperless always redirects to /admin | ||||
| #################################### | ||||
|  | ||||
| You probably had the old paperless installed at some point. Paperless installed | ||||
| a permanent redirect to /admin in your browser, and you need to clear your | ||||
| browsing data / cache to fix that. | ||||
|  | ||||
|  | ||||
| Operation not permitted | ||||
| ####################### | ||||
|  | ||||
| You might see errors such as: | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     chown: changing ownership of '../export': Operation not permitted | ||||
|  | ||||
| The container tries to set file ownership on the listed directories. This is | ||||
| required so that the user running paperless inside docker has write permissions | ||||
| to these folders. This happens when pointing these directories to NFS shares, | ||||
| for example. | ||||
|  | ||||
| Ensure that ``chown`` is possible on these directories. | ||||
|  | ||||
|  | ||||
| Classifier error: No training data available | ||||
| ############################################ | ||||
|  | ||||
| This indicates that the Auto matching algorithm found no documents to learn from. | ||||
| This may have two reasons: | ||||
|  | ||||
| *   You don't use the Auto matching algorithm: The error can be safely ignored in this case. | ||||
| *   You are using the Auto matching algorithm: The classifier explicitly excludes documents | ||||
|     with Inbox tags. Verify that there are documents in your archive without inbox tags. | ||||
|     The algorithm will only learn from documents not in your inbox. | ||||
|  | ||||
|  | ||||
| UserWarning in sklearn on every single document | ||||
| ############################################### | ||||
|  | ||||
| You may encounter warnings like this: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     /usr/local/lib/python3.7/site-packages/sklearn/base.py:315: | ||||
|     UserWarning: Trying to unpickle estimator CountVectorizer from version 0.23.2 when using version 0.24.0. | ||||
|     This might lead to breaking code or invalid results. Use at your own risk. | ||||
|  | ||||
| This happens when certain dependencies of paperless that are responsible for the auto matching algorithm are | ||||
| updated. After updating these, your current training data *might* not be compatible anymore. This can be ignored | ||||
| in most cases. This warning will disappear automatically when paperless updates the training data. | ||||
|  | ||||
| If you want to get rid of the warning or actually experience issues with automatic matching, delete | ||||
| the file ``classification_model.pickle`` in the data directory and let paperless recreate it. | ||||
|  | ||||
|  | ||||
| 504 Server Error: Gateway Timeout when adding Office documents | ||||
| ############################################################## | ||||
|  | ||||
| You may experience these errors when using the optional TIKA integration: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     requests.exceptions.HTTPError: 504 Server Error: Gateway Timeout for url: http://gotenberg:3000/forms/libreoffice/convert | ||||
|  | ||||
| Gotenberg is a server that converts Office documents into PDF documents and has a default timeout of 30 seconds. | ||||
| When conversion takes longer, Gotenberg raises this error. | ||||
|  | ||||
| You can increase the timeout by configuring a command flag for Gotenberg (see also `here <https://gotenberg.dev/docs/modules/api#properties>`__). | ||||
| If using docker-compose, this is achieved by the following configuration change in the ``docker-compose.yml`` file: | ||||
|  | ||||
| .. code:: yaml | ||||
|  | ||||
|     gotenberg: | ||||
|         image: gotenberg/gotenberg:7.6 | ||||
|         restart: unless-stopped | ||||
|         command: | ||||
|             - "gotenberg" | ||||
|             - "--chromium-disable-routes=true" | ||||
|             - "--api-timeout=60" | ||||
|  | ||||
| Permission denied errors in the consumption directory | ||||
| ##################################################### | ||||
|  | ||||
| You might encounter errors such as: | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     The following error occured while consuming document.pdf: [Errno 13] Permission denied: '/usr/src/paperless/src/../consume/document.pdf' | ||||
|  | ||||
| This happens when paperless does not have permission to delete files inside the consumption directory. | ||||
| Ensure that ``USERMAP_UID`` and ``USERMAP_GID`` are set to the user id and group id you use on the host operating system, if these are | ||||
| different from ``1000``. See :ref:`setup-docker_hub`. | ||||
|  | ||||
| Also ensure that you are able to read and write to the consumption directory on the host. | ||||
|  | ||||
|  | ||||
| OSError: [Errno 19] No such device when consuming files | ||||
| ####################################################### | ||||
|  | ||||
| If you experience errors such as: | ||||
|  | ||||
| .. code:: shell-session | ||||
|  | ||||
|     File "/usr/local/lib/python3.7/site-packages/whoosh/codec/base.py", line 570, in open_compound_file | ||||
|     return CompoundStorage(dbfile, use_mmap=storage.supports_mmap) | ||||
|     File "/usr/local/lib/python3.7/site-packages/whoosh/filedb/compound.py", line 75, in __init__ | ||||
|     self._source = mmap.mmap(fileno, 0, access=mmap.ACCESS_READ) | ||||
|     OSError: [Errno 19] No such device | ||||
|  | ||||
|     During handling of the above exception, another exception occurred: | ||||
|  | ||||
|     Traceback (most recent call last): | ||||
|     File "/usr/local/lib/python3.7/site-packages/django_q/cluster.py", line 436, in worker | ||||
|     res = f(*task["args"], **task["kwargs"]) | ||||
|     File "/usr/src/paperless/src/documents/tasks.py", line 73, in consume_file | ||||
|     override_tag_ids=override_tag_ids) | ||||
|     File "/usr/src/paperless/src/documents/consumer.py", line 271, in try_consume_file | ||||
|     raise ConsumerError(e) | ||||
|  | ||||
| Paperless uses a search index to provide better and faster full text searching. This search index is stored inside | ||||
| the ``data`` folder. The search index uses memory-mapped files (mmap). The above error indicates that paperless | ||||
| was unable to create and open these files. | ||||
|  | ||||
| This happens when you're trying to store the data directory on certain file systems (mostly network shares) | ||||
| that don't support memory-mapped files. | ||||
|  | ||||
|  | ||||
| Web-UI stuck at "Loading..." | ||||
| ############################ | ||||
|  | ||||
| This might have multiple reasons. | ||||
|  | ||||
|  | ||||
| 1.  If you built the docker image yourself or deployed using the bare metal route, | ||||
|     make sure that there are files in ``<paperless-root>/static/frontend/<lang-code>/``. | ||||
|     If there are no files, make sure that you executed ``collectstatic`` successfully, either | ||||
|     manually or as part of the docker image build. | ||||
|  | ||||
|     If the front end is still missing, make sure that the front end is compiled (files present in | ||||
|     ``src/documents/static/frontend``). If it is not, you need to compile the front end yourself | ||||
|     or download the release archive instead of cloning the repository. | ||||
|  | ||||
| 2.  Check the output of the web server. You might see errors like this: | ||||
|  | ||||
|  | ||||
|     .. code:: | ||||
|  | ||||
|         [2021-01-25 10:08:04 +0000] [40] [ERROR] Socket error processing request. | ||||
|         Traceback (most recent call last): | ||||
|         File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/sync.py", line 134, in handle | ||||
|             self.handle_request(listener, req, client, addr) | ||||
|         File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/sync.py", line 190, in handle_request | ||||
|             util.reraise(*sys.exc_info()) | ||||
|         File "/usr/local/lib/python3.7/site-packages/gunicorn/util.py", line 625, in reraise | ||||
|             raise value | ||||
|         File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/sync.py", line 178, in handle_request | ||||
|             resp.write_file(respiter) | ||||
|         File "/usr/local/lib/python3.7/site-packages/gunicorn/http/wsgi.py", line 396, in write_file | ||||
|             if not self.sendfile(respiter): | ||||
|         File "/usr/local/lib/python3.7/site-packages/gunicorn/http/wsgi.py", line 386, in sendfile | ||||
|             sent += os.sendfile(sockno, fileno, offset + sent, count) | ||||
|         OSError: [Errno 22] Invalid argument | ||||
|  | ||||
|     To fix this issue, add | ||||
|  | ||||
|     .. code:: | ||||
|  | ||||
|         SENDFILE=0 | ||||
|  | ||||
|     to your `docker-compose.env` file. | ||||
|  | ||||
| Error while reading metadata | ||||
| ############################ | ||||
|  | ||||
| You might find messages like these in your log files: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     [WARNING] [paperless.parsing.tesseract] Error while reading metadata | ||||
|  | ||||
| This indicates that paperless failed to read PDF metadata from one of your documents. This happens when you | ||||
| open the affected documents in paperless for editing. Paperless will continue to work, and will simply not | ||||
| show the invalid metadata. | ||||
|  | ||||
| Consumer fails with a FileNotFoundError | ||||
| ####################################### | ||||
|  | ||||
| You might find messages like these in your log files: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     [ERROR] [paperless.consumer] Error while consuming document SCN_0001.pdf: FileNotFoundError: [Errno 2] No such file or directory: '/tmp/ocrmypdf.io.yhk3zbv0/origin.pdf' | ||||
|     Traceback (most recent call last): | ||||
|       File "/app/paperless/src/paperless_tesseract/parsers.py", line 261, in parse | ||||
|         ocrmypdf.ocr(**args) | ||||
|       File "/usr/local/lib/python3.8/dist-packages/ocrmypdf/api.py", line 337, in ocr | ||||
|         return run_pipeline(options=options, plugin_manager=plugin_manager, api=True) | ||||
|       File "/usr/local/lib/python3.8/dist-packages/ocrmypdf/_sync.py", line 385, in run_pipeline | ||||
|         exec_concurrent(context, executor) | ||||
|       File "/usr/local/lib/python3.8/dist-packages/ocrmypdf/_sync.py", line 302, in exec_concurrent | ||||
|         pdf = post_process(pdf, context, executor) | ||||
|       File "/usr/local/lib/python3.8/dist-packages/ocrmypdf/_sync.py", line 235, in post_process | ||||
|         pdf_out = metadata_fixup(pdf_out, context) | ||||
|       File "/usr/local/lib/python3.8/dist-packages/ocrmypdf/_pipeline.py", line 798, in metadata_fixup | ||||
|         with pikepdf.open(context.origin) as original, pikepdf.open(working_file) as pdf: | ||||
|       File "/usr/local/lib/python3.8/dist-packages/pikepdf/_methods.py", line 923, in open | ||||
|         pdf = Pdf._open( | ||||
|     FileNotFoundError: [Errno 2] No such file or directory: '/tmp/ocrmypdf.io.yhk3zbv0/origin.pdf' | ||||
|  | ||||
| This probably indicates paperless tried to consume the same file twice.  This can happen for a number of reasons, | ||||
| depending on how documents are placed into the consume folder.  If paperless is using inotify (the default) to | ||||
| check for documents, try adjusting the :ref:`inotify configuration <configuration-inotify>`.  If polling is enabled, | ||||
| try adjusting the :ref:`polling configuration <configuration-polling>`. | ||||
|  | ||||
| Consumer fails waiting for file to remain unmodified. | ||||
| ##################################################### | ||||
|  | ||||
| You might find messages like these in your log files: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     [ERROR] [paperless.management.consumer] Timeout while waiting on file /usr/src/paperless/src/../consume/SCN_0001.pdf to remain unmodified. | ||||
|  | ||||
| This indicates paperless timed out while waiting for the file to be completely written to the consume folder. | ||||
| Adjusting :ref:`polling configuration <configuration-polling>` values should resolve the issue. | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     The user will need to manually move the file out of the consume folder and | ||||
|     back in, for the initial failing file to be consumed. | ||||
|  | ||||
| Consumer fails reporting "OS reports file as busy still". | ||||
| ######################################################### | ||||
|  | ||||
| You might find messages like these in your log files: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     [WARNING] [paperless.management.consumer] Not consuming file /usr/src/paperless/src/../consume/SCN_0001.pdf: OS reports file as busy still | ||||
|  | ||||
| This indicates paperless was unable to open the file, as the OS reported the file as still being in use.  To prevent a | ||||
| crash, paperless did not try to consume the file.  If paperless is using inotify (the default) to | ||||
| check for documents, try adjusting the :ref:`inotify configuration <configuration-inotify>`.  If polling is enabled, | ||||
| try adjusting the :ref:`polling configuration <configuration-polling>`. | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     The user will need to manually move the file out of the consume folder and | ||||
|     back in, for the initial failing file to be consumed. | ||||
|  | ||||
| Log reports "Creating PaperlessTask failed". | ||||
| ######################################################### | ||||
|  | ||||
| You might find messages like these in your log files: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|     [ERROR] [paperless.management.consumer] Creating PaperlessTask failed: db locked | ||||
|  | ||||
| You are likely using an sqlite based installation, with an increased number of workers and are running into sqlite's concurrency limitations. | ||||
| Uploading or consuming multiple files at once results in many workers attempting to access the database simultaneously. | ||||
|  | ||||
| Consider changing to the PostgreSQL database if you will be processing many documents at once often.  Otherwise, | ||||
| try tweaking the ``PAPERLESS_DB_TIMEOUT`` setting to allow more time for the database to unlock.  This may have | ||||
| minor performance implications. | ||||
|  | ||||
|  | ||||
| gunicorn fails to start with "is not a valid port number" | ||||
| ######################################################### | ||||
|  | ||||
| You are likely running using Kubernetes, which automatically creates an environment variable named `${serviceName}_PORT`. | ||||
| This is the same environment variable which is used by Paperless to optionally change the port gunicorn listens on. | ||||
|  | ||||
| To fix this, set `PAPERLESS_PORT` again to your desired port, or the default of 8000. | ||||
							
								
								
									
										483
									
								
								docs/usage.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,483 @@ | ||||
| # Usage Overview | ||||
|  | ||||
| Paperless is an application that manages your personal documents. With | ||||
| the help of a document scanner (see [the scanners wiki](https://github.com/paperless-ngx/paperless-ngx/wiki/Scanner-&-Software-Recommendations)), paperless transforms your wieldy physical document binders | ||||
| into a searchable archive and provides many utilities for finding and | ||||
| managing your documents. | ||||
|  | ||||
| ## Terms and definitions | ||||
|  | ||||
| Paperless essentially consists of two different parts for managing your | ||||
| documents: | ||||
|  | ||||
| - The _consumer_ watches a specified folder and adds all documents in | ||||
|   that folder to paperless. | ||||
| - The _web server_ provides a UI that you use to manage and search for | ||||
|   your scanned documents. | ||||
|  | ||||
| Each document has a couple of fields that you can assign to them: | ||||
|  | ||||
| - A _Document_ is a piece of paper that sometimes contains valuable | ||||
|   information. | ||||
| - The _correspondent_ of a document is the person, institution or | ||||
|   company that a document either originates from, or is sent to. | ||||
| - A _tag_ is a label that you can assign to documents. Think of labels | ||||
|   as more powerful folders: Multiple documents can be grouped together | ||||
|   with a single tag, however, a single document can also have multiple | ||||
|   tags. This is not possible with folders. The reason folders are not | ||||
|   implemented in paperless is simply that tags are much more versatile | ||||
|   than folders. | ||||
| - A _document type_ is used to demarcate the type of a document such | ||||
|   as letter, bank statement, invoice, contract, etc. It is used to | ||||
|   identify what a document is about. | ||||
| - The _date added_ of a document is the date the document was scanned | ||||
|   into paperless. You cannot and should not change this date. | ||||
| - The _date created_ of a document is the date the document was | ||||
|   initially issued. This can be the date you bought a product, the | ||||
|   date you signed a contract, or the date a letter was sent to you. | ||||
| - The _archive serial number_ (short: ASN) of a document is the | ||||
|   identifier of the document in your physical document binders. See | ||||
|   `usage-recommended_workflow`{.interpreted-text role="ref"} below. | ||||
| - The _content_ of a document is the text that was OCR'ed from the | ||||
|   document. This text is fed into the search engine and is used for | ||||
|   matching tags, correspondents and document types. | ||||
|  | ||||
| ## Adding documents to paperless | ||||
|  | ||||
| Once you've got Paperless setup, you need to start feeding documents | ||||
| into it. When adding documents to paperless, it will perform the | ||||
| following operations on your documents: | ||||
|  | ||||
| 1.  OCR the document, if it has no text. Digital documents usually have | ||||
|     text, and this step will be skipped for those documents. | ||||
| 2.  Paperless will create an archivable PDF/A document from your | ||||
|     document. If this document is coming from your scanner, it will have | ||||
|     embedded selectable text. | ||||
| 3.  Paperless performs automatic matching of tags, correspondents and | ||||
|     types on the document before storing it in the database. | ||||
|  | ||||
| !!! tip | ||||
|  | ||||
|     This process can be configured to fit your needs. If you don't want | ||||
|     paperless to create archived versions for digital documents, you can | ||||
|     configure that by configuring `PAPERLESS_OCR_MODE=skip_noarchive`. | ||||
|     Please read the | ||||
|     [relevant section in the documentation](/configuration#ocr). | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     No matter which options you choose, Paperless will always store the | ||||
|     original document that it found in the consumption directory or in the | ||||
|     mail and will never overwrite that document. Archived versions are | ||||
|     stored alongside the original versions. | ||||
|  | ||||
| ### The consumption directory | ||||
|  | ||||
| The primary method of getting documents into your database is by putting | ||||
| them in the consumption directory. The consumer runs in an infinite | ||||
| loop, looking for new additions to this directory. When it finds them, | ||||
| the consumer goes about the process of parsing them with the OCR, | ||||
| indexing what it finds, and storing it in the media directory. | ||||
|  | ||||
| Getting stuff into this directory is up to you. If you're running | ||||
| Paperless on your local computer, you might just want to drag and drop | ||||
| files there, but if you're running this on a server and want your | ||||
| scanner to automatically push files to this directory, you'll need to | ||||
| setup some sort of service to accept the files from the scanner. | ||||
| Typically, you're looking at an FTP server like | ||||
| [Proftpd](http://www.proftpd.org/) or a Windows folder share with | ||||
| [Samba](http://www.samba.org/). | ||||
|  | ||||
| ### Web UI Upload | ||||
|  | ||||
| The dashboard has a file drop field to upload documents to paperless. | ||||
| Simply drag a file onto this field or select a file with the file | ||||
| dialog. Multiple files are supported. | ||||
|  | ||||
| You can also upload documents on any other page of the web UI by | ||||
| dragging-and-dropping files into your browser window. | ||||
|  | ||||
| ### Mobile upload {#usage-mobile_upload} | ||||
|  | ||||
| The mobile app over at <https://github.com/qcasey/paperless_share> | ||||
| allows Android users to share any documents with paperless. This can be | ||||
| combined with any of the mobile scanning apps out there, such as Office | ||||
| Lens. | ||||
|  | ||||
| Furthermore, there is the [Paperless | ||||
| App](https://github.com/bauerj/paperless_app) as well, which not only | ||||
| has document upload, but also document browsing and download features. | ||||
|  | ||||
| ### IMAP (Email) {#usage-email} | ||||
|  | ||||
| You can tell paperless-ngx to consume documents from your email | ||||
| accounts. This is a very flexible and powerful feature, if you regularly | ||||
| received documents via mail that you need to archive. The mail consumer | ||||
| can be configured via the frontend settings (/settings/mail) in the following | ||||
| manner: | ||||
|  | ||||
| 1.  Define e-mail accounts. | ||||
| 2.  Define mail rules for your account. | ||||
|  | ||||
| These rules perform the following: | ||||
|  | ||||
| 1.  Connect to the mail server. | ||||
| 2.  Fetch all matching mails (as defined by folder, maximum age and the | ||||
|     filters) | ||||
| 3.  Check if there are any consumable attachments. | ||||
| 4.  If so, instruct paperless to consume the attachments and optionally | ||||
|     use the metadata provided in the rule for the new document. | ||||
| 5.  If documents were consumed from a mail, the rule action is performed | ||||
|     on that mail. | ||||
|  | ||||
| Paperless will completely ignore mails that do not match your filters. | ||||
| It will also only perform the action on mails that it has consumed | ||||
| documents from. | ||||
|  | ||||
| The actions all ensure that the same mail is not consumed twice by | ||||
| different means. These are as follows: | ||||
|  | ||||
| - **Delete:** Immediately deletes mail that paperless has consumed | ||||
|   documents from. Use with caution. | ||||
| - **Mark as read:** Mark consumed mail as read. Paperless will not | ||||
|   consume documents from already read mails. If you read a mail before | ||||
|   paperless sees it, it will be ignored. | ||||
| - **Flag:** Sets the 'important' flag on mails with consumed | ||||
|   documents. Paperless will not consume flagged mails. | ||||
| - **Move to folder:** Moves consumed mails out of the way so that | ||||
|   paperless wont consume them again. | ||||
| - **Add custom Tag:** Adds a custom tag to mails with consumed | ||||
|   documents (the IMAP standard calls these "keywords"). Paperless | ||||
|   will not consume mails already tagged. Not all mail servers support | ||||
|   this feature! | ||||
|  | ||||
| !!! warning | ||||
|  | ||||
|     The mail consumer will perform these actions on all mails it has | ||||
|     consumed documents from. Keep in mind that the actual consumption | ||||
|     process may fail for some reason, leaving you with missing documents in | ||||
|     paperless. | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     With the correct set of rules, you can completely automate your email | ||||
|     documents. Create rules for every correspondent you receive digital | ||||
|     documents from and paperless will read them automatically. The default | ||||
|     action "mark as read" is pretty tame and will not cause any damage or | ||||
|     data loss whatsoever. | ||||
|  | ||||
|     You can also setup a special folder in your mail account for paperless | ||||
|     and use your favorite mail client to move to be consumed mails into that | ||||
|     folder automatically or manually and tell paperless to move them to yet | ||||
|     another folder after consumption. It's up to you. | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     When defining a mail rule with a folder, you may need to try different | ||||
|     characters to define how the sub-folders are separated. Common values | ||||
|     include ".", "/" or "\|", but this varies by the mail server. | ||||
|     Check the documentation for your mail server. In the event of an error | ||||
|     fetching mail from a certain folder, check the Paperless logs. When a | ||||
|     folder is not located, Paperless will attempt to list all folders found | ||||
|     in the account to the Paperless logs. | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     Paperless will process the rules in the order defined in the admin page. | ||||
|  | ||||
|     You can define catch-all rules and have them executed last to consume | ||||
|     any documents not matched by previous rules. Such a rule may assign an | ||||
|     "Unknown mail document" tag to consumed documents so you can inspect | ||||
|     them further. | ||||
|  | ||||
| Paperless is set up to check your mails every 10 minutes. This can be | ||||
| configured on the 'Scheduled tasks' page in the admin. | ||||
|  | ||||
| ### REST API | ||||
|  | ||||
| You can also submit a document using the REST API, see | ||||
| `api-file_uploads`{.interpreted-text role="ref"} for details. | ||||
|  | ||||
| ## Best practices {#basic-searching} | ||||
|  | ||||
| Paperless offers a couple tools that help you organize your document | ||||
| collection. However, it is up to you to use them in a way that helps you | ||||
| organize documents and find specific documents when you need them. This | ||||
| section offers a couple ideas for managing your collection. | ||||
|  | ||||
| Document types allow you to classify documents according to what they | ||||
| are. You can define types such as "Receipt", "Invoice", or | ||||
| "Contract". If you used to collect all your receipts in a single | ||||
| binder, you can recreate that system in paperless by defining a document | ||||
| type, assigning documents to that type and then filtering by that type | ||||
| to only see all receipts. | ||||
|  | ||||
| Not all documents need document types. Sometimes its hard to determine | ||||
| what the type of a document is or it is hard to justify creating a | ||||
| document type that you only need once or twice. This is okay. As long as | ||||
| the types you define help you organize your collection in the way you | ||||
| want, paperless is doing its job. | ||||
|  | ||||
| Tags can be used in many different ways. Think of tags are more | ||||
| versatile folders or binders. If you have a binder for documents related | ||||
| to university / your car or health care, you can create these binders in | ||||
| paperless by creating tags and assigning them to relevant documents. | ||||
| Just as with documents, you can filter the document list by tags and | ||||
| only see documents of a certain topic. | ||||
|  | ||||
| With physical documents, you'll often need to decide which folder the | ||||
| document belongs to. The advantage of tags over folders and binders is | ||||
| that a single document can have multiple tags. A physical document | ||||
| cannot magically appear in two different folders, but with tags, this is | ||||
| entirely possible. | ||||
|  | ||||
| !!! tip | ||||
|  | ||||
|     This can be used in many different ways. One example: Imagine you're | ||||
|     working on a particular task, such as signing up for university. Usually | ||||
|     you'll need to collect a bunch of different documents that are already | ||||
|     sorted into various folders. With the tag system of paperless, you can | ||||
|     create a new group of documents that are relevant to this task without | ||||
|     destroying the already existing organization. When you're done with the | ||||
|     task, you could delete the tag again, which would be equal to sorting | ||||
|     documents back into the folder they belong into. Or keep the tag, up to | ||||
|     you. | ||||
|  | ||||
| All of the logic above applies to correspondents as well. Attach them to | ||||
| documents if you feel that they help you organize your collection. | ||||
|  | ||||
| When you've started organizing your documents, create a couple saved | ||||
| views for document collections you regularly access. This is equal to | ||||
| having labeled physical binders on your desk, except that these saved | ||||
| views are dynamic and simply update themselves as you add documents to | ||||
| the system. | ||||
|  | ||||
| Here are a couple examples of tags and types that you could use in your | ||||
| collection. | ||||
|  | ||||
| - An `inbox` tag for newly added documents that you haven't manually | ||||
|   edited yet. | ||||
| - A tag `car` for everything car related (repairs, registration, | ||||
|   insurance, etc) | ||||
| - A tag `todo` for documents that you still need to do something with, | ||||
|   such as reply, or perform some task online. | ||||
| - A tag `bank account x` for all bank statement related to that | ||||
|   account. | ||||
| - A tag `mail` for anything that you added to paperless via its mail | ||||
|   processing capabilities. | ||||
| - A tag `missing_metadata` when you still need to add some metadata to | ||||
|   a document, but can't or don't want to do this right now. | ||||
|  | ||||
| ## Searching {#basic-usage_searching} | ||||
|  | ||||
| Paperless offers an extensive searching mechanism that is designed to | ||||
| allow you to quickly find a document you're looking for (for example, | ||||
| that thing that just broke and you bought a couple months ago, that | ||||
| contract you signed 8 years ago). | ||||
|  | ||||
| When you search paperless for a document, it tries to match this query | ||||
| against your documents. Paperless will look for matching documents by | ||||
| inspecting their content, title, correspondent, type and tags. Paperless | ||||
| returns a scored list of results, so that documents matching your query | ||||
| better will appear further up in the search results. | ||||
|  | ||||
| By default, paperless returns only documents which contain all words | ||||
| typed in the search bar. However, paperless also offers advanced search | ||||
| syntax if you want to drill down the results further. | ||||
|  | ||||
| Matching documents with logical expressions: | ||||
|  | ||||
| ``` | ||||
| shopname AND (product1 OR product2) | ||||
| ``` | ||||
|  | ||||
| Matching specific tags, correspondents or types: | ||||
|  | ||||
| ``` | ||||
| type:invoice tag:unpaid | ||||
| correspondent:university certificate | ||||
| ``` | ||||
|  | ||||
| Matching dates: | ||||
|  | ||||
| ``` | ||||
| created:[2005 to 2009] | ||||
| added:yesterday | ||||
| modified:today | ||||
| ``` | ||||
|  | ||||
| Matching inexact words: | ||||
|  | ||||
| ``` | ||||
| produ*name | ||||
| ``` | ||||
|  | ||||
| !!! note | ||||
|  | ||||
|     Inexact terms are hard for search indexes. These queries might take a | ||||
|     while to execute. That's why paperless offers auto complete and query | ||||
|     correction. | ||||
|  | ||||
| All of these constructs can be combined as you see fit. If you want to | ||||
| learn more about the query language used by paperless, paperless uses | ||||
| Whoosh's default query language. Head over to [Whoosh query | ||||
| language](https://whoosh.readthedocs.io/en/latest/querylang.html). For | ||||
| details on what date parsing utilities are available, see [Date | ||||
| parsing](https://whoosh.readthedocs.io/en/latest/dates.html#parsing-date-queries). | ||||
|  | ||||
| ## The recommended workflow {#usage-recommended_workflow} | ||||
|  | ||||
| Once you have familiarized yourself with paperless and are ready to use | ||||
| it for all your documents, the recommended workflow for managing your | ||||
| documents is as follows. This workflow also takes into account that some | ||||
| documents have to be kept in physical form, but still ensures that you | ||||
| get all the advantages for these documents as well. | ||||
|  | ||||
| The following diagram shows how easy it is to manage your documents. | ||||
|  | ||||
| {width=400} | ||||
|  | ||||
| ### Preparations in paperless | ||||
|  | ||||
| - Create an inbox tag that gets assigned to all new documents. | ||||
| - Create a TODO tag. | ||||
|  | ||||
| ### Processing of the physical documents | ||||
|  | ||||
| Keep a physical inbox. Whenever you receive a document that you need to | ||||
| archive, put it into your inbox. Regularly, do the following for all | ||||
| documents in your inbox: | ||||
|  | ||||
| 1.  For each document, decide if you need to keep the document in | ||||
|     physical form. This applies to certain important documents, such as | ||||
|     contracts and certificates. | ||||
| 2.  If you need to keep the document, write a running number on the | ||||
|     document before scanning, starting at one and counting upwards. This | ||||
|     is the archive serial number, or ASN in short. | ||||
| 3.  Scan the document. | ||||
| 4.  If the document has an ASN assigned, store it in a _single_ binder, | ||||
|     sorted by ASN. Don't order this binder in any other way. | ||||
| 5.  If the document has no ASN, throw it away. Yay! | ||||
|  | ||||
| Over time, you will notice that your physical binder will fill up. If it | ||||
| is full, label the binder with the range of ASNs in this binder (i.e., | ||||
| "Documents 1 to 343"), store the binder in your cellar or elsewhere, | ||||
| and start a new binder. | ||||
|  | ||||
| The idea behind this process is that you will never have to use the | ||||
| physical binders to find a document. If you need a specific physical | ||||
| document, you may find this document by: | ||||
|  | ||||
| 1.  Searching in paperless for the document. | ||||
| 2.  Identify the ASN of the document, since it appears on the scan. | ||||
| 3.  Grab the relevant document binder and get the document. This is easy | ||||
|     since they are sorted by ASN. | ||||
|  | ||||
| ### Processing of documents in paperless | ||||
|  | ||||
| Once you have scanned in a document, proceed in paperless as follows. | ||||
|  | ||||
| 1.  If the document has an ASN, assign the ASN to the document. | ||||
| 2.  Assign a correspondent to the document (i.e., your employer, bank, | ||||
|     etc) This isn't strictly necessary but helps in finding a document | ||||
|     when you need it. | ||||
| 3.  Assign a document type (i.e., invoice, bank statement, etc) to the | ||||
|     document This isn't strictly necessary but helps in finding a | ||||
|     document when you need it. | ||||
| 4.  Assign a proper title to the document (the name of an item you | ||||
|     bought, the subject of the letter, etc) | ||||
| 5.  Check that the date of the document is correct. Paperless tries to | ||||
|     read the date from the content of the document, but this fails | ||||
|     sometimes if the OCR is bad or multiple dates appear on the | ||||
|     document. | ||||
| 6.  Remove inbox tags from the documents. | ||||
|  | ||||
| !!! tip | ||||
|  | ||||
|     You can setup manual matching rules for your correspondents and tags and | ||||
|     paperless will assign them automatically. After consuming a couple | ||||
|     documents, you can even ask paperless to *learn* when to assign tags and | ||||
|     correspondents by itself. For details on this feature, see | ||||
|     `advanced-matching`{.interpreted-text role="ref"}. | ||||
|  | ||||
| ### Task management | ||||
|  | ||||
| Some documents require attention and require you to act on the document. | ||||
| You may take two different approaches to handle these documents based on | ||||
| how regularly you intend to scan documents and use paperless. | ||||
|  | ||||
| - If you scan and process your documents in paperless regularly, | ||||
|   assign a TODO tag to all scanned documents that you need to process. | ||||
|   Create a saved view on the dashboard that shows all documents with | ||||
|   this tag. | ||||
| - If you do not scan documents regularly and use paperless solely for | ||||
|   archiving, create a physical todo box next to your physical inbox | ||||
|   and put documents you need to process in the TODO box. When you | ||||
|   performed the task associated with the document, move it to the | ||||
|   inbox. | ||||
|  | ||||
| ## Architectue | ||||
|  | ||||
| Paperless-ngx consists of the following components: | ||||
|  | ||||
| - **The webserver:** This serves the administration pages, the API, | ||||
|   and the new frontend. This is the main tool you'll be using to interact | ||||
|   with paperless. You may start the webserver directly with | ||||
|  | ||||
|   ```shell-session | ||||
|   $ cd /path/to/paperless/src/ | ||||
|   $ gunicorn -c ../gunicorn.conf.py paperless.wsgi | ||||
|   ``` | ||||
|  | ||||
|   or by any other means such as Apache `mod_wsgi`. | ||||
|  | ||||
| - **The consumer:** This is what watches your consumption folder for | ||||
|   documents. However, the consumer itself does not really consume your | ||||
|   documents. Now it notifies a task processor that a new file is ready | ||||
|   for consumption. I suppose it should be named differently. This was | ||||
|   also used to check your emails, but that's now done elsewhere as | ||||
|   well. | ||||
|  | ||||
|   Start the consumer with the management command `document_consumer`: | ||||
|  | ||||
|   ```shell-session | ||||
|   $ cd /path/to/paperless/src/ | ||||
|   $ python3 manage.py document_consumer | ||||
|   ``` | ||||
|  | ||||
| - **The task processor:** Paperless relies on [Celery - Distributed | ||||
|   Task Queue](https://docs.celeryq.dev/en/stable/index.html) for doing | ||||
|   most of the heavy lifting. This is a task queue that accepts tasks | ||||
|   from multiple sources and processes these in parallel. It also comes | ||||
|   with a scheduler that executes certain commands periodically. | ||||
|  | ||||
|   This task processor is responsible for: | ||||
|  | ||||
|   - Consuming documents. When the consumer finds new documents, it | ||||
|     notifies the task processor to start a consumption task. | ||||
|   - The task processor also performs the consumption of any | ||||
|     documents you upload through the web interface. | ||||
|   - Consuming emails. It periodically checks your configured | ||||
|     accounts for new emails and notifies the task processor to | ||||
|     consume the attachment of an email. | ||||
|   - Maintaining the search index and the automatic matching | ||||
|     algorithm. These are things that paperless needs to do from time | ||||
|     to time in order to operate properly. | ||||
|  | ||||
|   This allows paperless to process multiple documents from your | ||||
|   consumption folder in parallel! On a modern multi core system, this | ||||
|   makes the consumption process with full OCR blazingly fast. | ||||
|  | ||||
|   The task processor comes with a built-in admin interface that you | ||||
|   can use to check whenever any of the tasks fail and inspect the | ||||
|   errors (i.e., wrong email credentials, errors during consuming a | ||||
|   specific file, etc). | ||||
|  | ||||
| - A [redis](https://redis.io/) message broker: This is a really | ||||
|   lightweight service that is responsible for getting the tasks from | ||||
|   the webserver and the consumer to the task scheduler. These run in a | ||||
|   different process (maybe even on different machines!), and | ||||
|   therefore, this is necessary. | ||||
|  | ||||
| - Optional: A database server. Paperless supports PostgreSQL, MariaDB | ||||
|   and SQLite for storing its data. | ||||
| @@ -1,420 +0,0 @@ | ||||
| ************** | ||||
| Usage Overview | ||||
| ************** | ||||
|  | ||||
| Paperless is an application that manages your personal documents. With | ||||
| the help of a document scanner (see :ref:`scanners`), paperless transforms | ||||
| your wieldy physical document binders into a searchable archive and | ||||
| provides many utilities for finding and managing your documents. | ||||
|  | ||||
|  | ||||
| Terms and definitions | ||||
| ##################### | ||||
|  | ||||
| Paperless essentially consists of two different parts for managing your | ||||
| documents: | ||||
|  | ||||
| * The *consumer* watches a specified folder and adds all documents in that | ||||
|   folder to paperless. | ||||
| * The *web server* provides a UI that you use to manage and search for your | ||||
|   scanned documents. | ||||
|  | ||||
| Each document has a couple of fields that you can assign to them: | ||||
|  | ||||
| * A *Document* is a piece of paper that sometimes contains valuable | ||||
|   information. | ||||
| * The *correspondent* of a document is the person, institution or company that | ||||
|   a document either originates from, or is sent to. | ||||
| * A *tag* is a label that you can assign to documents. Think of labels as more | ||||
|   powerful folders: Multiple documents can be grouped together with a single | ||||
|   tag, however, a single document can also have multiple tags. This is not | ||||
|   possible with folders. The reason folders are not implemented in paperless | ||||
|   is simply that tags are much more versatile than folders. | ||||
| * A *document type* is used to demarcate the type of a document such as letter, | ||||
|   bank statement, invoice, contract, etc. It is used to identify what a document | ||||
|   is about. | ||||
| * The *date added* of a document is the date the document was scanned into | ||||
|   paperless. You cannot and should not change this date. | ||||
| * The *date created* of a document is the date the document was initially issued. | ||||
|   This can be the date you bought a product, the date you signed a contract, or | ||||
|   the date a letter was sent to you. | ||||
| * The *archive serial number* (short: ASN) of a document is the identifier of | ||||
|   the document in your physical document binders. See | ||||
|   :ref:`usage-recommended_workflow` below. | ||||
| * The *content* of a document is the text that was OCR'ed from the document. | ||||
|   This text is fed into the search engine and is used for matching tags, | ||||
|   correspondents and document types. | ||||
|  | ||||
|  | ||||
| Frontend overview | ||||
| ################# | ||||
|  | ||||
| .. warning:: | ||||
|  | ||||
|     TBD. Add some fancy screenshots! | ||||
|  | ||||
| Adding documents to paperless | ||||
| ############################# | ||||
|  | ||||
| Once you've got Paperless setup, you need to start feeding documents into it. | ||||
| When adding documents to paperless, it will perform the following operations on | ||||
| your documents: | ||||
|  | ||||
| 1.  OCR the document, if it has no text. Digital documents usually have text, | ||||
|     and this step will be skipped for those documents. | ||||
| 2.  Paperless will create an archivable PDF/A document from your document. | ||||
|     If this document is coming from your scanner, it will have embedded selectable text. | ||||
| 3.  Paperless performs automatic matching of tags, correspondents and types on the | ||||
|     document before storing it in the database. | ||||
|  | ||||
| .. hint:: | ||||
|  | ||||
|     This process can be configured to fit your needs. If you don't want paperless | ||||
|     to create archived versions for digital documents, you can configure that by | ||||
|     configuring ``PAPERLESS_OCR_MODE=skip_noarchive``. Please read the | ||||
|     :ref:`relevant section in the documentation <configuration-ocr>`. | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     No matter which options you choose, Paperless will always store the original | ||||
|     document that it found in the consumption directory or in the mail and | ||||
|     will never overwrite that document. Archived versions are stored alongside the | ||||
|     original versions. | ||||
|  | ||||
|  | ||||
| The consumption directory | ||||
| ========================= | ||||
|  | ||||
| The primary method of getting documents into your database is by putting them in | ||||
| the consumption directory.  The consumer runs in an infinite loop, looking for new | ||||
| additions to this directory. When it finds them, the consumer goes about the process | ||||
| of parsing them with the OCR, indexing what it finds, and storing it in the media directory. | ||||
|  | ||||
| Getting stuff into this directory is up to you.  If you're running Paperless | ||||
| on your local computer, you might just want to drag and drop files there, but if | ||||
| you're running this on a server and want your scanner to automatically push | ||||
| files to this directory, you'll need to setup some sort of service to accept the | ||||
| files from the scanner.  Typically, you're looking at an FTP server like | ||||
| `Proftpd`_ or a Windows folder share with `Samba`_. | ||||
|  | ||||
| .. _Proftpd: http://www.proftpd.org/ | ||||
| .. _Samba: http://www.samba.org/ | ||||
|  | ||||
| .. TODO: hyperref to configuration of the location of this magic folder. | ||||
|  | ||||
| Web UI Upload | ||||
| ============= | ||||
|  | ||||
| The dashboard has a file drop field to upload documents to paperless. Simply drag a file | ||||
| onto this field or select a file with the file dialog. Multiple files are supported. | ||||
|  | ||||
| You can also upload documents on any other page of the web UI by dragging-and-dropping | ||||
| files into your browser window. | ||||
|  | ||||
| .. _usage-mobile_upload: | ||||
|  | ||||
| Mobile upload | ||||
| ============= | ||||
|  | ||||
| The mobile app over at `<https://github.com/qcasey/paperless_share>`_ allows Android users | ||||
| to share any documents with paperless. This can be combined with any of the mobile | ||||
| scanning apps out there, such as Office Lens. | ||||
|  | ||||
| Furthermore, there is the  `Paperless App <https://github.com/bauerj/paperless_app>`_ as well, | ||||
| which not only has document upload, but also document browsing and download features. | ||||
|  | ||||
| .. _usage-email: | ||||
|  | ||||
| IMAP (Email) | ||||
| ============ | ||||
|  | ||||
| You can tell paperless-ngx to consume documents from your email accounts. | ||||
| This is a very flexible and powerful feature, if you regularly received documents | ||||
| via mail that you need to archive. The mail consumer can be configured by using the | ||||
| admin interface in the following manner: | ||||
|  | ||||
| 1.  Define e-mail accounts. | ||||
| 2.  Define mail rules for your account. | ||||
|  | ||||
| These rules perform the following: | ||||
|  | ||||
| 1.  Connect to the mail server. | ||||
| 2.  Fetch all matching mails (as defined by folder, maximum age and the filters) | ||||
| 3.  Check if there are any consumable attachments. | ||||
| 4.  If so, instruct paperless to consume the attachments and optionally | ||||
|     use the metadata provided in the rule for the new document. | ||||
| 5.  If documents were consumed from a mail, the rule action is performed | ||||
|     on that mail. | ||||
|  | ||||
| Paperless will completely ignore mails that do not match your filters. It will also | ||||
| only perform the action on mails that it has consumed documents from. | ||||
|  | ||||
| The actions all ensure that the same mail is not consumed twice by different means. | ||||
| These are as follows: | ||||
|  | ||||
| *   **Delete:** Immediately deletes mail that paperless has consumed documents from. | ||||
|     Use with caution. | ||||
| *   **Mark as read:** Mark consumed mail as read. Paperless will not consume documents | ||||
|     from already read mails. If you read a mail before paperless sees it, it will be | ||||
|     ignored. | ||||
| *   **Flag:** Sets the 'important' flag on mails with consumed documents. Paperless | ||||
|     will not consume flagged mails. | ||||
| *   **Move to folder:** Moves consumed mails out of the way so that paperless wont | ||||
|     consume them again. | ||||
| *   **Add custom Tag:** Adds a custom tag to mails with consumed documents (the IMAP | ||||
|     standard calls these "keywords"). Paperless will not consume mails already tagged. | ||||
|     Not all mail servers support this feature! | ||||
|  | ||||
| .. caution:: | ||||
|  | ||||
|     The mail consumer will perform these actions on all mails it has consumed | ||||
|     documents from. Keep in mind that the actual consumption process may fail | ||||
|     for some reason, leaving you with missing documents in paperless. | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     With the correct set of rules, you can completely automate your email documents. | ||||
|     Create rules for every correspondent you receive digital documents from and | ||||
|     paperless will read them automatically. The default action "mark as read" is | ||||
|     pretty tame and will not cause any damage or data loss whatsoever. | ||||
|  | ||||
|     You can also setup a special folder in your mail account for paperless and use | ||||
|     your favorite mail client to move to be consumed mails into that folder | ||||
|     automatically or manually and tell paperless to move them to yet another folder | ||||
|     after consumption. It's up to you. | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     When defining a mail rule with a folder, you may need to try different characters to | ||||
|     define how the sub-folders are separated.  Common values include ".", "/" or "|", but | ||||
|     this varies by the mail server.  Check the documentation for your mail server.  In the | ||||
|     event of an error fetching mail from a certain folder, check the Paperless logs.  When | ||||
|     a folder is not located, Paperless will attempt to list all folders found in the account | ||||
|     to the Paperless logs. | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     Paperless will process the rules in the order defined in the admin page. | ||||
|  | ||||
|     You can define catch-all rules and have them executed last to consume | ||||
|     any documents not matched by previous rules. Such a rule may assign an "Unknown | ||||
|     mail document" tag to consumed documents so you can inspect them further. | ||||
|  | ||||
| Paperless is set up to check your mails every 10 minutes. This can be configured on the | ||||
| 'Scheduled tasks' page in the admin. | ||||
|  | ||||
|  | ||||
| REST API | ||||
| ======== | ||||
|  | ||||
| You can also submit a document using the REST API, see :ref:`api-file_uploads` for details. | ||||
|  | ||||
| .. _basic-searching: | ||||
|  | ||||
|  | ||||
| Best practices | ||||
| ############## | ||||
|  | ||||
| Paperless offers a couple tools that help you organize your document collection. However, | ||||
| it is up to you to use them in a way that helps you organize documents and find specific | ||||
| documents when you need them. This section offers a couple ideas for managing your collection. | ||||
|  | ||||
| Document types allow you to classify documents according to what they are. You can define | ||||
| types such as "Receipt", "Invoice", or "Contract". If you used to collect all your receipts | ||||
| in a single binder, you can recreate that system in paperless by defining a document type, | ||||
| assigning documents to that type and then filtering by that type to only see all receipts. | ||||
|  | ||||
| Not all documents need document types. Sometimes its hard to determine what the type of a | ||||
| document is or it is hard to justify creating a document type that you only need once or twice. | ||||
| This is okay. As long as the types you define help you organize your collection in the way | ||||
| you want, paperless is doing its job. | ||||
|  | ||||
| Tags can be used in many different ways. Think of tags are more versatile folders or binders. | ||||
| If you have a binder for documents related to university / your car or health care, you can | ||||
| create these binders in paperless by creating tags and assigning them to relevant documents. | ||||
| Just as with documents, you can filter the document list by tags and only see documents of | ||||
| a certain topic. | ||||
|  | ||||
| With physical documents, you'll often need to decide which folder the document belongs to. | ||||
| The advantage of tags over folders and binders is that a single document can have multiple | ||||
| tags. A physical document cannot magically appear in two different folders, but with tags, | ||||
| this is entirely possible. | ||||
|  | ||||
| .. hint:: | ||||
|  | ||||
|   This can be used in many different ways. One example: Imagine you're working on a particular | ||||
|   task, such as signing up for university. Usually you'll need to collect a bunch of different | ||||
|   documents that are already sorted into various folders. With the tag system of paperless, | ||||
|   you can create a new group of documents that are relevant to this task without destroying | ||||
|   the already existing organization. When you're done with the task, you could delete the | ||||
|   tag again, which would be equal to sorting documents back into the folder they belong into. | ||||
|   Or keep the tag, up to you. | ||||
|  | ||||
| All of the logic above applies to correspondents as well. Attach them to documents if you | ||||
| feel that they help you organize your collection. | ||||
|  | ||||
| When you've started organizing your documents, create a couple saved views for document collections | ||||
| you regularly access. This is equal to having labeled physical binders on your desk, except | ||||
| that these saved views are dynamic and simply update themselves as you add documents to the system. | ||||
|  | ||||
| Here are a couple examples of tags and types that you could use in your collection. | ||||
|  | ||||
| * An ``inbox`` tag for newly added documents that you haven't manually edited yet. | ||||
| * A tag ``car`` for everything car related (repairs, registration, insurance, etc) | ||||
| * A tag ``todo`` for documents that you still need to do something with, such as reply, or | ||||
|   perform some task online. | ||||
| * A tag ``bank account x`` for all bank statement related to that account. | ||||
| * A tag ``mail`` for anything that you added to paperless via its mail processing capabilities. | ||||
| * A tag ``missing_metadata`` when you still need to add some metadata to a document, but can't | ||||
|   or don't want to do this right now. | ||||
|  | ||||
| .. _basic-usage_searching: | ||||
|  | ||||
| Searching | ||||
| ######### | ||||
|  | ||||
| Paperless offers an extensive searching mechanism that is designed to allow you to quickly | ||||
| find a document you're looking for (for example, that thing that just broke and you bought | ||||
| a couple months ago, that contract you signed 8 years ago). | ||||
|  | ||||
| When you search paperless for a document, it tries to match this query against your documents. | ||||
| Paperless will look for matching documents by inspecting their content, title, correspondent, | ||||
| type and tags. Paperless returns a scored list of results, so that documents matching your query | ||||
| better will appear further up in the search results. | ||||
|  | ||||
| By default, paperless returns only documents which contain all words typed in the search bar. | ||||
| However, paperless also offers advanced search syntax if you want to drill down the results | ||||
| further. | ||||
|  | ||||
| Matching documents with logical expressions: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|   shopname AND (product1 OR product2) | ||||
|  | ||||
| Matching specific tags, correspondents or types: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|   type:invoice tag:unpaid | ||||
|   correspondent:university certificate | ||||
|  | ||||
| Matching dates: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|   created:[2005 to 2009] | ||||
|   added:yesterday | ||||
|   modified:today | ||||
|  | ||||
| Matching inexact words: | ||||
|  | ||||
| .. code:: | ||||
|  | ||||
|   produ*name | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|   Inexact terms are hard for search indexes. These queries might take a while to execute. That's why paperless offers | ||||
|   auto complete and query correction. | ||||
|  | ||||
| All of these constructs can be combined as you see fit. | ||||
| If you want to learn more about the query language used by paperless, paperless uses Whoosh's default query language. | ||||
| Head over to `Whoosh query language <https://whoosh.readthedocs.io/en/latest/querylang.html>`_. | ||||
| For details on what date parsing utilities are available, see | ||||
| `Date parsing <https://whoosh.readthedocs.io/en/latest/dates.html#parsing-date-queries>`_. | ||||
|  | ||||
|  | ||||
| .. _usage-recommended_workflow: | ||||
|  | ||||
| The recommended workflow | ||||
| ######################## | ||||
|  | ||||
| Once you have familiarized yourself with paperless and are ready to use it | ||||
| for all your documents, the recommended workflow for managing your documents | ||||
| is as follows. This workflow also takes into account that some documents | ||||
| have to be kept in physical form, but still ensures that you get all the | ||||
| advantages for these documents as well. | ||||
|  | ||||
| The following diagram shows how easy it is to manage your documents. | ||||
|  | ||||
| .. image:: _static/recommended_workflow.png | ||||
|  | ||||
| Preparations in paperless | ||||
| ========================= | ||||
|  | ||||
| * Create an inbox tag that gets assigned to all new documents. | ||||
| * Create a TODO tag. | ||||
|  | ||||
| Processing of the physical documents | ||||
| ==================================== | ||||
|  | ||||
| Keep a physical inbox. Whenever you receive a document that you need to | ||||
| archive, put it into your inbox. Regularly, do the following for all documents | ||||
| in your inbox: | ||||
|  | ||||
| 1.  For each document, decide if you need to keep the document in physical | ||||
|     form. This applies to certain important documents, such as contracts and | ||||
|     certificates. | ||||
| 2.  If you need to keep the document, write a running number on the document | ||||
|     before scanning, starting at one and counting upwards. This is the archive | ||||
|     serial number, or ASN in short. | ||||
| 3.  Scan the document. | ||||
| 4.  If the document has an ASN assigned, store it in a *single* binder, sorted | ||||
|     by ASN. Don't order this binder in any other way. | ||||
| 5.  If the document has no ASN, throw it away. Yay! | ||||
|  | ||||
| Over time, you will notice that your physical binder will fill up. If it is | ||||
| full, label the binder with the range of ASNs in this binder (i.e., "Documents | ||||
| 1 to 343"), store the binder in your cellar or elsewhere, and start a new | ||||
| binder. | ||||
|  | ||||
| The idea behind this process is that you will never have to use the physical | ||||
| binders to find a document. If you need a specific physical document, you | ||||
| may find this document by: | ||||
|  | ||||
| 1.  Searching in paperless for the document. | ||||
| 2.  Identify the ASN of the document, since it appears on the scan. | ||||
| 3.  Grab the relevant document binder and get the document. This is easy since | ||||
|     they are sorted by ASN. | ||||
|  | ||||
| Processing of documents in paperless | ||||
| ==================================== | ||||
|  | ||||
| Once you have scanned in a document, proceed in paperless as follows. | ||||
|  | ||||
| 1.  If the document has an ASN, assign the ASN to the document. | ||||
| 2.  Assign a correspondent to the document (i.e., your employer, bank, etc) | ||||
|     This isn't strictly necessary but helps in finding a document when you need | ||||
|     it. | ||||
| 3.  Assign a document type (i.e., invoice, bank statement, etc) to the document | ||||
|     This isn't strictly necessary but helps in finding a document when you need | ||||
|     it. | ||||
| 4.  Assign a proper title to the document (the name of an item you bought, the | ||||
|     subject of the letter, etc) | ||||
| 5.  Check that the date of the document is correct. Paperless tries to read | ||||
|     the date from the content of the document, but this fails sometimes if the | ||||
|     OCR is bad or multiple dates appear on the document. | ||||
| 6.  Remove inbox tags from the documents. | ||||
|  | ||||
| .. hint:: | ||||
|  | ||||
|     You can setup manual matching rules for your correspondents and tags and | ||||
|     paperless will assign them automatically. After consuming a couple documents, | ||||
|     you can even ask paperless to *learn* when to assign tags and correspondents | ||||
|     by itself. For details on this feature, see :ref:`advanced-matching`. | ||||
|  | ||||
| Task management | ||||
| =============== | ||||
|  | ||||
| Some documents require attention and require you to act on the document. You | ||||
| may take two different approaches to handle these documents based on how | ||||
| regularly you intend to scan documents and use paperless. | ||||
|  | ||||
| * If you scan and process your documents in paperless regularly, assign a | ||||
|   TODO tag to all scanned documents that you need to process. Create a saved | ||||
|   view on the dashboard that shows all documents with this tag. | ||||
| * If you do not scan documents regularly and use paperless solely for archiving, | ||||
|   create a physical todo box next to your physical inbox and put documents you | ||||
|   need to process in the TODO box. When you performed the task associated with | ||||
|   the document, move it to the inbox. | ||||
							
								
								
									
										60
									
								
								mkdocs.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,60 @@ | ||||
| site_name: Paperless-ngx | ||||
| theme: | ||||
|   name: material | ||||
|   logo: assets/logo.svg | ||||
|   font: | ||||
|     text: Roboto | ||||
|     code: Roboto Mono | ||||
|   palette: | ||||
|     # Palette toggle for light mode | ||||
|     - media: "(prefers-color-scheme: light)" | ||||
|       scheme: default | ||||
|       toggle: | ||||
|         icon: material/brightness-7 | ||||
|         name: Switch to dark mode | ||||
|  | ||||
|     # Palette toggle for dark mode | ||||
|     - media: "(prefers-color-scheme: dark)" | ||||
|       scheme: slate | ||||
|       toggle: | ||||
|         icon: material/brightness-4 | ||||
|         name: Switch to light mode | ||||
|   features: | ||||
|     - navigation.tabs | ||||
|     - navigation.top | ||||
|     - toc.integrate | ||||
|   icon: | ||||
|     repo: fontawesome/brands/github | ||||
| repo_url: https://github.com/paperless-ngx/paperless-ngx | ||||
| extra_css: | ||||
|   - assets/extra.css | ||||
| markdown_extensions: | ||||
|   - attr_list | ||||
|   - md_in_html | ||||
|   - def_list | ||||
|   - admonition | ||||
|   - tables | ||||
|   - pymdownx.highlight: | ||||
|       anchor_linenums: true | ||||
|   - pymdownx.superfences | ||||
| nav: | ||||
|     - index.md | ||||
|     - setup.md | ||||
|     - 'Basic Usage': usage.md | ||||
|     - configuration.md | ||||
|     - administration.md | ||||
|     - advanced_usage.md | ||||
|     - 'REST API': api.md | ||||
|     - development.md | ||||
|     - 'FAQs': faq.md | ||||
|     - troubleshooting.md | ||||
|     - changelog.md | ||||
| copyright: Copyright © 2016 - 2022 Daniel Quinn, Jonas Winkler, and the Paperless-ngx team | ||||
| extra: | ||||
|   social: | ||||
|     - icon: fontawesome/brands/github | ||||
|       link: https://github.com/paperless-ngx/paperless-ngx | ||||
|     - icon: fontawesome/brands/docker | ||||
|       link: https://hub.docker.com/r/paperlessngx/paperless-ngx | ||||
|     - icon: material/chat | ||||
|       link: https://matrix.to/#/#paperless:matrix.org | ||||
 Michael Shamoon
					Michael Shamoon