Skip to content

Architecture and code map

This document explains how the repository is organised and where to make changes for the most common tasks. It is intended for those reading the code, not for the end user: for installation and usage see the manual.

[!NOTE] Gextto is a Go daemon. Gextto's application logic lives in a single Go package (github.com/buzzqw/gextto) in the main folder of the repo; cmd/gexttod is only its executable. The repository, however, also contains the standalone torrent daemon cmd/gx-torrent and the torrent engine internal/gxcore (pure Go), as well as the shared packages in internal/. The root files are therefore many, but grouped by prefix: the sections below are the map of those prefixes.

1. Folder overview

gextto/
├── cmd/gexttod/            Gextto executable (main): dispatches commands and starts the daemon
├── cmd/gx-torrent/         standalone executable of the torrent engine: daemon, UI and API
├── *.go                    the gextto package: Gextto's logic (see §3 and §4)
├── *_test.go               tests, next to the code they verify
├── internal/               shared packages and libraries (see §5), including gxcore (torrent engine)
├── uiweb/v2/               server-side UI: HTML templates and static assets
│   ├── templates/*.html
│   └── static/*            CSS, htmx, JS (v2-core.js)
├── uiweb/end2end/          Playwright tests (Node, not Go)
├── docs/                   documentation (this file, manuals, API...)
├── scripts/                build, update, packaging and service helpers; scripts/sql holds the archive maintenance SQL
├── systemd/                example unit files for the service
├── .github/                CI, CodeQL, dependabot, release
├── go.mod / go.sum         Go dependencies
├── Makefile                build/test commands
├── VERSION, build_number   version and build number (build_number committed, shared with CI)
└── bin/                    compiled binary (ignored by git)

Generated/local folders not to be confused with the code: bin/ (build), data/ (database and runtime state), uiweb/end2end/node_modules/, gextto-data/ (data directory of the service). They are listed in .gitignore.

2. How the binary is built

cmd/gexttod/main.go  →  gextto.Parse(args)
  ├── daemon command  →  runDaemon(...)                 (cmd/gexttod/main.go)
  │                       →  LoadConfig → PrepareDirs
  │                       →  OpenDatabase / OpenArchive / OpenComicsDb / OpenI18nDb
  │                       →  NewAppState(...)           (appstate.go)
  │                          → ConfigureTorrentEngine   (torrent_engine_select.go)
  │                       →  Serve(...)                 (web_serve.go)
  └── --update        →  gextto.Run(...)                (update.go)

Gextto's build number is generated by the script scripts/build-daemon.sh (and scripts/next-build-number.sh) and stamped into the binary. The gx-torrent daemon also has its own, independent counter: it increases by one on every real build via scripts/next-gx-build-number.sh and lives in gx-torrent.build_number, committed like build_number: CI reads it without incrementing, so a release carries the checkout's number (gx_version in release.json).

The version shown to people is <series>.<build>, derived from the build and from the series file (version_series for Gextto, gx_torrent.version_series for the daemon; AppVersion/GxTorrentVersion in internal/constants). The third number is always the build; the second number is raised by hand only when a new series is started. The full build and, for Gextto, the commit the binary was compiled from are shown in the footer of Maintenance.

The build is in pure Go: gexttod and the gx-torrent daemon, with no C or C++ dependency (CGO_ENABLED=0). gx-torrent is the default engine and the standalone client; the only other backend is the external/managed qBittorrent-nox.

3. Main package: files by area

Startup, orchestration and service

File Role
cli.go command parsing (gexttod --version, --update, ...).
appstate.go construction of the shared state AppState (NewAppState).
engine.go scrape/search engine: HTML/RSS feeds, Torznab, web engines.
orchestrator.go one complete acquisition cycle: candidates from the feeds, the archive and the pending queue, then the missing episodes (collectGapReleases, with the limits of readGapFillPolicy).
cycle_candidate.go the candidate pass of a cycle: each candidate's link, delay profile, archive comparison and approval, then the start of its download (candidatePass).
release_dedup.go copies of the same torrent from several sources merged into one release (infohash, declared hash, name + size within rounding; different hashes never), the others kept as mirrors the cycle falls back to when a link fails.
torrent_link_quarantine.go dead .torrent links (dead_torrent_links): a URL that fails in two different cycles is skipped for 6h, 24h, then a week, so the archive stops proposing it and the cycle stops counting it as an error; a success clears the row.
indexer_failure.go repeated .torrent failures from one source (an expired login, a dead proxy): a warning in the log and, at most every 12 hours, a notification naming the source and the action (sign in again, disable it in the searches); a resolved link re-arms it.
torrent_add_intent.go starting an approved release (add → approval → torrent_meta) and recovery of adds interrupted by a crash.
web_serve.go startup of the web server and background workers.
instance_lock.go flock on the data folder so a second Gextto stops before opening the databases; the interface address is checked at the same point.
service_restart.go scheduled systemd actions (e.g. service restart).
update.go self-update of the binary.
safety.go controlled restart of workers after a panic.
watcher.go "watched" folders: .torrent/.magnet files are added by themselves.

Configuration, state and database

File Role
config.go the Config model: read/write, generation, defaults.
database.go SQLite store: series, movies, torrents, feed history, provider backoff.
sqlite.go opening a SQLite DB with shared pragmas.
indexer_lanes.go Jackett and Prowlarr searched one indexer at a time: lanes read from the manager's list (10 min cache), per-lane slots, timeout, health and budget skip, cross-manager dedup by tracker. indexarr is one aggregate lane instead: it already queries its own sources in parallel and names the site of each result.
archive.go durable catalogue of archived releases (SQLite + FTS5 on titles): one row per magnet, stable indexer guid (for .torrent-only listings) or exact URL (magnet_key, a 16-byte digest) and one per infohash (idx_archive_hash; a new listing of a known torrent refreshes its row). The guid keeps one row when Jackett regenerates its download URL at every request. A .torrent-only listing stores the infohash the indexer declared next to the link, so the blocklist and duplicate checks recognise the torrent without opening the link; a later magnet copy replaces the ephemeral link, never the other way round.
archive_sql.go small engine for the curated scripts/sql/*.sql operations: loads them (embedded), validates one read-only SELECT or one DELETE, binds the selected language marker arrays to :tokens/:raw, runs previews and transactional deletions.
migrate.go migration of the data directory.
backup.go database backups (manual and scheduled).
library_alias.go helper for library persistence.
web_inputs_extra.go input structs of the web APIs.
transfer_policy.go transfer policy shared by every engine: download path (RAM disk included), free-space budget, torrent diagnosis and path helpers.
seed_rules.go how long a completed torrent keeps seeding: the torrent's own limits, then the first seed rule matching its origin, then the global ones.
speed_mode.go, speed_schedule.go the speed rule as one choice (Auto, fixed limits, per-weekday schedule) and the per-day table it is read from and written to.
setting_provenance.go where a setting's value came from (auto/manual), so the guided tuning never proposes over a value the operator saved.
restart_cause.go why the daemon started again, so a restart that followed an update is not read as instability by the tuning.
tuning.go, system_probe.go, sysinfo.go guided tuning: the machine facts read (memory, CPU, volumes, filesystem type, device ids), never written, and the proposal built from them with its reason.
null_engine.go placeholder backend when no transfer engine could be activated: lists nothing and refuses every operation with a capability error, so UI and automation keep working.
backend_config_validation.go field-specific validation of the engine settings from the settings page, instead of a typo surfacing at the next restart.
torrent_restore.go downloads lost by an unclean stop, added again from their magnet in the folder that already holds their data.
pending_queue.go the delay-profile queue with how long each title has waited, read-only, for the observability panel.

Media pipeline (release → archive)

File Role
parser.go parsing of release names and quality.
upgrade_until.go "stop improving" threshold (upgrade_until_score) applied to upgrade decisions.
decision.go (read-only) explanation of the decisions on a release.
cleaner.go archive index, detection of lower duplicates, cleanup.
postprocess.go post-processing: move, rename, sidecar.
hardlink.go import into the library as hardlinks of the seeding files, with fallback to copy.
media_guard.go guards on video files (extensions, protection).
mediainfo.go actual inspection of files via ffprobe.
comics.go comics: scraper, DB, HTTP download, dedicated cycle.
comicinfo.go writing of ComicInfo.xml into directly downloaded CBZ files.
audio_cleanup.go audio tracks in other languages removed after the import: video and the kept audio copied packet by packet, no re-encoding (mkvmerge first for Matroska, ffmpeg as the second chance and for the other containers), untagged tracks kept/removed/left alone by setting, a re-probe of the streams per type (codec, language, flags), duration and A/V offsets before the library file is replaced; no chmod on network shares.
audio_cleanup_packets.go the packet check of the audio cleanup: every packet of every kept stream compared with the source (MD5 of the payload, time relative to the stream start, distance from the first video packet).
audio_cleanup_queue.go the audio cleanup queue: one worker, no size limit, saved to audio_cleanup_queue.json in the data folder and resumed at startup.
maintenance_night.go the night maintenance window: settings, idle detection (download rate, imports, library and integrity checks, load), one heavy job at a time, the persisted status (maintenance_status.json), the worker and the night summary.
maintenance_db.go the database part of the night maintenance: PRAGMA optimize and VACUUM when worth it every night, a weekly integrity_check with an immediate notification.
maintenance_library.go the library report (files gone from the disk, unreadable folders apart) and the audio cleanup of the archived files, one at a time, remembered in audio_cleanup_library, hardlinked seeding files left for later.
uiweb_v2_night_maintenance.go, web_handlers_night_maintenance.go the Maintenance panel of the night maintenance and its API (/api/maintenance/night).
mediainfo_gate.go an upgrade is confirmed by probing both files with ffprobe: an attribute the streams do not show (resolution, video codec, audio family and channels, HDR10/HLG) discards the release, blocklists it and restores the archived row.
manual_import.go manual import of a file already on disk: parse the name, match a configured series or movie, propose the archive destination, replace an existing copy only on request.
upgrade_impact.go "what would the next cycles replace?": the archived releases replayed through the series decision in dry-run.
pack_precheck.go an in-progress pack read from its .torrent file list before it is downloaded, so a pack that does not hold the wanted episode is not downloaded at all.
pack_inspector.go a pack inspected as soon as its metadata arrives (a magnet has none until the swarm answers): a pack with nothing useful is removed and its upgrade backup restored.
orphan_cleanup.go guided cleanup of the download folders: entries no live torrent owns and whose videos all have a library copy at equal or better quality.
fileops.go long-running copies and moves registered so a shutdown waits for them: no half-copied file left in the library.

Sources, search and metadata

File Role
rss.go RSS/XML feeds of the sources.
websearch.go web search engines and shared limiter.
ed2ksearch.go eD2k/Kad through aMule: settings, shared EC client, cached status, search into models.Release (network, ed2k_link, sources), gap-filling fallback.
ed2k_downloads.go aMule's download queue: list for Downloads, add/pause/resume/remove, completion events fed to the torrent event loop with a copy-mode import.
uiweb_v2_ed2k.go the eD2k page: aMule status, servers, Kad, search, pasted links.
indexer_health.go indexer health (Prowlarr).
tmdb.go / tvdb.go TMDB and TheTVDB metadata.
series_metadata.go, tvdb_metadata.go where the series metadata comes from: TMDB when its key is set, otherwise TVDB with the same calls and result shapes.
anime.go absolute anime episode numbers mapped onto the seasons TMDB uses, for the series marked as anime.
integrations.go base URLs of the external integrations.
media_refresh.go targeted (per-folder) refresh of Jellyfin and Plex, with fallback to a full refresh.
calendar_ics.go iCal calendar /feed/calendar.ics: arrivals, original airings, local movie releases.

Notifications, hooks, i18n

File Role
notifier.go notifications via Telegram, HTTP webhook and SMTP, plus the dedicated Discord, Slack, Gotify, ntfy, Pushover and Apprise channels and a custom script (internal/notify), with per-event switches, anti-spam window and message language.
hooks.go user hooks on events.
i18n.go embedded translations (internal_translations*.yml), which the translation database mirrors at startup.

Torrent engines (transfer plane)

File Role
torrent_engine.go the TorrentEngine contract between Gextto and the engine.
torrent_engine_select.go backend selection from torrent_backend + preflight.
engine_fallback.go the engine-agnostic fallback chain (managed qBittorrent-nox downloaded on demand → recovery), its cooldown and the GEXTTO_ENGINE override.
gxtorrent_engine.go + gxtorrent_runtime.go + cmd/gx-torrent/ gx-torrent backend (pure Go, default): REST adapter, startup and supervision of the daemon, which uses the gx-core engine in internal/gxcore. The same daemon also runs on its own (standalone) on Linux and Windows; the platform layer is in cmd/gx-torrent/*_linux.go / *_windows.go / *_other.go (memory, disk class, gateway, data folder, link/junction, cross-volume move, browser opening, Windows service in service_windows.go).
qbittorrent_engine.go + qbittorrent_runtime.go qBittorrent backend: adapter, supervision, and the private managed runtime (download of the userdocs/qbittorrent-nox-static build, SHA-256 verified).
torrent_migration.go preparation of the migration between backends.
torrent_removal.go recording of manual removals.

Web/API and workers

File Role
web.go shared definitions: AppState, response/query helpers, setup.
web_router.go construction of the HTTP mux and route table.
auth.go optional access: middleware in front of all routes, local network exemption, login, API key.
web_handlers_core.go core handlers, log streaming, middleware.
web_system.go, web_maintenance.go, web_torrents.go, web_series.go, web_movies.go, web_comics.go HTTP handlers grouped by subject: daemon status/jobs/setup, archive and database maintenance, torrents, series, movies, comics.
web_settings.go, web_search.go, web_backup.go, web_integrations.go, web_metadata.go, web_calendar.go, web_media… the remaining subjects: settings, searches, backup, third-party integrations, metadata providers, calendar.
web_helpers.go, web_speed.go, web_ipfilter.go helpers shared by the handler files, and the speed and IP-filter machinery they use.
web_handlers_compat.go compatibility/diagnostics endpoints.
web_handlers_jobs.go, web_handlers_torrent_backend.go, web_handlers_torrent_diag.go specific handlers (jobs, backend, diagnostics).
web_handlers_series.go, web_handlers_torrent_stream.go series handlers (/api/series/{name}) and redirect to the streaming of the gx-torrent daemon, with the token added server-side.
quality_profiles.go named quality profiles (/api/quality-profiles): the saved list with stable ids, the title values a profile gives, the exact match of a title page, and the seed generated from the library until the list is saved.
api_v3.go the Sonarr/Radarr v3 subset a request manager (Jellyseerr) speaks: status, quality/language profiles, root folders, tags, lookup and add of series/movies, queue.
web_qbit.go the qBittorrent Web API subset (/api/v2) the browser extensions speak: login with the SID cookie, add of magnets and .torrent files, list, pause/resume, delete and recheck, all forwarded to the active engine.
library_bulk.go Edit selected of the Series and Movies tables: the same values on many titles, with a quality profile as a template.
web_torrent_events.go event machine of the torrent lifecycle.
web_background.go long-running background workers.
web_workers_media.go media workers: scheduled backup, MediaInfo backfill, calendar.
web_maintenance_rename.go folder rename with user review.
httpx.go shared HTTP client for sources and providers.
jsonutil.go faithful normalisation of JSON responses.
health.go health report (dashboard/endpoint).
acquisition.go + web_handlers_acquisitions.go download history: the log lines with a torrent hash (field acq: <id> of internal/logging) saved in acquisition_events; /api/acquisitions API, History tab and 📜 in the UI.
health_monitor.go monitor that logs the degraded state with reason and recovery.
cycle_monitor.go warnings when a source keeps failing or no cycle has completed cleanly for too long, read from the same history the Health page shows.
provider_monitor.go the forum login of the mircrew-indexer service watched through its /status: it keeps answering Torznab requests with a broken login, so no cycle failure would reveal it.
security_origin.go cross-site state-changing requests refused (net/http.CrossOriginProtection), because the LAN bypasses the login.
update_check.go the in-app side of updates: release.json, the newer build and the commits it brings, and the update request the root unit acts on.
web_compress.go gzip of the HTML pages and the shared assets.
ed2k_api.go JSON API of the aMule integration (download queue and actions, bandwidth limits, aMule log) used by the TUI and the bandwidth menu.
local_process.go resource usage of an external process on this machine, for the aMule badge: nothing to read when aMule runs elsewhere.
log_text.go helpers for the user-facing log lines: short sentences, rounded numbers with units, titles instead of internal identifiers.
jobs.go background job manager.

Server-side UI (uiweb v2)

File Role
uiweb.go view-model and formatters shared by the v2 SSR/HTMX UI; embed of the licence.
uiweb_pages.go data-driven list/action pages.
uiweb_sections.go reusable sections (table, actions, form, progress...).
uiweb_detail.go series/movie detail pages.
uiweb_shell.go UI "chrome": top bar, sidebar, status.
uiweb_settings.go, uiweb_settings_meta.go, uiweb_settings_defaults.go, uiweb_tooltips.go Configuration page: areas, sections and index with the panel (Group) of each setting; units, special values, control type and the toggle it depends on; defaults; descriptions.
uiweb_v2.go v2 shell (HTMX), fragment routing and rendering.
uiweb_v2_tr.go render-time translation: one parsed template set per language with tr/trTitle bound to its dictionary, and v2TranslateFragment for markup Go assembles.
uiweb_v2_dashboard.go, uiweb_v2_downloads.go, uiweb_v2_detail.go, uiweb_v2_search.go, uiweb_v2_comics.go, uiweb_v2_maintenance.go, uiweb_v2_archive_sql.go dedicated v2 pages.
uiweb_v2_gaps.go, uiweb_v2_import.go, uiweb_v2_library_layout.go, uiweb_v2_ports.go Missing tab grouped by series and season, manual-import page, poster view of the library, peer-port panel.
uiweb_v2_settings_insights.go, uiweb_v2_settings_mode.go, uiweb_v2_feed_stats.go, uiweb_v2_tuning.go Configuration: read-only insights next to the controls, the per-feed activity panel, the Facilitata/Esperto switch and the Gestione automatica card.
uiweb_v2_theme.go, uiweb_bandwidth_history.go theme picker (saved themes on the server, the active one per browser) and the bandwidth chart of the dashboard.
uiweb_v2_sections.go pages composed of sections (Maintenance, Integrations).
uiweb_v2_settings_extras.go structured editors of the v2 Configuration.
uiweb_v2_table.go generic server-side table renderer.
uiweb_v2_widgets.go migrated widgets (duplicates, database, RAM disk, rename, OAuth, jobs...).
uiweb_engine_stats.go "Torrent engine" panel of the Health page.
uiweb_v2_setup.go guided first-start configuration (/?view=setup).
uiweb_v2_pwa.go PWA support (installation as an app, magnet/.torrent sharing).
uiweb_v2_problems.go "To check" dashboard (what needs attention).
uiweb_v2_client_i18n.go dictionary for the strings set at runtime by the client.

4. File naming conventions

  • web_<subject>.go: the HTTP handlers of one subject (web_torrents.go, web_series.go, …); web_helpers.go holds what several subjects use. A new handler goes in the file of its subject, not in a numbered bucket.
  • uiweb_v2_*.go: everything related to UI v2 (SSR + HTMX). uiweb_*.go without _v2 is the shared layer (view-model and formatters) used by UI v2.
  • gxtorrent_*, qbittorrent_*: the torrent backends.
  • *_test.go: tests next to the file they verify.
  • The private helpers of a group use the group prefix (gh2_..., gh3_..., bg_...) to avoid collisions between files of the same package.

5. Packages in internal/

Package Content
internal/constants shared constants (ports, defaults, version/build).
internal/logging daemon logger; it turns hash fields into acq: <id> and passes those lines to the download history sink.
internal/models shared types.
internal/rules matching rules.
internal/utils generic utilities.
internal/cache cache.
internal/backoff exponential backoff.
internal/messages messages/texts.
internal/qbittorrent qBittorrent API client.
internal/tui terminal client (TUI).
internal/auth access control of the standalone daemon: password hashing and login sessions (/ui/login); the managed mode does not use it.
internal/dht DHT implementation, a module of its own under the main module.
internal/ed2k eD2k links (ed2k://|file|…|/, server links) and the name filter for search results.
internal/amule aMule External Connections (EC) client: packet codec, login, status, servers, Kad, downloads, search, preferences; amuletest is a fake core for tests.
internal/gxcore gx-core torrent engine (the gx-torrent binary): our original code (early versions built on MIT/BSD bases, since rewritten).
internal/queue manager of the gx-torrent queue (which torrents to run).
internal/bwschedule weekly bandwidth scheduler (a window and limits per weekday), shared by Gextto and gx-torrent.
internal/notify gx-torrent notifications: Telegram, e-mail, webhook (JSON, Discord, Slack, Gotify, ntfy, Pushover).
internal/rss parsing of RSS/Atom/Torznab feeds and HTML listings (ext.to, TorrentGalaxy: listing.go), ordered rules and episode filter.
internal/settings persistent key/value store of the gx-torrent standalone mode.
internal/torznab client for Torznab indexers (Jackett, Prowlarr, indexarr and similar).
internal/utp BEP 29 uTP socket and transport implementation in pure Go (EUPL-1.2).
internal/webui templates and embedded assets of the gx-torrent daemon UI (see §8).

6. The gx-torrent daemon (cmd/gx-torrent)

The standalone daemon of the torrent engine (gx-torrent, pure Go) has its own architecture, distinct from Gextto's main package. It exposes both its own web UI and two APIs: the native JSON one used by Gextto and the qBittorrent-compatible one.

File Role
main.go, daemon.go, lifecycle.go, mode.go startup and lifecycle of the daemon (managed or standalone mode).
ui.go, ui_search.go, ui_categories.go web UI of the daemon (handleUI), live fragments, search and categories.
ui_render.go, i18n_tr.go, i18n.go pages served in the request language: one parsed template set per page and per language with tr bound to its dictionary, and the catalog of every text in six languages. Nothing is translated after rendering.
internal/webui/assets/* templates and embedded assets of the daemon UI (see §7).
api.go routes of the native JSON API (/api/v1/...) and /ui/... pages.
api_qbit.go qBittorrent-compatible API (/api/v2/...).
cookies.go cookie store (settings page and the live jar used when fetching .torrent files and metadata).
setup.go guided first-start configuration (/ui/setup).
ui_feeds.go, ui_rss_edit.go RSS page: feeds (status, reload, edit, enable/disable), rules (edit, preview), indexers, RSS options.
feed.go, feed_search.go, wanted.go RSS engine: feed polling (including a single one), rules, Torznab searches, searched titles.
feed_archive.go, ui_archive.go feed archive (bbolt feed-archive.db with compact index) and Archive page.
ui_settings.go Settings page (folders, network, protocols, queue, bandwidth and scheduler).
ipfilter_refresh.go IP filter from a file or URL: loading at startup, periodic update, status.
optimize.go one-click optimisation (queue, cache, bandwidth) and measured peak status.
ui_browse.go server-side folder picker.
ui_wanted.go Wanted page: item cards, status badges and episode manager modal.
diskguard.go free space guard: unfinished downloads pause before the disk fills up.
autospeed.go standalone ping/latency auto-speed (anti-bufferbloat) upload bandwidth regulation.
latency_guard.go, line_usage.go, autotune_peaks.go managed Auto speed: Google/Cloudflare RTT probes, ramp/cut controller, optional user line maxima, router counters as diagnostics, peak recording for the tuning.
flaresolverr.go FlareSolverr integration for Cloudflare challenge clearance.
notify.go webhook notifications on rule matches and feed errors.
portmap.go, pcp.go port forwarding via UPnP, NAT-PMP and PCP (RFC 6887).
bep38.go BEP 38 hints (similar/collections) and discovery of local swarm merge candidates.
schedule.go bandwidth scheduler by day of week and time range.
stream.go media streaming server with HTTP Range requests.
standalone_auth.go standalone session tokens, password hashing and login management.
tracker_health.go tracker failure tracking and retry delay management.

7. eD2k and Kad through aMule (internal/amule)

Gextto does not run an eD2k engine of its own: it drives an amuled over the External Connections protocol. internal/amule is the EC client (framing, tag codec, salted MD5 login, one serialised connection that logs in again after a transport error). The Gextto side is in ed2ksearch.go, ed2k_downloads.go and uiweb_v2_ed2k.go; completed aMule files enter the same event loop as the torrents (web_background.go). See amule.md.

8. Assets embedded in the binary (go:embed)

  • uiweb/v2/templates/*.html, uiweb/v2/static/* — Gextto's web UI.
  • internal/webui/assets/* — gx-torrent daemon UI (ui.tmpl, login.html, setup.html, rss.html, settings.html, archive.html, token.html, wanted.html, theme.css, common.js, icons.svg, favicon.svg).
  • internal_translations*.yml — translations.
  • LICENSE — licence served by the app.

If you modify these files you need to recompile the binary to see them.

The user manual (docs/MANUAL.it.md, docs/MANUAL.en.md) and the changelog (changelog.md, changelog.en.md) are not embedded: the UI links the edition matching the interface language on GitHub. Editing them needs no rebuild; the old /?view=manual page redirects to the online manual.

9. Where to make changes (common tasks)

I want to... Files to touch
Add/modify an API endpoint web_router.go + a web_handlers_*.go (+ optional struct in web_inputs_extra.go)
Add a page or a UI widget uiweb_v2*.go + the template file of its subject in uiweb/v2/templates/ (shell.html, dashboard.html, downloads.html, detail.html, settings.html, health.html, ed2k.html, comics.html, tables.html, panels.html, misc.html, search.html, titles.html, …) (+ CSS/JS in uiweb/v2/static/)
Add a background worker web_serve.go (registration) + web_background.go or web_workers_media.go
Change the database schema database.go (+ tests) and, if needed, migrate.go
Add a setting config.go + uiweb_settings.go (section and Group) + uiweb_settings_meta.go (unit, special value, dependency) + uiweb_settings_defaults.go + uiweb_tooltips.go + internal_translations*.yml catalogues
Touch search/sources engine.go, rss.go, websearch.go, indexer_health.go
Touch a torrent engine torrent_engine*.go and the specific backend

10. Maintenance notes

  • Gextto's logic stays in a single main package. New shared modules go in internal/; any split of the main package must be done in phases, with builds and tests green at every step.
  • Update the tests. Every change in behaviour should update the test next to the file concerned; go test ./... is the safety net.

See also DEVELOPERS.md for build, test and contribution workflow.