feat: add author-username search to feed/gists/projects listings and partial-index migration

Extend `database.text_search_clause` with an `author_field` parameter that resolves username matches to user UIDs, enabling author-username search across the three public listings (`/feed`, `/gists`, `/projects`). Update the corresponding API docs and README route descriptions to reflect the new search scope. Add six partial indexes (`idx_comments_target_live`, `idx_votes_target_live`, `idx_reactions_target_live`, `idx_gists_live_created`, `idx_projects_live_created`, `idx_attachments_user_created_live`) to optimize filtered queries on non-deleted rows. Introduce a hot-settings cache (`_hot_settings`) with a 2-second TTL for `maintenance_mode`, `rate_limit_per_minute`, and `rate_limit_window_seconds`, plus a periodic rate-limit store sweep (`_sweep_rate_limit_store`) to evict stale IP entries every 60 seconds. Add `GZipMiddleware` to the FastAPI app for response compression.
This commit is contained in:
2026-06-19 22:24:51 +00:00
parent d10f1af118
commit e393722600
22 changed files with 269 additions and 52 deletions
+2 -2
View File
@@ -401,11 +401,11 @@ class BaseService(ABC):
def _metrics(self, state: dict) -> dict:
raw = state.get("metrics")
if not raw:
return {}
return self._safe_metrics()
try:
return json.loads(raw)
except (ValueError, TypeError):
return {}
return self._safe_metrics()
def describe(self) -> dict:
state = self._read_state()
+3 -3
View File
@@ -112,7 +112,7 @@ ACTIONS: tuple[Action, ...] = (
params=(
query("tab", "Feed tab to view."),
query("topic", "Filter by topic."),
query("search", "Search post title and content."),
query("search", "Search post title, content, and author username."),
query("before", "Pagination cursor."),
),
),
@@ -222,7 +222,7 @@ ACTIONS: tuple[Action, ...] = (
requires_auth=False,
params=(
query("tab", "Projects tab."),
query("search", "Search query."),
query("search", "Search project title, description, and author username."),
query("user_uid", "Filter by owner uid."),
query("project_type", "Filter by project type."),
query("before", "Pagination cursor."),
@@ -1107,7 +1107,7 @@ ACTIONS: tuple[Action, ...] = (
params=(
query("language", "Filter by language."),
query("user_uid", "Filter by owner uid."),
query("search", "Search gist title and description."),
query("search", "Search gist title, description, and author username."),
query("before", "Pagination cursor."),
),
),
+3 -1
View File
@@ -59,7 +59,9 @@ def list_rants(sort: str, limit: int, skip: int, viewer: Optional[dict]) -> list
def search_rants(term: str, viewer: Optional[dict], limit: int = 50) -> list:
posts_table = get_table("posts")
clause = text_search_clause(posts_table, term, ("title", "content"))
clause = text_search_clause(
posts_table, term, ("title", "content"), author_field="user_uid"
)
if clause is None:
return []
posts = list(
@@ -23,7 +23,6 @@ LINKER_MAX_TOKENS = 600
MAX_CONTEXT_CHARS = 11000
SCORE_MAX = 100
CONFIDENCE_BASELINE = 0.35
DIVERSITY_PAGES_PER_DOMAIN = 2.0
@dataclass
@@ -50,7 +49,7 @@ def source_diversity(pages: list) -> float:
domains.discard("")
if not domains:
return 0.0
ratio = len(domains) / max(1.0, len(pages) / DIVERSITY_PAGES_PER_DOMAIN)
ratio = len(domains) / len(pages)
return round(min(1.0, ratio), 3)