Skip to main content

Memories & Comments

What it is​

activity-log owns event "memories" — photo/video uploads guests and planners post to an event, plus reactions and moderation reporting. comment-service provides threaded comments on top of any entity (memories primarily), using the same interestId-scoping pattern as Chat.

Core concepts​

  • A memory is a specific kind of activity log entry (type='memory') — activity logs are the broader concept, but memory upload is the one that matters most: it's what feeds the Points system (both host and guest points are earned specifically by memory uploads), and it's the one users interact with via reactions, comments, and reports.
  • getExploreMemories is a cross-event public feed (GET /activity-log/explore-memories) — distinct from getEventMemories which is scoped to one event's planners/guests (isEventPlannerOrGuest()).
  • 3 reports auto-deletes a memory. Reporting is community-moderated, not just a flag for manual review — once a memory accumulates 3 unique reporters, it's automatically soft-deleted, no admin action required.
  • Comments use the same entityType-entityKey interestId scoping as chat, but note the delimiter differs: comment-service splits on -, chat splits on :. They're separate implementations of a similar idea, not a shared utility — don't assume an interestId string is interchangeable between the two modules.

How it works​

Memories​

  • POST /activity-log/events/:eventId — planner-created activity log entry (not necessarily a memory).
  • Guest memory upload goes through a dedicated endpoint (see Points for how upload triggers async point issuance via Pub/Sub).
  • GET /activity-log/events/:eventId/memories — list, accessible to planners or guests of that event.
  • DELETE /activity-log/events/:eventId/memories/:memoryId — same dual planner-or-guest access as listing (likely restricted further to the memory's own uploader at the service layer — verify before assuming any guest can delete any memory).
  • POST .../memories/:memoryId/reactions, POST .../activityId/:activityId/reactions — reactions on memories vs. general activity log entries are separate endpoints, not unified.
  • POST .../memories/:memoryId/report — moderation: a guest or planner flags a memory with a reason/description, handled by activityLogService.reportMemory. Each report increments a unique-reporter count (memory_reports table, one row per (memoryId, reportedBy) pair, DB-enforced so the same user can't report twice); hitting 3 auto-soft-deletes the memory. The creator gets a push + email notification after every report (1/3, 2/3, then a distinct "removed" notification at 3), not just at the threshold.
  • GET /event/memory-shareable — the picker list for "which event can I post a memory to," segmented into liveEvents (currently between start/end time) and pastEvents (ended), each independently sorted (soonest-first for live, most-recent-first for past). An event only appears if the caller is its creator, an accepted co-planner, or a guest — upcoming (not yet started) and archived events never appear, even for the creator.
  • GET /activity-log/events/:eventId/seen — read-tracking (which activity log entries this user has already seen), likely backing an unread-count/badge in the client.

The explore feed's relevance sources​

GET /activity-log/explore-memories merges up to seven sources into one personalized feed: memories from contact users directly, memories from events created by a contact, memories from events where a contact is an accepted co-planner, the caller's own memories, memories from the caller's own created events, memories from events the caller co-plans, and memories from events the caller attended as a guest (matched by user ID, email, or phone — so it still surfaces events you were invited to before you had an account). keepMemoriesPrivate (see Events & Event Types) is enforced as a filter across all seven sources, not just the contact-based ones — being someone's contact never overrides a private event's access list.

Comments​

Standard threaded-comment shape scoped by interestId: GET/POST /:interestId/comments, GET /:interestId/comments/count, GET/POST /:interestId/comments/:commentId/replies (one level of nesting), POST /:interestId/comments/:commentId/like (toggle), DELETE /:interestId/comments/:commentId.

Key business rules & edge cases​

  • Reactions on a memory and reactions on a general activity log entry go through different endpoints — if you're adding reaction support to a new entity type, check which of the two patterns actually applies rather than assuming one covers both.
  • The auto-delete threshold (3 reports) is a fixed constant, not per-event configurable — a small, tightly-knit event group could hit it faster (proportionally) than a large public one; there's no admin override endpoint to un-delete a wrongly-removed memory documented yet, only a soft-delete flag in the database.
  • If extending comment-service or chat to share logic, reconcile the interestId delimiter difference (- vs :) first — copy-pasting a chat interestId into a comment-service call (or vice versa) will fail to parse.

GET /v1/activity-log/explore-memories, GET /v1/activity-log/events/{eventId}/memories, POST /v1/activity-log/events/{eventId}/memories/{memoryId}/report, GET /v1/event/memory-shareable, GET /v1/comments/{interestId}/comments, POST /v1/comments/{interestId}/comments. Not yet in the generated OpenAPI spec.

  • src/modules/activity-log/activity-log.routes.ts, activity-log.controllers.ts, activity-log-service.ts
  • src/repositories/activitylog.repository.ts — findExploreMemoriesWithUserDetails
  • src/modules/comment-service/comment.routes.ts, comment.controller.ts — parseInterestId
  • Cross-reference: src/modules/points/host-points-issuance.service.ts, guest-points-issuance.service.ts — triggered by memory uploads