Ryan 6b06e08c08 BidaAngMamayan: public supporter tribute news desk for Senator BAM Aquino
Forked from Forthena (PERSONAL/forthena) and retargeted:
- NO login, NO LLM: the edition is public and the ranking is deterministic
  (stories that name Sen. BAM lead; freshest first) — Daniel: no
  like/dislike or store profile for visitors.
- Crawler scoped to BAM: Bing news keyword queries + Inquirer/Rappler
  fallback wires, with a two-tier relevance gate (named-BAM always;
  Aquino+legislative-context only from fallback) so op-eds and non-Bam
  senators are dropped.
- Desks: BAM (lead), Gaming, Education, Politics, Energy, PH, Business.
- Community board /board: 'Thank you Senator BAM' — nickname-only posts,
  HTML-stripped, URL-only rejected, IP rate-limited (3/10min, 20/day).
- Yellow-gamer theme (Orbitron/Rajdhani/JetBrains Mono, dark + gold,
  HUD corners), supporter disclaimer in header and footer.
- Tests: category/date/relevance/text suites + Mongo board suite +
  full HTTP e2e (all passing).

Infra: 66.181.46.132 (bidaangmamamayan.com), local Mongo 7.0,
nginx + certbot TLS, PM2 bama (:3000) + 15-min crawl cron.
2026-09-15 08:37:03 +00:00

38 lines
1.3 KiB
JavaScript

import { NextResponse } from "next/server";
// The community board — "Thank you Senator BAM".
// GET -> the last 200 posts, newest first.
// POST -> { nick, message } (nickname only, no account — by design).
//
// Public by nature; the controls live in lib/board.js (rate limit per IP,
// content caps, markup stripping, URL-only rejection).
export const dynamic = "force-dynamic";
export async function GET() {
try {
const { getBoard, boardCount } = await import("../../../lib/board");
const [posts, count] = await Promise.all([getBoard(), boardCount()]);
return NextResponse.json({ ok: true, posts, count });
} catch (e) {
return NextResponse.json({ ok: false, error: "board unavailable" }, { status: 500 });
}
}
export async function POST(req) {
let body;
try {
body = await req.json();
} catch {
return NextResponse.json({ ok: false, error: "expected json" }, { status: 400 });
}
try {
const { postBoard } = await import("../../../lib/board");
const r = await postBoard(req, body);
return NextResponse.json(r, { status: r.ok ? 200 : r.status });
} catch (e) {
console.warn("[bama] board post failed:", String((e && e.message) || e).slice(0, 160));
return NextResponse.json({ ok: false, error: "could not post right now" }, { status: 500 });
}
}