# Breakdown of epic-account-self-service. The order of the tables is the build order. # Entries 1 to 6 carry the spec stories 7 to 11; the test-share preparation and the closing sweep are added. [[entry]] id = 1 type = "story" title = "Password change" description = "Builds the password page with the Active Directory password policy listed before the user types, the current-password check after the throttle with the attempt cap, the LDAPS change, ending the user's other sessions, an audit entry and the confirmation e-mail through the outbox." verify = "A test user changes their password against the test OU with the policy shown first, a policy rejection is shown in plain words with no change, five wrong current passwords block further tries, the user's other sessions end and the confirmation e-mail arrives." covers = ["CAP-2", "CAP-8"] after = [] hitl = false risk = "high" plan_checkpoint = true done_checkpoint = true references = ["_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-2", "_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-3", "_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-8", "_bmad-output/ux-designs/ux-ping-mee-self-service-platform-2026-10-15/mockups/key-password.html"] notes = ["Test only against the test OU.", "Never log, store or audit a password.", "Adds the German text for every new string and a mail template in German formal."] [[entry]] id = 2 type = "story" title = "Profile edit" description = "Builds the profile page for first name, last name, display name, telephone and mobile with validation, LDAP escaping, the allow-listed write, an audit entry, and the account data read from the directory." verify = "A test user edits the five fields and the values appear in the matching AD attributes of the test user; injection strings change nothing else; a request naming another user is impossible by construction." covers = ["CAP-3", "CAP-8"] after = [] hitl = false risk = "medium" references = ["_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-2", "_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-3", "_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-4"] [[entry]] id = 3 type = "story" title = "E-mail change with confirmation and undo" description = "Builds the e-mail change flow: current password, a confirmation page reached from a link to the new address, a notice with a 24-hour undo link to the old address, and the undo effects (restore, end sessions, notify the Admin). Tokens are hashed at rest and single use; a link opened with GET changes nothing." verify = "A test user changes the e-mail address only after the current password and a confirmation from the new address; the old address receives an undo link whose use restores the address, ends the sessions and notifies the Admin; an opened link alone changes nothing." covers = ["CAP-3", "CAP-8"] after = [2] hitl = false risk = "high" references = ["_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-8", "_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-9"] notes = ["Confirmation links last 1 hour and undo links 24 hours.", "Pending e-mail change tokens are owned by the profile app (AD-19)."] [[entry]] id = 4 type = "story" title = "Prepare the picture share test environment" description = "A person provides a test source folder and a test processed folder on the Linux host that the existing sync task or a stand-in for it reads and writes, mounts them for the container, and notes the paths and how a processed MD5 file is produced." verify = "A file written to the test source folder is picked up by the sync task or stand-in, and the matching processed MD5 file appears; the paths are written down for the build." covers = ["CAP-4"] after = [] hitl = true risk = "medium" notes = ["Never write to the production source folder while testing.", "The existing PowerShell scripts stay unchanged."] [[entry]] id = 5 type = "story" title = "Picture backend" description = "Builds upload validation, decoding of JPEG, PNG, HEIC and WebP with size and pixel limits, orientation, metadata removal, square 512 by 512 JPEG re-encoding, the share adapter with atomic writes and timeouts and an in-memory fake, and the stored MD5 state with the Pending rule." verify = "Against the test folders a valid upload is written as .jpg atomically, an SVG, an oversized or corrupt file is refused with a reason, and Pending clears when the processed MD5 matches." covers = ["CAP-4", "CAP-8"] after = [4] hitl = false risk = "high" plan_checkpoint = true references = ["_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-10"] notes = ["Pin the HEIC library after checking current versions.", "Never store or serve the original upload.", "Open question to confirm at first use: early clearing of Pending after a failed AD write by the sync script (PRD Q-9)."] [[entry]] id = 6 type = "story" title = "Picture screens" description = "Builds the picture page with in-browser cropping and adjusting, the current picture, the Pending chip and the two-hour note read from the share and the database, the longer-than-expected message, and removal." verify = "A test user uploads a photo, crops it, sees Pending until the sync task has processed it, then sees the new picture, and can remove it; a refused file shows its reason before upload." covers = ["CAP-4"] after = [5] hitl = false risk = "medium" references = ["_bmad-output/ux-designs/ux-ping-mee-self-service-platform-2026-10-15/mockups/key-picture-pending.html"] [[entry]] id = 7 type = "story" title = "Refactor sweep" description = "Cleans up the epic's code using the plans and the review findings deferred during the epic; scope pushed out of another story is a new story, not part of this one." verify = "The test suite still passes and the deferred review findings from entries 1 to 6 are resolved or recorded." covers = [] after = [1, 2, 3, 4, 5, 6] hitl = false risk = "low"