[Story-1047] Add forum CRUD backend

Story 1047Epic None10 files · +1180/−32

PR #260 · pramaan-io/pramaan-functions · merged 2026-06-05

How it flows

sequenceDiagram
  autonumber
  participant client as Client
  participant router as Router
  participant service as Service
  participant db as DB
  client->>router: POST /app/forums
  router->>service: create_forum
  service->>service: resolve current user
  service->>service: trim + dup check
  service->>db: insert row
  service-->>client: ForumView
  service->>service: PATCH: omit vs null
  service->>service: DELETE: reference check

app-api.json · +446 — new methods

Methodin → outwhat it does
_current_user_id(session) → UUID
_key_for_name(name) → str
_find_duplicate_name(session, firm_id, name, excluding_forum_id) → Forum | None

What changed, file by file

Owns create/update/delete for firm forums — duplicate-name checks, reference checks, and the 403/409 error paths.

new methodsignature
_current_user_id(session) → UUID
_key_for_name(name) → str
_find_duplicate_name(session, firm_id, name, excluding_forum_id) → Forum | None
_get_visible_forum(session, forum_id) → Forum
_get_editable_firm_forum(session, forum_id, firm_id) → Forum
_raise_if_name_conflict(session, firm_id, name, excluding_forum_id) → None
_is_referenced(session, forum_id, firm_id) → bool
create_forum(session, payload) → ForumView
update_forum(session, forum_id, payload) → ForumView
delete_forum(session, forum_id) → None

Defines the request DTOs and the source enum — name and description get trimmed, description is capped at 512 characters.

new classsignature
ForumSource(class)
ForumCreateRequest(class)
_trim_name(value) → str | None
_trim_description(value) → str | None
ForumUpdateRequest(class)
New fields: name : str | Nonedescription : str | Noneavailability : ForumAvailability | Nonesource : ForumSourcefirm_id : UUID | None

Exposes POST/PATCH/DELETE for /app/forums, wiring the new service methods to the FastAPI surface.

new methodsignature
create_forum(req, db, _) → ForumView
update_forum(forum_id, req, db, _) → ForumView
delete_forum(forum_id, db, _) → Response

Adds a nullable description text column to business.forums, keyed as the 0072 Alembic migration.

new methodsignature
upgrade() → None
downgrade() → None
New fields: revision : strdown_revision : str | Sequence[str] | Nonebranch_labels : str | Sequence[str] | Nonedepends_on : str | Sequence[str] | None

Adds the optional description column onto the Forum ORM entity so it can be persisted and read back.

New fields: description : str | None

Failure cases, walled off

System venues stay read-only
Name conflicts surface early
Description capped at 512
PATCH must spell out omit vs null
Reference check blocks deletes

Files changed (10)

File±
alembic/versions/7b9d0f2a6c41_0072_forum_description.py+33
docs/walkthroughs/story-1047-walkthrough.html+94
openapi/app-api.json ★+446
src/domains/forum/dtos/__init__.py+7 −1
src/domains/forum/dtos/forum.py ★+79 −3
src/domains/forum/entity.py+8
src/domains/forum/router.py+55 −3
src/domains/forum/service.py ★+259 −3
tests/contract/test_app_forums_openapi.py+22 −8
tests/integration/test_app_forums.py+177 −14