mapik / watcher-crm
Watcher CRM
Requires
- php: >=8.2
- ext-bcmath: *
- ext-fileinfo: *
- ext-mbstring: *
- ext-pdo_pgsql: *
- ext-simplexml: *
- azuyalabs/yasumi: ^2.11
- cakedc/users: ^16.0
- cakephp/cakephp: ^5.3
- cakephp/migrations: ^5.1
- cakephp/plugin-installer: ^2.0
- capcom6/android-sms-gateway: ^2.2
- dereuromark/cakephp-audit-stash: ^2.0.1
- dereuromark/cakephp-decimal: ^2.4
- doctrine/sql-formatter: ^1.5
- evilfreelancer/routeros-api-php: ^1.6
- giggsey/libphonenumber-for-php: ^9.0
- josegonzalez/dotenv: ^4.0
- league/flysystem: ^3.36
- league/oauth2-google: ^5.0
- mapik/dbase: ^1.0
- mapik/pohoda-xml: ^1.25
- mlocati/ip-lib: ^1.22
- mobiledetect/mobiledetectlib: ^4.10
- tecnickcom/tc-lib-pdf: ^8
Requires (Dev)
- cakedc/cakephp-phpstan: ^4.2
- cakephp/bake: ^3.6
- cakephp/cakephp-codesniffer: ^5.3
- cakephp/debug_kit: ^5.2
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11.5 || ^12.5 || ^13.1
- psalm/phar: ^6.16
- rector/rector: ^2.4
Suggests
- ext-dbase: A faster way to read and write Pohoda's DBF files. Nothing needs it: mapik/dbase does the same work in PHP and steps aside wherever the extension is installed.
- ext-imagick: Reads HEIC, HEIF and TIFF, which no browser draws, and renders the first page of a PDF. Without it those scans still file and download, they just cannot be previewed.
- ext-redis: Lets the cache live in Redis rather than in files.
- cakephp/repl: Console tools for a REPL interface for CakePHP applications.
- dereuromark/cakephp-ide-helper: After baking your code, this keeps your annotations in sync with the code evolving from there on for maximum IDE and PHPStan/Psalm compatibility.
- markstory/asset_compress: An asset compression plugin which provides file concatenation and a flexible filter system for preprocessing and minification.
- phpstan/phpstan: PHPStan focuses on finding errors in your code without actually running it. It catches whole classes of bugs even before you write tests for the code.
Provides
None
Conflicts
None
Replaces
None
- 5.x-dev
- 4.x-dev
- 4.2.0
- 4.1.0
- 4.0.1
- 4.0.0
- 4.0.0-RC1
- 3.x-dev
- 3.2.1
- 3.2.0
- 3.1.1
- 3.1.0
- 3.0.1
- 3.0.0
- 3.0.0-RC3
- 3.0.0-RC2
- 3.0.0-RC1
- 2.x-dev
- 2.3.0
- 2.2.0
- 2.1.1
- 2.1.0
- 2.0.1
- 2.0.0
- 1.8.0
- 1.7.2
- 1.7.1
- 1.7.0
- 1.6.5
- 1.6.4
- 1.6.3
- 1.6.2
- 1.6.1
- 1.6.0
- 1.5.2
- 1.5.1
- 1.5.0
- 1.4.1
- 1.4.0
- 1.4.0-RC1
- 1.4.0-beta2
- 1.4.0-beta1
- 1.3.10
- 1.3.9
- 1.3.8
- 1.3.7
- 1.3.6
- 1.3.5
- 1.3.4
- 1.3.3
- 1.3.2
- 1.3.1
- 1.3.0
- 1.2.2
- 1.2.1
- 1.2.0
- 1.1.0
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
This package is auto-updated.
Last update: 2026-10-23 17:15:52 UTC
README
CRM for Internet Service Providers, built on CakePHP.
Description
- Customer Relationship Management system aimed at small and mid-size ISPs (customer / contract / billing / IP address management).
- Generates invoices in dBase format for the POHODA Stormware bookkeeping software.
- Integrates with optional services for RADIUS accounting, RouterOS device inventory, the geo-addresses-postgis registry lookup API (CZ RUIAN / HR DGU), and a few SaaS providers (Eurofaktura, SledovaniTV, Android SMS Gateway, …).
Requirements
- PHP 8.2 or newer
- PostgreSQL
- Redis
- PHP
imagickextension, and ghostscript alongside it for PDFs (only for the pictures of filed documents — without them a document is still filed and handed over, it just has no thumbnail) - PECL
dbaseextension (only when using the POHODA invoice export) - Watcher Agent — required only for
host reachability checks (ping), RADIUS session disconnect and changes on
RouterOS devices (the address list debtors are blocked by, the access lists
of access points). It is a separate service (run it in Docker, even on the
same host; it supports the PROXY protocol), and it holds the account for the
routers. These actions no longer run locally, so the app container needs no
pingbinary and no router passwords. - geo-addresses-postgis —
required only for address validation and registry lookups (CZ RUIAN / HR DGU).
It is a separate service exposing a REST API; point the app at it via
ADDRESSES_API_URL/ADDRESSES_API_KEY.
The Docker Compose stack below provides PostgreSQL and Redis out of the box, so on a fresh host you only need Docker.
Installation
Two install paths are supported. Docker Compose is recommended.
Option A — Docker Compose (recommended)
git clone https://github.com/Mapiiik/Watcher-CRM.git cd Watcher-CRM cp config/.env.example config/.env # edit config/.env — set APP_NAME and any integration URLs / API keys docker compose -f compose.production.yaml up -d
The production image runs composer run-script migrations and rebuilds the
schema cache automatically on container start, so the app is reachable at
https://localhost (with a certificate of Caddy's local CA) once the
container is healthy. It runs on our FrankenPHP
(Debian), whose Caddyfile docker/caddy/app.caddy fills in. Set SERVER_NAME in the
compose environment to a real domain and Caddy obtains a Let's Encrypt certificate itself.
The base image also restricts paths to administrators' addresses (ACCESS) and limits
sign-in attempts per address (RATE_LIMIT) when asked to, see its README.
Behind an SNI proxy such as HAProxy, set LISTENER_MODE=behind-proxy and PROXY_ALLOW to the
proxy's network. Only on an internal network, for a test before DNS points at the server or for
good, set LISTENER_MODE=internal: Caddy issues the certificate from its own CA and SERVER_NAME
can be the internal name or the server's IP address. Browsers warn until they trust its root
certificate, /data/caddy/pki/authorities/local/root.crt in the container.
Option B — Bare-metal (host nginx + PHP-FPM, FrankenPHP, …)
For hosts already running their own PHP webserver:
git clone https://github.com/Mapiiik/Watcher-CRM.git cd Watcher-CRM composer install --no-dev cp config/.env.example config/.env # edit config/.env — at minimum DATABASE_URL and CACHE_*_URL composer run-script migrations composer run-script schema-cache
Point your webserver's document root at the webroot/ directory. Install the
PECL dbase extension if you plan to use the POHODA invoice export in dBASE format.
Later updates of such an installation are one script:
./update.sh
It refuses to run on a tree with local changes, then pulls, installs, migrates,
relinks the plugin assets and clears the caches. Where opcache is configured not to
check file timestamps, set PHP_FPM_SERVICE to the service name and the script
reloads the pool at the end.
The first admin
A new installation has no account to sign in with. Add an admin; the password is made up for it and shown once:
bin/cake access add_admin <username> <email>
With Docker Compose, run it in the container:
docker compose -f compose.production.yaml exec webserver bin/cake access add_admin <username> <email>.
Upgrading from 4.x
5.x begins with one migration that takes the schema over from the last 4.x
release, so an installation has to go through that release first and migrate
there. 5.x also keeps the record of the migrations in one table instead of the
phinxlog tables of 4.x. Move it over once, then migrate:
bin/cake migrations upgrade --drop-tables ./update.sh
Until both are done, migrating stops and says which of them is missing.
Configuration
Runtime settings live in config/.env (or are passed in as environment
variables — see the environment: blocks in the compose files for the keys
read at boot). config/.env.example is the canonical list; common groups are:
- Database / cache:
DATABASE_URL,CACHE_*_URL - Integrations:
WATCHER_NMS_URL/_KEY,WATCHER_AGENT_URL/_KEY,ADDRESSES_API_URL/_KEY,ANDROID_SMS_GATEWAY_URL, …
Pictures of filed documents
Thumbnails and previews are drawn by ImageMagick from files somebody uploaded,
so it is worth telling it what it may open. The images already do — they carry
docker/imagemagick-policy.xml and copy it over the one ImageMagick ships.
A bare-metal install has nobody to do that for it, and what a distribution ships varies: the one on Ubuntu 24.04 leaves every coder open, while others refuse PDF outright and draw no preview of a scan at all. If you want the previews, take that file as a starting point and put it where your build reads it:
sudo cp docker/imagemagick-policy.xml /etc/ImageMagick-7/policy.xml # or -6
It allows the formats a scan or a photograph arrives in, lets ghostscript draw the first page of a PDF, and refuses everything else. Read it before you use it: it is commented throughout, and a deployment that files a format we did not think of will have to add it.
Two things are worth knowing if you edit it. ImageMagick 6 and 7 ask for the
ghostscript delegate under different names, which is why it is granted twice.
And leave the time limit out: on ImageMagick 6 it counts the processor time of
the whole process rather than of one conversion, so anything long-lived — a
nightly batch of previews, a worker answering all day — ends up unable to draw
at all.
Customizing the compose stack
If compose.production.yaml doesn't fit your environment, copy it to
compose.yaml and customize there — compose.yaml is git-ignored, so
git pull won't overwrite your changes.
cp compose.production.yaml compose.yaml
# edit compose.yaml as needed
docker compose up -d
Typical reasons to override: pointing services at infrastructure already running on the host (e.g. an existing PostgreSQL instance, external Redis, reverse proxy), removing bundled containers you don't need, or tweaking volumes / networks.
Backups
A deployment keeps its state in two places: the database, and the data root
(DATA_ROOT, the app-data volume by default) where the letterhead, the
signature and the documents live. A dump of the database alone is therefore
not a backup.
bin/cake backup /somewhere/outside # a directory named after the moment
bin/cake restore /somewhere/outside/2026-09-10-020000
The application image carries no PostgreSQL client, so under Docker the command prints what to run in the database container instead. See docs/2026-backing-up-a-deployment.txt for that, for the order the two halves have to be taken in, and for how to check that a backup is one.
Development
compose.development.yaml targets local development, with FrankenPHP
(HTTP/1.1, HTTP/2, HTTP/3). It bind-mounts the working tree into the container
and places vendor/, tmp/, logs/, node_modules/, plus the PostgreSQL
data directory and Redis data on tmpfs — fast iteration and disposable state, but everything in
those paths is lost when the stack is torn down.
docker compose -f compose.development.yaml up
The Postgres and Redis ports are exposed to the host (5432, 6379) so you
can connect with local clients while the stack is running.
License
Watcher CRM is licensed under the GNU Affero General Public License v3.0. Copyright (c) 2026 Martin Patočka.
What this means
You are free to use, modify and run this software. If you modify it and make it available to others (including as a network service), you must also make your modifications available under the same license.