Self-hosted Fider feedback board at feedback.nectenda.com #106

Closed
opened 2026-09-23 10:46:22 +01:00 by cruelacid · 1 comment
Owner

Why

Relay publishes a roadmap and release notes; Peerdraft publishes neither. A
public board where people post and vote on what gets built next is a signal the
product is alive and listening.

Self-hosting it is itself on-message. "Your feature requests do not go to a
SaaS vendor either" is a claim a hosted board cannot make, and GitHub Discussions
cannot make it either, because that route sends users to Microsoft.

Deferred — not being built now. The design below is done; this issue exists
so it is not re-derived. Featurebase's hosted equivalent puts SSO on its
Enterprise tier at $99/seat/month, which is more per month than the entire
infrastructure, so self-hosting remains the right answer whenever this is picked
up.

Why Fider, and not Featul

usefeatul/featul was evaluated first. It is MIT, does feedback + roadmap +
changelog in one, and would theme better (Tailwind 4, React 19). It was rejected
on evidence:

  • No Dockerfile and no compose file anywhere in the repo. The container would
    be ours to author, for a Bun/Turborepo monorepo of two Next.js 16 apps.
  • Its .env.example requires PostHog, Sentry, Upstash Redis, OpenRouter (an
    LLM key)
    , Cloudflare R2, a GitHub App, passkeys, Stripe with hardcoded plan
    price IDs, and a CMS. It is a SaaS codebase with the hosting wired in, not a
    self-hostable tool.
  • Repo created 15 January 2026, 13 stars, recent commits still cosmetic UI work.
  • It ships PostHog analytics by default — on the feedback board of a product
    whose pitch is that nobody is watching.

Fider: AGPL-3.0, 4,539 stars, active since 2017, Go binary plus Postgres,
official Docker images, Dockerfile and docker-compose.yml in-repo. Note its
releases page stops at 0.36.1 (July 2024) and looks abandoned — the commit
history does not: last commit 19 September 2026.

Design findings — do not re-derive these

Separate fider-postgres container, not a second database on GlitchTip's instance

Sharing was the first instinct and it is wrong. Every ops mechanism here is keyed
on a service name: deploy/console/actions.mjs:190 takes a snapshot when a
STATEFUL ops service is upgraded, so a shared instance makes "upgrade
glitchtip-postgres" an unannounced statement about Fider's storage too; and
snapshot.sh's pg() targets one container and one database from an env file
holding one credential pair. Cost of separating is near zero — same pinned
digest, so no extra layers, and the measured sibling is 32 MB.

Mount the parent (/srv/ops/fider-postgres:/var/lib/postgresql), per the
PG18 PGDATA comment already in the compose file, and carry the logging:
block every service there has.

Pin the tagged release, not :main

:main does not break deploy/inventory.mjs — it blinds it silently, which
is worse. tagLines('main') returns null, so compare() emits no lag flag and
no line flag, and the row reads ok with a blank mark, on a tag that moves per
commit. That is louislam/uptime-kuma:1 restated, against the file's own rule
that it "never reports a component as current on the strength of an absent
answer". Add a POLICY entry raising the staleness thresholds, since upstream
tags infrequently while main ships daily.

(The underlying checker gap is filed separately. Checked 23 September 2026:
every pin on the fleet today is numeric, so it is latent rather than live — but
this pin is exactly what would trip it.)

Two earlier readings that were wrong, recorded so they are not repeated

  • deploy/test/console.test.ts does not enforce pinned digests. Nothing
    does.
    renovate.json's pinDigests: true produces them. There is no test to
    reconcile and no allowlist to add.
  • verify-scrubber.sh is not weakened by a Fider database. It would sit
    outside pg_dump -d "$PD" either way, so nothing currently asserted becomes
    weaker. The real scrubber gap is the sign-in shim, filed separately.

AGPL-3.0 — two separate rules

  • §13's network source-offer obligation attaches when the operator modifies
    the program. So: no forked image, no baked-in patches, no compiled-in theme.
    Configure through env and the admin UI only. That keeps the obligation
    upstream's and the digest pin honest.
  • Separately, docs/positioning.md forbids "open source" of anything. Never
    describe the board's licence on nectenda.com at all
    — that is exactly where
    the word creeps in. Say what the board does; say nothing about licences.

Skinning

Logo upload plus custom CSS that changes "the design of nearly everything"
(v0.13+). Gilding tokens, and self-host Literata/Karla via @font-face — the
site removed the Google Fonts CDN deliberately, and reintroducing it on a
subdomain of a privacy product would undo that. This is skinning, not redesign;
the DOM stays Fider's.

SMTP

The existing ops credential is alerts@nectenda.com, documented as "one
internal-alerts credential". Fider sends customer-facing mail. Either give it
a feedback@ mailbox or reuse the credential with a distinct from-address and
write down that the sharing is deliberate. Do not let it default. Note the
smtp+ssl vs smtps trap already documented in glitchtip.env.example.

Remaining mechanics

Four-line Caddy vhost matching the existing shape (encode zstd gzip, bare
reverse_proxy — no lb_try_*, that is the shard/identity pattern); DNS A
record, DNS-only; fider.env.example committed and fider.env gitignored
explicitly, since .gitignore lists env files individually with no wildcard;
provision-ops.sh gains the write_files entry at 0600, the mkdir, an
extension of its placeholder-refusal loop, and the 32 KiB cloud-init guard that
provision-shard.sh has and it does not; UPGRADEABLE.ops and STATEFUL gain
both services; a Kuma monitor; deploy/README.md and deploy/UPGRADES.md
updated.

Capacity

Ops box is a cx23 at €5.49/month, 2 vCPU / 3.8 GB, measured 11 September 2026
at 440 MB of containers and ~1.0 GB of 3.8 GB used. Fider ~80 MB (single Go
binary, no worker), its Postgres ~35 MB → containers ~555 MB, ~2.7 GB free.
Headroom stays roughly fivefold. Incremental cost €0/month.

These are estimates and the baseline was an idle box. After it is up, run
docker stats --no-stream and free -m and paste the real numbers into
provision-ops.sh's comment block, where the last measurement lives.

Privacy — the part that matters most

Fider holds email, display name, and every post, comment and vote —
attributed, indefinitely, on a public page. That is a new processing purpose
and a new disclosure. docs/privacy.md needs a paragraph naming the board and
stating plainly that posts are public, a row in the location table
(Feedback board | Germany | our own servers) keeping the one-region claim true,
and a retention line.

Verify what Fider actually does on account deletion before writing that line.
If it deletes the user and leaves posts standing, say that, rather than promising
a removal the software does not perform.

A limit to write down rather than discover

Fider reports to nothing. It has no DSN and must not be modified to gain one,
so its exceptions exist only in docker compose logs fider, capped at 10m × 3.
Put that in UPGRADES.md as a known limit rather than an incident-time surprise.

Verification when this is picked up

  • caddy validate on the Caddyfile before pushing.
  • node deploy/inventory.mjs shows the pin with a real digest and a mark
    matching intent. A blank mark with IN LINE ? means the pin is wrong —
    that is the blinding failure, not a pass.
  • The real check is not that a login page renders: sign in, post an idea, vote
    on it, reload
    , then confirm a non-zero row count in fider-postgres
    directly.
## Why Relay publishes a roadmap and release notes; Peerdraft publishes neither. A public board where people post and vote on what gets built next is a signal the product is alive and listening. **Self-hosting it is itself on-message.** "Your feature requests do not go to a SaaS vendor either" is a claim a hosted board cannot make, and GitHub Discussions cannot make it either, because that route sends users to Microsoft. **Deferred — not being built now.** The design below is done; this issue exists so it is not re-derived. Featurebase's hosted equivalent puts SSO on its Enterprise tier at **$99/seat/month**, which is more per month than the entire infrastructure, so self-hosting remains the right answer whenever this is picked up. ## Why Fider, and not Featul `usefeatul/featul` was evaluated first. It is MIT, does feedback + roadmap + changelog in one, and would theme better (Tailwind 4, React 19). It was rejected on evidence: - **No Dockerfile and no compose file anywhere in the repo.** The container would be ours to author, for a Bun/Turborepo monorepo of two Next.js 16 apps. - Its `.env.example` requires PostHog, Sentry, Upstash Redis, **OpenRouter (an LLM key)**, Cloudflare R2, a GitHub App, passkeys, Stripe with hardcoded plan price IDs, and a CMS. It is a SaaS codebase with the hosting wired in, not a self-hostable tool. - Repo created 15 January 2026, 13 stars, recent commits still cosmetic UI work. - It ships **PostHog analytics by default** — on the feedback board of a product whose pitch is that nobody is watching. Fider: AGPL-3.0, 4,539 stars, active since 2017, Go binary plus Postgres, official Docker images, `Dockerfile` and `docker-compose.yml` in-repo. Note its *releases* page stops at 0.36.1 (July 2024) and looks abandoned — the commit history does not: last commit 19 September 2026. ## Design findings — do not re-derive these ### Separate `fider-postgres` container, not a second database on GlitchTip's instance Sharing was the first instinct and it is wrong. Every ops mechanism here is keyed on a **service name**: `deploy/console/actions.mjs:190` takes a snapshot when a `STATEFUL` ops service is upgraded, so a shared instance makes "upgrade `glitchtip-postgres`" an unannounced statement about Fider's storage too; and `snapshot.sh`'s `pg()` targets one container and one database from an env file holding one credential pair. Cost of separating is near zero — same pinned digest, so no extra layers, and the measured sibling is 32 MB. Mount the **parent** (`/srv/ops/fider-postgres:/var/lib/postgresql`), per the PG18 `PGDATA` comment already in the compose file, and carry the `logging:` block every service there has. ### Pin the tagged release, not `:main` `:main` does not break `deploy/inventory.mjs` — it **blinds it silently**, which is worse. `tagLines('main')` returns null, so `compare()` emits no `lag` flag and no `line` flag, and the row reads `ok` with a blank mark, on a tag that moves per commit. That is `louislam/uptime-kuma:1` restated, against the file's own rule that it "never reports a component as current on the strength of an absent answer". Add a `POLICY` entry raising the staleness thresholds, since upstream tags infrequently while `main` ships daily. *(The underlying checker gap is filed separately. Checked 23 September 2026: every pin on the fleet today is numeric, so it is latent rather than live — but this pin is exactly what would trip it.)* ### Two earlier readings that were wrong, recorded so they are not repeated - **`deploy/test/console.test.ts` does not enforce pinned digests. Nothing does.** `renovate.json`'s `pinDigests: true` produces them. There is no test to reconcile and no allowlist to add. - **`verify-scrubber.sh` is not weakened by a Fider database.** It would sit outside `pg_dump -d "$PD"` either way, so nothing currently asserted becomes weaker. The real scrubber gap is the sign-in shim, filed separately. ### AGPL-3.0 — two separate rules - §13's network source-offer obligation attaches when the operator **modifies** the program. So: no forked image, no baked-in patches, no compiled-in theme. Configure through env and the admin UI only. That keeps the obligation upstream's and the digest pin honest. - Separately, `docs/positioning.md` forbids "open source" of anything. **Never describe the board's licence on nectenda.com at all** — that is exactly where the word creeps in. Say what the board does; say nothing about licences. ### Skinning Logo upload plus custom CSS that changes "the design of nearly everything" (v0.13+). Gilding tokens, and self-host Literata/Karla via `@font-face` — the site removed the Google Fonts CDN deliberately, and reintroducing it on a subdomain of a privacy product would undo that. This is skinning, not redesign; the DOM stays Fider's. ### SMTP The existing ops credential is `alerts@nectenda.com`, documented as "one internal-alerts credential". Fider sends **customer-facing** mail. Either give it a `feedback@` mailbox or reuse the credential with a distinct from-address and write down that the sharing is deliberate. Do not let it default. Note the `smtp+ssl` vs `smtps` trap already documented in `glitchtip.env.example`. ### Remaining mechanics Four-line Caddy vhost matching the existing shape (`encode zstd gzip`, bare `reverse_proxy` — no `lb_try_*`, that is the shard/identity pattern); DNS A record, DNS-only; `fider.env.example` committed and `fider.env` gitignored **explicitly**, since `.gitignore` lists env files individually with no wildcard; `provision-ops.sh` gains the `write_files` entry at `0600`, the `mkdir`, an extension of its placeholder-refusal loop, and the 32 KiB cloud-init guard that `provision-shard.sh` has and it does not; `UPGRADEABLE.ops` and `STATEFUL` gain both services; a Kuma monitor; `deploy/README.md` and `deploy/UPGRADES.md` updated. ### Capacity Ops box is a **cx23 at €5.49/month**, 2 vCPU / 3.8 GB, measured 11 September 2026 at 440 MB of containers and ~1.0 GB of 3.8 GB used. Fider ~80 MB (single Go binary, no worker), its Postgres ~35 MB → containers ~555 MB, ~2.7 GB free. Headroom stays roughly fivefold. **Incremental cost €0/month.** These are estimates and the baseline was an **idle** box. After it is up, run `docker stats --no-stream` and `free -m` and paste the real numbers into `provision-ops.sh`'s comment block, where the last measurement lives. ### Privacy — the part that matters most Fider holds email, display name, and every post, comment and vote — **attributed, indefinitely, on a public page.** That is a new processing purpose *and a new disclosure*. `docs/privacy.md` needs a paragraph naming the board and stating plainly that posts are public, a row in the location table (`Feedback board | Germany | our own servers`) keeping the one-region claim true, and a retention line. **Verify what Fider actually does on account deletion before writing that line.** If it deletes the user and leaves posts standing, say that, rather than promising a removal the software does not perform. ### A limit to write down rather than discover **Fider reports to nothing.** It has no DSN and must not be modified to gain one, so its exceptions exist only in `docker compose logs fider`, capped at 10m × 3. Put that in `UPGRADES.md` as a known limit rather than an incident-time surprise. ## Verification when this is picked up - `caddy validate` on the Caddyfile before pushing. - `node deploy/inventory.mjs` shows the pin with a real digest and a mark matching intent. **A blank mark with `IN LINE ?` means the pin is wrong** — that is the blinding failure, not a pass. - The real check is not that a login page renders: sign in, **post an idea, vote on it, reload**, then confirm a non-zero row count in `fider-postgres` directly.
cruelacid added this to the Marketing project 2026-09-23 10:48:13 +01:00
Author
Owner

Moved to the Vikunja board as NEC-82: https://projectron.nerchure.com/tasks/82

Moved to the Vikunja board as **NEC-82**: https://projectron.nerchure.com/tasks/82
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Nectenda/nectenda#106
No description provided.