Complia Manual, as shipped in the download
Complia — User Manual
A register for data-protection complaints, and the acknowledgement clock that runs on each one. Version 3.1.4 [src: app/controllers/api.php:20].
About this manual
Every statement here was written by reading Complia's own source, and each one carries the file it came from in a bracketed src marker. Paths are relative to the folder this docs directory sits in. If a sentence disagrees with the application, the application is right and this manual has a bug — the markers exist so you can check rather than take our word for it.
Nothing is described that the code does not do. Where something is deliberately limited, that is said plainly rather than left out.
One framing point before anything else. Complia records complaints and computes dates from them. It does not decide whether you have complied with anything, and nothing in this manual is legal advice. Where the source cites a statute, this manual reports that the source cites it — not that the citation is current or correctly construed. Verify both with your own adviser.
What Complia is
A complaint arrives — through a public form or logged by a handler — and the product runs an acknowledgement clock on it, tracks it through a workflow, and keeps a register you can export [src: app/controllers/mcp.php:41].
The acknowledgement clock
The due date is the date received plus a window you configure [src: app/src/Complaints.php:44].
Why the default window is 29 days and not 30
This is the most considered decision in the product and it is worth reading, because it explains a number you might otherwise "correct".
The source cites DPA 2018 s.164A(3), which it describes as inserted by the Data (Use and Access) Act 2025 s.103, requiring acknowledgement "within the period of 30 days beginning when the complaint is received" [src: app/src/Complaints.php:5].
Its reasoning for defaulting to 29 [src: app/src/Complaints.php:11]:
The statute counts "beginning when the complaint is received" — unusual drafting, a new Act, and no case law yet. If the day of receipt is day 1, then received plus 30 days is one day late. A 29-day window is safe under both readings: the worst case is that you acknowledge a day early, which costs nothing, while the alternative worst case is a breach. If guidance settles the construction, change one setting — no code.
Two things follow for you as the operator. The window is configurable [src: app/src/Complaints.php:46], clamped between 1 and 365 days. And the choice of 29 is a deliberate margin, not a miscalculation.
Check the citation yourself. The source names a specific, recent instrument, and this manual takes no position on whether it remains current or on how it should be construed. If your adviser reads the drafting differently, the setting is where you express that.
Owners and reminders
A complaint can have a named owner, chosen from the active members and administrators; the choice is written to the complaint's log [src: app/controllers/v3.php:589]. When acknowledgement reminders are switched on in Settings, the owner and the notification address are emailed at each reminder step before the acknowledgement deadline (7, 3 and 1 days by default) and once on the day after it passes [src: app/controllers/v3.php:504]. The email gives the complaint number, the date and a link, nothing the complainant wrote. Each step is sent once and written to the complaint's log, sent or not; it is checked when someone opens the dashboard, and a daily cron call to reminders/run with the scheduled-backup token covers days nobody does [src: app/controllers/v3.php:568].
Status
Five stored statuses — received, acknowledged, investigating, resolved, rejected [src: app/src/Complaints.php:33] — and six displayed [src: app/src/Complaints.php:36].
The sixth is ack_overdue, and it is never stored. It is derived by comparing today against the due date on a complaint that has not yet been acknowledged [src: app/src/Complaints.php:73].
The precedence is deliberate: rejected and resolved win first, so a closed complaint can never turn overdue afterwards [src: app/src/Complaints.php:76]. Closed states stop the clock mattering entirely [src: app/src/Complaints.php:37].
"Acknowledged or beyond" counts investigating, resolved and rejected as well [src: app/src/Complaints.php:39] — moving straight to investigating does not leave the clock running.
The workflow is one-way
Transitions run forward only, and resolved and rejected are terminal [src: app/src/Complaints.php:85]. There is no reopen.
That is a deliberate contrast with a maintenance-ticket product, where reopening is normal. A closed complaint record is a document about what was decided; reopening it would rewrite that.
Closing requires an outcome
A complaint cannot be closed without an outcome summary, and the rule is enforced for agents as well as people [src: app/controllers/mcp.php:132].
The public form and tracking
A complainant gets a tracking token: 40 hexadecimal characters, unique, and checked for uniqueness as it is issued — the allocator throws rather than handing out a duplicate [src: app/src/Complaints.php:103].
Lookups are exact parameterised matches and a miss is a 404 [src: app/src/Complaints.php:23].
⚠️ The complainant's IP address is stored
Complia keeps the submitting IP address in the complaint row [src: app/src/Database.php:248], indexed with the timestamp [src: app/src/Database.php:255], and uses it for a per-address submission limit — ten an hour by default [src: app/src/Complaints.php:130].
That is a real trade-off and you should know which side of it you are on: the address is what makes abuse of a public form tractable, and it is also personal data about somebody making a data-protection complaint.
It is covered by the anonymisation routine — ip is one of the declared columns [src: app/controllers/v3.php:808] — so a subject-access erasure clears it. But until then it is held.
Files and size limits
Attachments are PDF, PNG, JPEG, TXT or EML, up to 10 MB each, decided by the file's own bytes [src: app/controllers/v3.php:868]. When the server's PHP upload limits are lower, the pages state the lower figure [src: app/controllers/v3.php:836]. A public form that exceeds the server's whole-form limit is returned to the complainant with the reason, instead of being lost [src: app/controllers/v3.php:851].
Subject access and anonymisation
Complia can export everything it holds about a complainant, and can anonymise it. The anonymisation map declares which columns are cleared on each table — the complainant's name, email and IP on the complaint itself, and the original filename and uploader on each attachment [src: app/controllers/v3.php:808], [src: app/controllers/v3.php:816].
Two defects the source records having fixed
Both are worth reading, because they tell you what the current behaviour is and why.
The anonymisation used to miss the attachments. The attachments table declared no columns, and the shared anonymiser skips a table with none — so a run reported attachments: 0 while a file's stored name still read "Jane_Smith_SAR_letter.pdf" and the uploaded files themselves sat untouched on disk, readable through the attachment route by anyone who could view the complaint. The source calls that, in a data-protection product, "the defect the product exists to prevent" [src: app/controllers/v3.php:810].
It is fixed: the columns are declared [src: app/controllers/v3.php:816], and the files are deleted by the controller, because the shared anonymiser blanks columns and does not touch disk [src: app/controllers/v3.php:815].
The subject-access export used to be reachable by a viewer. It was gated on complaint.view, which the viewer role satisfies through its wildcard — so any read-only account could download a complainant's complete file: name, email, phone, the full complaint text and every log entry. The source records that this was proven live, a viewer session receiving HTTP 200 on the export route [src: app/controllers/v3.php:825].
It is fixed: the export now takes the same standing as anonymisation [src: app/controllers/v3.php:828], on the reasoning that reading one complaint on screen is desk work, while exporting a data subject's entire record is a data-protection officer's act.
Users and roles
Three roles [src: app/controllers/app.php:66].
| Permission | viewer | member | admin |
|---|---|---|---|
complaint.view and other .view permissions | yes | yes | yes |
audit.view | yes | yes | yes |
complaint.create / .advance / .note / .attach / .export | — | yes | yes |
complaint.delete — and subject-access export | — | — | yes |
settings.edit, team.manage | — | — | yes |
⚠️ The audit trail is still readable by a viewer
The viewer role is granted *.view — a wildcard rather than a list [src: app/controllers/app.php:69]. The audit permission is named audit.view, so the wildcard matches it and a viewer can read and export the audit trail [src: app/controllers/v3.php:16], [src: app/controllers/v3.php:26].
Note the shape of that: the subject-access export was moved off .view precisely because the wildcard made it reachable [src: app/controllers/v3.php:825], but the wildcard itself remains, and the audit trail still sits behind it. This has been raised against the product.
Backups follow the model
Complia's database backup downloads are permission-gated, requiring the settings permission [src: app/controllers/api.php:245]. A viewer cannot download the database.
The API and agent access
Five tools are exposed to an agent, of which two write [src: app/controllers/mcp.php:47]: listing complaints, complaint detail and a deadlines report on the read side; creating a complaint and advancing its status on the write side.
The instructions bind an agent to the same rules a person faces: ack_overdue is derived and never stored, resolved and rejected are terminal, and closing requires an outcome summary [src: app/controllers/mcp.php:44].
The source states the constraint directly: the agent can never invent a deadline, skip the closing-needs-an-outcome rule, or reopen a closed complaint [src: app/controllers/mcp.php:11].
What Complia does not do
It does not tell you whether you have complied. It records what arrived, computes a date from a window you set, and shows you what is overdue.
It is not legal advice, and this manual does not verify the statutory citation in the source [src: app/src/Complaints.php:5]. Confirm it, and its construction, with your adviser.
It does not reopen a closed complaint [src: app/src/Complaints.php:85].
It does not let a complaint be closed silently [src: app/controllers/mcp.php:132].
It does not keep the complainant anonymous. The submitting address is stored [src: app/src/Database.php:248], and a public complaints form is not a whistleblowing channel.