장단콩 보드게임 & 미니어처 게임 클럽

자동 트로피 수여 Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 일정 마감과 참석 확정의 순서에 관계없이 모든 실제 참석 기반 트로피를 자동 수여한다.

Architecture: posts/{postId} 트리거가 참석자 변경 또는 이벤트 마감을 감지해, 마감된 이벤트의 확정 참석자 uid를 중복 없이 다시 판정한다. 기존 awardTrophies로 신규 업적만 추가한다.

Tech Stack: Firebase Cloud Functions v2, Firestore, Node node:test.

Global Constraints

Task 1: 마감·확정 순서 독립적인 참석 트리거

Files:

Interfaces:

const { trophyEligibleConfirmedUids } = require("./index.js");

test("trophyEligibleConfirmedUids: 마감 전 확정은 제외하고 마감 시 확정 참석자를 반환한다", () => {
  const before = { type: "event", confirmedAttendees: ["u1"] };
  const after = { type: "event", confirmedAttendees: ["u1"], closedAt: new Date() };
  assert.deepStrictEqual(trophyEligibleConfirmedUids(before, after), ["u1"]);
});

test("trophyEligibleConfirmedUids: 마감 후 참석 확정 시 변경된 전체 확정 참석자를 반환한다", () => {
  const before = { type: "event", closedAt: new Date(), confirmedAttendees: ["u1"] };
  const after = { type: "event", closedAt: new Date(), confirmedAttendees: ["u1", "u2", "u2"] };
  assert.deepStrictEqual(trophyEligibleConfirmedUids(before, after), ["u1", "u2"]);
});

Run: node --test functions/index.test.js

Expected: FAIL because trophyEligibleConfirmedUids is not exported.

function trophyEligibleConfirmedUids(beforeData, afterData) {
  if (!afterData || afterData.type !== "event" || !afterData.closedAt) return [];
  const attendeesChanged = confirmedAttendeesChanged(beforeData, afterData);
  const justClosed = becamePostClosed(beforeData, afterData);
  if (!attendeesChanged && !justClosed) return [];
  return [...new Set(afterData.confirmedAttendees || [])];
}

Export the helper. Make onPostConfirmed use its result and return when empty; retain its existing Firestore query, candidate calculation, and awardTrophies call. This replaces the separate early return based only on confirmedAttendeesChanged.

Run: node --test functions/index.test.js functions/trophies.test.js

Expected: PASS.

git add functions/index.js functions/index.test.js
git commit -m "fix: award attendance trophies when events close"

Task 2: 배포와 누락 복구

Run: node --test functions/*.test.js && node --test assets/js/*.test.mjs

Run: firebase deploy --only functions:onPostConfirmed

Open /stats/ as administrator and select “트로피 소급 재계산”; confirm the result includes no failed users.