No description
  • TypeScript 46.8%
  • Go 31.2%
  • HTML 15.8%
  • Python 3.2%
  • CSS 2.3%
  • Other 0.7%
Find a file
2026-06-18 18:20:12 +03:00
.claude Attachement preview window on lower menu is now draggable 2026-05-17 01:33:51 +03:00
cmd/server feat: rich text tooltip 2026-06-18 14:59:25 +03:00
internal fix: flip sender/recipient roles for Received nodes so rename masks keep party values 2026-06-18 18:02:54 +03:00
scripts Added attachment preview 2026-05-17 01:13:59 +03:00
web feat: topic field changes to 'None' when node type changes 2026-06-18 18:20:12 +03:00
.air.toml App core added to git 2026-05-07 00:20:21 +03:00
.dockerignore refactor: package.json outputs to web/dist/app.js 2026-06-17 16:31:09 +03:00
.env Added file upload, configurable options for upload size and allowed file extensions, node-specific file preview settings 2026-06-12 19:25:48 +03:00
.gitignore refactor: package.json outputs to web/dist/app.js 2026-06-17 16:31:09 +03:00
CLAUDE.md Changed folder handling for projetc to read pre-configured folder as their root folder for nodes to handle 2026-05-07 00:31:54 +03:00
compose.yaml chore: UPLOAD_NAME_MASK variable renamed to FILE_NAME_MASK 2026-06-18 14:32:19 +03:00
Dockerfile refactor: package.json outputs to web/dist/app.js 2026-06-17 16:31:09 +03:00
flake.lock App core added to git 2026-05-07 00:20:21 +03:00
flake.nix refactor: package.json outputs to web/dist/app.js 2026-06-17 16:31:09 +03:00
go.mod App core added to git 2026-05-07 00:20:21 +03:00
package-lock.json refactor: package.json outputs to web/dist/app.js 2026-06-17 16:31:09 +03:00
package.json refactor: package.json outputs to web/dist/app.js 2026-06-17 16:31:09 +03:00
presets.json feat: configurable 'topic' values for nodes 2026-06-17 01:14:52 +03:00
README.md chore: UPLOAD_NAME_MASK variable renamed to FILE_NAME_MASK 2026-06-18 14:32:19 +03:00
tsconfig.json refactor: package.json outputs to web/dist/app.js 2026-06-17 16:31:09 +03:00

PaperTracker - Econadzor's correspondence visualizer

WARNING: This project is AI-generated using Claude Code

Configuration

All configuration is supplied through environment variables, read once at startup (internal/config/config.go). For Docker, set them in .env / docker-compose.yml; for local development the Nix dev shell exports sensible defaults. Changing any value requires a restart.

Variable Default (dev) Default (container) Description
PORT 8080 8080 TCP port the HTTP server listens on.
DB_PATH ./dev-data/papertracker.db /data/papertracker.db Path to the SQLite database file. Created on first run; WAL files live alongside it.
DOCS_PATH ./docs /docs Root folder containing the document tree. Each project's folder is a subdirectory of this path. Mounted into the container (read-write — uploads are written into project folders).
PROJECT_STATUSES active,closed,archived active,closed,archived Comma-separated list of allowed project statuses. The first entry is the default for new projects.
MAX_UPLOAD_MB 25 25 Maximum upload size in megabytes. 0 = unlimited. Invalid values fall back to 25.
UPLOAD_EXTENSIONS pdf,doc,docx,odt,png,jpg,jpeg,bmp,gif,webp,tiff same Comma-separated allow-list of upload file extensions (case-insensitive, leading dots optional). Empty = allow any type.
FILE_NAME_MASK (unset) (unset) Go text/template controlling how uploaded files are renamed. Applies to the main document and is the fallback for attachments whose ATTACHMENT_NAME_MASK is unset. Unset = keep the original filename. The extension is appended automatically; the mask renders the stem only. See File rename mask.
PRESETS_FILE (unset) /config/presets.json Path to a JSON file holding sender/recipient presets. Preferred over PRESETS; if set but unreadable, falls back to PRESETS, then to the built-in default. See Presets.
PRESETS (unset) (unset) Inline JSON presets, same format as PRESETS_FILE. Used only when PRESETS_FILE is unset or unreadable.

Notes:

  • The Nix dev shell (flake.nix) exports PORT, DB_PATH, and DOCS_PATH and creates dev-data/ and docs/, so go run ./cmd/server works out of the box.
  • Do not set DOCS_PATH in your shell when running docker compose — it overrides the value in .env and can break the volume mount.

Presets

A preset groups a list of senders, a list of recipients and (optionally) two topic lists under a key (e.g. ОЭК). Each project selects one preset; its communication nodes then pick a sender and a recipient from that preset's party lists, and optionally a topic. The first preset in the list is the UI default; order is preserved.

Presets are loaded from PRESETS_FILE (preferred) or the PRESETS env var. Both use the same compact JSON: an array of presets whose senders/recipients are {short_name: full_name} maps and whose topics_sent/topics_received are plain string arrays.

[
  {
    "key": "ОЭК",
    "senders":         { "МОО": "Межрегиональная общественная организация Эконадзор" },
    "recipients":      { "ГП РФ": "Генеральная прокуратура" },
    "topics_sent":     ["Жалоба", "Запрос информации"],
    "topics_received": ["Ответ на запрос"]
  }
]

The full name is what's stored on a node and shown by default; the short name is used by the UI display setting (Short / Full / Both) and by the rename mask's party variables. Parties and topics keep the order they appear in the JSON. The two topic lists are optional and are offered by node type — topics_sent for sent nodes, topics_received for received ones. The node's topic field is a dropdown: pick one from the list, choose Custom… to type a free-form one, or leave it as None. If neither source is valid, a built-in ОЭК preset is used so the app always works.

File rename mask

FILE_NAME_MASK is a Go text/template. The rendered result is the file's stem; the real extension is appended automatically. Path separators produced by the mask are collapsed, and an empty result is rejected. It renames the main document and is also the fallback for attachments when ATTACHMENT_NAME_MASK is unset.

Variable Value
{{.Name}} Original filename without extension.
{{.Slug}} Name lowercased, spaces → -, unsafe characters stripped.
{{.Input}} User-entered name (spaces → _). Referencing this prompts the user for a name at upload time.
{{.Folder}} Project folder name.
{{.ProjectID}} Numeric project id.
{{.SenderShort}} Sender short name from the project's preset (empty if no match).
{{.SenderName}} Sender full name as selected on the node.
{{.RecipientShort}} Recipient short name from the project's preset (empty if no match).
{{.RecipientName}} Recipient full name as selected on the node.
{{.Topic}} Node topic (from the preset list or free-form), spaces → _. Empty if none chosen.
{{.Date}} Real (upload) date, YYYY-MM-DD.
{{.DateU}} Real (upload) date, YYYY_MM_DD (underscores).
{{.Time}} Real (upload) time, HH-MM-SS.
{{.DateTime}} Date_Time.
{{.Unix}} Real (upload) epoch seconds.
{{.NodeDate}} The communication's own date, YYYY-MM-DD (empty if unset).
{{.NodeDateU}} The communication's own date, YYYY_MM_DD (underscores).
{{.UUID}} 8-character random hex.
{{.Rand}} 4-character random hex.

Example:

- FILE_NAME_MASK={{.Date}}_{{.SenderShort}}-{{.RecipientShort}}_{{.Input}}

2026-06-16_МОО-ГП_РФ_my-file.pdf