fider Documentation

Open platform to collect and prioritize feedback

4,585 stars Go Go 4 files ยท ~2,692 tokens #customer#feature-request#feedback#ideas#suggestions
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy fider on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name fider -p 8025:8025 --restart always mailhog/mailhog:latest
Configured Services & Ports
โš™๏ธ smtp
image: mailhog/mailhog:latest
๐Ÿ”Œ Ports: 8025:8025, 1025:1025
โš™๏ธ pgdev
image: postgres:17
๐Ÿ”Œ Ports: 5555:5432
โš™๏ธ pgtest
image: postgres:17
๐Ÿ”Œ Ports: 5566:5432
โš™๏ธ s3test
image: minio/minio:RELEASE.2021-07-27T02-40-15Z
๐Ÿ”Œ Ports: 9000:9000, 9001:9001
docker-compose.yml
yaml (docker-compose.yml)
version: "3"
services:
  smtp:
    image: mailhog/mailhog:latest
    restart: always
    ports:
      - "8025:8025"
      - "1025:1025"
  pgdev:
    container_name: fider_pgdev
    restart: always
    image: postgres:17
    volumes:
      - pgdev-data:/var/lib/postgresql/data
    ports:
      - "5555:5432"
    environment:
      POSTGRES_USER: fider
      POSTGRES_PASSWORD: fider_pw
  pgtest:
    container_name: fider_pgtest
    restart: always
    image: postgres:17
    ports:
      - "5566:5432"
    environment:
      POSTGRES_USER: fider_test
      POSTGRES_PASSWORD: fider_test_pw
  s3test:
    container_name: fider_s3test
    restart: always
    image: minio/minio:RELEASE.2021-07-27T02-40-15Z
    ports:
      - "9000:9000"
      - "9001:9001"
    volumes:
      - s3test-data:/data
    environment:
      MINIO_ACCESS_KEY: s3user
      MINIO_SECRET_KEY: s3user-s3cr3t
    command: server /data --console-address ":9001"

volumes:
  pgdev-data:
  s3test-data:

Technical Documentation: getfider/fider

โ„น๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference

Overview (`README.md`)

Fider is a feedback portal for feature requests and suggestions.

Give your customers a voice and let them tell you what they need. Spend less time guessing and more time building the right product.

Getting Started

โ˜๏ธ **Fider Cloud**

The easiest and quickest way to get started. A fully managed services by the creators of Fider to help you get started in minutes. Forget about managing software updates and patches, we do it all for you! Sign up now

๐Ÿข **Self-Hosted**

Install Fider on your own servers, in your own infrastructure. It's totally free, but of course you're responsible for everything. Learn how

If you do self-host and enjoy Fider, please let us know where you're using it - we really appreciate it ๐Ÿ™

๐Ÿ’ฐ Donations and Sponsors

Support the development of Fider to help us make it the best feedback tool! You can set up donations as small or large as you want to help us keep Fider going. Donate

If your organization uses Fider, consider becoming a sponsor - set up a monthly donation and get your logo and link on the README. Become a sponsor

Contributors

This project exists thanks to all the amazing people who contribute!

Read our CONTRIBUTING guide to learn how you can contribute to Fider.


Overview (`locale/README.md`)

Adding a New Language to Fider ๐Ÿ’ช

This guide explains how to add a new language/locale to Fider.

Overview

All locale definitions are centralized in app/models/enum/locale.go. This is the single source of truth for backend locale metadata including locale codes, display names, pluralization rules, PostgreSQL text search configurations, and language detection mappings.

Step 1: Create Translation Files

  1. Create a new directory in /locale with the locale code (e.g., ko for Korean, pt-BR for Brazilian Portuguese)

  2. Create two JSON files in the new directory:

    • client.json - Frontend translations (UI strings)
    • server.json - Backend translations (emails, server-side messages)

The easiest way to do this is copy the english files, and remove all the translations, replacing them with ones in your language.

Step 2: Add Locale to Backend (Go)

Edit app/models/enum/locale.go:

  1. Add a new locale constant:

    go
    LocaleKorean = Locale{
        Code:              "ko",                 // Locale code
        Name:              "Korean",             // Display name
        MessageFormatCode: "ko",                 // Pluralization library culture code
        PostgresConfig:    "simple",             // PostgreSQL text search config
        LinguaLanguage:    lingua.Korean,        // Lingua-go language enum
        IsRTL:             false,                // Right-to-left text direction
    }
  2. Add the new locale to the AllLocales slice:

    go
    AllLocales = []Locale{
        LocaleEnglish,
        LocalePortugueseBR,
        // ... other locales
        LocaleKorean,  // Add your new locale here
    }

Field Explanations

  • Code: The locale code (e.g., "en", "pt-BR", "ko")
  • Name: Human-readable name shown in language selector
  • MessageFormatCode: Culture code for the messageformat library (used for pluralization)
  • PostgresConfig: PostgreSQL text search configuration name (see PostgreSQL docs)
    • Available configs: "english", "german", "french", "spanish", "portuguese", "italian", "dutch", "russian", "swedish", "turkish", "arabic"
    • Use "simple" if PostgreSQL doesn't have native support for your language
  • LinguaLanguage: The lingua-go enum for automatic language detection
    • See lingua-go documentation for available languages
  • IsRTL: Set to true for right-to-left languages (Arabic, Hebrew, Persian, etc.)

Step 3: Add Locale to Frontend

  1. Update locale/locales.ts

Add your locale to the locales object:

typescript
const locales: { [key: string]: Locale } = {
  en: {
    text: "English",
  },
  // ... other locales
  ko: {
    text: "Korean",
  },
}
  1. Update lingui.config.js

Add your locale code to the locales array:

javascript
locales: ["pt-BR", "es-ES", "nl", /* ... other locales, */ "ko"],
  1. Update public/ssr.tsx

Add your locale to the messages object for server-side rendering:

typescript
const messages: { [key: string]: any } = {
  en: require(`../locale/en/client`),
  // ... other locales
  ko: require(`../locale/ko/client`),
}

Step 4: Generate and Compile Translations

After adding the locale to all configuration files:

  1. Check that everything works..

    bash
    make build
  2. Run the server:

    bash
    make run
  3. Verify:

    • The new language appears in the language selector
    • Translations display correctly
    • Right-to-left rendering works (if applicable)
    • Search functionality works with the correct PostgreSQL configuration
  4. Open a pull request

When New Translation Strings Are Added

Fider uses LinguiJS for i18n management. When new features are added:

  1. New translation keys are automatically extracted and added to all locale files (client.json / server.json)
  2. A GitHub Action uses Google Cloud Translate to automatically translate missing keys
  3. Machine translations are submitted as a pull request for review

While the automated translations work well for most cases, you may want to refine them for accuracy and cultural context. Feel free to submit pull requests with improved translations at any time.


Overview (`app/services/sqlstore/dbEntities/README.md`)

dbEntities Package

This package contains database entity mapping structs that convert PostgreSQL query results to domain models.

Purpose

The dbEntities package provides a centralized location for database-to-model conversion logic, separating data mapping concerns from the business logic in the postgres package.

Exported Types

User (and UserProvider)

The User type is exported so it can be used across packages:

go
import "github.com/getfider/fider/app/services/sqlstore/dbEntities"

var user dbEntities.User
err := trx.Get(&user, "SELECT id, name, email... FROM users WHERE id = $1", userID)
if err != nil {
    return err
}

// Convert to entity.User
entityUser := user.ToModel(ctx)

Unexported Types

All other types (comment, post, tag, tenant, etc.) are unexported (lowercase) and only used internally by the postgres package. They can be exported later if needed by simply capitalizing the type name and its toModel method.

Testing

The package includes unit tests for the exported User type. Run them with:

bash
godotenv -f .test.env go test ./app/services/sqlstore/dbEntities/...

OAUTH ROLE RESTRICTION (`docs/OAUTH_ROLE_RESTRICTION.md`)

OAuth Role-Based Access Control

This feature allows you to restrict OAuth login to users who have specific roles provided by your OAuth provider.

Role restrictions are configured per custom OAuth provider in the Admin UI.
This means different providers can have completely independent role requirements.

Configuration

Admin Panel

  1. Go to Site Settings โ†’ Authentication โ†’ OAuth Providers
  2. Edit or create a custom OAuth provider
  3. Configure two fields together:
    • JSON User Roles Path โ€” the path in the provider's profile JSON where roles are found
    • Allowed Roles โ€” a comma-separated list of roles that are permitted to sign in

Both fields must be set for the role check to run. If either is empty, all users are allowed through for that provider.

Allowed Roles field format

  • Comma-separated list of role names, e.g. ROLE_ADMIN,ROLE_TEACHER
  • Case-sensitive: role names are matched exactly as they appear in the OAuth response
  • Leave empty to allow all users (default)

Examples

Allow only admins:

text
ROLE_ADMIN

Allow admins and teachers:

text
ROLE_ADMIN,ROLE_TEACHER

Allow all users (default):

Leave the Allowed Roles field empty.

JSON User Roles Path

The roles path tells Fider where to find roles in the OAuth profile response.

Examples

Single role as string:

json
{
  "id": "12345",
  "role": "ROLE_ADMIN"
}

JSON User Roles Path: role

Comma-separated string:

json
{
  "id": "12345",
  "roles": "ROLE_ADMIN,ROLE_TEACHER"
}

JSON User Roles Path: roles

Array of strings:

json
{
  "id": "12345",
  "name": "John Doe",
  "email": "[email protected]",
  "roles": ["ROLE_ADMIN", "ROLE_TEACHER"]
}

JSON User Roles Path: roles

Array of objects (extract specific field):

json
{
  "id": "12345",
  "roles": [
    { "id": "ROLE_ADMIN", "displayName": "Administrator" },
    { "id": "ROLE_TEACHER", "displayName": "Teacher" }
  ]
}

JSON User Roles Path: roles[].id

This extracts the id field from each object in the roles array.

Nested array:

json
{
  "user": {
    "profile": {
      "roles": ["ROLE_ADMIN"]
    }
  }
}

JSON User Roles Path: user.profile.roles

Nested array of objects:

json
{
  "id": "12345",
  "user": {
    "groups": [
      { "name": "ROLE_ADMIN" },
      { "name": "ROLE_USER" }
    ]
  }
}

JSON User Roles Path: user.groups[].name


--- METRICS ---