Each cycle holds an arbitrary number of markdown documents (briefs,
runbooks, handbooks, generated reports). Admins and leads create / edit /
delete; testers and observers read only. Inline media (images, video, PDF
attachments) is supported via the same DO Spaces upload pipeline.
AC-1 โ Given an admin/lead, when they POST a new doc, then a row
is inserted with kind โ {doc,brief,runbook,report} and the doc is
selected in the sidebar.
AC-2 โ Given a tester (cycle member, role=tester), when they
open the Docs tab, then docs are visible read-only (no edit/delete buttons).
AC-3 โ Given a non-member, when they call GET /api/test-cycles/:id/documents,
then the API returns 403.
AC-4 โ Given a markdown image is dropped into the editor, when the
upload completes, then a public DO Spaces URL is inserted into the
body and the rendered view shows the image inline.
AC-5 โ Given a doc has attachments, when the doc is deleted, then
attachments are cascade-deleted (verify on attachments table).
AC-6 โ Given the cycle is closed (status=closed), when the AI
cycle-close agent finishes, then a new doc with kind='report' exists
containing the AI summary (see F-14).
AC-7 โ Given the seed seed:tc-onboarding runs on container
startup, when the Hackorda Onboarding cycle exists, then its two
docs (handbook + test cases) are upserted from docs/qa/*.md (slug
uniqueness on (test_cycle_id, slug)).
Images are public-read in DO Spaces โ fine for our threat model, not
for confidential client cycles. Encrypted/private bucket flagged in
feature-matrix.md ยง5.4.
ProseMirror block-based editing deferred (markdown for v1).