# Breakdown of epic-platform-and-sign-in. The order of the tables is the build order. [[entry]] id = 1 type = "story" title = "Project scaffold, configuration and container" description = "Creates the Django project, environment-variable configuration that refuses to start when invalid, the multi-stage Docker image and compose file, a health check that does not call AD, JSON logging, security headers with a strict content-security policy, and the test setup with adapter fakes." verify = "The container starts with valid environment variables, refuses to start with an invalid one, and answers its health check on the Linux host." covers = ["CAP-10"] after = [] hitl = false risk = "medium" plan_checkpoint = true references = ["_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-13", "_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-18"] [[entry]] id = 2 type = "story" title = "Prepare the test environment" description = "A person creates a test OU in the production AD with a service account scoped to it and the delegated rights from the spine, supplies the internal CA bundle, creates a dedicated OIDC application in the production authentik restricted to test users, notes the Zoraxy route and trusted-proxy value, and prepares a test mailbox." verify = "The service account can read and write a test user in the test OU over LDAPS, the authentik application lets a test user sign in, and the values are written down for the build." covers = ["CAP-1"] after = [] hitl = true risk = "medium" notes = ["Authentik is production only; never change an existing authentik application.", "I can set up a test OU, but not a separate authentik."] [[entry]] id = 3 type = "story" title = "Audit, throttle and session foundations" description = "Builds the audit service, database-backed throttle counters, and server-side sessions with the username in its own column and a kill-by-user function; the other epics write audit entries and end sessions through these." verify = "Tests show an audit entry is written in the same transaction as a change, a throttle refuses after its limit, and ending a user's sessions removes every session of that user." covers = ["CAP-1", "CAP-8"] after = [1] hitl = false risk = "medium" references = ["_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-4", "_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-6", "_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-7"] [[entry]] id = 4 type = "story" title = "Directory adapter" description = "Builds the only code that talks to AD: lookup by sAMAccountName in the configured OU, group membership, account state, password verification, password policy read and the allow-listed writes, with an in-memory fake; sign-in and the account features call its interface." verify = "Against the test OU the adapter reads and writes allowed attributes over LDAPS with certificate verification, refuses others, and returns the password policy." covers = ["CAP-1", "CAP-2", "CAP-3"] after = [1, 2] hitl = false risk = "high" plan_checkpoint = true references = ["_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-1", "_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-2"] notes = ["Test only against the test OU, never the production OU."] [[entry]] id = 5 type = "story" title = "Sign-in with OIDC and roles" description = "Implements sign-in through the identity provider with the authorization-code flow, session creation, roles from AD group membership with a short cache, refusal of disabled or locked accounts, and the trusted-proxy client IP rule, using the directory adapter's interface." verify = "A test user signs in through authentik and reaches a page showing their own name; a user outside the Publisher and Admin groups cannot open those pages; a disabled account is refused." covers = ["CAP-1"] after = [2, 3, 4] 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-5", "_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-7"] [[entry]] id = 6 type = "story" title = "Page shell, preferences and translations" description = "Builds the base layout with the Fluent components bundled into the image: top bar, left menu with role-based groups, avatar menu for theme, language and German form of address, German and English text, light and dark themes, and the phone layout." verify = "After sign-in the shell shows the user's name, the menu groups match their role, the three preferences persist per device, and the layout works at phone width." covers = ["CAP-9"] after = [5] hitl = false risk = "medium" references = ["_bmad-output/ux-designs/ux-ping-mee-self-service-platform-2026-10-15/mockups/key-dashboard.html", "_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-15", "_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-16"] [[entry]] id = 7 type = "story" title = "Scheduler and mail outbox" description = "Builds the single 30-second scheduler tick with idempotent jobs and job-run records, the mailer adapter with the outbox, retries, backoff and rate limit, and a fake mailer; other epics only call its enqueue function." verify = "A queued test e-mail is sent through the configured SMTP server, a failed send is retried and recorded, and a restart sends nothing twice." covers = ["CAP-6", "CAP-10"] after = [3] hitl = false risk = "medium" references = ["_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-11", "_bmad-output/architecture/architecture-ping-mee-self-service-platform-2026-10-15/ARCHITECTURE-SPINE.md#ad-12"] [[entry]] id = 8 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 7 are resolved or recorded." covers = [] after = [1, 2, 3, 4, 5, 6, 7] hitl = false risk = "low"