Feedback App¶
Reusable feedback collection and lightweight feature-request infrastructure.
The app keeps the legacy Feedback contact-form model working, while adding a
small product-feedback layer for reviewable requests, votes, and comments.
Core Concepts¶
Legacy Feedback¶
Feedback remains a simple contact-form submission model:
from htk.apps.feedback.models import Feedback
feedback = Feedback.objects.create(
site=site,
user=user,
name='Jane',
email='jane@example.com',
comment='This page was confusing.',
uri='/dashboard',
)
The legacy API endpoint remains available:
POST /feedback/submit
FeedbackRequest¶
A request is the central reviewable item: feature request, bug report, content
issue, support question, or general feedback. New requests default to private
and needs_review=True; publish them only after staff review.
from htk.apps.feedback.constants import FEEDBACK_REQUEST_TYPE_FEATURE
from htk.apps.feedback.models import FeedbackRequest
feedback = FeedbackRequest.objects.create(
site=site,
created_by=user,
request_type=FEEDBACK_REQUEST_TYPE_FEATURE,
title='Add saved searches',
description='I would like to save searches and return to them later.',
source_uri='/search',
context={
'app': 'example-app',
'surface': 'search-results',
},
)
Bug Reports: User/Page State¶
For bug reports, downstream apps should submit structured context that makes the report reproducible. Keep files/uploads in the consuming app until there is a clear shared storage policy.
Suggested generic context:
{
"app": "example-app",
"surface": "search-results",
"path": "/search?q=grace",
"query": "grace",
"viewport": {"width": 1440, "height": 900},
"app_version": "2026.07.21"
}
API Endpoints¶
The app uses plain Django views and HTK JSON helpers, not DRF. Existing URL style omits trailing slashes.
List requests¶
GET /feedback/requests?q=search&type=feature_request&status=planned&order=popular
Response includes public, non-hidden, non-spam requests for normal users. Staff users may see private/hidden items.
Find likely duplicates¶
GET /feedback/requests/matches?q=saved%20searches
Use this while a user is typing a title/body so they can find an existing idea to vote on instead of creating a duplicate.
Submit a request¶
POST /feedback/requests/submit
Content-Type: application/json
{
"type": "feature_request",
"title": "Add saved searches",
"description": "I would like to save searches and return to them later.",
"context": {
"surface": "search-results"
}
}
Form-encoded submissions are also supported. Public-facing submissions default
to visibility=private and needs_review=true; non-staff users cannot
self-publish by passing visibility=public. Staff may intentionally set
visibility=public and needs_review=false after review.
Detail¶
GET /feedback/requests/<id>
Returns the request plus public comments.
Vote / unvote¶
POST /feedback/requests/<id>/vote
POST /feedback/requests/<id>/unvote
Authenticated users can vote once per request, with value=1 for an upvote
and value=-1 for a downvote. Omitting value preserves legacy upvote
behavior. Anonymous voting is intentionally not supported; require login so
the vote row only needs a user FK.
Comment¶
POST /feedback/requests/<id>/comment
Public comments are available by default. Staff users may pass
is_internal=true for staff-only comments.
Staff status update¶
POST /feedback/requests/<id>/status
Staff-only. Changes the request status directly.
My requests¶
GET /feedback/requests/my
Authenticated users can see requests they created or voted for.
Admin¶
The feature-request models live in the Django admin under Htk Feedback so downstream apps can use the shared HTK feedback infrastructure without making the models look product-owned.
The legacy Feedback contact-form model is registered in admin by default for backward compatibility. Downstream apps that only want the request/vote/comment surface can hide it with:
HTK_FEEDBACK_ENABLE_LEGACY_ADMIN = False
This setting only controls admin registration for the legacy model; it does not change migrations, tables, or public imports.
Model File Layout¶
Feedback uses the standard multi-model app package layout:
models/
├── __init__.py
├── feedback.py
├── feedback_legacy.py
├── vote.py
└── comment.py
Import from htk.apps.feedback.models unless you specifically need an internal model file. models/__init__.py is the stable public surface and imports every model explicitly.
Model Shape¶
FeedbackRequest— idea/feature/bug/content/support/general request.FeedbackRequestVote— one active upvote/downvote row per authenticated user.FeedbackRequestComment— public or internal discussion.
Integration Notes¶
- Keep new submissions private by default and publish only reviewed, public-safe requests.
- Keep status lightweight; add richer workflow only when a real queue needs it.
- Scope every request by
site. - Do not duplicate authenticated identity snapshots; use the
created_by/userFKs. - Keep anonymous request submission contact-free for now. Add app-local contact capture only when a real follow-up workflow exists.
- Add async email/webhook delivery in consuming apps or future HTK work.
- Use
contextJSON for app-specific page state andmetadataJSON for staff/integration-only data.