Skip to content

History

Revisions

  • Custom asset fields and import: user page + three developer guides User page: Recording anything — custom asset fields and import. Three developer guides rather than one, split by LAYER rather than by size: Typed-Fields-Engine-Developer-Guide the shared machinery. Two consumers today; adding a third should be a descriptor and a query, not a new engine Custom-Asset-Fields-Developer-Guide the assets consumer: catalogue, sets, the two ways a set attaches, and every surface the values have to reach Asset-Import-Developer-Guide the feature on top: reconciliation, the preview, the holding area Each carries the traps rather than just the design, because that is what a developer guide is for: the tenancy normalisation that would have duplicated the whole estate on every run, per-row atomicity, row_number being reserved in MySQL 8, mixed local/UTC timestamps, two phantom theme tokens, the guarded script block, t() not being bootstrapped in API endpoints, toast.js using textContent, and modal markup not being portable between two pages of the same module. Sidebar updated under Assets. Every internal link checked against an actual file, and every source file named checked to exist.

    @edmozley edmozley committed Aug 20, 2026
    6e40b60
  • Discussion #80: developer guides, sidebar, and the pages this made stale New: Email-Template-Sender-Rules-Developer-Guide Email-Signatures-Developer-Guide Updated because the change made them wrong, not merely incomplete: Email-Send-Log - Result is now Sent / Failed / Not sent Canned-Responses - [ticket_url] joins the merge code table Tickets - sender rules and [ticket_url] on email templates External-Issue-Trackers-Developer-Guide, Azure-DevOps-Connector-Developer-Guide - integrationsAbsoluteUrl now delegates to publicAbsoluteUrl, plus the subfolder fault it had _Sidebar - all five pages, nested under Tickets Every internal link in the changed pages checked against a real file.

    @edmozley edmozley committed Aug 19, 2026
    f4552b8
  • Email signatures: the reply-box half

    @edmozley edmozley committed Aug 19, 2026
    9ee2356
  • Email signatures: per analyst, several allowed, one default

    @edmozley edmozley committed Aug 19, 2026
    d5e7f48
  • Sender rules for email templates: specificity, not order

    @edmozley edmozley committed Aug 19, 2026
    82172ec
  • Public web address: the setting behind [ticket_url] and tracker links

    @edmozley edmozley committed Aug 19, 2026
    e5800f6
  • Issue #74: the default password could not be changed Write-up of the reported fault and the three further instances found with it, plus the Bugs-Resolved index row.

    @edmozley edmozley committed Aug 19, 2026
    09ca658
  • Issue #79 write-ups, Watchtower settings pair, browser extension dev guide Six new pages and five updated. New: - Issue-79-Ticket-Status-Not-Set — the reported status fault. Seven creation paths, the priority that survived because "Normal" is the same word in German, and the header fallback that displayed "Open" BECAUSE no status was stored. - Issue-79-Ticket-Source-Not-Set — the other half of the same report. Why it could not be a one-line fix (ticket_origins has no is_default and is company-scoped), the per-mailbox dropdown that dissolved it, and the dismissible health mark. - Configurable-Lookups-Developer-Guide — the through-line. Thirty-plus places across five modules, three of them wrong in English on a stock install; what to read instead of a name; the two derivations; the "don't borrow a domain fact for a view decision" rule; and the whole-payload rename diff that proves a fix. - Watchtower-Settings + Watchtower-Settings-Developer-Guide — the pair. - Browser-Extension-Developer-Guide — the endpoint, the payload keys, and the trap of being the second consumer of a shared payload. Updated: - Watchtower — was describing eight cards and metrics that no longer exist; now ten, with the settings link. - Browser-Extension — corrected the badge description, added the update notice and the dev guide link. - Mailbox-Authentication — the Default ticket origin and the ! mark, including why warnings can be dismissed and errors cannot. - Bugs-Resolved — three rows. - _Sidebar — nested entries under Watchtower, Browser Extension and Bugs resolved. Both validations clean across all 190 pages: every [Link] resolves to a real .md, and every backticked path exists in the repo. Seven bare filenames were promoted to full paths, as on the Forms and Slack pairs.

    @edmozley edmozley committed Aug 19, 2026
    544cbe9
  • Time tracking: user guide + developer guide (discussion #72) Time-Tracking recording time, the two switches and why the second one matters, per company, and what people will actually notice Time-Tracking-Developer-Guide why Tickets settings rather than System (every surface is a ticket surface), the new per-company settings layer and why it was worth building when the ACL table on #76 was not, why two switches, why per company is unusually clean here, the three enforcement points, and how to add the next setting Includes the trap this feature fell into twice in one day: a settings screen that renders a boolean BEFORE it knows the answer, so a failed load is indistinguishable from "off" — fixed on the Authentication page in the morning, reproduced on this tab in the evening by the person who wrote the warning. Sidebar entry under Tickets, beside Collision detection.

    @edmozley edmozley committed Aug 18, 2026
    b3747b0
  • Attached documents: user guide + two developer pages (discussion #76) Attached-Documents what it does, in plain terms: a file OR a link, one document on several records, who can see it, finding things, and the maintenance job Attached-Documents-Developer-Guide the colour-keyed file tables, the schema and the one decision that shaped it (the parent is a ROW), adding a module, extraction's two tiers, orphan collection, and the things that will bite Attached-Documents-Permissions-and-Search the rule and its consequences: why there is no permissions table, the two shapes of the same question, where the check happens, why attaching is itself a permission operation, why ⌘K asks twice, scale, the file on disk, and what the tests actually cover Split into two developer pages because it is a large feature and permissions is the half somebody will come back to on its own. Sidebar entry under Searching inside tickets, which is where the extraction pipeline this borrows from already lives.

    @edmozley edmozley committed Aug 17, 2026
    cee9679
  • Write-up for issue #77, and index it A Microsoft 365 mailbox could only ever collect mail from Inbox. Covers why it was never a regression (Graph accepts seven well-known folder names in a path and treats everything else as an identifier, so reading a folder BY NAME had never worked), why the screen contradicted itself (the move-to field had the resolver and a Verify button, the read-from field had neither), what changed, and what remains unproven -- a successful nested match, and the app-only combination. Adds the row to Bugs-Resolved and the sidebar entry.

    @edmozley edmozley committed Aug 17, 2026
    f8e8995
  • Write-up for issue #78, and index it The notification bell opened to nothing on the home page while working everywhere else. Covers why the badge stayed correct (the count is fetched by a function that touches no translations), why nothing was logged (the throw was one line ABOVE the try, so the fetch never ran and the catch that would have said "couldn't load" was never entered), and the two further pages that had the identical fault and were fixed with it. Adds the row to Bugs-Resolved and the sidebar entry.

    @edmozley edmozley committed Aug 17, 2026
    80daa04
  • Bugs Resolved index + write-up for issue #70 A landing page for resolved bug reports, linked from the sidebar, and the first dedicated write-up under it: why renaming the Operational impact level split the status board in two. The #70 page covers the reported symptom, the reason healthy services were the broken ones (their status is derived, not stored, so six places invented the literal 'Operational'), the four further faces of the same bug that were not reported, the fix via the is_default flag, a colour-keyed file table, and how it was verified including the positive control. The index also lists two closed bug reports that have no write-up yet, so the gap is visible rather than forgotten. Service-Status gains a paragraph on how a healthy service's status is derived, linking to the write-up.

    @edmozley edmozley committed Aug 17, 2026
    838ad17
  • Directory sync: three open questions, and three decisions the page had lost The open questions came from auditing this page's own 13-question list against the shipped code. All three are gaps against decisions recorded HERE, not new ideas - which is the point of keeping the list: 6. precedence between two directories holding the same person. §3.3 called multiple sources "already possible" and treated the plumbing as the easy part. The plumbing is fine; the policy was never decided. Every run claims the person, so values flap. Found by reading the code - a single-directory install never sees it. 7. custom attributes (§3.7) not built. 8. the users screen has one door, not the two §3.12 decided on, and §3.5's offboarding alert exists as a filter but not as a report. Separately: checking whether the page captured the reasoning found that it did not. Three decisions made DURING the build, all driven by using the thing rather than designing it, were missing entirely: 4.4 the modal was the wrong container - and the finding was not "it is cramped" but "I couldn't see the preview function". The button had been there the whole slice, below the fold. A feature that exists and cannot be found has not shipped, and neither the design nor the tests could detect that because both checked whether it worked. 4.5 "Everyone" must mean everyone. The filter quietly applied is_active = 1. The four scopes were named in the report itself and adopted verbatim; Holding equipment includes leavers because a leaver with a laptop is the most useful row on the screen. 4.6 a reporting line is stored once, pointing upwards, so "who does Bob manage" did not exist. Importing a hierarchy is only half of adopting one. Section 4 retitled, since half of it is no longer about the first answer being wrong.

    @edmozley edmozley committed Aug 16, 2026
    df7416f
  • Wiki: developer guides for directory sync LDAP-Developer-Guide covered sign-in and had one incidental mention of importing across 291 lines, so the whole import subsystem was undocumented for developers. Split by reader intent rather than by size: Directory-Sync-Developer-Guide how it works - scope model, the four safety rules, matching, the run log, the traps Extending-Directory-Sync how to change it - the checklists The split earns its keep because the second page is a set of lists that must be exhaustive or they are actively harmful. Adding one imported field touches FOURTEEN places, and missing one usually fails silently: the column exists, the mapping box exists, nothing writes to it. That list was produced by tracing `office` through the code, not from memory, and the page says so, because a stale checklist is worse than none. Every file path, function, constant and wiki link in both pages verified to resolve. LDAP-Developer-Guide now says plainly that it covers sign-in only.

    @edmozley edmozley committed Aug 16, 2026
    1e2cad7
  • Wiki: give importing people its own page It was a section two-thirds of the way down LDAP-and-Active-Directory, which is a page about signing in. Anybody sent that link had to read about bind accounts and group gating before reaching their answer, and the question people actually ask - "how do I import my AD users?" - was not the title of anything. Three pages, three jobs: LDAP-and-Active-Directory signing in Importing-People-from-a-Directory the how-to <- the one to send people Directory-Sync the design record The sign-in page keeps a short pointer explaining why importing exists at all (the people who hold equipment are largely the people who never log in), so the link is worth following rather than a bare cross-ref. Expanded on the way: prerequisites, step-by-step with the tree and the mapping test, the full table of what happens when somebody leaves or a branch is renamed, the CLI for scheduling until that is built, and a troubleshooting table keyed on what you actually see on screen. All links verified to resolve; sidebar updated.

    @edmozley edmozley committed Aug 16, 2026
    90ce07e
  • Directory sync: record what shipped, and the design note that was half right Directory-Sync.md was a design record for something now built. §3.8, §3.9 and §3.11 say how each idea actually turned out, the slice table marks what is done, and scheduling is named as the only outstanding piece. §3.9 had warned that storing DNs breaks when an OU is renamed. It was right, and incomplete: it only considered a renamed INCLUDE. A renamed EXCLUDE is worse - the people you carved out silently start being imported, and the sanity brake cannot see it because the brake only guards against a sudden DROP. Both are now detected; the page says so, says GUID self-healing was not built, and says why detection came first. LDAP-and-Active-Directory.md had NO mention of importing at all, so pointing at it as "the manual" would have been false and anyone reading it would never learn the feature exists. Added the how-to: what comes across, choosing branches, checking the mapping, previewing, and the table of what happens when somebody leaves or a branch is renamed. Every file path and wiki link in both pages verified to resolve.

    @edmozley edmozley committed Aug 16, 2026
    382a321
  • Directory sync: the full design conversation Records the whole thing rather than just the conclusions -- the request, what already exists, the thirteen questions and their answers with reasoning, the slicing, and the open questions. The most useful section is §4, "three things the first answer got wrong": - "two records unless you match on email" was IMPOSSIBLE -- users.email carries a UNIQUE index, so the second option could never have been built. The schema comment had already anticipated the entire question. Lesson: check the constraints before designing a setting that depends on them. - the setting that survived is better shaped: adopt an existing person or leave them alone and flag it -- with the consequence spelled out, that adopting kills their portal password. - usernames: a real problem but not the one it looked like. Global uniqueness exists BECAUSE the multi-company portal routes by email domain, so a mailbox-less user typing "smithj" has nothing to disambiguate them. Split into directory_username (per provider, never mangled) and username (global, only for people who actually sign in). Each of those was caught by a question rather than by testing, which is worth noting in itself. Linked from the sidebar under LDAP & Active Directory.

    @edmozley edmozley committed Aug 16, 2026
    f7b8479
  • Running on nginx: D009 section, dotfile rule now shipped on Apache too, .user.ini correction

    @edmozley edmozley committed Aug 16, 2026
    dda7ac4
  • Running on nginx: table of all twelve .htaccess files, each tested against real nginx with a probe file

    @edmozley edmozley committed Aug 16, 2026
    dee5a9d
  • Document the two-URL-depths trap and how it was fixed Running-on-nginx gains a full write-up: what broke (relative redirects in auth/ resolving to /auth/index.php once the page was reachable at its real path), why the routing tests passed anyway (they only covered signed-OUT journeys), the rule to follow, the BASE_URL idiom for all four kinds of outbound path, and the assertion that now guards it. Includes the irony worth remembering: the auth/.htaccess guard removed in #68 existed for exactly this reason, but its comment named only "relative assets", so the redirect targets were missed. Root-Folder-Tidy's correction notice now carries the rule and links to it.

    @edmozley edmozley committed Aug 16, 2026
    4934c90
  • Running on nginx (new); Root folder tidy correction notice for #68; Installation now says nginx needs its config

    @edmozley edmozley committed Aug 16, 2026
    99bbf28
  • Searching inside tickets: the actual Tika docker command, the -full/OCR trap, localhost binding, and the full format list

    @edmozley edmozley committed Aug 15, 2026
    5724435
  • Email send log: user page + developer guide (#1082), all eight routes

    @edmozley edmozley committed Aug 15, 2026
    1b6c7c1
  • Issue #67: add the mode-switch postscript (#1081) and its troubleshooting row

    @edmozley edmozley committed Aug 15, 2026
    9a9d413
  • Issue #67: app-only email sending — full write-up New page explaining why app-only mailboxes could not send, in plain English: what /me and /users/... actually mean, why the distinction only bites app-only, the two further faults behind the reported one, the fix, and why the implementation differs from the patch proposed in the issue. Mailbox-Authentication gains a developer section on the three things auth_mode changes, three troubleshooting rows, and a link to the new page. Sidebar updated.

    @edmozley edmozley committed Aug 15, 2026
    70a76f7
  • Scheduled tasks: add the attachment extraction worker, and catch up Checking rather than assuming turned up a real gap: the cron page listed FOUR jobs and the attachment worker shipped as a fifth. Somebody setting up a new install from that page would have configured everything except the one added this week. Added to the table and to both the Windows and Linux command blocks, with a note that it is the odd one out: its absence is NOT silent failure, because documents are still read opportunistically while people use FreeITSM. The job keeps up with a busy desk rather than being the only thing that works. That distinction matters on a page whose whole premise is "these fail silently". Full-Text-Search: #1078 and #1079 added to the shipped list. Searching-Inside-Tickets: "if a document is not turning up" now says System > Search names the file and the reason, rather than only implying totals.

    @edmozley edmozley committed Aug 15, 2026
    29d6b6d
  • Extraction guide: concurrency, the claim, and the page-hang bound Ed asked what happens with two or three analysts logged in at once. Nothing was ever at risk of corruption - every write is an idempotent upsert - but two workers would select the same rows and send the same files to the extractor, which for OCR is minutes of CPU paid for twice. §9.4 documents the claim: a conditional atomic UPDATE to a transient `extracting` status, why rowCount() is not enough to know which rows were won, and the stale-claim reaper. Includes the trap that `extracting` must ALSO be in the indexer's reconsider list, because the claiming worker is the one that then indexes - the same shape as the `pending` bug in §9.3, and worth stating as a rule: a transient status nothing acts on is just a different kind of leak. §9.5 on the opportunistic drain running inside somebody's request, and why it needed all THREE bounds - one item, a wall-clock deadline, and a shorter extractor timeout, because a single file cannot be interrupted once curl is waiting on it so the deadline alone does not help. Plus why that timeout is restored in a finally. §9.6 on the new "attachments that are not searchable" list: counts answer "is something wrong", only a filename answers "why can't I find that invoice". Status table gains `extracting` and marks `unsupported` as not final.

    @edmozley edmozley committed Aug 14, 2026
    bd9bdf3
  • Search: attachment extraction tier 2 (#1076-#1077). Discussion #53 closed. The extraction guide's §9 said "what tier 2 will need". It now describes something that exists. Documents the thing that shapes the whole tier: CONFIGURED and AVAILABLE are different states. tikaExtract() returns three outcomes, and a service being DOWN must write `pending`, never `failed` - a five-minute outage must not blacklist every PDF that arrived during it. Also why there is deliberately no health check before each file: the extraction attempt IS the check, and a ping per attachment would be an extra round trip each time. Why both drains exist: a cron-only design does nothing at all on an install that has not set one up, which includes every evaluation. And §9.3 on the two bugs, because they share a shape worth recognising - a queue that looks busy and clears nothing, which is much harder to notice than a crash. One: the indexer would not reconsider `pending`, so the drain could never move the depth. Two: the requeue was indiscriminate and put files Tika is never asked about into a queue that could not clear them. The general rule is written down: a status nothing will ever act on is a leak, so make the worker able to terminate those. Operational notes that will otherwise cost somebody an afternoon: use the -full image or there is no OCR, and Tika has no authentication at all so it must never be published. User page: PDFs and scanned documents move from "not read" to "read once you add a document reader", with where to set it up and where the background-work switches live. Full-Text-Search: all three of the discussion's original questions now answered yes. §8.2's three tiers are two-and-a-half - the external SEARCH ENGINE remains deliberately unbuilt and §9.5's argument still stands. All 13 files named verified to exist; all links resolve.

    @edmozley edmozley committed Aug 14, 2026
    10e60f6
  • Add "Attachment text extraction — Developer Guide" (#1075) A page of its own rather than another section on the corpus guide: the subject carries more security reasoning than anything else in search, and it needs room. Covers the two tiers and, importantly, that the split is drawn on a SECURITY line rather than a convenience one - tier 2 formats need a real document parser, and the input arrives from anyone who can email the service desk through an endpoint with no authentication at all. Includes an answer to the question that will keep coming up: "a PDF with a text layer is just compressed text, can't PHP do that?" Partly, and it is the most reasonable-sounding wrong turn available. Font encodings, compressed cross-reference tables, empty-password encryption and positioned-not-flowed text each break it, and the objection is the FAILURE MODE rather than the effort: unsupported is honest, silent mojibake looks indexed and quietly matches nothing. Records what a pure-PHP tier would have to promise (fail closed, never emit doubtful text) if it is ever wanted. Documents why attachment_text is the durable record and search_documents the derived copy, with the two things it buys - a rebuild reads no files, and whole-ticket reindexing re-opens nothing. Every guard with the reason it exists, including that zip bombs are refused on DECLARED sizes before an entry is read, and that writing the test for that guard exhausted PHP's memory twice, which is the demonstration. The OOXML welding trap in full, since it is the one that silently ruins search. Plus the known gaps stated honestly: docx headers/footers/ footnotes, xlsx inline numbers, pptx speaker notes. User page: attachments are now a table of what IS and is not read, leading on the fact that FreeITSM says which files it could not read rather than staying quiet. All links resolve; all eight files named verified to exist.

    @edmozley edmozley committed Aug 14, 2026
    64cfe5c